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 2026-08-21 17:01:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-dep-logic (Old)
 and      /work/SRC/openSUSE:Factory/.python-dep-logic.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-dep-logic"

Fri Aug 21 17:01:16 2026 rev:10 rq:1372809 version:0.7.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-dep-logic/python-dep-logic.changes        
2026-06-15 19:45:12.375845388 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-dep-logic.new.1258/python-dep-logic.changes  
    2026-08-21 17:02:35.862763807 +0200
@@ -1,0 +2,10 @@
+Fri Aug 21 10:19:59 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 0.7.1:
+  * Return AnyMarker in EqualityMarkerUnion for complement case
+    and add corresponding test
+- update to 0.7.0:
+  * Update dependencies and improve type hints across the
+    codebase
+
+-------------------------------------------------------------------

Old:
----
  dep_logic-0.6.0.tar.gz

New:
----
  dep_logic-0.7.1.tar.gz

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

Other differences:
------------------
++++++ python-dep-logic.spec ++++++
--- /var/tmp/diff_new_pack.VOPr2X/_old  2026-08-21 17:02:36.755795425 +0200
+++ /var/tmp/diff_new_pack.VOPr2X/_new  2026-08-21 17:02:36.757795495 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-dep-logic
-Version:        0.6.0
+Version:        0.7.1
 Release:        0
 Summary:        Python dependency specifications supporting logical operations
 License:        Apache-2.0

++++++ dep_logic-0.6.0.tar.gz -> dep_logic-0.7.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/PKG-INFO new/dep_logic-0.7.1/PKG-INFO
--- old/dep_logic-0.6.0/PKG-INFO        1970-01-01 01:00:00.000000000 +0100
+++ new/dep_logic-0.7.1/PKG-INFO        1970-01-01 01:00:00.000000000 +0100
@@ -1,19 +1,18 @@
 Metadata-Version: 2.1
 Name: dep-logic
-Version: 0.6.0
+Version: 0.7.1
 Summary: Python dependency specifications supporting logical operations
 Keywords: dependency,specification,logic,packaging
 Author-Email: Frost Ming <[email protected]>
 License: Apache-2.0
 Classifier: Intended Audience :: Developers
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
 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.9
+Requires-Python: >=3.10
 Requires-Dist: packaging>=22
 Description-Content-Type: text/markdown
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/pyproject.toml 
new/dep_logic-0.7.1/pyproject.toml
--- old/dep_logic-0.6.0/pyproject.toml  2026-05-19 13:17:55.957042500 +0200
+++ new/dep_logic-0.7.1/pyproject.toml  2026-08-10 11:31:10.026974200 +0200
@@ -7,7 +7,7 @@
 dependencies = [
     "packaging>=22",
 ]
-requires-python = ">=3.9"
+requires-python = ">=3.10"
 readme = "README.md"
 dynamic = []
 keywords = [
@@ -19,14 +19,13 @@
 classifiers = [
     "Intended Audience :: Developers",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.9",
     "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.6.0"
+version = "0.7.1"
 
 [project.license]
 text = "Apache-2.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/markers/__init__.py 
new/dep_logic-0.7.1/src/dep_logic/markers/__init__.py
--- old/dep_logic-0.6.0/src/dep_logic/markers/__init__.py       2026-05-19 
13:17:43.453691700 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/markers/__init__.py       2026-08-10 
11:30:59.525632900 +0200
@@ -20,14 +20,13 @@
 from dep_logic.utils import get_reflect_op
 
 if TYPE_CHECKING:
-    from typing import List, Literal, Tuple, Union
+    from collections.abc import Sequence
+    from typing import Literal
 
     from packaging.markers import Op, Value, Variable
 
-    _ParsedMarker = Tuple[Variable, Op, Value]
-    _ParsedMarkers = Union[
-        _ParsedMarker, List[Union["_ParsedMarkers", Literal["or", "and"]]]
-    ]
+    _ParsedMarker = tuple[Variable | Value, Op, Variable | Value]
+    _ParsedMarkers = _ParsedMarker | Sequence["_ParsedMarkers" | Literal["or", 
"and"]]
 
 
 __all__ = [
@@ -49,7 +48,7 @@
     """
 
 
[email protected]_cache(maxsize=None)
[email protected]
 def parse_marker(marker: str) -> BaseMarker:
     if marker == "<empty>":
         return EmptyMarker()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/markers/multi.py 
new/dep_logic-0.7.1/src/dep_logic/markers/multi.py
--- old/dep_logic-0.6.0/src/dep_logic/markers/multi.py  2026-05-19 
13:17:43.453745400 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/markers/multi.py  2026-08-10 
11:30:59.525668600 +0200
@@ -1,16 +1,16 @@
 from __future__ import annotations
 
+from collections.abc import Iterator
 from dataclasses import dataclass
-from typing import Iterator
 
 from dep_logic.markers.any import AnyMarker
 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
+from dep_logic.utils import flatten_items, intersection, union
 
 
-@dataclass(init=False, frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(init=False, frozen=True, unsafe_hash=True, slots=True, repr=False)
 class MultiMarker(BaseMarker):
     markers: tuple[BaseMarker, ...]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/markers/single.py 
new/dep_logic-0.7.1/src/dep_logic/markers/single.py
--- old/dep_logic-0.6.0/src/dep_logic/markers/single.py 2026-05-19 
13:17:43.453745400 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/markers/single.py 2026-08-10 
11:30:59.525668600 +0200
@@ -16,7 +16,7 @@
 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, 
normalize_name
+from dep_logic.utils import OrderedSet, get_reflect_op, normalize_name
 
 if t.TYPE_CHECKING:
     from dep_logic.markers.multi import MultiMarker
@@ -24,7 +24,7 @@
 
 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]
+Operator = t.Callable[[str, str | set[str]], bool]
 _operators: dict[str, Operator] = {
     "in": lambda lhs, rhs: lhs in rhs,
     "not in": lambda lhs, rhs: lhs not in rhs,
@@ -85,7 +85,7 @@
         raise NotImplementedError
 
 
-@dataclass(unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(unsafe_hash=True, slots=True, repr=False)
 class MarkerExpression(SingleMarker):
     name: str
     op: str
@@ -108,7 +108,10 @@
         if isinstance(specifier, VersionSpecifier):
             if not specifier.is_simple():
                 return None
-            pkg_spec = next(iter(specifier.to_specifierset()))
+            pkg_specs = specifier.to_specifierset()
+            if len(pkg_specs) != 1:
+                return None
+            pkg_spec = next(iter(pkg_specs))
             pkg_version = pkg_spec.version
             if (
                 dot_num := pkg_version.count(".")
@@ -211,7 +214,7 @@
         return oper(lhs, rhs)
 
 
-@dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(frozen=True, unsafe_hash=True, slots=True, repr=False)
 class EqualityMarkerUnion(SingleMarker):
     name: str
     values: OrderedSet[str]
@@ -264,7 +267,7 @@
                 return replace(self, values=self.values | {other.value})
             if other.op == "!=":
                 if other.value in self.values:
-                    AnyMarker()
+                    return AnyMarker()
                 return other
             if all(v in other.specifier for v in self.values):
                 return other
@@ -283,7 +286,7 @@
         return environment[self.name] in self.values
 
 
-@dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(frozen=True, unsafe_hash=True, slots=True, repr=False)
 class InequalityMultiMarker(SingleMarker):
     name: str
     values: OrderedSet[str]
@@ -359,7 +362,7 @@
         return environment[self.name] not in self.values
 
 
[email protected]_cache(maxsize=None)
[email protected]
 def _merge_single_markers(
     marker1: MarkerExpression,
     marker2: MarkerExpression,
@@ -376,9 +379,8 @@
 
     # "extra" is special because it can have multiple values at the same time.
     # That's why we can only merge two "extra" markers if they have the same 
value.
-    if marker1.name == "extra":
-        if marker1.value != marker2.value:  # type: ignore[attr-defined]
-            return None
+    if marker1.name == "extra" and marker1.value != marker2.value:  # type: 
ignore[attr-defined]
+        return None
     try:
         if merge_class is MultiMarker:
             result_specifier = marker1.specifier & marker2.specifier
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/markers/union.py 
new/dep_logic-0.7.1/src/dep_logic/markers/union.py
--- old/dep_logic-0.6.0/src/dep_logic/markers/union.py  2026-05-19 
13:17:43.453745400 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/markers/union.py  2026-08-10 
11:30:59.525668600 +0200
@@ -1,17 +1,17 @@
 from __future__ import annotations
 
+from collections.abc import Iterator
 from dataclasses import dataclass
-from typing import Iterator
 
 from dep_logic.markers.any import AnyMarker
 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
-from dep_logic.utils import DATACLASS_ARGS, flatten_items, intersection, union
+from dep_logic.utils import flatten_items, intersection, union
 
 
-@dataclass(init=False, frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(init=False, frozen=True, unsafe_hash=True, slots=True, repr=False)
 class MarkerUnion(BaseMarker):
     markers: tuple[BaseMarker, ...]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/markers/utils.py 
new/dep_logic-0.7.1/src/dep_logic/markers/utils.py
--- old/dep_logic-0.6.0/src/dep_logic/markers/utils.py  2026-05-19 
13:17:43.453745400 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/markers/utils.py  2026-08-10 
11:30:59.525668600 +0200
@@ -2,14 +2,16 @@
 
 import functools
 import itertools
-from typing import AbstractSet, Iterable, Iterator, TypeVar
+from collections.abc import Iterable, Iterator
+from collections.abc import Set as AbstractSet
+from typing import TypeVar
 
 from dep_logic.markers.base import BaseMarker
 
 T = TypeVar("T")
 
 
[email protected]_cache(maxsize=None)
[email protected]
 def cnf(marker: BaseMarker) -> BaseMarker:
     from dep_logic.markers.multi import MultiMarker
     from dep_logic.markers.union import MarkerUnion
@@ -30,7 +32,7 @@
     return marker
 
 
[email protected]_cache(maxsize=None)
[email protected]
 def dnf(marker: BaseMarker) -> BaseMarker:
     """Transforms the marker into DNF (disjunctive normal form)."""
     from dep_logic.markers.multi import MultiMarker
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/specifiers/__init__.py 
new/dep_logic-0.7.1/src/dep_logic/specifiers/__init__.py
--- old/dep_logic-0.6.0/src/dep_logic/specifiers/__init__.py    2026-05-19 
13:17:43.453745400 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/specifiers/__init__.py    2026-08-10 
11:30:59.525668600 +0200
@@ -119,15 +119,15 @@
 
 
 __all__ = [
-    "from_specifierset",
-    "parse_version_specifier",
-    "VersionSpecifier",
-    "EmptySpecifier",
     "AnySpecifier",
-    "RangeSpecifier",
-    "UnionSpecifier",
+    "ArbitrarySpecifier",
     "BaseSpecifier",
+    "EmptySpecifier",
     "GenericSpecifier",
-    "ArbitrarySpecifier",
     "InvalidSpecifier",
+    "RangeSpecifier",
+    "UnionSpecifier",
+    "VersionSpecifier",
+    "from_specifierset",
+    "parse_version_specifier",
 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/dep_logic-0.6.0/src/dep_logic/specifiers/arbitrary.py 
new/dep_logic-0.7.1/src/dep_logic/specifiers/arbitrary.py
--- old/dep_logic-0.6.0/src/dep_logic/specifiers/arbitrary.py   2026-05-19 
13:17:43.454097700 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/specifiers/arbitrary.py   2026-08-10 
11:30:59.525967400 +0200
@@ -7,10 +7,9 @@
 
 from dep_logic.specifiers.base import BaseSpecifier, UnparsedVersion, 
VersionSpecifier
 from dep_logic.specifiers.special import EmptySpecifier
-from dep_logic.utils import DATACLASS_ARGS
 
 
-@dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(frozen=True, unsafe_hash=True, slots=True, repr=False)
 class ArbitrarySpecifier(VersionSpecifier):
     """`===<version_string>` specifier."""
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/specifiers/base.py 
new/dep_logic-0.7.1/src/dep_logic/specifiers/base.py
--- old/dep_logic-0.6.0/src/dep_logic/specifiers/base.py        2026-05-19 
13:17:43.454097700 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/specifiers/base.py        2026-08-10 
11:30:59.525967400 +0200
@@ -6,7 +6,7 @@
 from packaging.specifiers import SpecifierSet
 from packaging.version import Version
 
-UnparsedVersion = t.Union[Version, str]
+UnparsedVersion = Version | str
 
 
 class InvalidSpecifier(ValueError):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/specifiers/generic.py 
new/dep_logic-0.7.1/src/dep_logic/specifiers/generic.py
--- old/dep_logic-0.6.0/src/dep_logic/specifiers/generic.py     2026-05-19 
13:17:43.454097700 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/specifiers/generic.py     2026-08-10 
11:30:59.525967400 +0200
@@ -6,12 +6,11 @@
 
 from dep_logic.specifiers.base import BaseSpecifier, InvalidSpecifier
 from dep_logic.specifiers.special import AnySpecifier, EmptySpecifier
-from dep_logic.utils import DATACLASS_ARGS
 
 Operator = t.Callable[[str, str], bool]
 
 
-@dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(frozen=True, unsafe_hash=True, slots=True, repr=False)
 class GenericSpecifier(BaseSpecifier):
     op: str
     value: str
@@ -86,11 +85,11 @@
             if this.value == that.value:
                 return AnySpecifier()
             return that
-        elif this.op == "!=" and that.op == "!=":
-            return AnySpecifier()
-        elif this.op == "in" and that.op == "not in" and this.value == 
that.value:
-            return AnySpecifier()
-        elif this.op == "!=" and that.op == "in" and this.value in that.value:
+        elif (
+            (this.op == "!=" and that.op == "!=")
+            or (this.op == "in" and that.op == "not in" and this.value == 
that.value)
+            or (this.op == "!=" and that.op == "in" and this.value in 
that.value)
+        ):
             return AnySpecifier()
         elif this.op == "!=" and that.op == "not in":
             if this.value in that.value:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/specifiers/range.py 
new/dep_logic-0.7.1/src/dep_logic/specifiers/range.py
--- old/dep_logic-0.6.0/src/dep_logic/specifiers/range.py       2026-05-19 
13:17:43.454097700 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/specifiers/range.py       2026-08-10 
11:30:59.525967400 +0200
@@ -14,10 +14,10 @@
     VersionSpecifier,
 )
 from dep_logic.specifiers.special import EmptySpecifier
-from dep_logic.utils import DATACLASS_ARGS, first_different_index, pad_zeros
+from dep_logic.utils import first_different_index, pad_zeros
 
 
-@dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(frozen=True, unsafe_hash=True, slots=True, repr=False)
 class RangeSpecifier(VersionSpecifier):
     min: Version | None = None
     max: Version | None = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/specifiers/union.py 
new/dep_logic-0.7.1/src/dep_logic/specifiers/union.py
--- old/dep_logic-0.6.0/src/dep_logic/specifiers/union.py       2026-05-19 
13:17:43.454097700 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/specifiers/union.py       2026-08-10 
11:30:59.525967400 +0200
@@ -10,10 +10,10 @@
 from dep_logic.specifiers.base import BaseSpecifier, UnparsedVersion, 
VersionSpecifier
 from dep_logic.specifiers.range import RangeSpecifier
 from dep_logic.specifiers.special import EmptySpecifier
-from dep_logic.utils import DATACLASS_ARGS, first_different_index, pad_zeros
+from dep_logic.utils import first_different_index, pad_zeros
 
 
-@dataclass(frozen=True, unsafe_hash=True, **DATACLASS_ARGS)
+@dataclass(frozen=True, unsafe_hash=True, slots=True, repr=False)
 class UnionSpecifier(VersionSpecifier):
     ranges: tuple[RangeSpecifier, ...]
     simplified: str | None = field(default=None, compare=False, hash=False)
@@ -31,23 +31,32 @@
     def _simplified_form(self) -> str | None:
         if self.simplified is not None:
             return self.simplified
+
         # try to get a not-equals form(!=) if possible
         left, right, *rest = self.ranges
         if rest:
             return None
+
+        def with_outer_bounds(exclusion: str) -> str:
+            parts: list[str] = []
+            if left.min is not None:
+                parts.append(f"{'>=' if left.include_min else '>'}{left.min}")
+            parts.append(exclusion)
+            if right.max is not None:
+                parts.append(f"{'<=' if right.include_max else 
'<'}{right.max}")
+            return ",".join(parts)
+
         if (
-            left.min is None
-            and right.max is None
-            and left.max == right.min
+            left.max == right.min
             and left.max is not None
+            and not left.include_max
+            and not right.include_min
         ):
-            # (-inf, version) | (version, inf) => != version
-            return f"!={left.max}"
+            # [lower, version) | (version, upper] => lower, != version, upper
+            return with_outer_bounds(f"!={left.max}")
 
         if (
-            left.min is None
-            and right.max is None
-            and not left.include_max
+            not left.include_max
             and right.include_min
             and left.max is not None
             and right.min is not None
@@ -72,7 +81,7 @@
             ):
                 epoch = "" if left.max.epoch == 0 else f"{left.max.epoch}!"
                 version = ".".join(map(str, 
left.max.release[:first_different])) + ".*"
-                return f"!={epoch}{version}"
+                return with_outer_bounds(f"!={epoch}{version}")
 
         return None
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/tags/__init__.py 
new/dep_logic-0.7.1/src/dep_logic/tags/__init__.py
--- old/dep_logic-0.6.0/src/dep_logic/tags/__init__.py  2026-05-19 
13:17:43.454097700 +0200
+++ new/dep_logic-0.7.1/src/dep_logic/tags/__init__.py  2026-08-10 
11:30:59.525967400 +0200
@@ -9,12 +9,12 @@
 )
 
 __all__ = [
+    "EnvCompatibility",
+    "EnvSpec",
+    "Implementation",
+    "InvalidWheelFilename",
     "Platform",
     "PlatformError",
     "TagsError",
     "UnsupportedImplementation",
-    "InvalidWheelFilename",
-    "EnvSpec",
-    "Implementation",
-    "EnvCompatibility",
 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/src/dep_logic/utils.py 
new/dep_logic-0.7.1/src/dep_logic/utils.py
--- old/dep_logic-0.6.0/src/dep_logic/utils.py  2026-05-19 13:17:43.454399600 
+0200
+++ new/dep_logic-0.7.1/src/dep_logic/utils.py  2026-08-10 11:30:59.526165000 
+0200
@@ -3,31 +3,20 @@
 import functools
 import itertools
 import re
-import sys
-from typing import TYPE_CHECKING, AbstractSet, Iterable, Iterator, Protocol, 
TypeVar
+from collections.abc import Iterable, Iterator
+from collections.abc import Set as AbstractSet
+from typing import TYPE_CHECKING, Protocol, TypeVar
 
 _prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
 
 if TYPE_CHECKING:
-    from typing import TypedDict
-
     from dep_logic.markers.base import BaseMarker
 
-    class _DataClassArgs(TypedDict, total=False):
-        slots: bool
-        repr: bool
-
-
-if sys.version_info >= (3, 10):
-    DATACLASS_ARGS: _DataClassArgs = {"slots": True, "repr": False}
-else:
-    DATACLASS_ARGS = {"repr": False}
-
 
 class Ident(Protocol):
     def __hash__(self) -> int: ...
 
-    def __eq__(self, __value: object) -> bool: ...
+    def __eq__(self, __value: object, /) -> bool: ...
 
 
 T = TypeVar("T", bound=Ident)
@@ -79,7 +68,7 @@
     return parts + [0] * (to_length - len(parts))
 
 
[email protected]_cache(maxsize=None)
[email protected]
 def cnf(marker: BaseMarker) -> BaseMarker:
     from dep_logic.markers.multi import MultiMarker
     from dep_logic.markers.union import MarkerUnion
@@ -100,7 +89,7 @@
     return marker
 
 
[email protected]_cache(maxsize=None)
[email protected]
 def dnf(marker: BaseMarker) -> BaseMarker:
     """Transforms the marker into DNF (disjunctive normal form)."""
     from dep_logic.markers.multi import MultiMarker
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/tests/marker/test_compound.py 
new/dep_logic-0.7.1/tests/marker/test_compound.py
--- old/dep_logic-0.6.0/tests/marker/test_compound.py   2026-05-19 
13:17:43.454690700 +0200
+++ new/dep_logic-0.7.1/tests/marker/test_compound.py   2026-08-10 
11:30:59.526422000 +0200
@@ -55,6 +55,15 @@
     assert m2 & m1.is_any()
 
 
+def test_equality_marker_union_with_complement_is_any() -> None:
+    marker = parse_marker('os_name == "a" or os_name == "b" or os_name != "a"')
+
+    assert marker.is_any()
+    assert marker.evaluate({"os_name": "a"})
+    assert marker.evaluate({"os_name": "b"})
+    assert marker.evaluate({"os_name": "c"})
+
+
 def test_multi_marker_intersect_multi() -> None:
     m = parse_marker('sys_platform == "darwin" and implementation_name == 
"cpython"')
 
@@ -354,8 +363,7 @@
 
     intersection = m & m2
     expected = (
-        'python_version >= "2.7" and python_version < "2.8" '
-        'or python_version ~= "3.4"'
+        'python_version >= "2.7" and python_version < "2.8" or python_version 
~= "3.4"'
     )
     assert str(intersection) == expected
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/tests/specifier/test_range.py 
new/dep_logic-0.7.1/tests/specifier/test_range.py
--- old/dep_logic-0.6.0/tests/specifier/test_range.py   2026-05-19 
13:17:43.454963700 +0200
+++ new/dep_logic-0.7.1/tests/specifier/test_range.py   2026-08-10 
11:30:59.526664500 +0200
@@ -97,7 +97,6 @@
         (RangeSpecifier(min=Version("1.0")), ">1.0"),
         (RangeSpecifier(min=Version("1.0"), include_min=True), ">=1.0"),
         (RangeSpecifier(max=Version("1.0")), "<1.0"),
-        (RangeSpecifier(max=Version("1.0")), "<1.0"),
         (
             RangeSpecifier(
                 min=Version("1.0"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dep_logic-0.6.0/tests/specifier/test_union.py 
new/dep_logic-0.7.1/tests/specifier/test_union.py
--- old/dep_logic-0.6.0/tests/specifier/test_union.py   2026-05-19 
13:17:43.454963700 +0200
+++ new/dep_logic-0.7.1/tests/specifier/test_union.py   2026-08-10 
11:30:59.526664500 +0200
@@ -1,4 +1,5 @@
 import pytest
+from packaging.specifiers import SpecifierSet
 from packaging.version import Version
 
 from dep_logic.specifiers import (
@@ -39,6 +40,23 @@
 
 
 @pytest.mark.parametrize(
+    "spec,expected",
+    [
+        (">=3,<4||>4", ">=3,!=4"),
+        (">=3,<4||>4,<5", ">=3,!=4,<5"),
+        ("<4||>4,<5", "!=4,<5"),
+        (">=1,<2.0||>=3.0", ">=1,!=2.*"),
+    ],
+)
+def test_simplify_union_with_outer_bounds(spec: str, expected: str) -> None:
+    value = parse_version_specifier(spec)
+    assert isinstance(value, UnionSpecifier)
+    assert value.is_simple()
+    assert str(value) == expected
+    assert value.to_specifierset() == SpecifierSet(expected)
+
+
[email protected](
     "spec,parsed",
     [
         (
@@ -72,7 +90,7 @@
 @pytest.mark.parametrize(
     "a,b,expected",
     [
-        ("!=2.0", ">=1.0", "~=1.0||>2.0"),
+        ("!=2.0", ">=1.0", ">=1.0,!=2.0"),
         ("!=2.0", ">=2.0", ">2.0"),
         ("~=2.7||>=3.6", "==3.3", "<empty>"),
         ("~=2.7||>=3.6", "<3.0", "~=2.7"),

Reply via email to