def test_restore_success(): with temp_chdir() as d: runner = CliRunner() env_name, fake_name = get_new_venv_name(count=2) venv_origin = os.path.join(d, env_name) venv_dir = os.path.join(get_venv_dir(), env_name) fake_venv = os.path.join(get_venv_dir(), fake_name) create_venv(venv_origin) copy_path(venv_origin, get_venv_dir()) os.makedirs(fake_venv) try: runner.invoke(hatch, ['env', env_name]) wait_until(is_venv, venv_dir) result = runner.invoke(hatch, ['env', '-r']) with venv(venv_dir): install_packages(['six']) installed_packages = get_installed_packages() finally: remove_path(venv_dir) remove_path(fake_venv) assert result.exit_code == 0 assert 'Successfully restored all available virtual envs.' in result.output assert 'six' in installed_packages
def test_get_new_venv_name_multiple(): current_names = os.listdir(get_venv_dir()) if os.path.exists( get_venv_dir()) else [] new_names = get_new_venv_name(2) assert len(new_names) == 2 assert new_names[0] not in current_names assert new_names[1] not in current_names
def test_envs(): with temp_chdir(): runner = CliRunner() env_name1, env_name2 = get_new_venv_name(count=2) venv_dir1 = os.path.join(get_venv_dir(), env_name1) venv_dir2 = os.path.join(get_venv_dir(), env_name2) create_venv(venv_dir1) try: result = runner.invoke(hatch, [ 'init', '-ne', '--basic', 'ok', '-e', '{}/{}'.format( env_name1, env_name2) ]) wait_until(is_venv, venv_dir2) with venv(venv_dir1): assert 'ok' in get_editable_packages() with venv(venv_dir2): assert 'ok' in get_editable_packages() finally: remove_path(venv_dir1) remove_path(venv_dir2) assert result.exit_code == 0 assert 'Creating virtual env `{}`... complete!'.format( env_name1) not in result.output assert 'Creating virtual env `{}`... complete!'.format( env_name2) in result.output assert 'Installing locally in virtual env `{}`... complete!'.format( env_name1) in result.output assert 'Installing locally in virtual env `{}`... complete!'.format( env_name2) in result.output
def list_envs(ctx, param, value): if not value or ctx.resilient_parsing: return venvs = get_available_venvs() if venvs: echo_success('Virtual environments found in `{}`:\n'.format( get_venv_dir())) for venv_name, venv_dir in venvs: with venv(venv_dir): echo_success('{} ->'.format(venv_name)) if value == 1: echo_info(' Version: {}'.format(get_python_version())) elif value == 2: echo_info(' Version: {}'.format(get_python_version())) echo_info(' Implementation: {}'.format( get_python_implementation())) else: echo_info(' Version: {}'.format(get_python_version())) echo_info(' Implementation: {}'.format( get_python_implementation())) echo_info(' Local packages: {}'.format(', '.join( sorted(get_editable_packages())))) # I don't want to move users' virtual environments # temporarily for tests as one may be in use. else: # no cov echo_failure('No virtual environments found in `{}`. To create ' 'one do `hatch env NAME`.'.format(get_venv_dir())) ctx.exit()
def test_env_multiple(): with temp_chdir(): runner = CliRunner() env_name1, env_name2 = get_new_venv_name(count=2) venv_dir1 = os.path.join(get_venv_dir(), env_name1) venv_dir2 = os.path.join(get_venv_dir(), env_name2) try: runner.invoke(hatch, ['env', env_name1]) wait_until(is_venv, venv_dir1) assert os.path.exists(venv_dir1) runner.invoke(hatch, ['env', env_name2]) wait_until(is_venv, venv_dir2) assert os.path.exists(venv_dir2) result = runner.invoke(hatch, ['shed', '-e', '{}/{}'.format(env_name1, env_name2)]) assert not os.path.exists(venv_dir1) assert not os.path.exists(venv_dir2) finally: remove_path(venv_dir1) remove_path(venv_dir2) assert result.exit_code == 0 assert 'Successfully removed virtual env named `{}`.'.format(env_name1) in result.output assert 'Successfully removed virtual env named `{}`.'.format(env_name2) in result.output
def test_clone_success(): with temp_chdir(): runner = CliRunner() origin, clone = get_new_venv_name(count=2) origin_dir = os.path.join(get_venv_dir(), origin) clone_dir = os.path.join(get_venv_dir(), clone) try: runner.invoke(hatch, ['env', origin]) wait_until(is_venv, origin_dir) with venv(origin_dir): install_packages(['requests']) result = runner.invoke(hatch, ['env', '-c', origin, clone]) wait_until(is_venv, clone_dir) with venv(clone_dir): install_packages(['six']) installed_packages = get_installed_packages() finally: remove_path(origin_dir) remove_path(clone_dir) assert result.exit_code == 0 assert 'Successfully cloned virtual env `{}` from `{}` to `{}`.'.format( clone, origin, clone_dir) in result.output assert 'requests' in installed_packages assert 'six' in installed_packages
def fix_available_venvs(): if not os.path.exists(get_venv_dir()): # no cov return for name in sorted(os.listdir(get_venv_dir())): try: fix_venv(os.path.join(get_venv_dir(), name)) except InvalidVirtualEnv: pass
def get_available_venvs(): venvs = [] if not os.path.exists(get_venv_dir()): # no cov return venvs for name in sorted(os.listdir(get_venv_dir())): venv_dir = os.path.join(get_venv_dir(), name) if is_venv(venv_dir): venvs.append((name, venv_dir)) return venvs
def test_pyname_and_env(): with temp_chdir() as d: runner = CliRunner() env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) try: runner.invoke(hatch, ['env', env_name]) wait_until(is_venv, venv_dir) assert os.path.exists(venv_dir) with temp_move_path(SETTINGS_FILE, d): settings = copy_default_settings() settings['pypaths']['pyname'] = 'pypath' save_settings(settings) result = runner.invoke(hatch, ['shed', '-p', 'pyname', '-e', env_name]) assert load_settings()['pypaths'] == {} assert not os.path.exists(venv_dir) finally: remove_path(venv_dir) assert result.exit_code == 0 assert 'Successfully removed Python path named `pyname`.' in result.output assert 'Successfully removed virtual env named `{}`.'.format(env_name) in result.output
def get_new_venv_name(count=1): if not os.path.exists(get_venv_dir()): # no cov if count == 1: return get_random_venv_name() else: return sorted(get_random_venv_name() for _ in range(count)) current_venvs = set(p.name for p in os.scandir(get_venv_dir())) new_venvs = set() while len(new_venvs) < count: name = get_random_venv_name() while name in current_venvs or name in new_venvs: # no cov name = get_random_venv_name() new_venvs.add(name) return new_venvs.pop() if count == 1 else sorted(new_venvs)
def test_list_success_1(): with temp_chdir(): runner = CliRunner() env_name1, env_name2 = get_new_venv_name(count=2) venv_dir1 = os.path.join(get_venv_dir(), env_name1) venv_dir2 = os.path.join(get_venv_dir(), env_name2) try: runner.invoke(hatch, ['env', env_name1]) wait_until(is_venv, venv_dir1) os.makedirs(venv_dir2) result = runner.invoke(hatch, ['env', '-l']) finally: remove_path(venv_dir1) remove_path(venv_dir2) assert result.exit_code == 0 assert ('{} ->\n' ' Version: {}'.format(env_name1, get_python_version())) in result.output
def test_list_success_3(): with temp_chdir(): runner = CliRunner() runner.invoke(hatch, ['init', 'ok', '-ne']) env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) try: runner.invoke(hatch, ['env', env_name]) wait_until(is_venv, venv_dir) runner.invoke(hatch, ['install', '-l', '-e', env_name]) result = runner.invoke(hatch, ['env', '-lll']) finally: remove_path(os.path.join(get_venv_dir(), env_name)) assert result.exit_code == 0 assert ('{} ->\n' ' Version: {}\n' ' Implementation: {}\n' ' Local packages: {}'.format(env_name, get_python_version(), get_python_implementation(), 'ok')) in result.output
def test_success(): with temp_chdir(): runner = CliRunner() env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) try: result = runner.invoke(hatch, ['env', env_name]) wait_until(is_venv, venv_dir) assert os.path.exists(venv_dir) finally: remove_path(venv_dir) assert result.exit_code == 0 assert 'Successfully saved virtual env `{}` to `{}`.'.format( env_name, venv_dir) in result.output
def test_env(): with temp_chdir(): runner = CliRunner() env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) create_venv(venv_dir) try: with venv(venv_dir): assert 'six' not in get_installed_packages() result = runner.invoke(hatch, ['install', '-e', env_name, 'six']) with venv(venv_dir): assert 'six' in get_installed_packages() finally: remove_path(venv_dir) assert result.exit_code == 0
def test_existing_venv(): with temp_chdir(): runner = CliRunner() env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) try: runner.invoke(hatch, ['env', env_name]) wait_until(is_venv, venv_dir) result = runner.invoke(hatch, ['env', env_name]) finally: remove_path(venv_dir) assert result.exit_code == 1 assert ('Virtual env `{name}` already exists. To remove ' 'it do `hatch shed -e {name}`.'.format( name=env_name)) in result.output
def test_env(): with temp_chdir(): runner = CliRunner() env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) create_venv(venv_dir) try: with venv(venv_dir): install_packages(['requests==2.17.3']) initial_version = get_version_as_bytes('requests') result = runner.invoke(hatch, ['update', '-e', env_name, '--all']) with venv(venv_dir): final_version = get_version_as_bytes('requests') finally: remove_path(venv_dir) assert result.exit_code == 0 assert initial_version < final_version
def test_pyname(): with temp_chdir() as d: runner = CliRunner() env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) try: with temp_move_path(SETTINGS_FILE, d): settings = copy_default_settings() settings['pypaths']['python'] = sys.executable save_settings(settings) result = runner.invoke(hatch, ['init', 'ok', '-py', 'python']) venv_dir = os.path.join(d, 'venv') global_version = get_python_version() wait_until(is_venv, venv_dir) with venv(venv_dir): assert get_python_version() == global_version finally: remove_path(venv_dir) assert result.exit_code == 0
def test_pyname(): with temp_chdir() as d: runner = CliRunner() env_name = get_new_venv_name() venv_dir = os.path.join(get_venv_dir(), env_name) try: with temp_move_path(SETTINGS_FILE, d): settings = copy_default_settings() settings['pypaths']['python'] = sys.executable save_settings(settings) result = runner.invoke(hatch, ['env', '-py', 'python', env_name]) wait_until(is_venv, venv_dir) assert os.path.exists(venv_dir) finally: remove_path(venv_dir) assert result.exit_code == 0 assert 'Successfully saved virtual env `{}` to `{}`.'.format( env_name, venv_dir) in result.output
def update(packages, no_detect, env_name, eager, all_packages, infra, global_install, admin, force, dev, as_module, self, quiet): """If the option --env is supplied, the update will be applied using that named virtual env. Unless the option --global is selected, the update will only affect the current user. Of course, this will have no effect if a virtual env is in use. The desired name of the admin user can be set with the `_DEFAULT_ADMIN_` environment variable. When performing a global update, your system may use an older version of pip that is incompatible with some features such as --eager. To force the use of these features, use --force. With no packages nor options selected, this will update packages by looking for a `requirements.txt` or a dev version of that in the current directory. If no --env is chosen, this will attempt to detect a project and use its virtual env before resorting to the default pip. No project detection will occur if a virtual env is active. To update this tool, use the --self flag. All other methods of updating will ignore `hatch`. See: https://github.com/pypa/pip/issues/1299 """ command = ['install', '--upgrade'] + (['-q'] if quiet else []) if not global_install or force: # no cov command.extend(['--upgrade-strategy', 'eager' if eager else 'only-if-needed']) infra_packages = ['pip', 'setuptools', 'wheel'] temp_dir = None # Windows' `runas` allows only a single argument for the # command so we catch this case and turn our command into # a string later. windows_admin_command = None if self: # no cov as_module = True if not self and env_name: venv_dir = os.path.join(get_venv_dir(), env_name) if not os.path.exists(venv_dir): echo_failure('Virtual env named `{}` does not exist.'.format(env_name)) sys.exit(1) with venv(venv_dir): executable = ( [get_proper_python(), '-m', 'pip'] if as_module or (infra and ON_WINDOWS) else [get_proper_pip()] ) command = executable + command if all_packages: installed_packages = infra_packages if infra else get_installed_packages() else: installed_packages = None elif not self and not venv_active() and not no_detect and is_project(): venv_dir = os.path.join(os.getcwd(), get_venv_folder()) if not is_venv(venv_dir): echo_info('A project has been detected!') echo_waiting('Creating a dedicated virtual env... ', nl=False) create_venv(venv_dir) echo_success('complete!') with venv(venv_dir): echo_waiting('Installing this project in the virtual env... ', nl=False) install_packages(['-q', '-e', '.']) echo_success('complete!') with venv(venv_dir): executable = ( [get_proper_python(), '-m', 'pip'] if as_module or (infra and ON_WINDOWS) else [get_proper_pip()] ) command = executable + command if all_packages: installed_packages = infra_packages if infra else get_installed_packages() else: installed_packages = None else: venv_dir = None executable = ( [sys.executable if self else get_proper_python(), '-m', 'pip'] if as_module or (infra and ON_WINDOWS) else [get_proper_pip()] ) command = executable + command if all_packages: installed_packages = infra_packages if infra else get_installed_packages() else: installed_packages = None if not venv_active(): # no cov if global_install: if not admin: if ON_WINDOWS: windows_admin_command = get_admin_command() else: command = get_admin_command() + command else: command.append('--user') if self: # no cov command.append('hatch') if ON_WINDOWS: echo_warning('After the update you may want to press Enter to flush stdout.') subprocess.Popen(command, shell=NEED_SUBPROCESS_SHELL) sys.exit() else: result = subprocess.run(command, shell=NEED_SUBPROCESS_SHELL) sys.exit(result.returncode) elif infra: command.extend(infra_packages) elif all_packages: installed_packages = [ package for package in installed_packages if package not in infra_packages and package != 'hatch' ] if not installed_packages: echo_failure('No packages installed.') sys.exit(1) command.extend(installed_packages) elif packages: packages = [package for package in packages if package != 'hatch'] if not packages: echo_failure('No packages to install.') sys.exit(1) command.extend(packages) # When https://github.com/pypa/pipfile is finalized, we'll use it. else: reqs = get_requirements_file(os.getcwd(), dev=dev) if not reqs: echo_failure('Unable to locate a requirements file.') sys.exit(1) with open(reqs, 'r') as f: lines = f.readlines() matches = [] for line in lines: match = re.match(r'^[^=<>]+', line.lstrip()) if match and match.group(0) == 'hatch': matches.append(line) if matches: for line in matches: lines.remove(line) temp_dir = TemporaryDirectory() reqs = os.path.join(temp_dir.name, basepath(reqs)) with open(reqs, 'w') as f: f.writelines(lines) command.extend(['-r', reqs]) if windows_admin_command: # no cov command = windows_admin_command + [' '.join(command)] if venv_dir: with venv(venv_dir): if env_name: echo_waiting('Updating virtual env `{}`...'.format(env_name)) else: echo_waiting('Updating for this project...') result = subprocess.run(command, shell=NEED_SUBPROCESS_SHELL) else: echo_waiting('Updating...') result = subprocess.run(command, shell=NEED_SUBPROCESS_SHELL) if temp_dir is not None: temp_dir.cleanup() sys.exit(result.returncode)
def env(name, pyname, pypath, global_packages, clone, verbose, restore, show): """Creates a new virtual env that can later be utilized with the `shell` command. \b $ hatch pypath -l py2 -> /usr/bin/python py3 -> /usr/bin/python3 $ hatch env -l No virtual environments found in /home/ofek/.virtualenvs. To create one do `hatch env NAME`. $ hatch env my-app Already using interpreter /usr/bin/python3 Successfully saved virtual env `my-app` to `/home/ofek/.virtualenvs/my-app`. $ hatch env -py py2 old Successfully saved virtual env `old` to `/home/ofek/.virtualenvs/old`. $ hatch env -pp ~/pypy3/bin/pypy fast Successfully saved virtual env `fast` to `/home/ofek/.virtualenvs/fast`. $ hatch env -ll Virtual environments found in /home/ofek/.virtualenvs: \b fast -> Version: 3.5.3 Implementation: PyPy my-app -> Version: 3.5.2 Implementation: CPython old -> Version: 2.7.12 Implementation: CPython """ if pyname: try: settings = load_settings() except FileNotFoundError: echo_failure( 'Unable to locate config file. Try `hatch config --restore`.') sys.exit(1) pypath = settings.get('pypaths', {}).get(pyname, None) if not pypath: echo_failure( 'Unable to find a Python path named `{}`.'.format(pyname)) sys.exit(1) venv_dir = os.path.join(get_venv_dir(), name) if os.path.exists(venv_dir): echo_failure('Virtual env `{name}` already exists. To remove ' 'it do `hatch shed -e {name}`.'.format(name=name)) sys.exit(1) if not clone and not pyname and pypath and not os.path.exists(pypath): echo_failure( 'Python path `{}` does not exist. Be sure to use the absolute path ' 'e.g. `/usr/bin/python` instead of simply `python`.'.format( pypath)) sys.exit(1) if clone: origin = os.path.join(get_venv_dir(), clone) if not os.path.exists(origin): echo_failure( 'Virtual env `{name}` does not exist.'.format(name=clone)) sys.exit(1) echo_waiting('Cloning virtual env `{}`...'.format(clone)) clone_venv(origin, venv_dir) echo_success( 'Successfully cloned virtual env `{}` from `{}` to `{}`.'.format( name, clone, venv_dir)) else: echo_waiting('Creating virtual env `{}`...'.format(name)) result = create_venv(venv_dir, pypath, use_global=global_packages, verbose=verbose) if result == 0: echo_success('Successfully saved virtual env `{}` to `{}`.'.format( name, venv_dir)) else: echo_failure('An unexpected failure may have occurred.') sys.exit(result)
is_flag=True, help='Gives the virtual environment access to the global site-packages.') @click.option('-c', '--clone', help='Specifies an existing virtual env to clone. (Experimental)' ) @click.option('-v', '--verbose', is_flag=True, help='Increases verbosity.') @click.option('-r', '--restore', is_flag=True, is_eager=True, callback=restore_envs, help=('Attempts to make all virtual envs in `{}` usable by ' 'fixing the executable paths in scripts and removing ' 'all compiled `*.pyc` files. (Experimental)'.format( get_venv_dir()))) @click.option('-l', '--list', 'show', count=True, is_eager=True, callback=list_envs, help=('Shows available virtual envs. Can stack up to 3 times to ' 'show more info.')) def env(name, pyname, pypath, global_packages, clone, verbose, restore, show): """Creates a new virtual env that can later be utilized with the `shell` command. \b $ hatch pypath -l py2 -> /usr/bin/python
def init(name, no_env, pyname, pypath, global_packages, env_name, basic, cli, licenses, interactive): """Creates a new Python project in the current directory. Values from your config file such as `name` and `pyversions` will be used to help populate fields. You can also specify things like the readme format and which CI service files to create. All options override the config file. By default a virtual env will be created in the project directory and will install the project locally so any edits will auto-update the installation. You can also locally install the created project in other virtual envs using the --env option. Here is an example using an unmodified config file: \b $ hatch init my-app Created project `my-app` here $ tree --dirsfirst . . ├── my_app │ └── __init__.py ├── tests │ └── __init__.py ├── LICENSE-APACHE ├── LICENSE-MIT ├── MANIFEST.in ├── README.rst ├── requirements.txt ├── setup.py └── tox.ini 2 directories, 8 files """ try: settings = load_settings() except FileNotFoundError: settings = copy_default_settings() echo_warning( 'Unable to locate config file; try `hatch config --restore`. ' 'The default project structure will be used.') cwd = os.getcwd() package_name = name or click.prompt('Project name', default=basepath(cwd)) if interactive or not name: settings['version'] = click.prompt('Version', default='0.0.1') settings['description'] = click.prompt('Description', default='') settings['name'] = click.prompt('Author', default=settings.get('name', '')) settings['email'] = click.prompt("Author's email", default=settings.get('email', '')) licenses = click.prompt('License(s)', default=licenses or 'mit,apache2') if licenses: settings['licenses'] = [str.strip(li) for li in licenses.split(',')] if basic: settings['basic'] = True settings['cli'] = cli create_package(cwd, package_name, settings) echo_success('Created project `{}` here'.format(package_name)) venvs = env_name.split('/') if env_name else [] if (venvs or not no_env) and pyname: try: settings = load_settings() except FileNotFoundError: # no cov echo_failure( 'Unable to locate config file. Try `hatch config --restore`.') sys.exit(1) pypath = settings.get('pypaths', {}).get(pyname, None) if not pypath: echo_failure( 'Unable to find a Python path named `{}`.'.format(pyname)) sys.exit(1) if not no_env: venv_dir = os.path.join(cwd, get_venv_folder()) echo_waiting('Creating its own virtual env... ', nl=False) create_venv(venv_dir, pypath=pypath, use_global=global_packages) echo_success('complete!') with venv(venv_dir): echo_waiting('Installing locally in the virtual env... ', nl=False) install_packages(['-q', '-e', '.']) echo_success('complete!') for vname in venvs: venv_dir = os.path.join(get_venv_dir(), vname) if not os.path.exists(venv_dir): echo_waiting('Creating virtual env `{}`... '.format(vname), nl=False) create_venv(venv_dir, pypath=pypath, use_global=global_packages) echo_success('complete!') with venv(venv_dir): echo_waiting( 'Installing locally in virtual env `{}`... '.format(vname), nl=False) install_packages(['-q', '-e', '.']) echo_success('complete!')
def shell(env_name, command, shell_name, temp_env, pyname, pypath, global_packages): # no cov """Activates or sends a command to a virtual environment. A default shell name (or command) can be specified in the config file entry `shell` or the environment variable `SHELL`. If there is no entry, env var, nor shell option provided, a system default will be used: `cmd` on Windows, `bash` otherwise. Any arguments provided after the first will be sent to the virtual env as a command without activating it. If there is only the env without args, it will be activated similarly to how you are accustomed. The name of the virtual env to use must be omitted if using the --temp env option. If no env is chosen, this will attempt to detect a project and activate its virtual env. To run a command in a project's virtual env, use `.` as the env name. Activation will not do anything to your current shell, but will rather spawn a subprocess to avoid any unwanted strangeness occurring in your current environment. If you would like to learn more about the benefits of this approach, be sure to read https://gist.github.com/datagrok/2199506. To leave a virtual env, type `exit`, or you can do `Ctrl+D` on non-Windows machines. `use` is an alias for this command. \b Activation: $ hatch env -ll Virtual environments found in `/home/ofek/.virtualenvs`: \b fast -> Version: 3.5.3 Implementation: PyPy my-app -> Version: 3.5.2 Implementation: CPython old -> Version: 2.7.12 Implementation: CPython $ which python /usr/bin/python $ hatch shell my-app (my-app) $ which python /home/ofek/.virtualenvs/my-app/bin/python \b Commands: $ hatch shell my-app pip list --format=columns Package Version ---------- ------- pip 9.0.1 setuptools 36.3.0 wheel 0.29.0 $ hatch shell my-app hatch install -q requests six $ hatch shell my-app pip list --format=columns Package Version ---------- ----------- certifi 2017.7.27.1 chardet 3.0.4 idna 2.6 pip 9.0.1 requests 2.18.4 setuptools 36.3.0 six 1.10.0 urllib3 1.22 wheel 0.29.0 \b Temporary env: $ hatch shell -t Already using interpreter /usr/bin/python3 Using base prefix '/usr' New python executable in /tmp/tmpzg73untp/Ihqd/bin/python3 Also creating executable in /tmp/tmpzg73untp/Ihqd/bin/python Installing setuptools, pip, wheel...done. $ which python /tmp/tmpzg73untp/Ihqd/bin/python """ venv_dir = None if resolve_path(env_name) == os.getcwd(): env_name = '' if not (env_name or temp_env): if is_project(): venv_dir = os.path.join(os.getcwd(), 'venv') if not is_venv(venv_dir): echo_info('A project has been detected!') echo_waiting('Creating a dedicated virtual env... ', nl=False) create_venv(venv_dir, use_global=global_packages) echo_success('complete!') with venv(venv_dir): echo_waiting('Installing this project in the virtual env... ', nl=False) install_packages(['-q', '-e', '.']) echo_success('complete!') else: echo_failure('No project found.') sys.exit(1) if env_name and temp_env: echo_failure('Cannot use more than one virtual env at a time!') sys.exit(1) if not command and '_HATCHING_' in os.environ: echo_failure( 'Virtual environments cannot be nested, sorry! To leave ' 'the current one type `exit` or press `Ctrl+D`.' ) sys.exit(1) if temp_env: if pyname: try: settings = load_settings() except FileNotFoundError: echo_failure('Unable to locate config file. Try `hatch config --restore`.') sys.exit(1) pypath = settings.get('pypaths', {}).get(pyname, None) if not pypath: echo_failure('Unable to find a Python path named `{}`.'.format(pyname)) sys.exit(1) temp_dir = TemporaryDirectory() env_name = get_random_venv_name() venv_dir = os.path.join(temp_dir.name, env_name) echo_waiting('Creating a temporary virtual env named `{}`...'.format(env_name)) create_venv(venv_dir, pypath=pypath, use_global=global_packages, verbose=True) else: temp_dir = None venv_dir = venv_dir or os.path.join(get_venv_dir(), env_name) if not os.path.exists(venv_dir): echo_failure('Virtual env named `{}` does not exist.'.format(env_name)) sys.exit(1) result = None try: if command: with venv(venv_dir): echo_waiting('Running `{}` in {}...'.format( ' '.join(c if len(c.split()) == 1 else '"{}"'.format(c) for c in command), '`{}`'.format(env_name) if env_name else "this project's env" )) result = subprocess.run(command, shell=NEED_SUBPROCESS_SHELL).returncode else: with venv(venv_dir) as exe_dir: result = run_shell(exe_dir, shell_name) finally: result = 1 if result is None else result if temp_dir is not None: temp_dir.cleanup() sys.exit(result)
def install(packages, no_detect, env_name, editable, global_install, admin, quiet): """If the option --env is supplied, the install will be applied using that named virtual env. Unless the option --global is selected, the install will only affect the current user. Of course, this will have no effect if a virtual env is in use. The desired name of the admin user can be set with the `_DEFAULT_ADMIN_` environment variable. With no packages selected, this will install using a `setup.py` in the current directory. If no --env is chosen, this will attempt to detect a project and use its virtual env before resorting to the default pip. No project detection will occur if a virtual env is active. """ packages = packages or ['.'] # Windows' `runas` allows only a single argument for the # command so we catch this case and turn our command into # a string later. windows_admin_command = None if editable: packages = ['-e', *packages] if env_name: venv_dir = os.path.join(get_venv_dir(), env_name) if not os.path.exists(venv_dir): echo_failure( 'Virtual env named `{}` does not exist.'.format(env_name)) sys.exit(1) with venv(venv_dir): command = [get_proper_pip(), 'install', *packages ] + (['-q'] if quiet else []) echo_waiting('Installing in virtual env `{}`...'.format(env_name)) result = subprocess.run(command, shell=NEED_SUBPROCESS_SHELL) elif not venv_active() and not no_detect and is_project(): venv_dir = os.path.join(os.getcwd(), 'venv') if not is_venv(venv_dir): echo_info('A project has been detected!') echo_waiting('Creating a dedicated virtual env... ', nl=False) create_venv(venv_dir) echo_success('complete!') with venv(venv_dir): echo_waiting('Installing this project in the virtual env... ', nl=False) install_packages(['-q', '-e', '.']) echo_success('complete!') with venv(venv_dir): command = [get_proper_pip(), 'install', *packages ] + (['-q'] if quiet else []) echo_waiting('Installing for this project...') result = subprocess.run(command, shell=NEED_SUBPROCESS_SHELL) else: command = [get_proper_pip(), 'install'] + (['-q'] if quiet else []) if not venv_active(): # no cov if global_install: if not admin: if ON_WINDOWS: windows_admin_command = get_admin_command() else: command = get_admin_command() + command else: command.append('--user') command.extend(packages) if windows_admin_command: # no cov command = windows_admin_command + [' '.join(command)] echo_waiting('Installing...') result = subprocess.run(command, shell=NEED_SUBPROCESS_SHELL) sys.exit(result.returncode)
def test_get_new_venv_name_single(): names = os.listdir(get_venv_dir()) if os.path.exists( get_venv_dir()) else [] assert get_new_venv_name() not in names
def shed(ctx, pyname, env_name): """Removes named Python paths or virtual environments. \b $ hatch pypath -l py2 -> /usr/bin/python py3 -> /usr/bin/python3 invalid -> :\/: $ hatch env -ll Virtual environments found in /home/ofek/.virtualenvs: \b duplicate -> Version: 3.5.2 Implementation: CPython fast -> Version: 3.5.3 Implementation: PyPy my-app -> Version: 3.5.2 Implementation: CPython old -> Version: 2.7.12 Implementation: CPython $ hatch shed -p invalid -e duplicate/old Successfully removed Python path named `invalid`. Successfully removed virtual env named `duplicate`. Successfully removed virtual env named `old`. """ if not (pyname or env_name): click.echo(ctx.get_help()) return if pyname: try: settings = load_settings() except FileNotFoundError: echo_failure( 'Unable to locate config file. Try `hatch config --restore`.') sys.exit(1) for pyname in pyname.split('/'): pypath = settings.get('pypaths', {}).pop(pyname, None) if pypath is not None: save_settings(settings) echo_success( 'Successfully removed Python path named `{}`.'.format( pyname)) else: echo_warning( 'Python path named `{}` already does not exist.'.format( pyname)) if env_name: for env_name in env_name.split('/'): venv_dir = os.path.join(get_venv_dir(), env_name) if os.path.exists(venv_dir): remove_path(venv_dir) echo_success( 'Successfully removed virtual env named `{}`.'.format( env_name)) else: echo_warning( 'Virtual env named `{}` already does not exist.'.format( env_name))