Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-dep-logic for 
openSUSE:Factory checked in at 2025-07-14 10:51:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-dep-logic (Old)
 and      /work/SRC/openSUSE:Factory/.python-dep-logic.new.7373 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-dep-logic"

Mon Jul 14 10:51:42 2025 rev:6 rq:1292441 version:0.5.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-dep-logic/python-dep-logic.changes        
2025-01-23 18:06:54.363835133 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-dep-logic.new.7373/python-dep-logic.changes  
    2025-07-14 10:57:01.481870034 +0200
@@ -1,0 +2,13 @@
+Sat Jul 12 17:31:35 UTC 2025 - Dirk Müller <dmuel...@suse.com>
+
+- update to 0.5.1:
+  * Improve docstrings and format
+- update to 0.5.0:
+  * Support 'extras' and 'dependency_groups' markers
+  * Improve logic for detecting msys2-based Python (works for
+    3.11 and 3.
+- update to 0.4.11:
+  * Handle irregular python tags
+  * Basic loongarch64 support
+
+-------------------------------------------------------------------

Old:
----
  dep_logic-0.4.10.tar.gz

New:
----
  dep_logic-0.5.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-dep-logic.spec ++++++
--- /var/tmp/diff_new_pack.2HD6dI/_old  2025-07-14 10:57:02.085895074 +0200
+++ /var/tmp/diff_new_pack.2HD6dI/_new  2025-07-14 10:57:02.089895240 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-dep-logic
-Version:        0.4.10
+Version:        0.5.1
 Release:        0
 Summary:        Python dependency specifications supporting logical operations
 License:        Apache-2.0

++++++ dep_logic-0.4.10.tar.gz -> dep_logic-0.5.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/PKG-INFO 
new/dep_logic-0.5.1/PKG-INFO
--- old/dep_logic-0.4.10/PKG-INFO       1970-01-01 01:00:00.000000000 +0100
+++ new/dep_logic-0.5.1/PKG-INFO        1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: dep-logic
-Version: 0.4.10
+Version: 0.5.1
 Summary: Python dependency specifications supporting logical operations
 Keywords: dependency,specification,logic,packaging
 Author-Email: Frost Ming <m...@frostming.com>
@@ -12,6 +12,7 @@
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
 Classifier: License :: OSI Approved :: Apache Software License
 Requires-Python: >=3.8
 Requires-Dist: packaging>=22
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/pyproject.toml 
new/dep_logic-0.5.1/pyproject.toml
--- old/dep_logic-0.4.10/pyproject.toml 2024-12-13 12:04:19.215864000 +0100
+++ new/dep_logic-0.5.1/pyproject.toml  2025-05-19 11:34:51.963228700 +0200
@@ -24,9 +24,10 @@
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
     "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13",
     "License :: OSI Approved :: Apache Software License",
 ]
-version = "0.4.10"
+version = "0.5.1"
 
 [project.license]
 text = "Apache-2.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/markers/__init__.py 
new/dep_logic-0.5.1/src/dep_logic/markers/__init__.py
--- old/dep_logic-0.4.10/src/dep_logic/markers/__init__.py      2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/markers/__init__.py       2025-05-19 
11:34:42.943260200 +0200
@@ -31,15 +31,15 @@
 
 
 __all__ = [
-    "parse_marker",
-    "from_pkg_marker",
-    "InvalidMarker",
-    "BaseMarker",
     "AnyMarker",
+    "BaseMarker",
     "EmptyMarker",
+    "InvalidMarker",
     "MarkerExpression",
     "MarkerUnion",
     "MultiMarker",
+    "from_pkg_marker",
+    "parse_marker",
 ]
 
 
@@ -99,3 +99,34 @@
         else:
             or_groups[-1] &= _build_markers(item)
     return MarkerUnion.of(*or_groups)
+
+
+def _patch_marker_parser() -> None:
+    import re
+
+    try:
+        from packaging._tokenizer import DEFAULT_RULES
+    except (ModuleNotFoundError, AttributeError):
+        return
+
+    DEFAULT_RULES["VARIABLE"] = re.compile(
+        r"""
+            \b(
+                python_version
+                |python_full_version
+                |os[._]name
+                |sys[._]platform
+                |platform_(release|system)
+                |platform[._](version|machine|python_implementation)
+                |python_implementation
+                |implementation_(name|version)
+                |extras?
+                |dependency_groups
+            )\b
+        """,
+        re.VERBOSE,
+    )
+
+
+_patch_marker_parser()
+del _patch_marker_parser
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/markers/any.py 
new/dep_logic-0.5.1/src/dep_logic/markers/any.py
--- old/dep_logic-0.4.10/src/dep_logic/markers/any.py   2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/markers/any.py    2025-05-19 
11:34:42.943260200 +0200
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from dep_logic.markers.base import BaseMarker
+from dep_logic.markers.base import BaseMarker, EvaluationContext
 
 
 class AnyMarker(BaseMarker):
@@ -17,7 +17,11 @@
     def is_any(self) -> bool:
         return True
 
-    def evaluate(self, environment: dict[str, str] | None = None) -> bool:
+    def evaluate(
+        self,
+        environment: dict[str, str | set[str]] | None = None,
+        context: EvaluationContext = "metadata",
+    ):
         return True
 
     def without_extras(self) -> BaseMarker:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/markers/base.py 
new/dep_logic-0.5.1/src/dep_logic/markers/base.py
--- old/dep_logic-0.4.10/src/dep_logic/markers/base.py  2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/markers/base.py   2025-05-19 
11:34:42.943260200 +0200
@@ -1,7 +1,9 @@
 from __future__ import annotations
 
 from abc import ABCMeta, abstractmethod
-from typing import Any
+from typing import Any, Literal
+
+EvaluationContext = Literal["lock_file", "metadata", "requirement"]
 
 
 class BaseMarker(metaclass=ABCMeta):
@@ -22,25 +24,41 @@
         raise NotImplementedError
 
     def is_any(self) -> bool:
+        """Returns True if the marker allows any environment."""
         return False
 
     def is_empty(self) -> bool:
+        """Returns True if the marker disallows any environment."""
         return False
 
     @abstractmethod
-    def evaluate(self, environment: dict[str, str] | None = None) -> bool:
+    def evaluate(
+        self,
+        environment: dict[str, str | set[str]] | None = None,
+        context: EvaluationContext = "metadata",
+    ) -> bool:
+        """Evaluates the marker against the given environment.
+
+        Args:
+            environment: The environment to evaluate against.
+            context: The context in which the evaluation is performed,
+                can be "lock_file", "metadata", or "requirement".
+        """
         raise NotImplementedError
 
     @abstractmethod
     def without_extras(self) -> BaseMarker:
+        """Generate a new marker from the current marker but without "extra" 
markers."""
         raise NotImplementedError
 
     @abstractmethod
     def exclude(self, marker_name: str) -> BaseMarker:
+        """Generate a new marker from the current marker but without the given 
marker."""
         raise NotImplementedError
 
     @abstractmethod
     def only(self, *marker_names: str) -> BaseMarker:
+        """Generate a new marker from the current marker but only with the 
given markers."""
         raise NotImplementedError
 
     def __repr__(self) -> str:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/markers/empty.py 
new/dep_logic-0.5.1/src/dep_logic/markers/empty.py
--- old/dep_logic-0.4.10/src/dep_logic/markers/empty.py 2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/markers/empty.py  2025-05-19 
11:34:42.943260200 +0200
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from dep_logic.markers.base import BaseMarker
+from dep_logic.markers.base import BaseMarker, EvaluationContext
 
 
 class EmptyMarker(BaseMarker):
@@ -17,7 +17,11 @@
     def is_empty(self) -> bool:
         return True
 
-    def evaluate(self, environment: dict[str, str] | None = None) -> bool:
+    def evaluate(
+        self,
+        environment: dict[str, str | set[str]] | None = None,
+        context: EvaluationContext = "metadata",
+    ) -> bool:
         return False
 
     def without_extras(self) -> BaseMarker:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/markers/multi.py 
new/dep_logic-0.5.1/src/dep_logic/markers/multi.py
--- old/dep_logic-0.4.10/src/dep_logic/markers/multi.py 2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/markers/multi.py  2025-05-19 
11:34:42.943260200 +0200
@@ -4,7 +4,7 @@
 from typing import Iterator
 
 from dep_logic.markers.any import AnyMarker
-from dep_logic.markers.base import BaseMarker
+from dep_logic.markers.base import BaseMarker, EvaluationContext
 from dep_logic.markers.empty import EmptyMarker
 from dep_logic.markers.single import MarkerExpression, SingleMarker
 from dep_logic.utils import DATACLASS_ARGS, flatten_items, intersection, union
@@ -135,8 +135,12 @@
 
         return None
 
-    def evaluate(self, environment: dict[str, str] | None = None) -> bool:
-        return all(m.evaluate(environment) for m in self.markers)
+    def evaluate(
+        self,
+        environment: dict[str, str | set[str]] | None = None,
+        context: EvaluationContext = "metadata",
+    ) -> bool:
+        return all(m.evaluate(environment, context) for m in self.markers)
 
     def without_extras(self) -> BaseMarker:
         return self.exclude("extra")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/markers/single.py 
new/dep_logic-0.5.1/src/dep_logic/markers/single.py
--- old/dep_logic-0.4.10/src/dep_logic/markers/single.py        2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/markers/single.py 2025-05-19 
11:34:42.943260200 +0200
@@ -1,24 +1,44 @@
 from __future__ import annotations
 
 import functools
+import operator
 import typing as t
+from abc import abstractmethod
 from dataclasses import dataclass, field, replace
 
-from packaging.markers import Marker as _Marker
+from packaging.markers import default_environment
+from packaging.specifiers import InvalidSpecifier, Specifier
+from packaging.version import InvalidVersion
 
 from dep_logic.markers.any import AnyMarker
-from dep_logic.markers.base import BaseMarker
+from dep_logic.markers.base import BaseMarker, EvaluationContext
 from dep_logic.markers.empty import EmptyMarker
 from dep_logic.specifiers import BaseSpecifier
 from dep_logic.specifiers.base import VersionSpecifier
 from dep_logic.specifiers.generic import GenericSpecifier
-from dep_logic.utils import DATACLASS_ARGS, OrderedSet, get_reflect_op
+from dep_logic.utils import DATACLASS_ARGS, OrderedSet, get_reflect_op, 
normalize_name
 
 if t.TYPE_CHECKING:
     from dep_logic.markers.multi import MultiMarker
     from dep_logic.markers.union import MarkerUnion
 
 PYTHON_VERSION_MARKERS = {"python_version", "python_full_version"}
+MARKERS_ALLOWING_SET = {"extras", "dependency_groups"}
+Operator = t.Callable[[str, t.Union[str, t.Set[str]]], bool]
+_operators: dict[str, Operator] = {
+    "in": lambda lhs, rhs: lhs in rhs,
+    "not in": lambda lhs, rhs: lhs not in rhs,
+    "<": operator.lt,
+    "<=": operator.le,
+    "==": operator.eq,
+    "!=": operator.ne,
+    ">=": operator.ge,
+    ">": operator.gt,
+}
+
+
+class UndefinedComparison(ValueError):
+    pass
 
 
 class SingleMarker(BaseMarker):
@@ -44,16 +64,25 @@
 
         return self
 
-    def evaluate(self, environment: dict[str, str] | None = None) -> bool:
-        pkg_marker = _Marker(str(self))
-        if self.name != "extra" or not environment or "extra" not in 
environment:
-            return pkg_marker.evaluate(environment)
-        extras = [extra] if isinstance(extra := environment["extra"], str) 
else extra
-        assert isinstance(self, MarkerExpression)
-        is_negated = self.op in ("not in", "!=")
-        if is_negated:
-            return all(pkg_marker.evaluate({"extra": extra}) for extra in 
extras)
-        return any(pkg_marker.evaluate({"extra": extra}) for extra in extras)
+    def evaluate(
+        self,
+        environment: dict[str, str | set[str]] | None = None,
+        context: EvaluationContext = "metadata",
+    ) -> bool:
+        current_environment = t.cast("dict[str, str|set[str]]", 
default_environment())
+        if context == "metadata":
+            current_environment["extra"] = ""
+        elif context == "lock_file":
+            current_environment.update(extras=set(), dependency_groups=set())
+        if environment:
+            current_environment.update(environment)
+        if "extra" in current_environment and current_environment["extra"] is 
None:
+            current_environment["extra"] = ""
+        return self._evaluate(current_environment)
+
+    @abstractmethod
+    def _evaluate(self, environment: dict[str, str | set[str]]) -> bool:
+        raise NotImplementedError
 
 
 @dataclass(unsafe_hash=True, **DATACLASS_ARGS)
@@ -141,6 +170,46 @@
 
         return MarkerUnion(self, other)
 
+    def _evaluate(self, environment: dict[str, str | set[str]]) -> bool:
+        if self.name == "extra":
+            # Support batch comparison for "extra" markers
+            extra = environment["extra"]
+            if isinstance(extra, str):
+                extra = {extra}
+            assert self.op in ("==", "!=")
+            value = normalize_name(self.value)
+            extra = {normalize_name(v) for v in extra}
+            return value in extra if self.op == "==" else value not in extra
+
+        target = environment[self.name]
+        if self.reversed:
+            lhs, rhs = self.value, target
+            oper = _operators.get(get_reflect_op(self.op))
+        else:
+            lhs, rhs = target, self.value
+            assert isinstance(lhs, str)
+            oper = _operators.get(self.op)
+        if self.name in MARKERS_ALLOWING_SET:
+            lhs = normalize_name(lhs)
+            if isinstance(rhs, set):
+                rhs = {normalize_name(v) for v in rhs}
+            else:
+                rhs = normalize_name(rhs)
+        if isinstance(rhs, str):
+            try:
+                spec = Specifier(f"{self.op}{rhs}")
+            except InvalidSpecifier:
+                pass
+            else:
+                try:
+                    return spec.contains(lhs)
+                except InvalidVersion:
+                    pass
+
+        if oper is None:
+            raise UndefinedComparison(f"Undefined comparison {self}")
+        return oper(lhs, rhs)
+
 
 @dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
 class EqualityMarkerUnion(SingleMarker):
@@ -210,6 +279,9 @@
     __rand__ = __and__
     __ror__ = __or__
 
+    def _evaluate(self, environment: dict[str, str | set[str]]) -> bool:
+        return environment[self.name] in self.values
+
 
 @dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
 class InequalityMultiMarker(SingleMarker):
@@ -283,6 +355,9 @@
     __rand__ = __and__
     __ror__ = __or__
 
+    def _evaluate(self, environment: dict[str, str | set[str]]) -> bool:
+        return environment[self.name] not in self.values
+
 
 @functools.lru_cache(maxsize=None)
 def _merge_single_markers(
@@ -375,5 +450,5 @@
         splitted[-1] = str(int(splitted[-1]) + 1)
         op = "<"
 
-    spec = parse_version_specifier(f'{op}{".".join(splitted)}')
+    spec = parse_version_specifier(f"{op}{'.'.join(splitted)}")
     return spec
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/markers/union.py 
new/dep_logic-0.5.1/src/dep_logic/markers/union.py
--- old/dep_logic-0.4.10/src/dep_logic/markers/union.py 2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/markers/union.py  2025-05-19 
11:34:42.943260200 +0200
@@ -4,7 +4,7 @@
 from typing import Iterator
 
 from dep_logic.markers.any import AnyMarker
-from dep_logic.markers.base import BaseMarker
+from dep_logic.markers.base import BaseMarker, EvaluationContext
 from dep_logic.markers.empty import EmptyMarker
 from dep_logic.markers.multi import MultiMarker
 from dep_logic.markers.single import SingleMarker
@@ -135,8 +135,12 @@
 
         return None
 
-    def evaluate(self, environment: dict[str, str] | None = None) -> bool:
-        return any(m.evaluate(environment) for m in self.markers)
+    def evaluate(
+        self,
+        environment: dict[str, str | set[str]] | None = None,
+        context: EvaluationContext = "metadata",
+    ) -> bool:
+        return any(m.evaluate(environment, context) for m in self.markers)
 
     def without_extras(self) -> BaseMarker:
         return self.exclude("extra")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/specifiers/range.py 
new/dep_logic-0.5.1/src/dep_logic/specifiers/range.py
--- old/dep_logic-0.4.10/src/dep_logic/specifiers/range.py      2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/specifiers/range.py       2025-05-19 
11:34:42.944260100 +0200
@@ -81,7 +81,7 @@
         simplified = self._simplified_form
         if simplified is not None:
             return simplified
-        return f'{">=" if self.include_min else ">"}{self.min},{"<=" if 
self.include_max else "<"}{self.max}'
+        return f"{'>=' if self.include_min else '>'}{self.min},{'<=' if 
self.include_max else '<'}{self.max}"
 
     def contains(
         self, version: UnparsedVersion, prereleases: bool | None = None
@@ -115,11 +115,8 @@
         if self.min is None:
             return True
 
-        return (
-            self.min < other.min
-            or self.min == other.min
-            and self.include_min
-            and not other.include_min
+        return self.min < other.min or (
+            self.min == other.min and self.include_min and not 
other.include_min
         )
 
     def allows_higher(self, other: RangeSpecifier) -> bool:
@@ -128,11 +125,8 @@
         if self.max is None:
             return True
 
-        return (
-            self.max > other.max
-            or self.max == other.max
-            and self.include_max
-            and not other.include_max
+        return self.max > other.max or (
+            self.max == other.max and self.include_max and not 
other.include_max
         )
 
     def is_strictly_lower(self, other: RangeSpecifier) -> bool:
@@ -142,10 +136,8 @@
         if self.max is None or other.min is None:
             return False
 
-        return (
-            self.max < other.min
-            or self.max == other.min
-            and False in (self.include_max, other.include_min)
+        return self.max < other.min or (
+            self.max == other.min and False in (self.include_max, 
other.include_min)
         )
 
     def is_adjacent_to(self, other: RangeSpecifier) -> bool:
@@ -162,22 +154,24 @@
         return self.allows_lower(other)
 
     def is_superset(self, other: RangeSpecifier) -> bool:
-        min_lower = (
-            self.min is None
-            or other.min is not None
+        min_lower = self.min is None or (
+            other.min is not None
             and (
                 self.min < other.min
-                or self.min == other.min
-                and not (not self.include_min and other.include_min)
+                or (
+                    self.min == other.min
+                    and not (not self.include_min and other.include_min)
+                )
             )
         )
-        max_higher = (
-            self.max is None
-            or other.max is not None
+        max_higher = self.max is None or (
+            other.max is not None
             and (
                 self.max > other.max
-                or self.max == other.max
-                and not (not self.include_max and other.include_max)
+                or (
+                    self.max == other.max
+                    and not (not self.include_max and other.include_max)
+                )
             )
         )
         return min_lower and max_higher
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/specifiers/special.py 
new/dep_logic-0.5.1/src/dep_logic/specifiers/special.py
--- old/dep_logic-0.4.10/src/dep_logic/specifiers/special.py    2024-12-13 
12:04:09.695863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/specifiers/special.py     2025-05-19 
11:34:42.944260100 +0200
@@ -36,7 +36,7 @@
         return True
 
     def __contains__(self, value: str) -> bool:
-        return True
+        return False
 
 
 class AnySpecifier(BaseSpecifier):
@@ -72,4 +72,4 @@
         return True
 
     def __contains__(self, value: str) -> bool:
-        return False
+        return True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/tags/platform.py 
new/dep_logic-0.5.1/src/dep_logic/tags/platform.py
--- old/dep_logic-0.4.10/src/dep_logic/tags/platform.py 2024-12-13 
12:04:09.696863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/tags/platform.py  2025-05-19 
11:34:42.944260100 +0200
@@ -118,9 +118,11 @@
             # Ex: macosx-11.2-arm64
             version, architecture = version_arch.rsplit("-", 1)
         else:
-            # Ex: linux-x86_64
+            # Ex: linux-x86_64 or x86_64_msvcrt_gnu
             version = None
             architecture = version_arch
+            if version_arch.startswith("x86_64"):
+                architecture = "x86_64"
 
         if operating_system == "linux":
             from packaging._manylinux import _get_glibc_version
@@ -337,6 +339,7 @@
     X86_64 = "x86_64"
     S390X = "s390x"
     RISCV64 = "riscv64"
+    LoongArch64 = "loongarch64"
 
     def __str__(self) -> str:
         return self.value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/tags/tags.py 
new/dep_logic-0.5.1/src/dep_logic/tags/tags.py
--- old/dep_logic-0.4.10/src/dep_logic/tags/tags.py     2024-12-13 
12:04:09.696863000 +0100
+++ new/dep_logic-0.5.1/src/dep_logic/tags/tags.py      2025-05-19 
11:34:42.944260100 +0200
@@ -155,7 +155,7 @@
         self, python_tag: str, abi_tag: str
     ) -> tuple[int, int, int] | None:
         """Return a tuple of (major, minor, abi) if the wheel is compatible 
with the environment, or None otherwise."""
-        impl, major, minor = python_tag[:2], python_tag[2], python_tag[3:]
+        impl, major, minor = python_tag[:2], python_tag[2:3], python_tag[3:]
         if self.implementation is not None and impl not in [
             self.implementation.short,
             "py",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/src/dep_logic/utils.py 
new/dep_logic-0.5.1/src/dep_logic/utils.py
--- old/dep_logic-0.4.10/src/dep_logic/utils.py 2024-12-13 12:04:09.696863000 
+0100
+++ new/dep_logic-0.5.1/src/dep_logic/utils.py  2025-05-19 11:34:42.944260100 
+0200
@@ -191,3 +191,7 @@
 
     def peek(self) -> T:
         return self._data[0]
+
+
+def normalize_name(name: str) -> str:
+    return re.sub(r"[-_.]+", "-", name).lower()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.4.10/tests/marker/test_evaluation.py 
new/dep_logic-0.5.1/tests/marker/test_evaluation.py
--- old/dep_logic-0.4.10/tests/marker/test_evaluation.py        2024-12-13 
12:04:09.696863000 +0100
+++ new/dep_logic-0.5.1/tests/marker/test_evaluation.py 2025-05-19 
11:34:42.945260000 +0200
@@ -21,17 +21,17 @@
             True,
         ),
         (
-            "python_version ~= '2.7.0' and (os_name == 'foo' or " "os_name == 
'bar')",
+            "python_version ~= '2.7.0' and (os_name == 'foo' or os_name == 
'bar')",
             {"os_name": "foo", "python_version": "2.7.4"},
             True,
         ),
         (
-            "python_version ~= '2.7.0' and (os_name == 'foo' or " "os_name == 
'bar')",
+            "python_version ~= '2.7.0' and (os_name == 'foo' or os_name == 
'bar')",
             {"os_name": "bar", "python_version": "2.7.4"},
             True,
         ),
         (
-            "python_version ~= '2.7.0' and (os_name == 'foo' or " "os_name == 
'bar')",
+            "python_version ~= '2.7.0' and (os_name == 'foo' or os_name == 
'bar')",
             {"os_name": "other", "python_version": "2.7.4"},
             False,
         ),
@@ -48,10 +48,9 @@
     ],
 )
 def test_evaluates(
-    marker_string: str, environment: dict[str, str], expected: bool
+    marker_string: str, environment: dict[str, str | set[str]], expected: bool
 ) -> None:
-    args = [] if environment is None else [environment]
-    assert parse_marker(marker_string).evaluate(*args) == expected
+    assert parse_marker(marker_string).evaluate(environment) == expected
 
 
 @pytest.mark.parametrize(
@@ -103,6 +102,7 @@
             {"platform_machine": "x86_64"},
             False,
         ),
+        ("platform_release >= '6'", {"platform_release": "6.1-foobar"}, True),
         # extras
         # single extra
         ("extra != 'security'", {"extra": "quux"}, True),
@@ -144,7 +144,7 @@
     ],
 )
 def test_evaluate_extra(
-    marker_string: str, environment: dict[str, str] | None, expected: bool
+    marker_string: str, environment: dict[str, str | set[str]] | None, 
expected: bool
 ) -> None:
     m = parse_marker(marker_string)
 
@@ -160,7 +160,43 @@
         )
     ],
 )
-def test_parse_version_like_markers(marker: str, env: dict[str, str]) -> None:
+def test_parse_version_like_markers(
+    marker: str, env: dict[str, str | set[str]]
+) -> None:
     m = parse_marker(marker)
 
     assert m.evaluate(env)
+
+
+@pytest.mark.parametrize("variable", ["extras", "dependency_groups"])
+@pytest.mark.parametrize(
+    "expression,result",
+    [
+        pytest.param('"foo" in {0}', True, id="value-in-foo"),
+        pytest.param('"bar" in {0}', True, id="value-in-bar"),
+        pytest.param('"baz" in {0}', False, id="value-not-in"),
+        pytest.param('"baz" not in {0}', True, id="value-not-in-negated"),
+        pytest.param('"foo" in {0} and "bar" in {0}', True, id="and-in"),
+        pytest.param('"foo" in {0} or "bar" in {0}', True, id="or-in"),
+        pytest.param('"baz" in {0} and "foo" in {0}', False, 
id="short-circuit-and"),
+        pytest.param('"foo" in {0} or "baz" in {0}', True, 
id="short-circuit-or"),
+        pytest.param('"Foo" in {0}', True, id="case-sensitive"),
+    ],
+)
+def test_extras_and_dependency_groups(
+    variable: str, expression: str, result: bool
+) -> None:
+    environment: dict[str, str | set[str]] = {variable: {"foo", "bar"}}
+    assert parse_marker(expression.format(variable)).evaluate(environment) == 
result
+
+
+@pytest.mark.parametrize("variable", ["extras", "dependency_groups"])
+def test_extras_and_dependency_groups_disallowed(variable: str) -> None:
+    marker = parse_marker(f'"foo" in {variable}')
+    assert not marker.evaluate(context="lock_file")
+
+    with pytest.raises(KeyError):
+        marker.evaluate()
+
+    with pytest.raises(KeyError):
+        marker.evaluate(context="requirement")

Reply via email to