Skip to content

Commit

Permalink
fix docstring
Browse files Browse the repository at this point in the history
Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
  • Loading branch information
gaborbernat committed Jan 4, 2023
1 parent 7ff1bef commit 5311af3
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 36 deletions.
2 changes: 1 addition & 1 deletion docs/changelog/2791.bugfix.rst
@@ -1 +1 @@
Fix extracting extras from markers with >2 extras - by :user:`dconathan`
Fix extracting extras from markers with more than 2 extras in an or chain - by :user:`dconathan`.
68 changes: 37 additions & 31 deletions src/tox/tox_env/python/virtual_env/package/util.py
@@ -1,8 +1,9 @@
from __future__ import annotations

from copy import deepcopy
from typing import Optional, Set, cast

from packaging.markers import Variable # type: ignore[attr-defined]
from packaging.markers import Marker, Op, Value, Variable # type: ignore[attr-defined]
from packaging.requirements import Requirement


Expand All @@ -29,37 +30,42 @@ def dependencies_with_extras(deps: list[Requirement], extras: set[str], package_


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[tuple[Requirement, set[str | None]]] = []
for req in deps:
req = deepcopy(req)
markers: list[str | tuple[Variable, Variable, Variable]] = getattr(req.marker, "_markers", []) or []
new_markers: list[str | tuple[Variable, Variable, Variable]] = []
"""
Extract extra markers from dependencies.
def _is_extra_marker(_marker: str | tuple[Variable, Variable, Variable]) -> bool:
return (
isinstance(_marker, tuple)
and len(_marker) == 3
and _marker[0].value == "extra"
and _marker[1].value == "=="
)
:param deps: the dependencies
:return: a list of requirement, extras set
"""
result = [_extract_extra_markers(d) for d in deps]
return result

extra_markers = set()
marker = markers.pop(0) if markers else None
while marker:
if _is_extra_marker(marker):
extra_markers.add(marker[2].value) # type: ignore
if new_markers and new_markers[-1] in ("and", "or"):
del new_markers[-1]
marker = markers.pop(0) if markers else None
if marker in ("and", "or"):
marker = markers.pop(0) if markers else None
else:
new_markers.append(marker)

def _extract_extra_markers(req: Requirement) -> tuple[Requirement, set[str | None]]:
req = deepcopy(req)
markers: list[str | tuple[Variable, Op, Variable]] = getattr(req.marker, "_markers", []) or []
new_markers: list[str | tuple[Variable, Op, Variable]] = []
extra_markers: set[str] = set() # markers that have a key of extra
marker = markers.pop(0) if markers else None
while marker:
extra = _get_extra(marker)
if extra is not None:
extra_markers.add(extra)
if new_markers and new_markers[-1] in ("and", "or"):
del new_markers[-1]
marker = markers.pop(0) if markers else None
if marker in ("and", "or"):
marker = markers.pop(0) if markers else None
if new_markers:
req.marker._markers = new_markers # type: ignore
else:
req.marker = None
result.append((req, extra_markers or {None}))
return result
new_markers.append(marker)
marker = markers.pop(0) if markers else None
if new_markers:
cast(Marker, req.marker)._markers = new_markers
else:
req.marker = None
return req, cast(Set[Optional[str]], extra_markers) or {None}


def _get_extra(_marker: str | tuple[Variable, Op, Value]) -> str | None:
if isinstance(_marker, tuple) and len(_marker) == 3 and _marker[0].value == "extra" and _marker[1].value == "==":
return cast(str, _marker[2].value)
return None
Expand Up @@ -72,8 +72,8 @@ def test_load_dependency_requirement_or_extras() -> None:
assert [str(r) for r in result] == ["filelock<4.0.0,>=3.9.0"]


def test_load_dependency_requirement_many_or_extras() -> None:
@pytest.mark.parametrize("extra", ["extras1", "extras2", "extras3"])
def test_load_dependency_requirement_many_or_extras(extra: str) -> None:
requires = [Requirement('filelock<4.0.0,>=3.9.0; extra == "extras1" or extra == "extras2" or extra == "extras3"')]
for extras in ["extras1", "extras2", "extras3"]:
result = dependencies_with_extras(requires, {extras}, "")
assert [str(r) for r in result] == ["filelock<4.0.0,>=3.9.0"]
result = dependencies_with_extras(requires, {extra}, "")
assert [str(r) for r in result] == ["filelock<4.0.0,>=3.9.0"]

0 comments on commit 5311af3

Please sign in to comment.