From 61630dc2fe58022ca17bec0c6b773bd48e785b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Tue, 6 Dec 2022 16:42:41 -0800 Subject: [PATCH] Do not conflate extra markers and extra dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- docs/changelog/2603.bugfix.rst | 1 + .../tox_env/python/virtual_env/package/util.py | 17 ++++++++--------- .../package/test_python_package_util.py | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 docs/changelog/2603.bugfix.rst diff --git a/docs/changelog/2603.bugfix.rst b/docs/changelog/2603.bugfix.rst new file mode 100644 index 000000000..8edac452f --- /dev/null +++ b/docs/changelog/2603.bugfix.rst @@ -0,0 +1 @@ +Fix extras not being kept for install dependencies - by :user:`gaborbernat`. diff --git a/src/tox/tox_env/python/virtual_env/package/util.py b/src/tox/tox_env/python/virtual_env/package/util.py index b84f687a5..9936c7f26 100644 --- a/src/tox/tox_env/python/virtual_env/package/util.py +++ b/src/tox/tox_env/python/virtual_env/package/util.py @@ -7,20 +7,18 @@ def dependencies_with_extras(deps: list[Requirement], extras: set[str], package_name: str) -> list[Requirement]: - deps = _normalize_req(deps) + deps_with_markers = extract_extra_markers(deps) result: list[Requirement] = [] found: set[str] = set() todo: set[str | None] = extras | {None} visited: set[str | None] = set() while todo: new_extras: set[str | None] = set() - for req in deps: - if todo & (req.extras or {None}): # type: ignore[arg-type] + for req, extra_markers in deps_with_markers: + if todo & extra_markers: if req.name == package_name: # support for recursive extras new_extras.update(req.extras or set()) else: - req = deepcopy(req) - req.extras.clear() # strip the extra part as the installation will invoke it without req_str = str(req) if req_str not in found: found.add(req_str) @@ -30,20 +28,21 @@ def dependencies_with_extras(deps: list[Requirement], extras: set[str], package_ return result -def _normalize_req(deps: list[Requirement]) -> list[Requirement]: +def extract_extra_markers(deps: list[Requirement]) -> list[tuple[Requirement, set[str | None]]]: # extras might show up as markers, move them into extras property - result: list[Requirement] = [] + result: list[tuple[Requirement, set[str | None]]] = [] for req in deps: req = deepcopy(req) markers: list[str | tuple[Variable, Variable, Variable]] = getattr(req.marker, "_markers", []) or [] _at: int | None = None + extra_markers = set() for _at, (marker_key, op, marker_value) in ( (_at_marker, marker) for _at_marker, marker in enumerate(markers) if isinstance(marker, tuple) and len(marker) == 3 ): if marker_key.value == "extra" and op.value == "==": # pragma: no branch - req.extras.add(marker_value.value) + extra_markers.add(marker_value.value) del markers[_at] _at -= 1 if _at > 0 and (isinstance(markers[_at], str) and markers[_at] in ("and", "or")): @@ -51,5 +50,5 @@ def _normalize_req(deps: list[Requirement]) -> list[Requirement]: if len(markers) == 0: req.marker = None break - result.append(req) + result.append((req, extra_markers or {None})) return result diff --git a/tests/tox_env/python/virtual_env/package/test_python_package_util.py b/tests/tox_env/python/virtual_env/package/test_python_package_util.py index 4ff9e348a..25d84283e 100644 --- a/tests/tox_env/python/virtual_env/package/test_python_package_util.py +++ b/tests/tox_env/python/virtual_env/package/test_python_package_util.py @@ -50,12 +50,12 @@ def test_load_dependency_many_extra(pkg_with_extras: PathDistribution) -> None: def test_loads_deps_recursive_extras() -> None: requires = [ Requirement("no-extra"), - Requirement("dep1[dev]"), - Requirement("dep1[test]"), - Requirement("dep2[test]"), - Requirement("dep3[docs]"), - Requirement("name[dev]"), - Requirement("name[test,dev]"), + Requirement('dep1[magic]; extra=="dev"'), + Requirement('dep1; extra=="test"'), + Requirement('dep2[a,b]; extra=="test"'), + Requirement('dep3; extra=="docs"'), + Requirement('name; extra=="dev"'), + Requirement('name[test]; extra=="dev"'), ] result = dependencies_with_extras(requires, {"dev"}, "name") - assert [str(i) for i in result] == ["no-extra", "dep1", "dep2"] + assert [str(i) for i in result] == ["no-extra", "dep1[magic]", "dep1", "dep2[a,b]"]