{"record":{"id":"d792701b63ae4c70","repo":"pypa/pip","slug":"cannot-create-versionrange-instances-directly-u","errorCode":null,"errorMessage":"cannot create 'VersionRange' instances directly; use SpecifierSet.to_range(), VersionRange.full(), VersionRange.empty(), or VersionRange.singleton() instead","messagePattern":"cannot create 'VersionRange' instances directly; use SpecifierSet\\.to_range\\(\\), VersionRange\\.full\\(\\), VersionRange\\.empty\\(\\), or VersionRange\\.singleton\\(\\) instead","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/ranges.py","lineNumber":998,"sourceCode":"    #: configured override). The opt-in flows only from the pre-release-naming\n    #: specifiers that built the range. :meth:`_build` clips the region to the\n    #: bounds, so it is always a subset of them: an opt-in that overflowed its\n    #: own cap cannot ride a later union into versions no specifier asked for.\n    #: :meth:`union` and :meth:`intersection` accumulate the operands' clipped\n    #: regions and re-clip to the result bounds; :meth:`difference` keeps only\n    #: the minuend's; and :meth:`complement` drops it, since an exclusion grants\n    #: no opt-in. Equality keys on the clipped region, so it stays a congruence.\n    _pre_region: tuple[Interval, ...]\n\n    #: Raw configured pre-release override of the originating specifier set\n    #: (an explicit ``True`` / ``False``, else ``None``). When set, :meth:`_build`\n    #: forces ``_pre_region`` empty since the policy governs globally.\n    #: :meth:`intersection` and :meth:`union` require it to match on both\n    #: operands. Part of equality.\n    _prereleases_configured: bool | None\n\n    def __new__(cls, *args: object, **kwargs: object) -> VersionRange:  # noqa: PYI034\n        raise TypeError(\n            \"cannot create 'VersionRange' instances directly; use \"\n            \"SpecifierSet.to_range(), VersionRange.full(), \"\n            \"VersionRange.empty(), or VersionRange.singleton() instead\"\n        )\n\n    @classmethod\n    def _build(\n        cls,\n        bounds: tuple[Interval, ...],\n        admit: frozenset[str] = frozenset(),\n        reject: frozenset[str] = frozenset(),\n        admit_arbitrary: bool = False,\n        *,\n        pre_region: tuple[Interval, ...] = (),\n        prereleases_configured: bool | None = None,\n    ) -> VersionRange:\n        \"\"\"Internal factory; bypasses :meth:`__new__`.\n","sourceCodeStart":980,"sourceCodeEnd":1016,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/ranges.py#L980-L1016","documentation":"TypeError raised by VersionRange.__new__ because direct instantiation is intentionally blocked. VersionRange is an immutable value type with canonicalization invariants enforced by internal factories, so callers must construct it through the documented entry points: SpecifierSet.to_range(), VersionRange.full(), VersionRange.empty(), or VersionRange.singleton().","triggerScenarios":"Calling VersionRange(...) directly, e.g. VersionRange() or VersionRange('>=1.0'). The overridden __new__ unconditionally raises before any arguments are considered.","commonSituations":"A developer guessing the API from the class name; migrating code that built a SpecifierSet and now wants a range; copy-pasting from a tutorial that predates the factory API.","solutions":["Replace VersionRange(...) with the appropriate factory: VersionRange.full() for all versions, VersionRange.empty() for none, VersionRange.singleton('1.0') for exactly one version.","For a specifier-derived range, build a SpecifierSet first and call .to_range(): SpecifierSet('>=1.0,<2.0').to_range().","If you need the union/intersection of existing ranges, use .union()/.intersection() on ranges you already have rather than constructing a new one directly.","Check the docstring of the factory you choose for pre-release-policy semantics."],"exampleFix":"# before\nr = VersionRange('>=1.0,<2.0')\n\n# after\nfrom packaging.specifiers import SpecifierSet\nr = SpecifierSet('>=1.0,<2.0').to_range()\n# or for a single point / full / empty:\n# VersionRange.singleton('1.0'), VersionRange.full(), VersionRange.empty()","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"# Reject direct construction at the boundary; only allow factory results.\nfrom packaging.ranges import VersionRange\n\ndef is_version_range(x) -> bool:\n    return isinstance(x, VersionRange)\n\n# construction helper that never calls VersionRange(...) directly\ndef make_range(spec_or_kind):\n    if isinstance(spec_or_kind, VersionRange):\n        return spec_or_kind\n    if spec_or_kind in ('full', 'empty'):\n        return VersionRange.full() if spec_or_kind == 'full' else VersionRange.empty()\n    from packaging.specifiers import SpecifierSet\n    return SpecifierSet(spec_or_kind).to_range()","tryCatchPattern":"try:\n    r = make_range(spec)\nexcept TypeError:\n    # called VersionRange(...) directly by mistake; route through a factory\n    raise","preventionTips":["Never call VersionRange(...); remember the four entry points: full, empty, singleton, SpecifierSet.to_range().","Wrap range creation in a helper so all call sites go through factories.","Type-hint helpers as VersionRange so misuse shows up in static analysis."],"tags":["packaging","versionrange","api-misuse","constructor"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}