Skip to content

Fully cover handling arbitrary equality (===) in Specifier and SpecifierSet. #943

Closed

Description

@notatallshaw

As part of implementing #940 I am finding a lot of gaps in SpecifierSet for arbitrary equality.

For example are any of these valid SpecifierSets:

  • ===1.0
  • ===1.0,===1.0
  • ===1.0,===1.0.0
  • >=1.0,===1.0.0
  • ===foo
  • >=1.0,===foo

The problem is _coerce_version has to be used as part of filter to properly implement PEP 440, but it will break if arbitrary strings are used validly as part of ===foo.

I believe the first step is to accept #932, and then add many edge cases tests for arbitrary equality and review if their output looks reasonable or not.

I am not yet working on a PR for this, I will wait until #932 is accepted or rejected.

Activity

  1. notatallshaw commented on Oct 14, 2025

    @notatallshaw
    MemberAuthor

    Here's are some specific issues:

    === works are expected when filtering against one specifier:

    >>> list(SpecifierSet("===1.0").filter(["1.0"]))
    ['1.0']
    >>> list(SpecifierSet("===1.0").filter(["1.0.0"]))
    []
    >>> list(SpecifierSet("===1.0.0").filter(["1.0"]))
    []
    >>> list(SpecifierSet("===1.0.0").filter(["1.0.0"]))
    ['1.0.0']
    

    But breaks when filtering against two specifiers:

    >>> list(SpecifierSet("===1.0,===1.0.0").filter(["1.0"]))
    ['1.0']
    

    Further, arbitrary versions do not work as per PEP 440:

    >>> list(SpecifierSet("===foo").filter(["foo"]))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/home/damian/opensource/contributions/packaging/src/packaging/specifiers.py", line 945, in filter
        if prereleases is None and self.prereleases is not None:
      File "/home/damian/opensource/contributions/packaging/src/packaging/specifiers.py", line 727, in prereleases
        if any(s.prereleases for s in self._specs):
      File "/home/damian/opensource/contributions/packaging/src/packaging/specifiers.py", line 727, in <genexpr>
        if any(s.prereleases for s in self._specs):
      File "/home/damian/opensource/contributions/packaging/src/packaging/specifiers.py", line 265, in prereleases
        if Version(version).is_prerelease:
      File "/home/damian/opensource/contributions/packaging/src/packaging/version.py", line 203, in __init__
        raise InvalidVersion(f"Invalid version: {version!r}")
    packaging.version.InvalidVersion: Invalid version: 'foo'
    
  2. notatallshaw commented on May 17, 2026

    @notatallshaw
    MemberAuthor

    @Sean-Kenneth-Doherty thanks for the reminder, indeed fully covered this already, including clarifying the standards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions