ranges.py 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. """Public :class:`VersionRange` API.
  5. A set-algebra view of the versions accepted by a
  6. :class:`~packaging.specifiers.SpecifierSet`. Ranges support intersection,
  7. union, complement, and difference; membership and filtering match the
  8. originating specifier set; and conversion back to a
  9. :class:`~packaging.specifiers.SpecifierSet` is available where a PEP 440 form
  10. exists.
  11. .. testsetup::
  12. from packaging.ranges import VersionRange
  13. from packaging.specifiers import SpecifierSet
  14. from packaging.version import Version
  15. """
  16. from __future__ import annotations
  17. import enum
  18. import typing
  19. from typing import (
  20. TYPE_CHECKING,
  21. Any,
  22. TypeVar,
  23. Union,
  24. )
  25. from ._ranges import (
  26. FULL_RANGE,
  27. MIN_VERSION,
  28. NEG_INF,
  29. POS_INF,
  30. BoundaryKind,
  31. BoundaryVersion,
  32. LowerBound,
  33. UpperBound,
  34. coerce_version,
  35. filter_by_ranges,
  36. intersect_ranges,
  37. least_version_above,
  38. matches_bounds_only,
  39. range_is_empty,
  40. ranges_are_prerelease_only,
  41. trim_release,
  42. )
  43. from .version import Version
  44. if TYPE_CHECKING:
  45. from collections.abc import Callable, Iterable, Iterator, Sequence
  46. from ._ranges import Interval
  47. from .specifiers import SpecifierSet
  48. __all__ = ["VersionRange"]
  49. T = TypeVar("T")
  50. UnparsedVersion = Union[Version, str]
  51. UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion)
  52. #: The most ``!=`` exclusion fragments (``!=V`` points or ``!=P.*`` prefixes)
  53. #: that :meth:`VersionRange.to_specifier_set` will materialize to spell a
  54. #: single gap or run. Every site that expands a version-number-driven chain
  55. #: charges it against this cap, and chains that spell one gap together share
  56. #: it (see :func:`_decompose_dev0_gap` and :func:`_encode_gap`),
  57. #: so no gap ever materializes more than this many exclusions. Past the cap
  58. #: the recovery returns ``None`` rather than emit the unbounded chain a range
  59. #: such as ``==5.* | ==1000000.*`` would otherwise drive.
  60. _MAX_EXCLUSION_RUN = 128
  61. class _SetOp(enum.Enum):
  62. """The binary set operation ``_combine_literals`` resolves over ``===`` literals."""
  63. INTERSECTION = enum.auto()
  64. UNION = enum.auto()
  65. DIFFERENCE = enum.auto()
  66. def __dir__() -> list[str]:
  67. return __all__
  68. # Range algebra: intersection and the empty-interval test live in the engine
  69. # (``intersect_ranges`` / ``range_is_empty``); union and complement are only
  70. # needed here, so they live in this module.
  71. def _union_ranges(
  72. left: Sequence[Interval],
  73. right: Sequence[Interval],
  74. ) -> list[Interval]:
  75. """Union two sorted, non-overlapping interval lists.
  76. A linear merge over the two pre-sorted inputs followed by a single
  77. coalescing pass: adjacent or overlapping intervals collapse so the result
  78. is itself sorted and non-overlapping.
  79. """
  80. if not left:
  81. return list(right)
  82. if not right:
  83. return list(left)
  84. merged_input: list[Interval] = []
  85. left_index = right_index = 0
  86. while left_index < len(left) and right_index < len(right):
  87. if left[left_index][0] <= right[right_index][0]:
  88. merged_input.append(left[left_index])
  89. left_index += 1
  90. else:
  91. merged_input.append(right[right_index])
  92. right_index += 1
  93. merged_input.extend(left[left_index:])
  94. merged_input.extend(right[right_index:])
  95. merged: list[Interval] = [merged_input[0]]
  96. for lower, upper in merged_input[1:]:
  97. prev_lower, prev_upper = merged[-1]
  98. if (
  99. prev_upper.version is None
  100. or lower.version is None
  101. or prev_upper.version > lower.version
  102. ):
  103. overlaps = True
  104. elif prev_upper.version == lower.version:
  105. overlaps = prev_upper.inclusive or lower.inclusive
  106. else:
  107. # An ordering gap may still hold no version when the two bounds
  108. # straddle a synthetic boundary; merge across an empty gap to
  109. # stay canonical.
  110. gap_lower = LowerBound(prev_upper.version, not prev_upper.inclusive)
  111. gap_upper = UpperBound(lower.version, not lower.inclusive)
  112. overlaps = range_is_empty(gap_lower, gap_upper)
  113. if overlaps:
  114. merged[-1] = (prev_lower, max(prev_upper, upper))
  115. else:
  116. merged.append((lower, upper))
  117. return merged
  118. def _complement_ranges(ranges: Sequence[Interval]) -> list[Interval]:
  119. """Complement a sorted, non-overlapping interval list.
  120. Yields the gaps between intervals plus a leading gap before the first and
  121. a trailing gap after the last. Bound inclusivity flips so that
  122. complement-of-complement round-trips back to the input.
  123. """
  124. if not ranges:
  125. return list(FULL_RANGE)
  126. result: list[Interval] = []
  127. prev_upper: UpperBound | None = None
  128. for lower, upper in ranges:
  129. if prev_upper is None:
  130. # Leading gap below the first interval. Every range reaching here is
  131. # floor-canonical: ``_canonical_floor`` has already folded an
  132. # inclusive lower at or below ``0.dev0`` into ``-inf``. So a finite
  133. # first lower always leaves a non-empty gap down to ``-inf``, while a
  134. # ``-inf`` lower leaves no leading gap at all.
  135. if lower.version is not None:
  136. gap_upper = UpperBound(lower.version, not lower.inclusive)
  137. result.append((NEG_INF, gap_upper))
  138. else:
  139. gap_lower = LowerBound(prev_upper.version, not prev_upper.inclusive)
  140. gap_upper = UpperBound(lower.version, not lower.inclusive)
  141. # Input intervals are canonical (sorted, disjoint, non-touching),
  142. # so the gap between two of them always holds at least one version.
  143. result.append((gap_lower, gap_upper))
  144. prev_upper = upper
  145. # The empty-input early return guarantees the loop ran.
  146. assert prev_upper is not None
  147. if prev_upper.version is not None:
  148. gap_lower = LowerBound(prev_upper.version, not prev_upper.inclusive)
  149. result.append((gap_lower, POS_INF))
  150. return result
  151. def _canonical_floor(bounds: tuple[Interval, ...]) -> tuple[Interval, ...]:
  152. """Collapse the PEP 440 floor in a sorted interval list.
  153. Only the first interval can touch ``0.dev0`` (the minimum version). An
  154. inclusive lower at or below it admits everything below, the same as
  155. ``-inf``, so ``>=0.dev0`` becomes the one canonical full range. An
  156. exclusive upper at or below it leaves the interval empty, so it is dropped.
  157. """
  158. if not bounds:
  159. return bounds
  160. lower, upper = bounds[0]
  161. if range_is_empty(NEG_INF, upper):
  162. return bounds[1:]
  163. if (
  164. lower.inclusive
  165. and isinstance(lower.version, Version)
  166. and lower.version <= MIN_VERSION
  167. ):
  168. return ((NEG_INF, upper), *bounds[1:])
  169. return bounds
  170. def _predecessor_boundary(version: Version) -> BoundaryVersion | None:
  171. """The boundary whose least successor is *version*, or ``None``.
  172. Inverse of :func:`~packaging._ranges.least_version_above`. A plain version
  173. that is exactly such a successor (``1.0a2.dev0`` sits just above
  174. ``AFTER_POSTS(1.0a1)``) folds back to that boundary, so ``>=1.0a2.dev0`` and
  175. ``>1.0a1`` share one form. The proposed boundary is confirmed by
  176. round-tripping through ``least_version_above``.
  177. """
  178. # Only a least successor carries a dev segment, so nothing else can fold.
  179. if version.dev is None:
  180. return None
  181. candidate: BoundaryVersion | None = None
  182. if version.pre is not None and version.dev == 0 and version.post is None:
  183. # 1.0a2.dev0 -> AFTER_POSTS(1.0a1)
  184. kind, number = version.pre
  185. if number >= 1:
  186. candidate = BoundaryVersion(
  187. version.__replace__(pre=(kind, number - 1), dev=None),
  188. BoundaryKind.AFTER_POSTS,
  189. )
  190. elif version.dev >= 1:
  191. # 1.0.dev3 -> AFTER_LOCALS(1.0.dev2)
  192. candidate = BoundaryVersion(
  193. version.__replace__(dev=version.dev - 1), BoundaryKind.AFTER_LOCALS
  194. )
  195. elif version.dev == 0 and version.post is not None:
  196. # 1.0.post1.dev0 -> AFTER_LOCALS(1.0.post0); 1.0.post0.dev0 -> AFTER_LOCALS(1.0)
  197. base = (
  198. version.__replace__(post=None, dev=None)
  199. if version.post == 0
  200. else version.__replace__(post=version.post - 1, dev=None)
  201. )
  202. candidate = BoundaryVersion(base, BoundaryKind.AFTER_LOCALS)
  203. if candidate is not None and least_version_above(candidate) == version:
  204. return candidate
  205. return None
  206. def _canonicalize(bounds: tuple[Interval, ...]) -> tuple[Interval, ...]:
  207. """Fold least-successor bounds to their boundary form.
  208. ``>=1.0a2.dev0`` and ``>1.0a1`` denote the same set, so both must reduce to
  209. one representation for ``==`` and ``hash`` to agree. An inclusive lower or
  210. exclusive upper sitting on a boundary's least successor becomes that
  211. boundary; the engine's emptiness check has already dropped the synthetic
  212. gaps such intervals would otherwise leave.
  213. """
  214. result: list[Interval] = []
  215. for lower, upper in bounds:
  216. new_lower, new_upper = lower, upper
  217. if isinstance(lower.version, Version) and lower.inclusive:
  218. boundary = _predecessor_boundary(lower.version)
  219. if boundary is not None:
  220. new_lower = LowerBound(boundary, inclusive=False)
  221. if isinstance(upper.version, Version) and not upper.inclusive:
  222. boundary = _predecessor_boundary(upper.version)
  223. if boundary is not None:
  224. new_upper = UpperBound(boundary, inclusive=True)
  225. result.append((new_lower, new_upper))
  226. return tuple(result)
  227. def _struct_admits(
  228. bounds: tuple[Interval, ...], admit_arbitrary: bool, literal: str
  229. ) -> bool:
  230. """True when the bounds (plus arbitrary admission) admit ``literal``.
  231. Skips the explicit admit/reject sets, which the caller layers on top. A
  232. non-version string matches via ``admit_arbitrary`` only on full bounds;
  233. on narrower bounds the flag is metadata only.
  234. """
  235. parsed = coerce_version(literal)
  236. if parsed is None:
  237. return admit_arbitrary and bounds == FULL_RANGE
  238. return matches_bounds_only(bounds, parsed)
  239. # Repr helpers:
  240. def _bound_version_str(value: BoundaryVersion | Version) -> str:
  241. """Printout for a bound's inner value, kind-tagged for boundaries."""
  242. if isinstance(value, BoundaryVersion):
  243. return f"{value.version}[{value.kind.name}]"
  244. return str(value)
  245. def _format_lower(bound: LowerBound) -> str:
  246. if bound.version is None:
  247. return "(-inf"
  248. bracket = "[" if bound.inclusive else "("
  249. return f"{bracket}{_bound_version_str(bound.version)}"
  250. def _format_upper(bound: UpperBound) -> str:
  251. if bound.version is None:
  252. return "+inf)"
  253. bracket = "]" if bound.inclusive else ")"
  254. return f"{_bound_version_str(bound.version)}{bracket}"
  255. def _format_intervals(intervals: Sequence[Interval]) -> str:
  256. """Render a sorted interval list as ``lower, upper | lower, upper``."""
  257. return " | ".join(
  258. f"{_format_lower(lower)}, {_format_upper(upper)}" for lower, upper in intervals
  259. )
  260. # ``to_specifier_set`` recovery: encode a range's interval list back into
  261. # specifier fragments. Each helper returns ``None`` when its shape has no
  262. # PEP 440 form. The ``keep_dev0`` argument threaded through is a spelling
  263. # mode, not a pre-release policy: false emits a prerelease-free form (no
  264. # synthetic ``.dev0``, so the recovered range has an empty opt-in region),
  265. # true keeps the ``.dev0`` markers (so the range opts its bounds in).
  266. # ``to_specifier_set`` encodes in both modes and keeps whichever round-trips.
  267. #
  268. # Bound and interval encoding: turn one interval's bounds into fragments.
  269. def _is_dev0_version(version: Version) -> bool:
  270. """True when version is exactly ``X[.Y]*.dev0`` (the shape ``<X`` makes)."""
  271. return (
  272. version.dev == 0
  273. and version.pre is None
  274. and version.post is None
  275. and version.local is None
  276. )
  277. def _clean_lower(version: Version) -> list[str] | None:
  278. """A prerelease-free spelling for an inclusive ``[version`` lower, or ``None``.
  279. Several ``[V`` lowers come from an operator whose own spelling carries no
  280. synthetic ``.dev0``. Recovering that spelling gives the range an empty opt-in
  281. region, so it is offered in the prerelease-free spelling mode (see
  282. :meth:`VersionRange.to_specifier_set`).
  283. """
  284. if version.dev != 0 or version.pre is not None or version.local is not None:
  285. return None
  286. # ``[B.post(k).dev0`` is the lower ``>B.post(k-1)`` builds (k >= 1).
  287. if version.post is not None:
  288. if version.post < 1:
  289. return None
  290. return [f">{version.__replace__(post=version.post - 1, dev=None)}"]
  291. # ``[F.dev0`` is family F's base. The prefix P just below F has
  292. # ``==P.* == [P.dev0, F.dev0)``, so ``>=P,!=P.*`` lands exactly on ``[F.dev0``.
  293. family = trim_release(version.release)
  294. last = family[-1]
  295. if last < 1:
  296. return None
  297. below_release = (*family[:-1], last - 1)
  298. below = Version.from_parts(epoch=version.epoch, release=below_release)
  299. # At the epoch-0 floor ``==P.*`` already reaches ``0.dev0``, so the ``>=P``
  300. # half is redundant: ``[1.dev0, +inf)`` is plain ``!=0.*``.
  301. if version.epoch == 0 and not any(below_release):
  302. return [f"!={below}.*"]
  303. return [f">={below}", f"!={below}.*"]
  304. def _epoch_floor_lower(
  305. lower: LowerBound, upper: UpperBound
  306. ) -> tuple[Version, int, bool] | None:
  307. """The ``E!0`` family of a lower sitting on an epoch>0 zero-family floor.
  308. An epoch>0 zero-family base such as ``1!0.dev0`` has no ``>=P,!=P.*`` spelling
  309. since no version sorts below ``E!0`` within the epoch. While the interval
  310. stays within ``==E!0.*`` it is that wildcard, trimmed by the upper and with a
  311. leading ``.dev`` run excluded: an ``AFTER_LOCALS(E!0.dev(k))`` lower drops
  312. ``E!0.dev0..E!0.dev(k)``, a plain inclusive ``E!0.dev0`` lower drops none.
  313. Returns the ``E!0`` family, how many leading ``.dev`` releases to exclude, and
  314. whether the upper sits at the family cap (so ``==E!0.*`` needs no upper), else
  315. ``None``.
  316. """
  317. version = lower.version
  318. if isinstance(version, BoundaryVersion):
  319. if version.kind != BoundaryKind.AFTER_LOCALS:
  320. return None
  321. version = version.version
  322. if version.dev is None:
  323. return None
  324. excluded_devs = version.dev + 1
  325. elif isinstance(version, Version) and lower.inclusive:
  326. # A plain inclusive lower only reaches the floor as ``>=E!0.dev0``;
  327. # higher ``.dev`` would have canonicalized to an AFTER_LOCALS boundary.
  328. if version.dev != 0:
  329. return None
  330. excluded_devs = 0
  331. else:
  332. return None
  333. # Only the bare ``E!0`` floor of a non-zero epoch qualifies.
  334. if version.epoch == 0:
  335. return None
  336. if version.pre is not None or version.post is not None or version.local is not None:
  337. return None
  338. if any(trim_release(version.release)):
  339. return None
  340. # ``==E!0.*`` spans ``[E!0.dev0, E!1.dev0)``; it fits only below that cap.
  341. next_family = Version.from_parts(epoch=version.epoch, release=(1,), dev=0)
  342. cap = UpperBound(next_family, False)
  343. if upper > cap:
  344. return None
  345. family = Version.from_parts(epoch=version.epoch, release=(0,))
  346. return family, excluded_devs, upper == cap
  347. def _dev_family_anchor(family: Version) -> list[str] | None:
  348. """Prerelease-free fragments for ``[family, ..)``, or ``None`` if it has none.
  349. ``family`` is an ``X.dev0``. The floor gives ``[]`` (every version); a release
  350. base its ``_clean_lower`` family-floor spelling (``!=0.*`` ...); an ``X.post0``
  351. base ``>=X,!=X``. A pre-release base has no prerelease-free spelling.
  352. """
  353. if family <= MIN_VERSION:
  354. return []
  355. clean = _clean_lower(family)
  356. if clean is not None:
  357. return clean
  358. if family.pre is None and family.post == 0:
  359. base = family.__replace__(post=None, dev=None)
  360. return [f">={base}", f"!={base}"]
  361. return None
  362. def _encode_lower(lower: LowerBound, keep_dev0: bool) -> list[str] | None:
  363. """Encode a lower bound as specifier fragments, or ``None``.
  364. ``[]`` for ``-inf``. An ``AFTER_POSTS(V)`` lower is ``>V``. An
  365. ``AFTER_LOCALS(V)`` lower is the set ``[successor, ..)`` and emits ``>=V,!=V``,
  366. except in the prerelease-free spelling mode (``keep_dev0`` false), where it
  367. recovers a spelling with no synthetic ``.dev0`` when one exists:
  368. ``>3.8.post1`` for a post release, or a dev family's anchor plus the dev run
  369. up to V for a ``.dev`` release.
  370. """
  371. lower_version = lower.version
  372. if lower_version is None:
  373. return []
  374. if isinstance(lower_version, BoundaryVersion):
  375. if lower_version.kind == BoundaryKind.AFTER_POSTS:
  376. # AFTER_POSTS only ever appears as an exclusive ``>V`` lower.
  377. return [f">{lower_version.version}"]
  378. inner = lower_version.version
  379. if inner <= MIN_VERSION:
  380. # The ``(-inf, V)`` side was dropped at the floor, so the lone
  381. # ``(AFTER_LOCALS(0.dev0), +inf)`` interval is exactly ``!=0.dev0``.
  382. return [f"!={inner}"]
  383. # An ``(AFTER_LOCALS(V), ..)`` lower is the set ``[successor, ..)``. In
  384. # the prerelease-free mode, recover a spelling with no synthetic ``.dev0``
  385. # so the range's opt-in region stays empty.
  386. if not keep_dev0:
  387. if inner.dev is not None:
  388. # A ``.dev`` V makes ``[successor, ..)`` its dev family's
  389. # prerelease-free anchor minus the finite dev run up to ``V``
  390. # (e.g. ``>=1.0,!=1.0,!=1.0.post0.dev0``), carrying no synthetic
  391. # ``.dev0``.
  392. family = inner.__replace__(dev=0)
  393. anchor = _dev_family_anchor(family)
  394. if anchor is not None:
  395. if inner.dev + 1 > _MAX_EXCLUSION_RUN:
  396. return None
  397. run = [
  398. f"!={family.__replace__(dev=d)}" for d in range(inner.dev + 1)
  399. ]
  400. return anchor + run
  401. else:
  402. # A ``.post`` release recovers its prerelease-free ``>`` spelling
  403. # from the successor (``>3.8.post1`` for ``AFTER_LOCALS(3.8.post1)``).
  404. successor = least_version_above(lower_version)
  405. clean = _clean_lower(successor) if successor is not None else None
  406. if clean is not None:
  407. return clean
  408. # Otherwise it is ``[V, ..)`` minus V's local family, i.e. ``>=V,!=V``.
  409. # The prerelease-free recoveries above have already returned in that mode;
  410. # a residual ``.dev`` V here opts pre-releases in, so this spelling round
  411. # trips only for a range whose opt-in region wants it.
  412. return [f">={inner}", f"!={inner}"]
  413. if not lower.inclusive:
  414. return None
  415. # In the prerelease-free mode a ``.dev0`` lower prefers its clean spelling.
  416. if not keep_dev0:
  417. clean = _clean_lower(lower_version)
  418. if clean is not None:
  419. return clean
  420. return [f">={lower_version}"]
  421. def _encode_upper(upper: UpperBound, keep_dev0: bool) -> list[str] | None:
  422. """Encode an upper bound as specifier fragments, or ``None``.
  423. ``[]`` for ``+inf``. In the prerelease-free spelling mode (``keep_dev0``
  424. false) the ``<X`` spelling is used for the ``X.dev0`` upper that ``<X``
  425. builds; otherwise the synthetic ``.dev0`` is kept so the range opts its
  426. bounds in.
  427. """
  428. upper_version = upper.version
  429. if upper_version is None:
  430. return []
  431. if isinstance(upper_version, BoundaryVersion):
  432. # A boundary upper is always inclusive (a boundary already sits between
  433. # versions, so no specifier produces an exclusive one).
  434. if upper_version.kind == BoundaryKind.AFTER_LOCALS:
  435. inner = upper_version.version
  436. if (
  437. not keep_dev0
  438. and inner.pre is None
  439. and inner.post is not None
  440. and inner.dev is None
  441. ):
  442. # ``AFTER_LOCALS(post-release)]`` upper is ``<next-post`` (e.g.
  443. # ``<3.8.post1`` for ``AFTER_LOCALS(3.8.post0)``), the ``<P``
  444. # spelling a post-release upper builds, with no ``.dev0``.
  445. return [f"<{inner.__replace__(post=inner.post + 1)}"]
  446. return [f"<={inner}"]
  447. # ``AFTER_POSTS(P)`` sits just below the next pre-release's ``.dev0``
  448. # (canonicalization of a ``<P.preN.dev0`` upper), so it is ``<`` that
  449. # least successor. A final-release AFTER_POSTS has no successor or form.
  450. successor = least_version_above(upper_version)
  451. if successor is not None:
  452. return [f"<{successor}"]
  453. return None
  454. if not upper.inclusive:
  455. # ``<X`` builds an exclusive ``X.dev0`` upper (X final or post-release;
  456. # never pre/local). ``<X`` and ``<X.dev0`` define the same bound but
  457. # differ in the opt-in they imply, so pick by the spelling mode.
  458. if (
  459. upper_version.dev == 0
  460. and upper_version.pre is None
  461. and upper_version.local is None
  462. ):
  463. if not keep_dev0:
  464. return [f"<{upper_version.__replace__(dev=None)}"]
  465. return [f"<{upper_version}"]
  466. # ``V`` (exclusive) upper, including V's pre-releases.
  467. return [f"<={upper_version}", f"!={upper_version}"]
  468. return None
  469. def _detect_equal_wildcard(lower: LowerBound, upper: UpperBound) -> Version | None:
  470. """If ``[lower, upper)`` is the ``==V.*`` shape, return ``V``."""
  471. if isinstance(lower.version, BoundaryVersion) or isinstance(
  472. upper.version, BoundaryVersion
  473. ):
  474. return None
  475. if lower.version is None or upper.version is None:
  476. return None
  477. if not lower.inclusive or upper.inclusive:
  478. return None
  479. if not (_is_dev0_version(lower.version) and _is_dev0_version(upper.version)):
  480. return None
  481. if lower.version.epoch != upper.version.epoch:
  482. return None
  483. lower_release = trim_release(lower.version.release)
  484. upper_release = trim_release(upper.version.release)
  485. padded_length = max(len(lower_release), len(upper_release))
  486. assert padded_length > 0
  487. lower_release += (0,) * (padded_length - len(lower_release))
  488. upper_release += (0,) * (padded_length - len(upper_release))
  489. if lower_release[:-1] != upper_release[:-1]:
  490. return None
  491. # A genuine ``==V.*`` spans one family: the upper is exactly the next prefix.
  492. # A wider span like ``[3.8.dev0, 3.14.dev0)`` shares the prefix but is not a
  493. # single wildcard, so it falls through to the generic ``>=...,<...`` form.
  494. if upper_release[-1] != lower_release[-1] + 1:
  495. return None
  496. return lower.version.__replace__(release=lower_release, dev=None)
  497. def _encode_interval(
  498. lower: LowerBound, upper: UpperBound, keep_dev0: bool
  499. ) -> list[str] | None:
  500. """Encode one interval as specifier fragments, or ``None``.
  501. Special-cases the ``==V`` singleton (``[V, AFTER_LOCALS(V)]`` for a plain
  502. ``V``, and ``[V+local, V+local]`` for a local one) and the ``==V.*`` shape
  503. so the fragment is one equality rather than a bound pair.
  504. """
  505. # ``[V+local, V+local]`` (an inclusive local point) is the singleton ``==V+local``.
  506. if (
  507. lower.version is not None
  508. and upper.version is not None
  509. and not isinstance(lower.version, BoundaryVersion)
  510. and not isinstance(upper.version, BoundaryVersion)
  511. and lower.inclusive
  512. and upper.inclusive
  513. and lower.version == upper.version
  514. and lower.version.local is not None
  515. ):
  516. return [f"=={lower.version}"]
  517. # ``[V, AFTER_LOCALS(V)]`` (V without a local) is the singleton ``==V``,
  518. # which also matches V's local family: one equality, not ``>=V,<=V``.
  519. if (
  520. isinstance(lower.version, Version)
  521. and lower.inclusive
  522. and upper.inclusive
  523. and isinstance(upper.version, BoundaryVersion)
  524. and upper.version.kind == BoundaryKind.AFTER_LOCALS
  525. and upper.version.version == lower.version
  526. ):
  527. return [f"=={lower.version}"]
  528. wildcard = _detect_equal_wildcard(lower, upper)
  529. if wildcard is not None:
  530. return [f"=={wildcard}.*"]
  531. # A ``[E!0.dev0`` lower has no prerelease-free ``>=`` spelling; within its own
  532. # family it is ``==E!0.*`` trimmed by the upper.
  533. floor = _epoch_floor_lower(lower, upper) if not keep_dev0 else None
  534. if floor is not None:
  535. family, excluded_devs, upper_at_cap = floor
  536. if excluded_devs > _MAX_EXCLUSION_RUN:
  537. return None
  538. parts = [f"=={family}.*"]
  539. parts.extend(f"!={family.__replace__(dev=d)}" for d in range(excluded_devs))
  540. # ``==E!0.*`` already caps at the next family; add the upper only if tighter.
  541. if not upper_at_cap:
  542. upper_parts = _encode_upper(upper, keep_dev0)
  543. if upper_parts is None:
  544. return None
  545. parts.extend(upper_parts)
  546. return parts
  547. lower_parts = _encode_lower(lower, keep_dev0)
  548. if lower_parts is None:
  549. return None
  550. upper_parts = _encode_upper(upper, keep_dev0)
  551. if upper_parts is None:
  552. return None
  553. return lower_parts + upper_parts
  554. # Gap encoding: spell the gap between two adjacent intervals as exclusions.
  555. def _detect_not_equal(
  556. left_upper: UpperBound, right_lower: LowerBound
  557. ) -> list[Version] | None:
  558. """If the gap between two intervals is a ``!=V`` chain, list its points.
  559. A plain exclusive left upper names the first excluded V directly; an inclusive
  560. boundary left upper names it via its least successor. Adjacent exclusions
  561. (``V`` and its immediate successors) share a single gap spanning a contiguous
  562. dev run, so one gap can name a short chain: ``!=1.0,!=1.0.post0.dev0`` is one
  563. gap from ``1.0`` up to ``AFTER_LOCALS(1.0.post0.dev0)``.
  564. """
  565. if isinstance(left_upper.version, BoundaryVersion):
  566. # A boundary upper is always inclusive; its least successor is the first
  567. # excluded V (``None`` for a final AFTER_POSTS, which names no point).
  568. first = least_version_above(left_upper.version)
  569. if first is None:
  570. return None
  571. elif left_upper.version is None or left_upper.inclusive:
  572. return None
  573. else:
  574. first = left_upper.version
  575. if not isinstance(right_lower.version, BoundaryVersion):
  576. if (
  577. right_lower.version is not None
  578. and not right_lower.inclusive
  579. and right_lower.version == first
  580. and first.local is not None
  581. ):
  582. return [first]
  583. return None
  584. if right_lower.version.kind != BoundaryKind.AFTER_LOCALS:
  585. return None
  586. # The right interval resumes just above the last excluded V and its locals.
  587. last = right_lower.version.version
  588. if first == last:
  589. return [first]
  590. # Adjacent exclusions: the successor of ``first`` opens a ``.dev`` family and
  591. # every later point is a higher ``.dev`` in that same family, so the gap is
  592. # exactly ``first`` plus a contiguous dev run up to ``last``. Any other gap
  593. # (e.g. ``2.3`` to ``AFTER_LOCALS(2.7)`` from complementing ``>=2.3,<=2.7``)
  594. # spans a whole interval and fails this test.
  595. second = least_version_above(BoundaryVersion(first, BoundaryKind.AFTER_LOCALS))
  596. if (
  597. second is not None
  598. and second.dev is not None
  599. and last.dev is not None
  600. and last.dev >= second.dev
  601. and last.__replace__(dev=second.dev) == second
  602. ):
  603. # ``first`` and the run spell this gap together, so they share the cap.
  604. if last.dev - second.dev + 2 > _MAX_EXCLUSION_RUN:
  605. return None
  606. run = (second.__replace__(dev=d) for d in range(second.dev, last.dev + 1))
  607. return [first, *run]
  608. return None
  609. def _decompose_dev0_gap(
  610. lower_trim: tuple[int, ...],
  611. upper_trim: tuple[int, ...],
  612. epoch: int,
  613. budget: int = _MAX_EXCLUSION_RUN,
  614. ) -> list[Version] | None:
  615. """Decompose the gap ``[L.dev0, U.dev0)`` into wildcard prefixes.
  616. ``lower_trim``/``upper_trim`` are trimmed release tuples with
  617. ``lower_trim < upper_trim`` lexicographically. The chain sweeps at the
  618. first differing level. The gap is undecomposable when L has trailing
  619. components below that level (the chain cannot escape L's subtree), or when
  620. the chain, summed across levels, would exceed ``budget`` prefixes.
  621. """
  622. diff = 0
  623. while (
  624. diff < len(lower_trim)
  625. and diff < len(upper_trim)
  626. and lower_trim[diff] == upper_trim[diff]
  627. ):
  628. diff += 1
  629. if len(lower_trim) > diff + 1:
  630. return None
  631. common = lower_trim[:diff]
  632. lower_val = lower_trim[diff] if len(lower_trim) > diff else 0
  633. upper_val = upper_trim[diff]
  634. span = upper_val - lower_val
  635. if span > budget:
  636. return None
  637. fragments = [
  638. Version.from_parts(epoch=epoch, release=(*common, segment))
  639. for segment in range(lower_val, upper_val)
  640. ]
  641. if len(upper_trim) == diff + 1:
  642. return fragments
  643. # Recurse into the next release component, charging at least one to the budget
  644. # per level (not just the span), so a run of zero-span levels (a release with
  645. # many trailing components) exhausts the budget and returns None instead of
  646. # recursing past the interpreter's stack limit.
  647. tail = _decompose_dev0_gap(
  648. (*common, upper_val), upper_trim, epoch, budget - max(span, 1)
  649. )
  650. if tail is None:
  651. return None
  652. return fragments + tail
  653. def _encode_gap(left_upper: UpperBound, right_lower: LowerBound) -> list[str] | None:
  654. """Encode the gap between two adjacent intervals as ``!=`` fragments.
  655. A point chain becomes ``!=V`` fragments and a dev0 family span becomes
  656. ``!=P.*`` prefixes, followed by a leading dev run in the last family when
  657. the gap ends inside it. Any other gap has no exclusion form and returns
  658. ``None``.
  659. """
  660. # Cheapest first: a plain ``!=V`` chain never pays for the budgeted
  661. # wildcard sweep below.
  662. points = _detect_not_equal(left_upper, right_lower)
  663. if points is not None:
  664. return [f"!={point}" for point in points]
  665. # Both wildcard shapes start at an exclusive family base ``L.dev0``.
  666. left_v = left_upper.version
  667. if (
  668. not isinstance(left_v, Version)
  669. or left_upper.inclusive
  670. or not _is_dev0_version(left_v)
  671. ):
  672. return None
  673. right_v = right_lower.version
  674. if isinstance(right_v, Version) and right_lower.inclusive:
  675. # ``[L.dev0, U.dev0)`` is a pure ``!=P.*`` chain up to U's family.
  676. upper_dev0 = right_v
  677. run_length = 0
  678. budget = _MAX_EXCLUSION_RUN
  679. elif (
  680. isinstance(right_v, BoundaryVersion)
  681. and right_v.kind == BoundaryKind.AFTER_LOCALS
  682. and not right_lower.inclusive
  683. ):
  684. # ``[L.dev0, AFTER_LOCALS(U.dev(k))]`` ends inside U's family: the
  685. # ``!=P.*`` chain, then the ``U.dev0..U.dev(k)`` run. Both spell the
  686. # gap together, so they share one ``_MAX_EXCLUSION_RUN`` budget.
  687. upper = right_v.version
  688. if upper.dev is None or upper.dev + 1 > _MAX_EXCLUSION_RUN:
  689. return None
  690. upper_dev0 = upper.__replace__(dev=0)
  691. run_length = upper.dev + 1
  692. budget = _MAX_EXCLUSION_RUN - run_length
  693. else:
  694. return None
  695. # ``U`` must be a plain release base in L's epoch, above L.
  696. # ``_is_dev0_version`` on ``U.dev0`` rejects any pre/post/local on ``U``.
  697. if not _is_dev0_version(upper_dev0):
  698. return None
  699. if left_v.epoch != upper_dev0.epoch or left_v >= upper_dev0:
  700. return None
  701. prefixes = _decompose_dev0_gap(
  702. trim_release(left_v.release),
  703. trim_release(upper_dev0.release),
  704. left_v.epoch,
  705. budget,
  706. )
  707. if prefixes is None:
  708. return None
  709. exclusions = [f"!={prefix}.*" for prefix in prefixes]
  710. exclusions.extend(f"!={upper_dev0.__replace__(dev=d)}" for d in range(run_length))
  711. return exclusions
  712. def _encode_gaps(bounds: Sequence[Interval]) -> list[str] | None:
  713. """Encode every between-interval gap as ``!=`` fragments, or ``None``.
  714. When each gap has an exclusion spelling, the intervals fuse into one
  715. contiguous span (``==1.* | ==3.*`` is ``!=0.*,!=2.*,<4``): the outer
  716. interval across all the bounds plus these exclusions. A gap with no
  717. exclusion spelling makes the bounds a disjoint union, which no single
  718. set expresses.
  719. """
  720. exclusions: list[str] = []
  721. for index in range(1, len(bounds)):
  722. gap = _encode_gap(bounds[index - 1][1], bounds[index][0])
  723. if gap is None:
  724. return None
  725. exclusions.extend(gap)
  726. return exclusions
  727. def _tighten_no_prereleases(bounds: tuple[Interval, ...]) -> tuple[Interval, ...]:
  728. """Snap the range's final upper out of the pre-release band ``False`` drops.
  729. An exclusive upper at a final ``V`` admits the versions in ``[V.dev0, V)`` at
  730. the bounds level, but a ``prereleases=False`` policy filters them all out, so
  731. it accepts the same releases as ``<V`` (upper at ``V.dev0``). Snapping it lets
  732. :meth:`VersionRange.to_specifier_set` reach the ``<V`` spelling.
  733. Only the last interval's upper is snapped, the one that gives a terser outer
  734. bound. Inner uppers are left alone: snapping one turns its gap to the next
  735. interval into a ``.dev0`` wildcard gap, which a far-apart neighbour would blow
  736. up into an unbounded ``!=N.*`` chain. Those shapes recover as ``None`` here,
  737. the same as under ``None`` / ``True``. The snap is conservative (it skips
  738. boundary, pre-release, and local uppers); the caller keeps it only when it
  739. stays release-equivalent, so an unsnapped shape falls back to the exact form.
  740. """
  741. lower, upper = bounds[-1]
  742. version = upper.version
  743. if (
  744. isinstance(version, Version)
  745. and not upper.inclusive
  746. and not version.is_prerelease
  747. and version.local is None
  748. ):
  749. upper = UpperBound(version.__replace__(dev=0), inclusive=False)
  750. return (*bounds[:-1], (lower, upper))
  751. return bounds
  752. class VersionRange:
  753. """A set of :class:`~packaging.version.Version` values accepted by a
  754. :class:`~packaging.specifiers.SpecifierSet`.
  755. Construct via :meth:`~packaging.specifiers.SpecifierSet.to_range`, or with
  756. the :meth:`full`, :meth:`empty`, and :meth:`singleton` class methods.
  757. Compose with :meth:`intersection`, :meth:`union`, :meth:`complement`, and
  758. :meth:`difference` (or the ``&`` / ``|`` / ``~`` / ``-`` operators). Test
  759. membership with ``in`` or :meth:`contains`, filter an iterable with
  760. :meth:`filter`, and convert back to a
  761. :class:`~packaging.specifiers.SpecifierSet` with :meth:`to_specifier_set`.
  762. The configured pre-release policy of the originating specifier set carries
  763. onto the range and controls whether pre-releases are admitted under ``in``,
  764. :meth:`contains`, and :meth:`filter`. With no configured policy,
  765. :meth:`filter` also admits pre-releases in the autodetected opt-in region
  766. (the versions a pre-release-naming specifier asked for). Set algebra keeps
  767. that opt-in scoped to those versions, so unrelated pre-releases are not
  768. admitted wholesale.
  769. :meth:`intersection`, :meth:`union`, :meth:`difference`, and the
  770. :meth:`is_subset` / :meth:`is_superset` / :meth:`is_disjoint` predicates
  771. require both operands to share the same configured policy.
  772. >>> r = SpecifierSet(">=1.0,<2.0").to_range()
  773. >>> "1.5" in r
  774. True
  775. >>> "2.0" in r
  776. False
  777. >>> SpecifierSet(">=2.0,<1.0").to_range().is_empty
  778. True
  779. PEP 440's ``===`` operator matches a candidate string verbatim
  780. (case-insensitive) rather than a set of versions. Ranges built from
  781. ``===`` specifiers still support membership, set operations, and conversion
  782. back to a :class:`~packaging.specifiers.SpecifierSet`; matching follows the
  783. literal-equality rule. A ``===`` literal that names a pre-release is
  784. admitted under the default policy by both :meth:`contains` and
  785. :meth:`filter`, since it was named outright.
  786. .. versionadded:: 26.3
  787. """
  788. __slots__ = (
  789. "_admit",
  790. "_admit_arbitrary",
  791. "_bounds",
  792. "_pre_region",
  793. "_prereleases_configured",
  794. "_reject",
  795. )
  796. #: The disjoint, sorted, non-overlapping interval list.
  797. _bounds: tuple[Interval, ...]
  798. #: Whether this range matches non-version strings as well as versions.
  799. #: True only by construction on ``SpecifierSet("")`` / :meth:`full`. The flag
  800. #: rides set algebra but is inert except at full bounds (see
  801. #: :meth:`_arbitrary_active`). An intersection or difference that shrinks
  802. #: the bounds drops it (``full() & ~full()`` is plain empty, and
  803. #: ``full() - r == full() & ~r``); :meth:`complement` and a union of
  804. #: empty-bounds operands keep it, so ``~~full() == full()`` and
  805. #: ``~full() | ~full() == ~full()``. Part of equality, since membership
  806. #: reads it.
  807. _admit_arbitrary: bool
  808. #: Case-folded strings the range admits in addition to its bounds.
  809. #: ``===wat`` produces ``_admit = {"wat"}``.
  810. _admit: frozenset[str]
  811. #: Case-folded strings the range rejects (overrides ``_admit`` and the
  812. #: bounds). Populated by :meth:`complement` of an admit-bearing range and by
  813. #: literal resolution in :meth:`_combine_literals`.
  814. _reject: frozenset[str]
  815. #: Sorted, disjoint intervals where pre-releases are force-admitted under
  816. #: the PEP 440 default policy (a ``None`` ``prereleases`` argument and no
  817. #: configured override). The opt-in flows only from the pre-release-naming
  818. #: specifiers that built the range. :meth:`_build` clips the region to the
  819. #: bounds, so it is always a subset of them: an opt-in that overflowed its
  820. #: own cap cannot ride a later union into versions no specifier asked for.
  821. #: :meth:`union` and :meth:`intersection` accumulate the operands' clipped
  822. #: regions and re-clip to the result bounds; :meth:`difference` keeps only
  823. #: the minuend's; and :meth:`complement` drops it, since an exclusion grants
  824. #: no opt-in. Equality keys on the clipped region, so it stays a congruence.
  825. _pre_region: tuple[Interval, ...]
  826. #: Raw configured pre-release override of the originating specifier set
  827. #: (an explicit ``True`` / ``False``, else ``None``). When set, :meth:`_build`
  828. #: forces ``_pre_region`` empty since the policy governs globally.
  829. #: :meth:`intersection` and :meth:`union` require it to match on both
  830. #: operands. Part of equality.
  831. _prereleases_configured: bool | None
  832. def __new__(cls, *args: object, **kwargs: object) -> VersionRange: # noqa: PYI034
  833. raise TypeError(
  834. "cannot create 'VersionRange' instances directly; use "
  835. "SpecifierSet.to_range(), VersionRange.full(), "
  836. "VersionRange.empty(), or VersionRange.singleton() instead"
  837. )
  838. @classmethod
  839. def _build(
  840. cls,
  841. bounds: tuple[Interval, ...],
  842. admit: frozenset[str] = frozenset(),
  843. reject: frozenset[str] = frozenset(),
  844. admit_arbitrary: bool = False,
  845. *,
  846. pre_region: tuple[Interval, ...] = (),
  847. prereleases_configured: bool | None = None,
  848. ) -> VersionRange:
  849. """Internal factory; bypasses :meth:`__new__`.
  850. Canonicalizes the bounds so equal version sets share one representation,
  851. then drops admit literals the bounds already admit and reject literals
  852. the bounds do not match anyway. Reject wins over admit on overlap. The
  853. pre-release policy is set here and never reassigned afterwards;
  854. ``pre_region`` is canonicalized like the bounds and clipped to them,
  855. or dropped when a configured policy makes it inert.
  856. """
  857. bounds = _canonicalize(bounds)
  858. if admit and reject:
  859. admit = admit - reject
  860. if admit:
  861. admit = frozenset(
  862. literal
  863. for literal in admit
  864. if not _struct_admits(bounds, admit_arbitrary, literal)
  865. )
  866. if reject:
  867. reject = frozenset(
  868. literal
  869. for literal in reject
  870. if _struct_admits(bounds, admit_arbitrary, literal)
  871. )
  872. instance = object.__new__(cls)
  873. instance._bounds = bounds
  874. instance._admit = admit
  875. instance._reject = reject
  876. instance._admit_arbitrary = admit_arbitrary
  877. instance._prereleases_configured = prereleases_configured
  878. # A configured policy makes the region inert, so drop it. Otherwise fold
  879. # least-successor bounds (_from_specifier_set passes the region unfolded),
  880. # so ``>1.0a1`` and ``>=1.0a2.dev0`` carry the same region, then clip it
  881. # to the bounds so the opt-in never reaches past the range's own versions.
  882. if prereleases_configured is not None or not pre_region:
  883. instance._pre_region = ()
  884. else:
  885. instance._pre_region = tuple(
  886. intersect_ranges(_canonicalize(pre_region), bounds)
  887. )
  888. return instance
  889. def _has_literals(self) -> bool:
  890. return bool(self._admit) or bool(self._reject)
  891. def _arbitrary_active(self) -> bool:
  892. """True when ``_admit_arbitrary`` actually admits non-version strings.
  893. The flag rides through set algebra but only fires admission on full
  894. bounds. Intersection and difference drop it when the bounds shrink, so
  895. away from full bounds it survives only on empty-bounds ranges, where
  896. it keeps ``~~full() == full()`` and union idempotent.
  897. """
  898. return self._admit_arbitrary and self._bounds == FULL_RANGE
  899. def _is_plain(self) -> bool:
  900. """True when membership is decided by ``_bounds`` alone, enabling the
  901. bounds-only fast paths in :meth:`is_subset` and :meth:`is_disjoint`.
  902. """
  903. return (
  904. not self._has_literals()
  905. and not self._admit_arbitrary
  906. and self._prereleases_configured is not False
  907. )
  908. def _check_policy_compat(self, other: VersionRange) -> None:
  909. """Refuse combining ranges with different pre-release policies."""
  910. if not isinstance(other, VersionRange):
  911. raise TypeError(f"expected VersionRange, got {type(other).__name__}")
  912. if self._prereleases_configured != other._prereleases_configured:
  913. raise ValueError(
  914. "Cannot combine VersionRange operands with different "
  915. f"pre-release policies: {self._prereleases_configured!r} "
  916. f"and {other._prereleases_configured!r}"
  917. )
  918. def _merged_region(self, other: VersionRange) -> tuple[Interval, ...]:
  919. """Union of ``self`` and ``other``'s opt-in regions.
  920. Used by :meth:`union` and :meth:`intersection`; :meth:`_build` clips the
  921. merge to the result bounds. A configured operand carries an empty region,
  922. so it contributes nothing to the merge.
  923. """
  924. # Reuse an operand's canonical tuple when only one side has a region;
  925. # an empty side contributes nothing to the union.
  926. if not other._pre_region:
  927. return self._pre_region
  928. if not self._pre_region:
  929. return other._pre_region
  930. # Both sides carry a region; merge them. _build re-canonicalizes and
  931. # clips, so the plain union is fine here.
  932. return tuple(_union_ranges(self._pre_region, other._pre_region))
  933. def _with_policy(
  934. self, *, pre_region: tuple[Interval, ...], configured: bool | None
  935. ) -> VersionRange:
  936. """A structural copy of this range carrying the given pre-release policy."""
  937. return self._build(
  938. self._bounds,
  939. admit=self._admit,
  940. reject=self._reject,
  941. admit_arbitrary=self._admit_arbitrary,
  942. pre_region=pre_region,
  943. prereleases_configured=configured,
  944. )
  945. @classmethod
  946. def empty(cls, *, prereleases: bool | None = None) -> VersionRange:
  947. """Return the empty range. No version satisfies it.
  948. >>> VersionRange.empty().is_empty
  949. True
  950. >>> "1.0" in VersionRange.empty()
  951. False
  952. """
  953. return cls._build((), prereleases_configured=prereleases)
  954. @classmethod
  955. def full(
  956. cls, *, admit_arbitrary: bool = True, prereleases: bool | None = None
  957. ) -> VersionRange:
  958. """Return the full range. Every PEP 440 version satisfies it.
  959. ``admit_arbitrary=False`` restricts the range to PEP 440 versions only
  960. (matching the same versions as ``SpecifierSet(">=0.dev0").to_range()``);
  961. its complement is :meth:`empty`. The flag propagates through set algebra
  962. and is part of equality. Default ``True`` so that ``r & full()``
  963. preserves ``r``'s own flag structurally.
  964. >>> "1.0" in VersionRange.full()
  965. True
  966. >>> "wat" in VersionRange.full()
  967. True
  968. >>> "wat" in VersionRange.full(admit_arbitrary=False)
  969. False
  970. """
  971. return cls._build(
  972. FULL_RANGE,
  973. admit_arbitrary=admit_arbitrary,
  974. prereleases_configured=prereleases,
  975. )
  976. @classmethod
  977. def singleton(
  978. cls, version: Version | str, *, prereleases: bool | None = None
  979. ) -> VersionRange:
  980. """Return the strict singleton range ``{version}``.
  981. Built as the closed interval ``[version, version]`` with strict
  982. equality. ``Specifier("==V")`` matches ``V+local`` too, so the strict
  983. singleton is narrower:
  984. >>> "1.0+local" in VersionRange.singleton("1.0")
  985. False
  986. >>> "1.0+local" in SpecifierSet("==1.0").to_range()
  987. True
  988. :raises packaging.version.InvalidVersion: if version is a string that
  989. does not parse as a PEP 440 version.
  990. """
  991. if not isinstance(version, Version):
  992. version = Version(version)
  993. lower = LowerBound(version, True)
  994. upper = UpperBound(version, True)
  995. # Collapse the floor: nothing sorts below ``MIN_VERSION``, so the
  996. # ``0.dev0`` singleton is ``(-inf, 0.dev0]`` in canonical form.
  997. return cls._build(
  998. _canonical_floor(((lower, upper),)),
  999. prereleases_configured=prereleases,
  1000. )
  1001. def intersection(self, other: VersionRange) -> VersionRange:
  1002. """Range containing exactly the versions in both self and other.
  1003. Both operands must share the same configured pre-release policy;
  1004. otherwise :exc:`ValueError` is raised.
  1005. >>> a = SpecifierSet(">=1.0").to_range()
  1006. >>> b = SpecifierSet("<2.0").to_range()
  1007. >>> a.intersection(b) == SpecifierSet(">=1.0,<2.0").to_range()
  1008. True
  1009. """
  1010. self._check_policy_compat(other)
  1011. configured = self._prereleases_configured
  1012. new_bounds = tuple(intersect_ranges(self._bounds, other._bounds))
  1013. new_region = self._merged_region(other)
  1014. # An empty intersection (e.g. ``full() & ~full()``) is the empty range,
  1015. # so it drops the arbitrary flag, agreeing with difference when the
  1016. # subtrahend consumes the bounds.
  1017. combined_arb = (
  1018. self._admit_arbitrary and other._admit_arbitrary and bool(new_bounds)
  1019. )
  1020. if not self._has_literals() and not other._has_literals():
  1021. return self._build(
  1022. new_bounds,
  1023. admit_arbitrary=combined_arb,
  1024. pre_region=new_region,
  1025. prereleases_configured=configured,
  1026. )
  1027. return self._combine_literals(
  1028. other,
  1029. new_bounds,
  1030. op=_SetOp.INTERSECTION,
  1031. admit_arbitrary=combined_arb,
  1032. pre_region=new_region,
  1033. prereleases_configured=configured,
  1034. )
  1035. def union(self, other: VersionRange) -> VersionRange:
  1036. """Range containing every version in self or other.
  1037. Both operands must share the same configured pre-release policy;
  1038. otherwise :exc:`ValueError` is raised.
  1039. >>> a = VersionRange.singleton("1.0")
  1040. >>> b = VersionRange.singleton("2.0")
  1041. >>> "1.0" in a.union(b) and "2.0" in a.union(b)
  1042. True
  1043. >>> "1.5" in a.union(b)
  1044. False
  1045. """
  1046. self._check_policy_compat(other)
  1047. configured = self._prereleases_configured
  1048. new_bounds = tuple(_union_ranges(self._bounds, other._bounds))
  1049. new_region = self._merged_region(other)
  1050. # An empty-bounds operand (e.g. ``~full()``) carries an inert arbitrary
  1051. # flag only to keep complement an involution; it admits nothing, so it
  1052. # must not revive arbitrary admission as the union re-widens the bounds.
  1053. if new_bounds:
  1054. combined_arb = (self._admit_arbitrary and bool(self._bounds)) or (
  1055. other._admit_arbitrary and bool(other._bounds)
  1056. )
  1057. else:
  1058. # Nothing widened, so keeping the flags keeps ``r | r == r``.
  1059. combined_arb = self._admit_arbitrary or other._admit_arbitrary
  1060. if not self._has_literals() and not other._has_literals():
  1061. return self._build(
  1062. new_bounds,
  1063. admit_arbitrary=combined_arb,
  1064. pre_region=new_region,
  1065. prereleases_configured=configured,
  1066. )
  1067. return self._combine_literals(
  1068. other,
  1069. new_bounds,
  1070. op=_SetOp.UNION,
  1071. admit_arbitrary=combined_arb,
  1072. pre_region=new_region,
  1073. prereleases_configured=configured,
  1074. )
  1075. def complement(self) -> VersionRange:
  1076. """Range containing every version not in self.
  1077. Preserves the configured pre-release policy. On the version set, double
  1078. negation holds for a range with no ``===`` literals (the arbitrary-string
  1079. flag round-trips, so ``~~full() == full()``); for ``===`` ranges
  1080. complement is one-way. The opt-in region is not restored (see below).
  1081. The opt-in region is dropped: a complement is an exclusion, and an
  1082. exclusion expresses no pre-release preference. This is what lets
  1083. ``a & ~b`` shed ``b``'s opt-in, so an excluded ``b`` never force-admits a
  1084. pre-release into the result. Complement stays involutive on the version
  1085. set, but not on the opt-in region: ``~~r`` covers the same versions as
  1086. ``r`` yet force-admits none of its pre-releases.
  1087. >>> r = SpecifierSet(">=1.0").to_range()
  1088. >>> "0.5" in r.complement()
  1089. True
  1090. >>> "1.5" in r.complement()
  1091. False
  1092. >>> r.complement().complement() == r
  1093. True
  1094. """
  1095. # Complement swaps literal admission: what the range rejects, its
  1096. # complement admits.
  1097. return self._build(
  1098. tuple(_complement_ranges(self._bounds)),
  1099. admit=self._reject,
  1100. reject=self._admit,
  1101. admit_arbitrary=self._admit_arbitrary,
  1102. pre_region=(),
  1103. prereleases_configured=self._prereleases_configured,
  1104. )
  1105. def difference(self, other: VersionRange) -> VersionRange:
  1106. """Range containing the versions in self but not in other.
  1107. Matches ``self & ~other`` on the version set and the opt-in region;
  1108. ``other`` acts as a bounds-only exclusion that grants no opt-in. The
  1109. arbitrary-string flag survives only when ``other`` removed no versions:
  1110. a difference that shrinks the bounds forgets it, as ``self & ~other``
  1111. would, so no later widening union can revive it. They still part on
  1112. ``===`` literals, whose complement is one-way: a ``===`` literal stays
  1113. when ``self`` admits it and ``other`` does not. Both operands must
  1114. share the same configured pre-release policy (as :meth:`intersection`
  1115. and :meth:`union` require); otherwise :exc:`ValueError` is raised.
  1116. ``a - empty()`` returns a range equal to ``a``.
  1117. >>> a = SpecifierSet(">=1.0").to_range()
  1118. >>> b = SpecifierSet(">=2.0").to_range()
  1119. >>> "1.5" in a.difference(b)
  1120. True
  1121. >>> "2.0" in a.difference(b)
  1122. False
  1123. >>> a.difference(VersionRange.empty()) == a
  1124. True
  1125. """
  1126. self._check_policy_compat(other)
  1127. # Subtracting a nothing-admitting set is a no-op; return self unchanged.
  1128. if not other._bounds and not other._admit:
  1129. return self
  1130. # Bound complement is two-way, so subtracting other's versions is an
  1131. # intersection with its gaps.
  1132. new_bounds = tuple(
  1133. intersect_ranges(self._bounds, _complement_ranges(other._bounds))
  1134. )
  1135. # Match ``self & ~other`` on the opt-in region: a complement carries no
  1136. # opt-in, so only ``self``'s region survives. ``other`` acts as a
  1137. # bounds-only exclusion. A configured ``self`` keeps no region.
  1138. new_region: tuple[Interval, ...] = ()
  1139. if self._prereleases_configured is None:
  1140. new_region = self._pre_region
  1141. # Keep self's arbitrary admission only when subtracting removed no
  1142. # versions. A difference that shrinks the bounds forgets the flag, as
  1143. # ``self & ~other`` would, so no later widening union can revive an
  1144. # admission neither operand had.
  1145. combined_arb = self._admit_arbitrary and new_bounds == self._bounds
  1146. if not self._has_literals() and not other._has_literals():
  1147. return self._build(
  1148. new_bounds,
  1149. admit_arbitrary=combined_arb,
  1150. pre_region=new_region,
  1151. prereleases_configured=self._prereleases_configured,
  1152. )
  1153. return self._combine_literals(
  1154. other,
  1155. new_bounds,
  1156. op=_SetOp.DIFFERENCE,
  1157. admit_arbitrary=combined_arb,
  1158. pre_region=new_region,
  1159. prereleases_configured=self._prereleases_configured,
  1160. )
  1161. def _combine_literals(
  1162. self,
  1163. other: VersionRange,
  1164. new_bounds: tuple[Interval, ...],
  1165. *,
  1166. op: _SetOp,
  1167. admit_arbitrary: bool,
  1168. pre_region: tuple[Interval, ...],
  1169. prereleases_configured: bool | None,
  1170. ) -> VersionRange:
  1171. """Resolve admit/reject for ``self`` ``op`` ``other`` over their literals."""
  1172. admits: set[str] = set()
  1173. rejects: set[str] = set()
  1174. # Each literal is decided independently of the others.
  1175. for literal in self._admit | self._reject | other._admit | other._reject:
  1176. self_in = self._matches_literal(literal)
  1177. other_in = other._matches_literal(literal)
  1178. if op is _SetOp.INTERSECTION:
  1179. want = self_in and other_in
  1180. elif op is _SetOp.UNION:
  1181. want = self_in or other_in
  1182. else:
  1183. want = self_in and not other_in
  1184. if want:
  1185. admits.add(literal)
  1186. else:
  1187. rejects.add(literal)
  1188. return self._build(
  1189. new_bounds,
  1190. admit=frozenset(admits),
  1191. reject=frozenset(rejects),
  1192. admit_arbitrary=admit_arbitrary,
  1193. pre_region=pre_region,
  1194. prereleases_configured=prereleases_configured,
  1195. )
  1196. def _matches_literal(self, literal: str) -> bool:
  1197. """Whether literal (case-folded) matches this range's predicate."""
  1198. if literal in self._reject:
  1199. return False
  1200. if literal in self._admit:
  1201. return True
  1202. parsed = coerce_version(literal)
  1203. if parsed is None:
  1204. return self._arbitrary_active()
  1205. return matches_bounds_only(self._bounds, parsed)
  1206. def __and__(self, other: object) -> VersionRange:
  1207. """Operator alias for :meth:`intersection`."""
  1208. if not isinstance(other, VersionRange):
  1209. return NotImplemented
  1210. return self.intersection(other)
  1211. def __or__(self, other: object) -> VersionRange:
  1212. """Operator alias for :meth:`union`."""
  1213. if not isinstance(other, VersionRange):
  1214. return NotImplemented
  1215. return self.union(other)
  1216. def __invert__(self) -> VersionRange:
  1217. """Operator alias for :meth:`complement`."""
  1218. return self.complement()
  1219. def __sub__(self, other: object) -> VersionRange:
  1220. """Operator alias for :meth:`difference`."""
  1221. if not isinstance(other, VersionRange):
  1222. return NotImplemented
  1223. return self.difference(other)
  1224. def is_subset(self, other: VersionRange) -> bool:
  1225. """Return whether every member of self is also a member of other.
  1226. On versions and ``===`` literals this is
  1227. ``self.difference(other).is_empty``: subtracting other leaves nothing
  1228. behind. A live arbitrary admission (the flag at full bounds) is only a
  1229. subset of another live one.
  1230. Both operands must share the same configured pre-release policy;
  1231. otherwise :exc:`ValueError` is raised.
  1232. >>> inner = SpecifierSet(">=1.5,<1.8").to_range()
  1233. >>> outer = SpecifierSet(">=1.0,<2.0").to_range()
  1234. >>> inner.is_subset(outer)
  1235. True
  1236. >>> outer.is_subset(inner)
  1237. False
  1238. >>> VersionRange.empty().is_subset(outer)
  1239. True
  1240. """
  1241. self._check_policy_compat(other)
  1242. # A live arbitrary admission has non-version strings as members, which
  1243. # no bounds cover; only another live admission contains them.
  1244. if self._arbitrary_active() and not other._arbitrary_active():
  1245. return False
  1246. # Plain ranges: subset reduces to bounds containment, no algebra needed.
  1247. if self._is_plain() and other._is_plain():
  1248. return not intersect_ranges(self._bounds, _complement_ranges(other._bounds))
  1249. # difference (unlike intersection with the one-way complement) resolves
  1250. # ``===`` literals against both operands, so it stays correct for them.
  1251. return self.difference(other).is_empty
  1252. def is_superset(self, other: VersionRange) -> bool:
  1253. """Return whether every member of other is also a member of self.
  1254. The mirror of :meth:`is_subset`: ``a.is_superset(b)`` is
  1255. ``b.is_subset(a)``.
  1256. Both operands must share the same configured pre-release policy;
  1257. otherwise :exc:`ValueError` is raised.
  1258. >>> outer = SpecifierSet(">=1.0,<2.0").to_range()
  1259. >>> outer.is_superset(SpecifierSet(">=1.5,<1.8").to_range())
  1260. True
  1261. """
  1262. # Type-guards a non-VersionRange other before delegating to is_subset.
  1263. self._check_policy_compat(other)
  1264. return other.is_subset(self)
  1265. def is_disjoint(self, other: VersionRange) -> bool:
  1266. """Return whether self and other share no member.
  1267. Equivalent to ``(self & other).is_empty``.
  1268. Both operands must share the same configured pre-release policy;
  1269. otherwise :exc:`ValueError` is raised.
  1270. >>> a = SpecifierSet(">=1.0,<2.0").to_range()
  1271. >>> a.is_disjoint(SpecifierSet(">=2.0,<3.0").to_range())
  1272. True
  1273. >>> a.is_disjoint(SpecifierSet(">=1.5,<2.5").to_range())
  1274. False
  1275. """
  1276. self._check_policy_compat(other)
  1277. # Plain ranges: disjointness is an empty bounds intersection.
  1278. if self._is_plain() and other._is_plain():
  1279. return not intersect_ranges(self._bounds, other._bounds)
  1280. return self.intersection(other).is_empty
  1281. def _same_releases(self, other: VersionRange) -> bool:
  1282. """Whether self and other admit the same non-pre-release versions.
  1283. Used by :meth:`to_specifier_set` under a ``prereleases=False`` policy,
  1284. where pre-releases are unobservable: the symmetric difference is empty
  1285. exactly when the two ranges accept the same releases. Both operands
  1286. carry that policy, so the difference below reads emptiness through it.
  1287. """
  1288. return self.difference(other).is_empty and other.difference(self).is_empty
  1289. @typing.overload
  1290. def filter(
  1291. self,
  1292. iterable: Iterable[UnparsedVersionVar],
  1293. prereleases: bool | None = None,
  1294. key: None = ...,
  1295. ) -> Iterator[UnparsedVersionVar]: ...
  1296. @typing.overload
  1297. def filter(
  1298. self,
  1299. iterable: Iterable[T],
  1300. prereleases: bool | None = None,
  1301. key: Callable[[T], UnparsedVersion] = ...,
  1302. ) -> Iterator[T]: ...
  1303. def filter(
  1304. self,
  1305. iterable: Iterable[Any],
  1306. prereleases: bool | None = None,
  1307. key: Callable[[Any], Version | str] | None = None,
  1308. ) -> Iterator[Any]:
  1309. """Yield items from iterable whose version falls inside the range.
  1310. With prereleases ``None`` the PEP 440 default applies: pre-releases are
  1311. buffered and only emitted if no final release in iterable is in range,
  1312. except that a pre-release inside the autodetected opt-in region, or named
  1313. outright by a ``===`` literal, is force-admitted in place (as
  1314. ``prereleases=True`` would yield it). A flushed buffer comes after
  1315. every in-place yield, so the output is not version-sorted.
  1316. The signature mirrors
  1317. :meth:`~packaging.specifiers.SpecifierSet.filter`.
  1318. >>> r = SpecifierSet(">=1.0,<2.0").to_range()
  1319. >>> list(r.filter(["0.9", "1.5", "2.0"]))
  1320. ['1.5']
  1321. """
  1322. region: tuple[Interval, ...] = ()
  1323. if prereleases is None:
  1324. # The region applies only under the autodetect default; a configured
  1325. # policy governs instead (and then ``_pre_region`` is already empty).
  1326. prereleases = self._prereleases_configured
  1327. region = self._pre_region
  1328. arbitrary_active = self._arbitrary_active()
  1329. if not self._admit and not self._reject and not arbitrary_active:
  1330. # A region spanning the whole bounds force-admits every in-bounds
  1331. # pre-release, i.e. ``prereleases=True``; take the cheaper no-buffer
  1332. # path. (Confined to this branch: the admission path orders arbitrary
  1333. # strings differently under True than under the region.)
  1334. if region and region == self._bounds:
  1335. return filter_by_ranges(self._bounds, iterable, key, True)
  1336. return filter_by_ranges(self._bounds, iterable, key, prereleases, region)
  1337. return self._filter_with_admission(
  1338. iterable, key, prereleases, arbitrary_active, region
  1339. )
  1340. def _filter_with_admission(
  1341. self,
  1342. iterable: Iterable[Any],
  1343. key: Callable[[Any], Version | str] | None,
  1344. prereleases: bool | None,
  1345. arbitrary_active: bool,
  1346. region: tuple[Interval, ...],
  1347. ) -> Iterator[Any]:
  1348. """Filter for ranges with admit/reject literals or live arbitrary
  1349. admission (including the universal ``SpecifierSet("")`` range)."""
  1350. admit_set = self._admit
  1351. reject_set = self._reject
  1352. def admit(item: Any) -> tuple[bool, Version | None, bool]: # noqa: ANN401
  1353. raw: Version | str = item if key is None else key(item)
  1354. raw_lower = str(raw).lower()
  1355. if reject_set and raw_lower in reject_set:
  1356. return False, None, False
  1357. if admit_set and raw_lower in admit_set:
  1358. # An explicit ``===`` literal names this version outright.
  1359. return True, coerce_version(raw), True
  1360. parsed = coerce_version(raw)
  1361. if parsed is None:
  1362. return arbitrary_active, None, False
  1363. if not matches_bounds_only(self._bounds, parsed):
  1364. return False, None, False
  1365. return True, parsed, False
  1366. if prereleases is True:
  1367. for item in iterable:
  1368. ok, _, _ = admit(item)
  1369. if ok:
  1370. yield item
  1371. return
  1372. if prereleases is False:
  1373. for item in iterable:
  1374. ok, parsed, _ = admit(item)
  1375. if not ok:
  1376. continue
  1377. if parsed is not None and parsed.is_prerelease:
  1378. continue
  1379. yield item
  1380. return
  1381. # PEP 440 default: emit finals eagerly and buffer the other pre-releases,
  1382. # releasing the buffer only if no final ever matches.
  1383. all_nonfinal: list[Any] = []
  1384. arbitrary_strings: list[Any] = []
  1385. found_final = False
  1386. for item in iterable:
  1387. ok, parsed, by_literal = admit(item)
  1388. if not ok:
  1389. continue
  1390. if parsed is None:
  1391. if found_final:
  1392. yield item
  1393. else:
  1394. arbitrary_strings.append(item)
  1395. all_nonfinal.append(item)
  1396. continue
  1397. if not parsed.is_prerelease:
  1398. if not found_final:
  1399. yield from arbitrary_strings
  1400. arbitrary_strings.clear()
  1401. found_final = True
  1402. yield item
  1403. continue
  1404. # A pre-release is force-admitted when it is named outright by a
  1405. # ``===`` literal or falls in the opt-in region, as ``prereleases=True``
  1406. # would yield it; otherwise the PEP 440 default buffers it.
  1407. if by_literal or (region and matches_bounds_only(region, parsed)):
  1408. yield item
  1409. continue
  1410. if not found_final:
  1411. all_nonfinal.append(item)
  1412. if not found_final:
  1413. yield from all_nonfinal
  1414. @classmethod
  1415. def _from_specifier_set(cls, specifier_set: SpecifierSet) -> VersionRange:
  1416. """Build the range accepted by ``specifier_set``.
  1417. Friend constructor for :meth:`~packaging.specifiers.SpecifierSet.to_range`.
  1418. The intersection of every specifier in the set: an empty set yields the
  1419. full range, an unsatisfiable set yields the empty range, and ``===``
  1420. specifiers contribute literal-string admission.
  1421. """
  1422. if not specifier_set:
  1423. result = cls.full()
  1424. elif not specifier_set._has_arbitrary:
  1425. result = cls._build(
  1426. bounds=_canonical_floor(tuple(specifier_set._get_ranges()))
  1427. )
  1428. else:
  1429. result = cls.full()
  1430. for spec in specifier_set:
  1431. if spec.operator == "===":
  1432. operand = cls._build(
  1433. bounds=(), admit=frozenset({spec.version.lower()})
  1434. )
  1435. else:
  1436. operand = cls._build(
  1437. bounds=_canonical_floor(tuple(spec._to_ranges()))
  1438. )
  1439. result = result.intersection(operand)
  1440. # Each pre-release-naming specifier opts its own versions in; their union,
  1441. # clipped to the set's bounds by _build, is the region. Clipping refolds
  1442. # under intersection, so a set built directly equals one built by
  1443. # intersecting its specifiers one at a time.
  1444. region: list[Interval] = []
  1445. if specifier_set._prereleases is None: # a configured policy has no region
  1446. for spec in specifier_set:
  1447. # ``===`` literals are not a range; filter force-admits them.
  1448. if spec.operator != "===" and spec.prereleases:
  1449. spec_bounds = _canonical_floor(tuple(spec._to_ranges()))
  1450. region = _union_ranges(region, spec_bounds)
  1451. return result._with_policy(
  1452. pre_region=tuple(region),
  1453. configured=specifier_set._prereleases,
  1454. )
  1455. def to_specifier_set(self) -> SpecifierSet | None:
  1456. """Return a :class:`~packaging.specifiers.SpecifierSet` matching the same
  1457. versions as self, or ``None`` if no single set expresses it.
  1458. PEP 440 has no syntax for the strict singleton ``{V}`` (an exclusive
  1459. plain-version bound), a disjoint union of two or more intervals, or a
  1460. partial pre-release opt-in region, so ranges built by set algebra often
  1461. return ``None``. A gap that takes more than ``_MAX_EXCLUSION_RUN``
  1462. contiguous ``!=`` exclusions to spell returns ``None`` too,
  1463. rather than a pathologically long chain; reaching that cap takes either
  1464. set algebra or a specifier set that already spells the gap out with
  1465. over a hundred contiguous ``!=N.*`` exclusions. An empty range maps to
  1466. ``SpecifierSet("<0")``, unless it still carries the arbitrary-string
  1467. flag (which no set reproduces), and a full range that admits arbitrary
  1468. strings maps to ``SpecifierSet("")``.
  1469. A range built from a :class:`~packaging.specifiers.SpecifierSet`
  1470. re-encodes, short of that exclusion cap. The result is the simplest
  1471. candidate whose own
  1472. :meth:`~packaging.specifiers.SpecifierSet.to_range` reproduces self
  1473. exactly (bounds, ``===`` literals, and the opt-in region are all part of
  1474. equality), so it filters the same versions. Two cases relax that
  1475. exactness without changing what is filtered: an empty range recovers as
  1476. the canonical empty range (same versions, none, but not self's bounds),
  1477. and under a ``prereleases=False`` policy the result need only match self's
  1478. releases, so ``(-inf, 3.14)`` recovers as the tighter ``<3.14`` rather
  1479. than ``!=3.14,<=3.14``.
  1480. Each call encodes a handful of candidate spellings and keeps the
  1481. simplest one that verifies, where verifying means parsing the candidate
  1482. and round-tripping it through
  1483. :meth:`~packaging.specifiers.SpecifierSet.to_range`. The work grows
  1484. with the number of intervals and exclusions in the range, and the
  1485. result is not cached, so convert once and reuse the returned set rather
  1486. than converting per candidate version in a hot loop.
  1487. >>> str(SpecifierSet(">=1.0,<2.0").to_range().to_specifier_set())
  1488. '<2.0,>=1.0'
  1489. >>> str(SpecifierSet("==1.0").to_range().to_specifier_set())
  1490. '==1.0'
  1491. >>> VersionRange.singleton("1.5").to_specifier_set() is None
  1492. True
  1493. """
  1494. from .specifiers import InvalidSpecifier, SpecifierSet # noqa: PLC0415
  1495. configured = self._prereleases_configured
  1496. if self._reject:
  1497. return None
  1498. if self._admit_arbitrary and self._bounds != FULL_RANGE:
  1499. return None
  1500. if self.is_empty:
  1501. # Every member-free spelling accepts the same versions (none), so the
  1502. # canonical ``<0`` stands in for all of them; a configured policy
  1503. # rides along it.
  1504. return SpecifierSet("<0", prereleases=configured)
  1505. if not self._bounds:
  1506. # Pure ``===`` literals; only a single literal has a single-set form.
  1507. if len(self._admit) != 1:
  1508. return None
  1509. (literal,) = self._admit
  1510. bases = [f"==={literal}"]
  1511. elif self._admit:
  1512. # Bounds plus literals cannot be one set.
  1513. return None
  1514. elif self._bounds == FULL_RANGE:
  1515. bases = ["" if self._admit_arbitrary else ">=0.dev0"]
  1516. else:
  1517. # Under ``prereleases=False`` an exclusive final upper admits the same
  1518. # releases as ``<V`` (the ``[V.dev0, V)`` band is excluded), so offer
  1519. # the tightened bounds as well; a tightening that is not
  1520. # release-equivalent is dropped by the acceptance check below.
  1521. layouts = [self._bounds]
  1522. if configured is False:
  1523. tightened = _tighten_no_prereleases(self._bounds)
  1524. if tightened != self._bounds:
  1525. layouts.append(tightened)
  1526. # Encode each layout in both spelling modes: prerelease-free, then
  1527. # keeping the synthetic ``.dev0`` markers. Which spelling reproduces
  1528. # self is settled by the round trip below, not up front. The gap
  1529. # exclusions do not depend on the mode, so they encode once.
  1530. bases = []
  1531. for layout in layouts:
  1532. exclusions = _encode_gaps(layout)
  1533. if exclusions is None:
  1534. continue
  1535. for keep_dev0 in (False, True):
  1536. outer = _encode_interval(layout[0][0], layout[-1][1], keep_dev0)
  1537. if outer is None:
  1538. continue
  1539. base = ",".join(outer + exclusions)
  1540. if base not in bases:
  1541. bases.append(base)
  1542. # A trailing no-op ``>=0.dev0`` floor restores a ``True`` opt-in that
  1543. # rode on a floor the clean encoding dropped (e.g. ``>=0.dev0,!=1.0``).
  1544. # It always recovers the whole bounds as the opt-in region, so it can
  1545. # only round-trip when self opts everything in.
  1546. add_floor = configured is None and self._pre_region == self._bounds
  1547. # Keep the simplest candidate that recovers self. ``==`` compares bounds,
  1548. # literals, and the opt-in region, so a candidate that would filter
  1549. # differently, or an op-built range with no single-set form, is rejected
  1550. # below. Under ``prereleases=False`` a candidate need only match self's
  1551. # releases (policies never mix, so the excluded pre-releases are
  1552. # unobservable), which admits the tightened spellings above.
  1553. best: SpecifierSet | None = None
  1554. best_key = (0, 0)
  1555. for base in bases:
  1556. candidates = [base]
  1557. if add_floor:
  1558. candidates.append(f"{base},>=0.dev0" if base else ">=0.dev0")
  1559. for spec_str in candidates:
  1560. # A ``===`` literal can hold a comma (its arbitrary version
  1561. # excludes only whitespace, ``;`` and ``)``), which the set
  1562. # string splits on. Such a literal has no single specifier-set
  1563. # spelling, so drop the unparsable candidate and let the range
  1564. # fall through to ``None`` rather than raise.
  1565. try:
  1566. recovered = SpecifierSet(spec_str, prereleases=configured)
  1567. except InvalidSpecifier:
  1568. continue
  1569. # Fewest fragments, then shortest string. Rank before the round
  1570. # trip so a candidate that cannot beat the best skips the check
  1571. # (its ``==`` and, under ``False``, two ``difference`` calls).
  1572. key = (len(recovered), len(str(recovered)))
  1573. if best is not None and key >= best_key:
  1574. continue
  1575. # Accept an exact round trip, or (under ``False``) one that only
  1576. # matches the releases the policy leaves observable.
  1577. candidate = recovered.to_range()
  1578. matches = candidate == self or (
  1579. configured is False and self._same_releases(candidate)
  1580. )
  1581. if matches:
  1582. best, best_key = recovered, key
  1583. return best
  1584. @property
  1585. def is_empty(self) -> bool:
  1586. """``True`` if no version or string satisfies this range.
  1587. Agrees with :meth:`~packaging.specifiers.SpecifierSet.is_unsatisfiable`,
  1588. including the pre-release policy: a range whose only members are
  1589. pre-releases is empty when that policy excludes them.
  1590. >>> SpecifierSet(">=2,<1").to_range().is_empty
  1591. True
  1592. >>> SpecifierSet(">=1,<2").to_range().is_empty
  1593. False
  1594. >>> SpecifierSet("==1.0a1", prereleases=False).to_range().is_empty
  1595. True
  1596. """
  1597. # An arbitrary-string admission or a surviving ``===`` literal is a
  1598. # member; a literal that is a pre-release is dropped when the policy is.
  1599. if self._arbitrary_active():
  1600. return False
  1601. excludes_prereleases = self._prereleases_configured is False
  1602. for literal in self._admit:
  1603. if excludes_prereleases:
  1604. parsed = coerce_version(literal)
  1605. if parsed is not None and parsed.is_prerelease:
  1606. continue
  1607. return False
  1608. if not self._bounds:
  1609. return True
  1610. return excludes_prereleases and ranges_are_prerelease_only(self._bounds)
  1611. def contains(
  1612. self,
  1613. item: Version | str,
  1614. prereleases: bool | None = None,
  1615. installed: bool | None = None,
  1616. ) -> bool:
  1617. """Return whether item is contained in this range.
  1618. :param item: a version string or :class:`~packaging.version.Version`.
  1619. :param prereleases: whether to match pre-releases. ``None`` (default)
  1620. uses the range's own policy.
  1621. :param installed: when ``True``, accept a pre-release item even if the
  1622. range would not otherwise allow it.
  1623. Unlike :meth:`filter`, this does not consult the autodetected pre-release
  1624. opt-in region; it reads only the configured policy. This mirrors
  1625. :meth:`~packaging.specifiers.SpecifierSet.contains` versus
  1626. :meth:`~packaging.specifiers.SpecifierSet.filter`.
  1627. Unparsable strings do not match, except where the full
  1628. ``SpecifierSet`` would also match: the full range admits any string,
  1629. and a ``===`` range admits items equal to the literal
  1630. case-insensitively.
  1631. >>> r = SpecifierSet(">=1.0,<2.0").to_range()
  1632. >>> r.contains("1.5")
  1633. True
  1634. >>> r.contains("2.0")
  1635. False
  1636. :raises TypeError: if item is not a str or Version.
  1637. """
  1638. if not isinstance(item, (str, Version)):
  1639. raise TypeError(
  1640. f"VersionRange.contains() expected str or Version, "
  1641. f"got {type(item).__name__}"
  1642. )
  1643. parsed: Version | None = item if isinstance(item, Version) else None
  1644. if installed and parsed is None:
  1645. parsed = coerce_version(item)
  1646. if installed and parsed is not None and parsed.is_prerelease:
  1647. prereleases = True
  1648. effective_pre = (
  1649. self._prereleases_configured if prereleases is None else prereleases
  1650. )
  1651. if self._admit or self._reject:
  1652. item_str = str(item).lower()
  1653. if item_str in self._reject:
  1654. return False
  1655. if item_str in self._admit:
  1656. if effective_pre is False:
  1657. literal_parsed = coerce_version(item_str)
  1658. if literal_parsed is not None and literal_parsed.is_prerelease:
  1659. return False
  1660. return True
  1661. if not isinstance(item, Version):
  1662. if parsed is None:
  1663. parsed = coerce_version(item)
  1664. if parsed is None:
  1665. return self._arbitrary_active()
  1666. item = parsed
  1667. if effective_pre is False and item.is_prerelease:
  1668. return False
  1669. return matches_bounds_only(self._bounds, item)
  1670. def __contains__(self, item: Version | str) -> bool:
  1671. """Return whether item is contained in this range.
  1672. Forwards to :meth:`contains` with default arguments.
  1673. >>> "1.5" in SpecifierSet(">=1.0,<2.0").to_range()
  1674. True
  1675. """
  1676. return self.contains(item)
  1677. def __eq__(self, other: object) -> bool:
  1678. """Structural equality.
  1679. Compares the bounds, the ``===`` admit/reject literals, the
  1680. arbitrary-string flag, the configured pre-release policy, and the
  1681. opt-in region, not just the version set. Keying on the region makes
  1682. equality a congruence (equal ranges stay equal under further operations),
  1683. so equal implies same :meth:`contains` and :meth:`filter`, but not the
  1684. converse: an empty range keeps the flag it was built with, so two empty
  1685. ranges need not be equal.
  1686. Different specifiers for the same range fold to one canonical form:
  1687. >>> SpecifierSet(">1.0a1").to_range() == SpecifierSet(">=1.0a2.dev0").to_range()
  1688. True
  1689. The opt-in region is part of equality, so ``<=1.0`` (no pre-releases) and
  1690. ``<1.0.post0.dev0`` (autodetects a ``.dev`` opt-in) cover the same
  1691. versions yet compare unequal:
  1692. >>> le, lt = SpecifierSet("<=1.0"), SpecifierSet("<1.0.post0.dev0")
  1693. >>> le.to_range() == lt.to_range()
  1694. False
  1695. >>> r = SpecifierSet(">=1.0,<2.0").to_range()
  1696. >>> r == SpecifierSet(">=1.0,<2.0").to_range()
  1697. True
  1698. """
  1699. if not isinstance(other, VersionRange):
  1700. return NotImplemented
  1701. return (
  1702. self._bounds == other._bounds
  1703. and self._admit == other._admit
  1704. and self._reject == other._reject
  1705. and self._admit_arbitrary == other._admit_arbitrary
  1706. and self._prereleases_configured == other._prereleases_configured
  1707. and self._pre_region == other._pre_region
  1708. )
  1709. def __hash__(self) -> int:
  1710. return hash(
  1711. (
  1712. self._bounds,
  1713. self._admit,
  1714. self._reject,
  1715. self._admit_arbitrary,
  1716. self._prereleases_configured,
  1717. self._pre_region,
  1718. )
  1719. )
  1720. def __repr__(self) -> str:
  1721. """Human-readable representation for debugging.
  1722. >>> SpecifierSet(">=1.0,<2.0").to_range()
  1723. <VersionRange '[1.0, 2.0.dev0)'>
  1724. >>> SpecifierSet("").to_range()
  1725. <VersionRange '(-inf, +inf)' arbitrary>
  1726. >>> SpecifierSet(">=2.0,<1.0").to_range()
  1727. <VersionRange '(empty)'>
  1728. """
  1729. # Body: the bounds and any ``===``-admitted literals.
  1730. parts: list[str] = []
  1731. if self._bounds:
  1732. parts.append(_format_intervals(self._bounds))
  1733. if self._admit:
  1734. parts.append("{" + ", ".join(sorted(self._admit)) + "}")
  1735. body = " | ".join(parts) if parts else "(empty)"
  1736. # Rejected literals subtract from the body.
  1737. if self._reject:
  1738. body = f"{body} \\ {{{', '.join(sorted(self._reject))}}}"
  1739. # Tail: the policy flags carried alongside the version set.
  1740. tail = ""
  1741. if self._admit_arbitrary:
  1742. tail += " arbitrary"
  1743. if self._prereleases_configured is not None:
  1744. tail += f" pre={self._prereleases_configured}"
  1745. if self._pre_region:
  1746. tail += f" pre-region={_format_intervals(self._pre_region)!r}"
  1747. return f"<{self.__class__.__name__} {body!r}{tail}>"