{"record":{"id":"5f8ee8ec94f084f8","repo":"pypa/pip","slug":"set-relations-do-not-support-specifiers","errorCode":null,"errorMessage":"set relations do not support === specifiers","messagePattern":"set relations do not support === specifiers","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/specifiers.py","lineNumber":1147,"sourceCode":"        \"\"\"Return the :class:`~packaging.ranges.VersionRange` this set accepts.\n\n        An empty set yields the full range; an unsatisfiable set yields the\n        empty range. ``===`` specifiers contribute literal-string admission.\n\n        >>> SpecifierSet(\">=1.0,<2.0\").to_range()\n        <VersionRange '[1.0, 2.0.dev0)'>\n\n        .. versionadded:: 26.3\n        \"\"\"\n        from .ranges import VersionRange  # noqa: PLC0415\n\n        return VersionRange._from_specifier_set(self)\n\n    def _check_relation_operand(self, other: object) -> None:\n        if not isinstance(other, SpecifierSet):\n            raise TypeError(\"expected a SpecifierSet\")\n        if self._has_arbitrary or other._has_arbitrary:\n            raise ValueError(\"set relations do not support === specifiers\")\n\n    def is_subset(self, other: SpecifierSet) -> bool:\n        \"\"\"Return whether every version matching this set also matches other.\n\n        :raises ValueError:\n            If either set uses ``===`` specifiers, or the two sets were\n            given different ``prereleases`` arguments (unset on one side\n            counts as different).\n        :raises TypeError:\n            If other is not a :class:`SpecifierSet`.\n\n        >>> SpecifierSet(\">=3.12,<3.13\").is_subset(SpecifierSet(\">=3.12\"))\n        True\n        >>> SpecifierSet(\">=3.12\").is_subset(SpecifierSet(\">=3.12,<3.13\"))\n        False\n\n        .. versionadded:: 26.3\n        \"\"\"","sourceCodeStart":1129,"sourceCodeEnd":1165,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/specifiers.py#L1129-L1165","documentation":"Raised as ValueError by SpecifierSet._check_relation_operand (specifiers.py:1147) when either operand of a set relation (is_subset/is_superset/etc.) contains an arbitrary-equality (===) specifier. The _has_arbitrary flag (set during construction from any '===' token) makes set relations mathematically undefined, because === does literal string matching rather than version-range admission, so subset/superset reasoning does not apply.","triggerScenarios":"SpecifierSet('===1.0').is_subset(SpecifierSet('>=1.0')); either side built from a requirement that uses '===' (e.g. a local/version-locked pin '===1.0.0+local'); combining a frozen-pin requirement with a range-based policy check.","commonSituations":"A lock file or resolver that emits '===' pins being fed into a dependency-overlap analyzer using is_subset; tools that compare 'compatible ranges' across packages where one package uses arbitrary equality; PEP 440 edge-case testing.","solutions":["Filter out or convert === specifiers before computing set relations, or skip the relation for sets that use them.","Detect _has_arbitrary (or '===' in str(ss)) and report that comparison is unsupported for arbitrary pins.","Replace the === pin with an == pin if exact version admission (rather than literal string equality) is intended, then re-run the relation.","Restructure to compare via contains() per-candidate instead of subset/superset when === is involved."],"exampleFix":"# before\na = SpecifierSet('===1.2.3')\nb = SpecifierSet('>=1.0')\na.is_subset(b)  # ValueError: set relations do not support === specifiers\n\n# after - guard and skip, or convert to ==\nif '===' in str(a) or '===' in str(b):\n    raise NotImplementedError('subset not defined for === pins')\n# or: a = SpecifierSet('==1.2.3')  # if exact version admission is meant","handlingStrategy":"validation","validationCode":"from packaging.specifiers import SpecifierSet\n\ndef safe_subset(a: SpecifierSet, b: SpecifierSet):\n    if '===' in str(a) or '===' in str(b):\n        raise NotImplementedError('set relations unsupported with === specifiers')\n    return a.is_subset(b)","typeGuard":"from packaging.specifiers import SpecifierSet\ndef has_no_arbitrary(ss: SpecifierSet) -> bool:\n    return not ss._has_arbitrary","tryCatchPattern":"try:\n    a.is_subset(b)\nexcept ValueError:\n    # fall back to per-candidate contains() checks\n    ...","preventionTips":["Avoid === specifiers except for literal string pins; prefer ==.","Check _has_arbitrary (or '===' in str) before calling set relations.","Document that === pins are excluded from subset/superset analysis."],"tags":["packaging","specifiers","pep440","arbitrary-equality","api-usage"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}