def test_activate_activates_non_existing_virtualenv_no_envs_file( tmp_dir, manager, poetry, config, mocker): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] config.merge({"virtualenvs": {"path": str(tmp_dir)}}) mocker.patch( "poetry.utils._compat.subprocess.check_output", side_effect=check_output_wrapper(), ) mocker.patch( "poetry.utils._compat.subprocess.Popen.communicate", side_effect=[("/prefix", None), ("/prefix", None)], ) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv) env = manager.activate("python3.7", NullIO()) venv_name = EnvManager.generate_env_name("simple-project", str(poetry.file.parent)) m.assert_called_with(os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7") envs_file = TomlFile(Path(tmp_dir) / "envs.toml") assert envs_file.exists() envs = envs_file.read() assert envs[venv_name]["minor"] == "3.7" assert envs[venv_name]["patch"] == "3.7.1" assert env.path == Path(tmp_dir) / "{}-py3.7".format(venv_name) assert env.base == Path("/prefix")
def test_env_system_packages(tmp_path: Path, poetry: "Poetry"): venv_path = tmp_path / "venv" pyvenv_cfg = venv_path / "pyvenv.cfg" EnvManager(poetry).build_venv(path=venv_path, flags={"system-site-packages": True}) assert "include-system-site-packages = true" in pyvenv_cfg.read_text()
def _update(self, version: Version) -> None: from poetry.core.packages.dependency import Dependency from poetry.core.packages.project_package import ProjectPackage from poetry.config.config import Config from poetry.installation.installer import Installer from poetry.packages.locker import NullLocker from poetry.repositories.installed_repository import InstalledRepository from poetry.utils.env import EnvManager env = EnvManager.get_system_env(naive=True) installed = InstalledRepository.load(env) root = ProjectPackage("poetry-updater", "0.0.0") root.python_versions = ".".join(str(c) for c in env.version_info[:3]) root.add_dependency(Dependency("poetry", version.text)) installer = Installer( self.io, env, root, NullLocker(self.data_dir.joinpath("poetry.lock"), {}), self.pool, Config(), installed=installed, ) installer.update(True) installer.dry_run(self.option("dry-run")) installer.run()
def handle(self) -> int: from pathlib import Path from cleo.io.inputs.string_input import StringInput from cleo.io.io import IO from poetry.factory import Factory from poetry.utils.env import EnvManager plugins = self.argument("plugins") system_env = EnvManager.get_system_env(naive=True) env_dir = Path(os.getenv("POETRY_HOME") or system_env.path) # From this point forward, all the logic will be deferred to # the remove command, by using the global `pyproject.toml` file. application = cast(Application, self.application) remove_command: RemoveCommand = cast(RemoveCommand, application.find("remove")) # We won't go through the event dispatching done by the application # so we need to configure the command manually remove_command.set_poetry(Factory().create_poetry(env_dir)) remove_command.set_env(system_env) application._configure_installer(remove_command, self._io) argv = ["remove"] + plugins if self.option("dry-run"): argv.append("--dry-run") return remove_command.run( IO( StringInput(" ".join(argv)), self._io.output, self._io.error_output, ))
def test_activated(app, tmp_dir, config): app.poetry._config = config config.add_property("settings.virtualenvs.path", str(tmp_dir)) venv_name = EnvManager.generate_env_name("simple_project", str(app.poetry.file.parent)) (Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir() (Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir() envs_file = TomlFile(Path(tmp_dir) / "envs.toml") doc = tomlkit.document() doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"} envs_file.write(doc) command = app.find("env list") tester = CommandTester(command) tester.execute() expected = """\ {}-py3.6 {}-py3.7 (Activated) """.format(venv_name, venv_name) assert expected == tester.io.fetch_output()
def test_remove_by_python_version(app, tmp_dir, config, mocker): app.poetry._config = config config.add_property("settings.virtualenvs.path", str(tmp_dir)) venv_name = EnvManager.generate_env_name("simple_project", str(app.poetry.file.parent)) (Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir() (Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir() check_output = mocker.patch( "poetry.utils._compat.subprocess.check_output", side_effect=check_output_wrapper(Version.parse("3.6.6")), ) command = app.find("env remove") tester = CommandTester(command) tester.execute("3.6") assert check_output.called assert not (Path(tmp_dir) / "{}-py3.6".format(venv_name)).exists() expected = "Deleted virtualenv: {}\n".format( (Path(tmp_dir) / "{}-py3.6".format(venv_name))) assert expected == tester.io.fetch_output()
def test_activate_activates_non_existing_virtualenv_no_envs_file( tmp_dir: str, manager: EnvManager, poetry: Poetry, config: Config, mocker: MockerFixture, ): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] config.merge({"virtualenvs": {"path": str(tmp_dir)}}) mocker.patch( "subprocess.check_output", side_effect=check_output_wrapper(), ) mocker.patch( "subprocess.Popen.communicate", side_effect=[("/prefix", None), ("/prefix", None)], ) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv) env = manager.activate("python3.7", NullIO()) venv_name = EnvManager.generate_env_name("simple-project", str(poetry.file.parent)) m.assert_called_with( Path(tmp_dir) / f"{venv_name}-py3.7", executable="/usr/bin/python3.7", flags={ "always-copy": False, "system-site-packages": False, "no-pip": False, "no-setuptools": False, }, prompt="simple-project-py3.7", ) envs_file = TOMLFile(Path(tmp_dir) / "envs.toml") assert envs_file.exists() envs = envs_file.read() assert envs[venv_name]["minor"] == "3.7" assert envs[venv_name]["patch"] == "3.7.1" assert env.path == Path(tmp_dir) / f"{venv_name}-py3.7" assert env.base == Path("/prefix")
def handle(self): from poetry.__version__ import __version__ from poetry.core.semver import Version from poetry.utils.env import EnvManager new_update_method = False try: self._check_recommended_installation() except RuntimeError as e: env = EnvManager.get_system_env(naive=True) try: env.path.relative_to(self.data_dir) except ValueError: raise e new_update_method = True version = self.argument("version") if not version: version = ">=" + __version__ repo = self.pool.repositories[0] packages = repo.find_packages( Dependency("poetry", version, allows_prereleases=self.option("preview"))) if not packages: self.line("No release found for the specified version") return packages.sort(key=cmp_to_key(lambda x, y: 0 if x.version == y.version else int(x.version < y.version or -1))) release = None for package in packages: if package.is_prerelease(): if self.option("preview"): release = package break continue release = package break if release is None: self.line("No new release found") return if release.version == Version.parse(__version__): self.line("You are using the latest version") return if new_update_method: return self.update_with_new_method(release.version) self.update(release)
def set_env(self, event, event_name, _): # type: (PreHandleEvent, str, Any) -> None from poetry.utils.env import EnvManager command = event.command.config.handler # type: EnvCommand if not isinstance(command, EnvCommand): return io = event.io poetry = command.poetry env_manager = EnvManager(poetry) env = env_manager.create_venv(io) if env.is_venv() and io.is_verbose(): io.write_line("Using virtualenv: <comment>{}</>".format(env.path)) command.set_env(env)
def _get_poetry_env(project_dir: Path): from clikit.io import ConsoleIO from poetry.factory import Factory from poetry.utils.env import EnvManager poetry = Factory().create_poetry(project_dir) # TODO: unify ConsoleIO with ui.output return EnvManager(poetry).create_venv(ConsoleIO())
def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, config): venv_path = Path(tmp_dir) / "Virtual Env" EnvManager(config).build_venv(str(venv_path)) venv = VirtualEnv(venv_path) assert venv.run("python", "-V", shell=True).startswith("Python")
def handle(self): # type: () -> None from poetry.utils.env import EnvManager manager = EnvManager(self.poetry) current_env = manager.get() for venv in manager.list(): name = venv.path.name if self.option("full-path"): name = str(venv.path) if venv == current_env: self.line("<info>{} (Activated)</info>".format(name)) continue self.line(name)
def handle(self): from poetry.utils.env import EnvManager poetry = self.poetry manager = EnvManager(poetry.config) current_env = manager.get(self.poetry.file.parent) for venv in manager.list(self.poetry.file.parent): name = venv.path.name if self.option("full-path"): name = str(venv.path) if venv == current_env: self.line("<info>{} (Activated)</info>".format(name)) continue self.line(name)
def tmp_venv(tmp_dir, config, request): venv_path = Path(tmp_dir) / "venv" EnvManager(config).build_venv(str(venv_path)) venv = VirtualEnv(venv_path) yield venv shutil.rmtree(str(venv.path))
def test_remove_by_name(tmp_dir, config, mocker): config.add_property("settings.virtualenvs.path", str(tmp_dir)) venv_name = EnvManager.generate_env_name("simple_project", str(CWD)) (Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir() (Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir() mocker.patch( "poetry.utils._compat.subprocess.check_output", side_effect=check_output_wrapper(Version.parse("3.6.6")), ) manager = EnvManager(config) venv = manager.remove("{}-py3.6".format(venv_name), CWD) assert (Path(tmp_dir) / "{}-py3.6".format(venv_name)) == venv.path assert not (Path(tmp_dir) / "{}-py3.6".format(venv_name)).exists()
def test_activate_activates_same_virtualenv_with_envs_file( tmp_dir: str, manager: EnvManager, poetry: Poetry, config: Config, mocker: MockerFixture, ): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) envs_file = TOMLFile(Path(tmp_dir) / "envs.toml") doc = tomlkit.document() doc[venv_name] = {"minor": "3.7", "patch": "3.7.1"} envs_file.write(doc) os.mkdir(os.path.join(tmp_dir, f"{venv_name}-py3.7")) config.merge({"virtualenvs": {"path": str(tmp_dir)}}) mocker.patch( "subprocess.check_output", side_effect=check_output_wrapper(), ) mocker.patch( "subprocess.Popen.communicate", side_effect=[("/prefix", None)], ) m = mocker.patch("poetry.utils.env.EnvManager.create_venv") env = manager.activate("python3.7", NullIO()) m.assert_not_called() assert envs_file.exists() envs = envs_file.read() assert envs[venv_name]["minor"] == "3.7" assert envs[venv_name]["patch"] == "3.7.1" assert env.path == Path(tmp_dir) / f"{venv_name}-py3.7" assert env.base == Path("/prefix")
def test_deactivate_activated( tmp_dir: str, manager: EnvManager, poetry: Poetry, config: Config, mocker: MockerFixture, ): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) version = Version.from_parts(*sys.version_info[:3]) other_version = Version.parse( "3.4") if version.major == 2 else version.next_minor() (Path(tmp_dir) / f"{venv_name}-py{version.major}.{version.minor}").mkdir() (Path(tmp_dir) / f"{venv_name}-py{other_version.major}.{other_version.minor}").mkdir() envs_file = TOMLFile(Path(tmp_dir) / "envs.toml") doc = tomlkit.document() doc[venv_name] = { "minor": f"{other_version.major}.{other_version.minor}", "patch": other_version.text, } envs_file.write(doc) config.merge({"virtualenvs": {"path": str(tmp_dir)}}) mocker.patch( "subprocess.check_output", side_effect=check_output_wrapper(), ) manager.deactivate(NullIO()) env = manager.get() assert env.path == Path( tmp_dir) / f"{venv_name}-py{version.major}.{version.minor}" assert Path("/prefix") envs = envs_file.read() assert len(envs) == 0
def test_activate_does_not_recreate_when_switching_minor(tmp_dir, config, mocker): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] venv_name = EnvManager.generate_env_name("simple_project", str(CWD)) envs_file = TomlFile(Path(tmp_dir) / "envs.toml") doc = tomlkit.document() doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"} envs_file.write(doc) os.mkdir(os.path.join(tmp_dir, "{}-py3.7".format(venv_name))) os.mkdir(os.path.join(tmp_dir, "{}-py3.6".format(venv_name))) config.merge({"virtualenvs": {"path": str(tmp_dir)}}) mocker.patch( "poetry.utils._compat.subprocess.check_output", side_effect=check_output_wrapper(Version.parse("3.6.6")), ) mocker.patch( "poetry.utils._compat.subprocess.Popen.communicate", side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)], ) build_venv_m = mocker.patch( "poetry.utils.env.EnvManager.build_venv", side_effect=build_venv ) remove_venv_m = mocker.patch( "poetry.utils.env.EnvManager.remove_venv", side_effect=remove_venv ) env = EnvManager(config).activate("python3.6", CWD, NullIO()) build_venv_m.assert_not_called() remove_venv_m.assert_not_called() assert envs_file.exists() envs = envs_file.read() assert envs[venv_name]["minor"] == "3.6" assert envs[venv_name]["patch"] == "3.6.6" assert env.path == Path(tmp_dir) / "{}-py3.6".format(venv_name) assert env.base == Path("/prefix") assert (Path(tmp_dir) / "{}-py3.6".format(venv_name)).exists()
def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir( manager: EnvManager, poetry: Poetry, config: Config, tmp_dir: str, mocker: MockerFixture, ): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] config.merge({ "virtualenvs": { "path": str(Path(tmp_dir) / "virtualenvs"), "in-project": True, } }) mocker.patch( "subprocess.check_output", side_effect=check_output_wrapper(), ) mocker.patch( "subprocess.Popen.communicate", side_effect=[("/prefix", None), ("/prefix", None)], ) m = mocker.patch("poetry.utils.env.EnvManager.build_venv") manager.activate("python3.7", NullIO()) m.assert_called_with( poetry.file.parent / ".venv", executable="/usr/bin/python3.7", flags={ "always-copy": False, "system-site-packages": False, "no-pip": False, "no-setuptools": False, }, prompt="simple-project-py3.7", ) envs_file = TOMLFile(Path(tmp_dir) / "virtualenvs" / "envs.toml") assert not envs_file.exists()
def handle(self) -> int: from poetry.utils.env import EnvManager manager = EnvManager(self.poetry) current_env = manager.get() for venv in manager.list(): name = venv.path.name if self.option("full-path"): name = str(venv.path) if venv == current_env: self.line(f"<info>{name} (Activated)</info>") continue self.line(name) return 0
def test_env_get_in_project_venv(tmp_dir, config): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] (Path(tmp_dir) / ".venv").mkdir() venv = EnvManager(config).get(Path(tmp_dir)) assert venv.path == Path(tmp_dir) / ".venv" shutil.rmtree(str(venv.path))
def test_env_get_venv_with_venv_folder_present( manager: EnvManager, poetry: "Poetry", in_project_venv_dir: Path, in_project: Optional[bool], ): poetry.config.config["virtualenvs"]["in-project"] = in_project venv = manager.get() if in_project is False: assert venv.path != in_project_venv_dir else: assert venv.path == in_project_venv_dir
def test_env_system_packages(tmp_path, config): venv_path = tmp_path / "venv" pyvenv_cfg = venv_path / "pyvenv.cfg" EnvManager(config).build_venv(path=venv_path, flags={"system-site-packages": True}) if sys.version_info >= (3, 3): assert "include-system-site-packages = true" in pyvenv_cfg.read_text() elif (2, 6) < sys.version_info < (3, 0): assert not venv_path.joinpath( "lib", "python2.7", "no-global-site-packages.txt" ).exists()
def test_create_venv_fails_if_no_compatible_python_version_could_be_found( manager: EnvManager, poetry: Poetry, config: Config, mocker: MockerFixture): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] poetry.package.python_versions = "^4.8" mocker.patch("subprocess.check_output", side_effect=["", "", "", ""]) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "") with pytest.raises(NoCompatiblePythonVersionFound) as e: manager.create_venv(NullIO()) expected_message = ("Poetry was unable to find a compatible version. " "If you have one, you can explicitly use it " 'via the "env use" command.') assert str(e.value) == expected_message assert m.call_count == 0
def test_create_venv_uses_patch_version_to_detect_compatibility( manager: EnvManager, poetry: Poetry, config: Config, mocker: MockerFixture, config_virtualenvs_path: Path, ): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] version = Version.from_parts(*sys.version_info[:3]) poetry.package.python_versions = "^" + ".".join( str(c) for c in sys.version_info[:3]) venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) mocker.patch("sys.version_info", (version.major, version.minor, version.patch + 1)) check_output = mocker.patch( "subprocess.check_output", side_effect=check_output_wrapper(Version.parse("3.6.9")), ) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "") manager.create_venv(NullIO()) assert not check_output.called m.assert_called_with( config_virtualenvs_path / f"{venv_name}-py{version.major}.{version.minor}", executable=None, flags={ "always-copy": False, "system-site-packages": False, "no-pip": False, "no-setuptools": False, }, prompt=f"simple-project-py{version.major}.{version.minor}", )
def test_deactivate_activated(tmp_dir, config, mocker): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] venv_name = EnvManager.generate_env_name("simple_project", str(CWD)) version = Version.parse(".".join(str(c) for c in sys.version_info[:3])) other_version = Version.parse("3.4") if version.major == 2 else version.next_minor ( Path(tmp_dir) / "{}-py{}.{}".format(venv_name, version.major, version.minor) ).mkdir() ( Path(tmp_dir) / "{}-py{}.{}".format(venv_name, other_version.major, other_version.minor) ).mkdir() envs_file = TomlFile(Path(tmp_dir) / "envs.toml") doc = tomlkit.document() doc[venv_name] = { "minor": "{}.{}".format(other_version.major, other_version.minor), "patch": other_version.text, } envs_file.write(doc) config.merge({"virtualenvs": {"path": str(tmp_dir)}}) mocker.patch( "poetry.utils._compat.subprocess.check_output", side_effect=check_output_wrapper(), ) EnvManager(config).deactivate(CWD, NullIO()) env = EnvManager(config).get(CWD) assert env.path == Path(tmp_dir) / "{}-py{}.{}".format( venv_name, version.major, version.minor ) assert Path("/prefix") envs = envs_file.read() assert len(envs) == 0
def handle(self): from poetry.layouts import layout from poetry.utils._compat import Path from poetry.utils.env import EnvManager from poetry.vcs.git import GitConfig if self.option("src"): layout_ = layout("src") else: layout_ = layout("standard") path = Path.cwd() / Path(self.argument("path")) name = self.option("name") if not name: name = path.name if path.exists(): if list(path.glob("*")): # Directory is not empty. Aborting. raise RuntimeError( "Destination <fg=yellow>{}</> " "exists and is not empty".format(path) ) readme_format = "rst" config = GitConfig() author = None if config.get("user.name"): author = config["user.name"] author_email = config.get("user.email") if author_email: author += " <{}>".format(author_email) current_env = EnvManager().get(Path.cwd()) default_python = "^{}".format( ".".join(str(v) for v in current_env.version_info[:2]) ) layout_ = layout_( name, "0.1.0", author=author, readme_format=readme_format, python=default_python, ) layout_.create(path) self.line( "Created package <info>{}</> in <fg=blue>{}</>".format( name, path.relative_to(Path.cwd()) ) )
def test_deactivate_non_activated_but_existing(tmp_dir, config, mocker): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] venv_name = EnvManager.generate_env_name("simple_project", str(CWD)) (Path(tmp_dir) / "{}-py{}".format( venv_name, ".".join(str(c) for c in sys.version_info[:2]))).mkdir() config.add_property("settings.virtualenvs.path", str(tmp_dir)) mocker.patch( "poetry.utils._compat.subprocess.check_output", side_effect=check_output_wrapper(), ) EnvManager(config).deactivate(CWD, NullIO()) env = EnvManager(config).get(CWD) assert env.path == Path(tmp_dir) / "{}-py{}".format( venv_name, ".".join(str(c) for c in sys.version_info[:2])) assert Path("/prefix")
def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable( manager: EnvManager, poetry: "Poetry", config: "Config", mocker: "MockerFixture", config_virtualenvs_path: Path, ): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] version = Version.from_parts(*sys.version_info[:3]) poetry.package.python_versions = f"~{version.major}.{version.minor-1}.0" venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) check_output = mocker.patch( "subprocess.check_output", side_effect=check_output_wrapper( Version.parse(f"{version.major}.{version.minor - 1}.0")), ) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "") manager.create_venv( NullIO(), executable=f"python{version.major}.{version.minor - 1}") assert check_output.called m.assert_called_with( config_virtualenvs_path / f"{venv_name}-py{version.major}.{version.minor - 1}", executable=f"python{version.major}.{version.minor - 1}", flags={ "always-copy": False, "system-site-packages": False }, with_pip=True, with_setuptools=True, with_wheel=True, )
def test_create_venv_does_not_try_to_find_compatible_versions_with_executable( manager: EnvManager, poetry: Poetry, config: Config, mocker: MockerFixture): if "VIRTUAL_ENV" in os.environ: del os.environ["VIRTUAL_ENV"] poetry.package.python_versions = "^4.8" mocker.patch("subprocess.check_output", side_effect=["3.8.0"]) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "") with pytest.raises(NoCompatiblePythonVersionFound) as e: manager.create_venv(NullIO(), executable="3.8") expected_message = ( "The specified Python version (3.8.0) is not supported by the project (^4.8).\n" "Please choose a compatible version or loosen the python constraint " "specified in the pyproject.toml file.") assert str(e.value) == expected_message assert m.call_count == 0