Browse Source

Evaluate markers under environment with empty "extra" (#550)

Co-authored-by: Pradyun Gedam <pradyunsg@gmail.com>
pull/554/head
Blazej Michalik 2 months ago committed by GitHub
parent
commit
1aa82a856a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CHANGELOG.rst
  2. 11
      docs/markers.rst
  3. 23
      packaging/markers.py
  4. 9
      tests/test_markers.py

4
CHANGELOG.rst

@ -4,7 +4,9 @@ Changelog
*unreleased*
~~~~~~~~~~~~
No unreleased changes.
* ``Marker.evaluate`` will now assume evaluation environment with empty ``extra``.
Evaluating markers like ``"extra == 'xyz'"`` without passing any extra in the
``environment`` will no longer raise an exception.
21.3 - 2021-11-17
~~~~~~~~~~~~~~~~~

11
docs/markers.rst

@ -34,17 +34,6 @@ Usage
>>> # Markers can be also used with extras, to pull in dependencies if
>>> # a certain extra is being installed
>>> extra = Marker('extra == "bar"')
>>> # Evaluating an extra marker with no environment is an error
>>> try:
... extra.evaluate()
... except UndefinedEnvironmentName:
... pass
>>> extra_environment = {'extra': ''}
>>> extra.evaluate(environment=extra_environment)
False
>>> extra_environment['extra'] = 'bar'
>>> extra.evaluate(environment=extra_environment)
True
>>> # You can do simple comparisons between marker objects:
>>> Marker("python_version > '3.6'") == Marker("python_version > '3.6'")
True

23
packaging/markers.py

@ -215,24 +215,6 @@ def _eval_op(lhs: str, op: Op, rhs: str) -> bool:
return oper(lhs, rhs)
class Undefined:
pass
_undefined = Undefined()
def _get_env(environment: Dict[str, str], name: str) -> str:
value: Union[str, Undefined] = environment.get(name, _undefined)
if isinstance(value, Undefined):
raise UndefinedEnvironmentName(
f"{name!r} does not exist in evaluation environment."
)
return value
def _normalize(*values: str, key: str) -> Tuple[str, ...]:
# PEP 685 – Comparison of extra names for optional distribution dependencies
# https://peps.python.org/pep-0685/
@ -258,12 +240,12 @@ def _evaluate_markers(markers: List[Any], environment: Dict[str, str]) -> bool:
if isinstance(lhs, Variable):
environment_key = lhs.value
lhs_value = _get_env(environment, environment_key)
lhs_value = environment[environment_key]
rhs_value = rhs.value
else:
lhs_value = lhs.value
environment_key = rhs.value
rhs_value = _get_env(environment, environment_key)
rhs_value = environment[environment_key]
lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key)
groups[-1].append(_eval_op(lhs_value, op, rhs_value))
@ -287,6 +269,7 @@ def default_environment() -> Dict[str, str]:
iver = format_full_version(sys.implementation.version)
implementation_name = sys.implementation.name
return {
"extra": "",
"implementation_name": implementation_name,
"implementation_version": iver,
"os_name": os.name,

9
tests/test_markers.py

@ -15,7 +15,6 @@ from packaging.markers import (
Marker,
Node,
UndefinedComparison,
UndefinedEnvironmentName,
default_environment,
format_full_version,
)
@ -110,6 +109,7 @@ class TestDefaultEnvironment:
)
assert environment == {
"extra": "",
"implementation_name": sys.implementation.name,
"implementation_version": iver,
"os_name": os.name,
@ -253,11 +253,8 @@ class TestMarker:
# Markers should not be comparable to other kinds of objects.
assert Marker("os_name == 'nt'") != "os_name == 'nt'"
def test_extra_with_no_extra_in_environment(self):
# We can't evaluate an extra if no extra is passed into the environment
m = Marker("extra == 'security'")
with pytest.raises(UndefinedEnvironmentName):
m.evaluate()
def test_environment_assumes_empty_extra(self):
assert Marker('extra == "im_valid"').evaluate() is False
@pytest.mark.parametrize(
("marker_string", "environment", "expected"),

Loading…
Cancel
Save