From 95dd8d31314a5a123a0cc906c0125030b0500df2 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sun, 16 Apr 2023 12:41:39 +0100 Subject: [PATCH 1/2] Python 3.12 in pipelines --- .github/workflows/main.yml | 5 +++-- docs/configuration.md | 6 ++++++ poetry.lock | 2 +- pyproject.toml | 2 +- tests/utils/test_env.py | 8 ++++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d6487b91713..1f1a4214a1f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: strategy: matrix: os: [Ubuntu, macOS, Windows] - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12-dev"] include: - os: Ubuntu image: ubuntu-22.04 @@ -117,7 +117,8 @@ jobs: ref: refs/tags/${{ steps.poetry-plugin-export-version.outputs.version }} - name: Run pytest (poetry-plugin-export) - run: poetry run pytest -v poetry-plugin-export/tests/ + working-directory: ./poetry-plugin-export + run: poetry run -C .. pytest -v - name: Check for clean working tree run: | diff --git a/docs/configuration.md b/docs/configuration.md index 43be234a587..1a0199428af 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -375,6 +375,12 @@ If set to `true` the `--no-setuptools` parameter is passed to `virtualenv` on cr means when a new virtual environment is created, `setuptools` will not be installed in the environment. Poetry, for its internal operations, does not require `setuptools` and this can safely be set to `true`. +For environments using python 3.12 or later, `virtualenv` defaults to not +installing `setuptools` when creating a virtual environment. +In such environments this poetry configuration option therefore has no effect: +`setuptools` is not installed either way. +If your project relies on `setuptools`, you should declare it as a dependency. + {{% warning %}} Some development tools like IDEs, make an assumption that `setuptools` (and other) packages are always present and available within a virtual environment. This can cause some features in these tools to not work as expected. diff --git a/poetry.lock b/poetry.lock index 7452401e7cf..dc334d61ddb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1682,4 +1682,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "12ff5da9d9bc41c06665f74354ba6f2a4383ea54665e9aa873d983a8b105c4cf" +content-hash = "0d812f44af5236a0c19333ffc633476118ce239229dc64e49b1b8c052e215a5b" diff --git a/pyproject.toml b/pyproject.toml index 73e31be5de7..0536853ed00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ tomli = { version = "^2.0.1", python = "<3.11" } tomlkit = ">=0.11.4,<1.0.0" # trove-classifiers uses calver, so version is unclamped trove-classifiers = ">=2022.5.19" -virtualenv = "^20.22.0" +virtualenv = "^20.23.0" xattr = { version = "^0.10.0", markers = "sys_platform == 'darwin'" } [tool.poetry.group.dev.dependencies] diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index 3845a7e1177..688fa98c73d 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -1513,6 +1513,14 @@ def test_env_no_pip( if package.name != "sqlite3" } + # For python >= 3.12, virtualenv defaults to "--no-setuptools" and "--no-wheel" + # behaviour, so setting these values to False becomes meaningless. + if sys.version_info >= (3, 12): + if not flags.get("no-setuptools", True): + packages.discard("setuptools") + if not flags.get("no-wheel", True): + packages.discard("wheel") + assert installed_packages == packages From 73501aa2bb46946aaa4f848cc6d1947c6c91e99f Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sun, 3 Sep 2023 15:01:22 +0100 Subject: [PATCH 2/2] rearrange EnvManager build_venv() so that it is possible to force installation of setuptools and wheel --- src/poetry/inspection/info.py | 2 +- src/poetry/utils/env/__init__.py | 2 +- src/poetry/utils/env/env_manager.py | 48 +++++++++++++++++------------ tests/utils/test_env.py | 7 +++-- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/poetry/inspection/info.py b/src/poetry/inspection/info.py index e45046dceea..2fa1f7e97e0 100644 --- a/src/poetry/inspection/info.py +++ b/src/poetry/inspection/info.py @@ -579,7 +579,7 @@ def get_pep517_metadata(path: Path) -> PackageInfo: return info with ephemeral_environment( - flags={"no-pip": False, "no-setuptools": False, "no-wheel": False} + flags={"no-pip": False, "setuptools": "bundle", "wheel": "bundle"} ) as venv: # TODO: cache PEP 517 build environment corresponding to each project venv dest_dir = venv.path.parent / "dist" diff --git a/src/poetry/utils/env/__init__.py b/src/poetry/utils/env/__init__.py index dc5bc36b4ad..ed22bb3797b 100644 --- a/src/poetry/utils/env/__init__.py +++ b/src/poetry/utils/env/__init__.py @@ -41,7 +41,7 @@ @contextmanager def ephemeral_environment( executable: Path | None = None, - flags: dict[str, bool] | None = None, + flags: dict[str, str | bool] | None = None, ) -> Iterator[VirtualEnv]: with temporary_directory() as tmp_dir: # TODO: cache PEP 517 build environment corresponding to each project venv diff --git a/src/poetry/utils/env/env_manager.py b/src/poetry/utils/env/env_manager.py index 1fa70afad1f..e7b0cc751d9 100644 --- a/src/poetry/utils/env/env_manager.py +++ b/src/poetry/utils/env/env_manager.py @@ -612,35 +612,40 @@ def build_venv( cls, path: Path, executable: Path | None = None, - flags: dict[str, bool] | None = None, + flags: dict[str, str | bool] | None = None, with_pip: bool | None = None, with_wheel: bool | None = None, with_setuptools: bool | None = None, prompt: str | None = None, ) -> virtualenv.run.session.Session: - if WINDOWS: - path = get_real_windows_path(path) - executable = get_real_windows_path(executable) if executable else None - flags = flags or {} - flags["no-pip"] = ( - not with_pip if with_pip is not None else flags.pop("no-pip", True) - ) + if with_pip is not None: + flags["no-pip"] = not with_pip - flags["no-setuptools"] = ( - not with_setuptools - if with_setuptools is not None - else flags.pop("no-setuptools", True) - ) + if with_wheel is not None: + wheel_flags: dict[str, str | bool] = ( + {"wheel": "bundle"} if with_wheel else {"no-wheel": True} + ) + flags.update(wheel_flags) - # we want wheels to be enabled when pip is required and it has not been - # explicitly disabled - flags["no-wheel"] = ( - not with_wheel - if with_wheel is not None - else flags.pop("no-wheel", flags["no-pip"]) - ) + if with_setuptools is not None: + setuptools_flags: dict[str, str | bool] = ( + {"setuptools": "bundle"} if with_setuptools else {"no-setuptools": True} + ) + flags.update(setuptools_flags) + + flags.setdefault("no-pip", True) + + if "setuptools" not in flags and "no-setuptools" not in flags: + flags["no-setuptools"] = True + + if "wheel" not in flags and "no-wheel" not in flags: + flags["no-wheel"] = True + + if WINDOWS: + path = get_real_windows_path(path) + executable = get_real_windows_path(executable) if executable else None executable_str = None if executable is None else executable.resolve().as_posix() @@ -658,6 +663,9 @@ def build_venv( if value is True: args.append(f"--{flag}") + elif value is not False: + args.append(f"--{flag}={value}") + args.append(str(path)) cli_result = virtualenv.cli_run(args) diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index 688fa98c73d..dafd9af4c08 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -1489,18 +1489,21 @@ def test_env_system_packages_are_relative_to_lib( @pytest.mark.parametrize( ("flags", "packages"), [ - ({"no-pip": False}, {"pip", "wheel"}), + ({"no-pip": False}, {"pip"}), ({"no-pip": False, "no-wheel": True}, {"pip"}), + ({"no-pip": False, "no-wheel": False}, {"pip", "wheel"}), ({"no-pip": True}, set()), ({"no-setuptools": False}, {"setuptools"}), ({"no-setuptools": True}, set()), + ({"setuptools": "bundle"}, {"setuptools"}), ({"no-pip": True, "no-setuptools": False}, {"setuptools"}), ({"no-wheel": False}, {"wheel"}), + ({"wheel": "bundle"}, {"wheel"}), ({}, set()), ], ) def test_env_no_pip( - tmp_path: Path, poetry: Poetry, flags: dict[str, bool], packages: set[str] + tmp_path: Path, poetry: Poetry, flags: dict[str, str | bool], packages: set[str] ) -> None: venv_path = tmp_path / "venv" EnvManager(poetry).build_venv(path=venv_path, flags=flags)