PKR9N# 33prp/__init__.py"""PRP - a Python runner""" __version__ = '0.2.0' PK+aNhhprp/__main__.py# Enable ``python -m piptools ...``. if __name__ == '__main__': from prp.cli import main main() PKSNO͂G"G"prp/appdirs.py""" This code was taken from https://github.com/ActiveState/appdirs and modified to suit our purposes. """ import os import sys WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt") def expanduser(path): """ Expand ~ and ~user constructions. Includes a workaround for http://bugs.python.org/issue14768 """ expanded = os.path.expanduser(path) if path.startswith("~/") and expanded.startswith("//"): expanded = expanded[1:] return expanded def user_cache_dir(appname): r""" Return full path to the user-specific cache dir for this application. "appname" is the name of application. Typical user cache directories are: macOS: ~/Library/Caches/ Unix: ~/.cache/ (XDG default) Windows: C:\Users\\AppData\Local\\Cache On Windows the only suggestion in the MSDN docs is that local settings go in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming app data dir (the default returned by `user_data_dir`). Apps typically put cache data somewhere *under* the given dir here. Some examples: ...\Mozilla\Firefox\Profiles\\Cache ...\Acme\SuperApp\Cache\1.0 OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. """ if WINDOWS: # Get the base path path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) # Add our app name and Cache directory to it path = os.path.join(path, appname, "Cache") elif sys.platform == "darwin": # Get the base path path = expanduser("~/Library/Caches") # Add our app name to it path = os.path.join(path, appname) else: # Get the base path path = os.getenv("XDG_CACHE_HOME", expanduser("~/.cache")) # Add our app name to it path = os.path.join(path, appname) return path def user_data_dir(appname, roaming=False): r""" Return full path to the user-specific data dir for this application. "appname" is the name of application. If None, just the system directory is returned. "roaming" (boolean, default False) can be set True to use the Windows roaming appdata directory. That means that for users on a Windows network setup for roaming profiles, this user data will be sync'd on login. See for a discussion of issues. Typical user data directories are: macOS: ~/Library/Application Support/ Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined Win XP (not roaming): C:\Documents and Settings\\ ... ...Application Data\ Win XP (roaming): C:\Documents and Settings\\Local ... ...Settings\Application Data\ Win 7 (not roaming): C:\Users\\AppData\Local\ Win 7 (roaming): C:\Users\\AppData\Roaming\ For Unix, we follow the XDG spec and support $XDG_DATA_HOME. That means, by default "~/.local/share/". """ if WINDOWS: const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" path = os.path.join(os.path.normpath(_get_win_folder(const)), appname) elif sys.platform == "darwin": path = os.path.join(expanduser("~/Library/Application Support/"), appname) else: path = os.path.join( os.getenv("XDG_DATA_HOME", expanduser("~/.local/share")), appname ) return path def user_config_dir(appname, roaming=True): """Return full path to the user-specific config dir for this application. "appname" is the name of application. If None, just the system directory is returned. "roaming" (boolean, default True) can be set False to not use the Windows roaming appdata directory. That means that for users on a Windows network setup for roaming profiles, this user data will be sync'd on login. See for a discussion of issues. Typical user data directories are: macOS: same as user_data_dir Unix: ~/.config/ Win *: same as user_data_dir For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. That means, by default "~/.config/". """ if WINDOWS: path = user_data_dir(appname, roaming=roaming) elif sys.platform == "darwin": path = user_data_dir(appname) else: path = os.getenv("XDG_CONFIG_HOME", expanduser("~/.config")) path = os.path.join(path, appname) return path # for the discussion regarding site_config_dirs locations # see def site_config_dirs(appname): r"""Return a list of potential user-shared config dirs for this application. "appname" is the name of application. Typical user config directories are: macOS: /Library/Application Support// Unix: /etc or $XDG_CONFIG_DIRS[i]// for each value in $XDG_CONFIG_DIRS Win XP: C:\Documents and Settings\All Users\Application ... ...Data\\ Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) Win 7: Hidden, but writeable on Win 7: C:\ProgramData\\ """ if WINDOWS: path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) pathlist = [os.path.join(path, appname)] elif sys.platform == "darwin": pathlist = [os.path.join("/Library/Application Support", appname)] else: # try looking in $XDG_CONFIG_DIRS xdg_config_dirs = os.getenv("XDG_CONFIG_DIRS", "/etc/xdg") if xdg_config_dirs: pathlist = [ os.path.join(expanduser(x), appname) for x in xdg_config_dirs.split(os.pathsep) ] else: pathlist = [] # always look in /etc directly as well pathlist.append("/etc") return pathlist # -- Windows support functions -- def _get_win_folder_from_registry(csidl_name): """ This is a fallback technique at best. I'm not sure if using the registry for this guarantees us the correct answer for all CSIDL_* names. """ import _winreg shell_folder_name = { "CSIDL_APPDATA": "AppData", "CSIDL_COMMON_APPDATA": "Common AppData", "CSIDL_LOCAL_APPDATA": "Local AppData", }[csidl_name] key = _winreg.OpenKey( _winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", ) directory, _type = _winreg.QueryValueEx(key, shell_folder_name) return directory def _get_win_folder_with_ctypes(csidl_name): csidl_const = { "CSIDL_APPDATA": 26, "CSIDL_COMMON_APPDATA": 35, "CSIDL_LOCAL_APPDATA": 28, }[csidl_name] buf = ctypes.create_unicode_buffer(1024) ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) # Downgrade to short path name if have highbit chars. See # . has_high_char = False for c in buf: if ord(c) > 255: has_high_char = True break if has_high_char: buf2 = ctypes.create_unicode_buffer(1024) if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): buf = buf2 return buf.value if WINDOWS: try: import ctypes _get_win_folder = _get_win_folder_with_ctypes except ImportError: _get_win_folder = _get_win_folder_from_registry def _win_path_to_bytes(path): """Encode Windows paths to bytes. Only used on Python 2. Motivation is to be consistent with other operating systems where paths are also returned as bytes. This avoids problems mixing bytes and Unicode elsewhere in the codebase. For more details and discussion see . If encoding using ASCII and MBCS fails, return the original Unicode path. """ for encoding in ("ASCII", "MBCS"): try: return path.encode(encoding) except (UnicodeEncodeError, LookupError): pass return path PK8Nć.. prp/cli.pyimport os import shlex import sys import venv from argparse import ArgumentParser, Namespace from subprocess import Popen from prp import config from prp import utils def parse_args(args=None) -> Namespace: parser = ArgumentParser("prp", description="Run a command in a virtualenv") parser.add_argument( "-v", "--venv", nargs="?", const="", help="The virtualenv" ) parser.add_argument("cmd", nargs="+", help="The command to run") return parser.parse_args() def main(): args = parse_args() print(args) cmd = args.cmd cmd_name = cmd[0] alias = config.get_alias(cmd_name) if alias is not None: cmd = shlex.split(alias) + cmd[1:] if args.venv == "": venv_path = utils.get_virtualenv_path() print(venv_path) elif args.venv is not None: if os.path.exists(args.venv): venv_path = args.venv else: venv_path = utils.get_virtualenv_path() else: venv_path = utils.get_virtualenv_path() if not venv_path.exists(): print(f"Creating {venv_path}") venv.EnvBuilder(with_pip=True).create(venv_path) # Add the virtualenv to PYTHONPATH sys.path.insert(0, str(venv_path)) # Add the virtualenv bin directory to PATH os.environ["PATH"] = os.pathsep.join( [str(venv_path.joinpath("bin")), os.environ["PATH"]] ) with Popen(cmd, bufsize=0, universal_newlines=True): # print to flush buffers and get a new command promp print("", end="") if __name__ == "__main__": main() PKaNX prp/config.pyfrom functools import lru_cache from pathlib import Path import toml @lru_cache() def _load_pyproject_toml(): pyproject_path = Path(Path.cwd(), "pyproject.toml") with open(pyproject_path, 'r') as f: d = toml.load(f) return d.get('tool', {}).get('prp', {}) def get(key, default=None): config = _load_pyproject_toml() return config.get(key, default) def get_alias(name): d = _load_pyproject_toml() return d.get('aliases', {}).get(name, None) PKaNMb9 prp/utils.pyimport sys from pathlib import Path import prp.config as config from prp.appdirs import user_cache_dir def get_virtualenv_path() -> Path: unique_name = get_unique_name() return Path( user_cache_dir('prp'), 'virtualenvs', unique_name ) def get_unique_name() -> str: name = config.get('name') if name is None: raise ValueError('The applications name is not defined ' 'in pyproject.toml [tool.prp]') python_version = config.get('python_version') if python_version is None: python_version = '.'.join([ sys.version_info.major, sys.version_info.major ]) return f'{name}-py{python_version}' PK!HG$$$prp-0.2.0.dist-info/entry_points.txtN+I/N.,()*(*bL<..PK[NY PPprp-0.2.0.dist-info/LICENSEThe MIT License (MIT) Copyright (c) 2019 Brett Adams Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HPOprp-0.2.0.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,szd&Y)r$[)T&UrPK!H4prp-0.2.0.dist-info/METADATAURr1 +4!.INiKP@@am ݿ\iN$/uY?1DC^-|<,ʡZ'kukX=  $0odz/f>mِ5U.=7 (˧'jy0nW@MWåB|̕3J&`,.iX~xqꡚbl,F 9FŦ"+qtlԤ1Aibi-0NA 5LyIfIR彘mn7)@5nsIy C4^ӎ:+f2>7۠_:,v0JS5]0^336ϪI@"p2"(@OIh㮣s 97^Й#™q'aH1;' WFwwS]昇c#)PK!Hiprp-0.2.0.dist-info/RECORDm˒@| 8B.fAC@TdC!(IL&e*{zZ.fĴi8o ѪW@7ɪ}PZ'X+uθHUjYdV=%D${zNʎb.ǒƠRx2эH81S6v/͟5+$aze濉 4yQbi.[/J1F{_xT}G'wZF w.P:u+QlMi o5,el>fv,-H]3UIuӶ!f w[뤄՜b"ֳڌ~I={·;2Ͳt2dS%S')MY?U16>Eݻ.1 my~> 0tڣ~\k,W_z&vDYtOrIcThJ#ʙѠsp Q[θf'3PKR9N# 33prp/__init__.pyPK+aNhh`prp/__main__.pyPKSNO͂G"G"prp/appdirs.pyPK8Nć.. h#prp/cli.pyPKaNX )prp/config.pyPKaNMb9 +prp/utils.pyPK!HG$$$.prp-0.2.0.dist-info/entry_points.txtPK[NY PP-/prp-0.2.0.dist-info/LICENSEPK!HPO3prp-0.2.0.dist-info/WHEELPK!H4=4prp-0.2.0.dist-info/METADATAPK!Hi'6prp-0.2.0.dist-info/RECORDPK f8