specifiers.py 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  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. """
  5. .. testsetup::
  6. from packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier
  7. from packaging.version import Version
  8. """
  9. import abc
  10. import itertools
  11. import re
  12. from typing import (
  13. Callable,
  14. Iterable,
  15. Iterator,
  16. List,
  17. Optional,
  18. Set,
  19. Tuple,
  20. TypeVar,
  21. Union,
  22. )
  23. from .utils import canonicalize_version
  24. from .version import Version
  25. UnparsedVersion = Union[Version, str]
  26. UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion)
  27. CallableOperator = Callable[[Version, str], bool]
  28. def _coerce_version(version: UnparsedVersion) -> Version:
  29. if not isinstance(version, Version):
  30. version = Version(version)
  31. return version
  32. class InvalidSpecifier(ValueError):
  33. """
  34. Raised when attempting to create a :class:`Specifier` with a specifier
  35. string that is invalid.
  36. >>> Specifier("lolwat")
  37. Traceback (most recent call last):
  38. ...
  39. packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat'
  40. """
  41. class BaseSpecifier(metaclass=abc.ABCMeta):
  42. @abc.abstractmethod
  43. def __str__(self) -> str:
  44. """
  45. Returns the str representation of this Specifier-like object. This
  46. should be representative of the Specifier itself.
  47. """
  48. @abc.abstractmethod
  49. def __hash__(self) -> int:
  50. """
  51. Returns a hash value for this Specifier-like object.
  52. """
  53. @abc.abstractmethod
  54. def __eq__(self, other: object) -> bool:
  55. """
  56. Returns a boolean representing whether or not the two Specifier-like
  57. objects are equal.
  58. :param other: The other object to check against.
  59. """
  60. @property
  61. @abc.abstractmethod
  62. def prereleases(self) -> Optional[bool]:
  63. """Whether or not pre-releases as a whole are allowed.
  64. This can be set to either ``True`` or ``False`` to explicitly enable or disable
  65. prereleases or it can be set to ``None`` (the default) to use default semantics.
  66. """
  67. @prereleases.setter
  68. def prereleases(self, value: bool) -> None:
  69. """Setter for :attr:`prereleases`.
  70. :param value: The value to set.
  71. """
  72. @abc.abstractmethod
  73. def contains(self, item: str, prereleases: Optional[bool] = None) -> bool:
  74. """
  75. Determines if the given item is contained within this specifier.
  76. """
  77. @abc.abstractmethod
  78. def filter(
  79. self, iterable: Iterable[UnparsedVersionVar], prereleases: Optional[bool] = None
  80. ) -> Iterator[UnparsedVersionVar]:
  81. """
  82. Takes an iterable of items and filters them so that only items which
  83. are contained within this specifier are allowed in it.
  84. """
  85. class Specifier(BaseSpecifier):
  86. """This class abstracts handling of version specifiers.
  87. .. tip::
  88. It is generally not required to instantiate this manually. You should instead
  89. prefer to work with :class:`SpecifierSet` instead, which can parse
  90. comma-separated version specifiers (which is what package metadata contains).
  91. """
  92. _operator_regex_str = r"""
  93. (?P<operator>(~=|==|!=|<=|>=|<|>|===))
  94. """
  95. _version_regex_str = r"""
  96. (?P<version>
  97. (?:
  98. # The identity operators allow for an escape hatch that will
  99. # do an exact string match of the version you wish to install.
  100. # This will not be parsed by PEP 440 and we cannot determine
  101. # any semantic meaning from it. This operator is discouraged
  102. # but included entirely as an escape hatch.
  103. (?<====) # Only match for the identity operator
  104. \s*
  105. [^\s;)]* # The arbitrary version can be just about anything,
  106. # we match everything except for whitespace, a
  107. # semi-colon for marker support, and a closing paren
  108. # since versions can be enclosed in them.
  109. )
  110. |
  111. (?:
  112. # The (non)equality operators allow for wild card and local
  113. # versions to be specified so we have to define these two
  114. # operators separately to enable that.
  115. (?<===|!=) # Only match for equals and not equals
  116. \s*
  117. v?
  118. (?:[0-9]+!)? # epoch
  119. [0-9]+(?:\.[0-9]+)* # release
  120. # You cannot use a wild card and a pre-release, post-release, a dev or
  121. # local version together so group them with a | and make them optional.
  122. (?:
  123. \.\* # Wild card syntax of .*
  124. |
  125. (?: # pre release
  126. [-_\.]?
  127. (alpha|beta|preview|pre|a|b|c|rc)
  128. [-_\.]?
  129. [0-9]*
  130. )?
  131. (?: # post release
  132. (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
  133. )?
  134. (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
  135. (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
  136. )?
  137. )
  138. |
  139. (?:
  140. # The compatible operator requires at least two digits in the
  141. # release segment.
  142. (?<=~=) # Only match for the compatible operator
  143. \s*
  144. v?
  145. (?:[0-9]+!)? # epoch
  146. [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
  147. (?: # pre release
  148. [-_\.]?
  149. (alpha|beta|preview|pre|a|b|c|rc)
  150. [-_\.]?
  151. [0-9]*
  152. )?
  153. (?: # post release
  154. (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
  155. )?
  156. (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
  157. )
  158. |
  159. (?:
  160. # All other operators only allow a sub set of what the
  161. # (non)equality operators do. Specifically they do not allow
  162. # local versions to be specified nor do they allow the prefix
  163. # matching wild cards.
  164. (?<!==|!=|~=) # We have special cases for these
  165. # operators so we want to make sure they
  166. # don't match here.
  167. \s*
  168. v?
  169. (?:[0-9]+!)? # epoch
  170. [0-9]+(?:\.[0-9]+)* # release
  171. (?: # pre release
  172. [-_\.]?
  173. (alpha|beta|preview|pre|a|b|c|rc)
  174. [-_\.]?
  175. [0-9]*
  176. )?
  177. (?: # post release
  178. (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
  179. )?
  180. (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
  181. )
  182. )
  183. """
  184. _regex = re.compile(
  185. r"^\s*" + _operator_regex_str + _version_regex_str + r"\s*$",
  186. re.VERBOSE | re.IGNORECASE,
  187. )
  188. _operators = {
  189. "~=": "compatible",
  190. "==": "equal",
  191. "!=": "not_equal",
  192. "<=": "less_than_equal",
  193. ">=": "greater_than_equal",
  194. "<": "less_than",
  195. ">": "greater_than",
  196. "===": "arbitrary",
  197. }
  198. def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None:
  199. """Initialize a Specifier instance.
  200. :param spec:
  201. The string representation of a specifier which will be parsed and
  202. normalized before use.
  203. :param prereleases:
  204. This tells the specifier if it should accept prerelease versions if
  205. applicable or not. The default of ``None`` will autodetect it from the
  206. given specifiers.
  207. :raises InvalidSpecifier:
  208. If the given specifier is invalid (i.e. bad syntax).
  209. """
  210. match = self._regex.search(spec)
  211. if not match:
  212. raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
  213. self._spec: Tuple[str, str] = (
  214. match.group("operator").strip(),
  215. match.group("version").strip(),
  216. )
  217. # Store whether or not this Specifier should accept prereleases
  218. self._prereleases = prereleases
  219. # https://github.com/python/mypy/pull/13475#pullrequestreview-1079784515
  220. @property # type: ignore[override]
  221. def prereleases(self) -> bool:
  222. # If there is an explicit prereleases set for this, then we'll just
  223. # blindly use that.
  224. if self._prereleases is not None:
  225. return self._prereleases
  226. # Look at all of our specifiers and determine if they are inclusive
  227. # operators, and if they are if they are including an explicit
  228. # prerelease.
  229. operator, version = self._spec
  230. if operator in ["==", ">=", "<=", "~=", "==="]:
  231. # The == specifier can include a trailing .*, if it does we
  232. # want to remove before parsing.
  233. if operator == "==" and version.endswith(".*"):
  234. version = version[:-2]
  235. # Parse the version, and if it is a pre-release than this
  236. # specifier allows pre-releases.
  237. if Version(version).is_prerelease:
  238. return True
  239. return False
  240. @prereleases.setter
  241. def prereleases(self, value: bool) -> None:
  242. self._prereleases = value
  243. @property
  244. def operator(self) -> str:
  245. """The operator of this specifier.
  246. >>> Specifier("==1.2.3").operator
  247. '=='
  248. """
  249. return self._spec[0]
  250. @property
  251. def version(self) -> str:
  252. """The version of this specifier.
  253. >>> Specifier("==1.2.3").version
  254. '1.2.3'
  255. """
  256. return self._spec[1]
  257. def __repr__(self) -> str:
  258. """A representation of the Specifier that shows all internal state.
  259. >>> Specifier('>=1.0.0')
  260. <Specifier('>=1.0.0')>
  261. >>> Specifier('>=1.0.0', prereleases=False)
  262. <Specifier('>=1.0.0', prereleases=False)>
  263. >>> Specifier('>=1.0.0', prereleases=True)
  264. <Specifier('>=1.0.0', prereleases=True)>
  265. """
  266. pre = (
  267. f", prereleases={self.prereleases!r}"
  268. if self._prereleases is not None
  269. else ""
  270. )
  271. return f"<{self.__class__.__name__}({str(self)!r}{pre})>"
  272. def __str__(self) -> str:
  273. """A string representation of the Specifier that can be round-tripped.
  274. >>> str(Specifier('>=1.0.0'))
  275. '>=1.0.0'
  276. >>> str(Specifier('>=1.0.0', prereleases=False))
  277. '>=1.0.0'
  278. """
  279. return "{}{}".format(*self._spec)
  280. @property
  281. def _canonical_spec(self) -> Tuple[str, str]:
  282. canonical_version = canonicalize_version(
  283. self._spec[1],
  284. strip_trailing_zero=(self._spec[0] != "~="),
  285. )
  286. return self._spec[0], canonical_version
  287. def __hash__(self) -> int:
  288. return hash(self._canonical_spec)
  289. def __eq__(self, other: object) -> bool:
  290. """Whether or not the two Specifier-like objects are equal.
  291. :param other: The other object to check against.
  292. The value of :attr:`prereleases` is ignored.
  293. >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0")
  294. True
  295. >>> (Specifier("==1.2.3", prereleases=False) ==
  296. ... Specifier("==1.2.3", prereleases=True))
  297. True
  298. >>> Specifier("==1.2.3") == "==1.2.3"
  299. True
  300. >>> Specifier("==1.2.3") == Specifier("==1.2.4")
  301. False
  302. >>> Specifier("==1.2.3") == Specifier("~=1.2.3")
  303. False
  304. """
  305. if isinstance(other, str):
  306. try:
  307. other = self.__class__(str(other))
  308. except InvalidSpecifier:
  309. return NotImplemented
  310. elif not isinstance(other, self.__class__):
  311. return NotImplemented
  312. return self._canonical_spec == other._canonical_spec
  313. def _get_operator(self, op: str) -> CallableOperator:
  314. operator_callable: CallableOperator = getattr(
  315. self, f"_compare_{self._operators[op]}"
  316. )
  317. return operator_callable
  318. def _compare_compatible(self, prospective: Version, spec: str) -> bool:
  319. # Compatible releases have an equivalent combination of >= and ==. That
  320. # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
  321. # implement this in terms of the other specifiers instead of
  322. # implementing it ourselves. The only thing we need to do is construct
  323. # the other specifiers.
  324. # We want everything but the last item in the version, but we want to
  325. # ignore suffix segments.
  326. prefix = _version_join(
  327. list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1]
  328. )
  329. # Add the prefix notation to the end of our string
  330. prefix += ".*"
  331. return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
  332. prospective, prefix
  333. )
  334. def _compare_equal(self, prospective: Version, spec: str) -> bool:
  335. # We need special logic to handle prefix matching
  336. if spec.endswith(".*"):
  337. # In the case of prefix matching we want to ignore local segment.
  338. normalized_prospective = canonicalize_version(
  339. prospective.public, strip_trailing_zero=False
  340. )
  341. # Get the normalized version string ignoring the trailing .*
  342. normalized_spec = canonicalize_version(spec[:-2], strip_trailing_zero=False)
  343. # Split the spec out by bangs and dots, and pretend that there is
  344. # an implicit dot in between a release segment and a pre-release segment.
  345. split_spec = _version_split(normalized_spec)
  346. # Split the prospective version out by bangs and dots, and pretend
  347. # that there is an implicit dot in between a release segment and
  348. # a pre-release segment.
  349. split_prospective = _version_split(normalized_prospective)
  350. # 0-pad the prospective version before shortening it to get the correct
  351. # shortened version.
  352. padded_prospective, _ = _pad_version(split_prospective, split_spec)
  353. # Shorten the prospective version to be the same length as the spec
  354. # so that we can determine if the specifier is a prefix of the
  355. # prospective version or not.
  356. shortened_prospective = padded_prospective[: len(split_spec)]
  357. return shortened_prospective == split_spec
  358. else:
  359. # Convert our spec string into a Version
  360. spec_version = Version(spec)
  361. # If the specifier does not have a local segment, then we want to
  362. # act as if the prospective version also does not have a local
  363. # segment.
  364. if not spec_version.local:
  365. prospective = Version(prospective.public)
  366. return prospective == spec_version
  367. def _compare_not_equal(self, prospective: Version, spec: str) -> bool:
  368. return not self._compare_equal(prospective, spec)
  369. def _compare_less_than_equal(self, prospective: Version, spec: str) -> bool:
  370. # NB: Local version identifiers are NOT permitted in the version
  371. # specifier, so local version labels can be universally removed from
  372. # the prospective version.
  373. return Version(prospective.public) <= Version(spec)
  374. def _compare_greater_than_equal(self, prospective: Version, spec: str) -> bool:
  375. # NB: Local version identifiers are NOT permitted in the version
  376. # specifier, so local version labels can be universally removed from
  377. # the prospective version.
  378. return Version(prospective.public) >= Version(spec)
  379. def _compare_less_than(self, prospective: Version, spec_str: str) -> bool:
  380. # Convert our spec to a Version instance, since we'll want to work with
  381. # it as a version.
  382. spec = Version(spec_str)
  383. # Check to see if the prospective version is less than the spec
  384. # version. If it's not we can short circuit and just return False now
  385. # instead of doing extra unneeded work.
  386. if not prospective < spec:
  387. return False
  388. # This special case is here so that, unless the specifier itself
  389. # includes is a pre-release version, that we do not accept pre-release
  390. # versions for the version mentioned in the specifier (e.g. <3.1 should
  391. # not match 3.1.dev0, but should match 3.0.dev0).
  392. if not spec.is_prerelease and prospective.is_prerelease:
  393. if Version(prospective.base_version) == Version(spec.base_version):
  394. return False
  395. # If we've gotten to here, it means that prospective version is both
  396. # less than the spec version *and* it's not a pre-release of the same
  397. # version in the spec.
  398. return True
  399. def _compare_greater_than(self, prospective: Version, spec_str: str) -> bool:
  400. # Convert our spec to a Version instance, since we'll want to work with
  401. # it as a version.
  402. spec = Version(spec_str)
  403. # Check to see if the prospective version is greater than the spec
  404. # version. If it's not we can short circuit and just return False now
  405. # instead of doing extra unneeded work.
  406. if not prospective > spec:
  407. return False
  408. # This special case is here so that, unless the specifier itself
  409. # includes is a post-release version, that we do not accept
  410. # post-release versions for the version mentioned in the specifier
  411. # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
  412. if not spec.is_postrelease and prospective.is_postrelease:
  413. if Version(prospective.base_version) == Version(spec.base_version):
  414. return False
  415. # Ensure that we do not allow a local version of the version mentioned
  416. # in the specifier, which is technically greater than, to match.
  417. if prospective.local is not None:
  418. if Version(prospective.base_version) == Version(spec.base_version):
  419. return False
  420. # If we've gotten to here, it means that prospective version is both
  421. # greater than the spec version *and* it's not a pre-release of the
  422. # same version in the spec.
  423. return True
  424. def _compare_arbitrary(self, prospective: Version, spec: str) -> bool:
  425. return str(prospective).lower() == str(spec).lower()
  426. def __contains__(self, item: Union[str, Version]) -> bool:
  427. """Return whether or not the item is contained in this specifier.
  428. :param item: The item to check for.
  429. This is used for the ``in`` operator and behaves the same as
  430. :meth:`contains` with no ``prereleases`` argument passed.
  431. >>> "1.2.3" in Specifier(">=1.2.3")
  432. True
  433. >>> Version("1.2.3") in Specifier(">=1.2.3")
  434. True
  435. >>> "1.0.0" in Specifier(">=1.2.3")
  436. False
  437. >>> "1.3.0a1" in Specifier(">=1.2.3")
  438. False
  439. >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True)
  440. True
  441. """
  442. return self.contains(item)
  443. def contains(
  444. self, item: UnparsedVersion, prereleases: Optional[bool] = None
  445. ) -> bool:
  446. """Return whether or not the item is contained in this specifier.
  447. :param item:
  448. The item to check for, which can be a version string or a
  449. :class:`Version` instance.
  450. :param prereleases:
  451. Whether or not to match prereleases with this Specifier. If set to
  452. ``None`` (the default), it uses :attr:`prereleases` to determine
  453. whether or not prereleases are allowed.
  454. >>> Specifier(">=1.2.3").contains("1.2.3")
  455. True
  456. >>> Specifier(">=1.2.3").contains(Version("1.2.3"))
  457. True
  458. >>> Specifier(">=1.2.3").contains("1.0.0")
  459. False
  460. >>> Specifier(">=1.2.3").contains("1.3.0a1")
  461. False
  462. >>> Specifier(">=1.2.3", prereleases=True).contains("1.3.0a1")
  463. True
  464. >>> Specifier(">=1.2.3").contains("1.3.0a1", prereleases=True)
  465. True
  466. """
  467. # Determine if prereleases are to be allowed or not.
  468. if prereleases is None:
  469. prereleases = self.prereleases
  470. # Normalize item to a Version, this allows us to have a shortcut for
  471. # "2.0" in Specifier(">=2")
  472. normalized_item = _coerce_version(item)
  473. # Determine if we should be supporting prereleases in this specifier
  474. # or not, if we do not support prereleases than we can short circuit
  475. # logic if this version is a prereleases.
  476. if normalized_item.is_prerelease and not prereleases:
  477. return False
  478. # Actually do the comparison to determine if this item is contained
  479. # within this Specifier or not.
  480. operator_callable: CallableOperator = self._get_operator(self.operator)
  481. return operator_callable(normalized_item, self.version)
  482. def filter(
  483. self, iterable: Iterable[UnparsedVersionVar], prereleases: Optional[bool] = None
  484. ) -> Iterator[UnparsedVersionVar]:
  485. """Filter items in the given iterable, that match the specifier.
  486. :param iterable:
  487. An iterable that can contain version strings and :class:`Version` instances.
  488. The items in the iterable will be filtered according to the specifier.
  489. :param prereleases:
  490. Whether or not to allow prereleases in the returned iterator. If set to
  491. ``None`` (the default), it will be intelligently decide whether to allow
  492. prereleases or not (based on the :attr:`prereleases` attribute, and
  493. whether the only versions matching are prereleases).
  494. This method is smarter than just ``filter(Specifier().contains, [...])``
  495. because it implements the rule from :pep:`440` that a prerelease item
  496. SHOULD be accepted if no other versions match the given specifier.
  497. >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
  498. ['1.3']
  499. >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")]))
  500. ['1.2.3', '1.3', <Version('1.4')>]
  501. >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"]))
  502. ['1.5a1']
  503. >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
  504. ['1.3', '1.5a1']
  505. >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
  506. ['1.3', '1.5a1']
  507. """
  508. yielded = False
  509. found_prereleases = []
  510. kw = {"prereleases": prereleases if prereleases is not None else True}
  511. # Attempt to iterate over all the values in the iterable and if any of
  512. # them match, yield them.
  513. for version in iterable:
  514. parsed_version = _coerce_version(version)
  515. if self.contains(parsed_version, **kw):
  516. # If our version is a prerelease, and we were not set to allow
  517. # prereleases, then we'll store it for later in case nothing
  518. # else matches this specifier.
  519. if parsed_version.is_prerelease and not (
  520. prereleases or self.prereleases
  521. ):
  522. found_prereleases.append(version)
  523. # Either this is not a prerelease, or we should have been
  524. # accepting prereleases from the beginning.
  525. else:
  526. yielded = True
  527. yield version
  528. # Now that we've iterated over everything, determine if we've yielded
  529. # any values, and if we have not and we have any prereleases stored up
  530. # then we will go ahead and yield the prereleases.
  531. if not yielded and found_prereleases:
  532. for version in found_prereleases:
  533. yield version
  534. _prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
  535. def _version_split(version: str) -> List[str]:
  536. """Split version into components.
  537. The split components are intended for version comparison. The logic does
  538. not attempt to retain the original version string, so joining the
  539. components back with :func:`_version_join` may not produce the original
  540. version string.
  541. """
  542. result: List[str] = []
  543. epoch, _, rest = version.rpartition("!")
  544. result.append(epoch or "0")
  545. for item in rest.split("."):
  546. match = _prefix_regex.search(item)
  547. if match:
  548. result.extend(match.groups())
  549. else:
  550. result.append(item)
  551. return result
  552. def _version_join(components: List[str]) -> str:
  553. """Join split version components into a version string.
  554. This function assumes the input came from :func:`_version_split`, where the
  555. first component must be the epoch (either empty or numeric), and all other
  556. components numeric.
  557. """
  558. epoch, *rest = components
  559. return f"{epoch}!{'.'.join(rest)}"
  560. def _is_not_suffix(segment: str) -> bool:
  561. return not any(
  562. segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post")
  563. )
  564. def _pad_version(left: List[str], right: List[str]) -> Tuple[List[str], List[str]]:
  565. left_split, right_split = [], []
  566. # Get the release segment of our versions
  567. left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
  568. right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
  569. # Get the rest of our versions
  570. left_split.append(left[len(left_split[0]) :])
  571. right_split.append(right[len(right_split[0]) :])
  572. # Insert our padding
  573. left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
  574. right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
  575. return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
  576. class SpecifierSet(BaseSpecifier):
  577. """This class abstracts handling of a set of version specifiers.
  578. It can be passed a single specifier (``>=3.0``), a comma-separated list of
  579. specifiers (``>=3.0,!=3.1``), or no specifier at all.
  580. """
  581. def __init__(
  582. self, specifiers: str = "", prereleases: Optional[bool] = None
  583. ) -> None:
  584. """Initialize a SpecifierSet instance.
  585. :param specifiers:
  586. The string representation of a specifier or a comma-separated list of
  587. specifiers which will be parsed and normalized before use.
  588. :param prereleases:
  589. This tells the SpecifierSet if it should accept prerelease versions if
  590. applicable or not. The default of ``None`` will autodetect it from the
  591. given specifiers.
  592. :raises InvalidSpecifier:
  593. If the given ``specifiers`` are not parseable than this exception will be
  594. raised.
  595. """
  596. # Split on `,` to break each individual specifier into it's own item, and
  597. # strip each item to remove leading/trailing whitespace.
  598. split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
  599. # Parsed each individual specifier, attempting first to make it a
  600. # Specifier.
  601. parsed: Set[Specifier] = set()
  602. for specifier in split_specifiers:
  603. parsed.add(Specifier(specifier))
  604. # Turn our parsed specifiers into a frozen set and save them for later.
  605. self._specs = frozenset(parsed)
  606. # Store our prereleases value so we can use it later to determine if
  607. # we accept prereleases or not.
  608. self._prereleases = prereleases
  609. @property
  610. def prereleases(self) -> Optional[bool]:
  611. # If we have been given an explicit prerelease modifier, then we'll
  612. # pass that through here.
  613. if self._prereleases is not None:
  614. return self._prereleases
  615. # If we don't have any specifiers, and we don't have a forced value,
  616. # then we'll just return None since we don't know if this should have
  617. # pre-releases or not.
  618. if not self._specs:
  619. return None
  620. # Otherwise we'll see if any of the given specifiers accept
  621. # prereleases, if any of them do we'll return True, otherwise False.
  622. return any(s.prereleases for s in self._specs)
  623. @prereleases.setter
  624. def prereleases(self, value: bool) -> None:
  625. self._prereleases = value
  626. def __repr__(self) -> str:
  627. """A representation of the specifier set that shows all internal state.
  628. Note that the ordering of the individual specifiers within the set may not
  629. match the input string.
  630. >>> SpecifierSet('>=1.0.0,!=2.0.0')
  631. <SpecifierSet('!=2.0.0,>=1.0.0')>
  632. >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False)
  633. <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=False)>
  634. >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True)
  635. <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=True)>
  636. """
  637. pre = (
  638. f", prereleases={self.prereleases!r}"
  639. if self._prereleases is not None
  640. else ""
  641. )
  642. return f"<SpecifierSet({str(self)!r}{pre})>"
  643. def __str__(self) -> str:
  644. """A string representation of the specifier set that can be round-tripped.
  645. Note that the ordering of the individual specifiers within the set may not
  646. match the input string.
  647. >>> str(SpecifierSet(">=1.0.0,!=1.0.1"))
  648. '!=1.0.1,>=1.0.0'
  649. >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False))
  650. '!=1.0.1,>=1.0.0'
  651. """
  652. return ",".join(sorted(str(s) for s in self._specs))
  653. def __hash__(self) -> int:
  654. return hash(self._specs)
  655. def __and__(self, other: Union["SpecifierSet", str]) -> "SpecifierSet":
  656. """Return a SpecifierSet which is a combination of the two sets.
  657. :param other: The other object to combine with.
  658. >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1'
  659. <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
  660. >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1')
  661. <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
  662. """
  663. if isinstance(other, str):
  664. other = SpecifierSet(other)
  665. elif not isinstance(other, SpecifierSet):
  666. return NotImplemented
  667. specifier = SpecifierSet()
  668. specifier._specs = frozenset(self._specs | other._specs)
  669. if self._prereleases is None and other._prereleases is not None:
  670. specifier._prereleases = other._prereleases
  671. elif self._prereleases is not None and other._prereleases is None:
  672. specifier._prereleases = self._prereleases
  673. elif self._prereleases == other._prereleases:
  674. specifier._prereleases = self._prereleases
  675. else:
  676. raise ValueError(
  677. "Cannot combine SpecifierSets with True and False prerelease "
  678. "overrides."
  679. )
  680. return specifier
  681. def __eq__(self, other: object) -> bool:
  682. """Whether or not the two SpecifierSet-like objects are equal.
  683. :param other: The other object to check against.
  684. The value of :attr:`prereleases` is ignored.
  685. >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1")
  686. True
  687. >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) ==
  688. ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True))
  689. True
  690. >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1"
  691. True
  692. >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0")
  693. False
  694. >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2")
  695. False
  696. """
  697. if isinstance(other, (str, Specifier)):
  698. other = SpecifierSet(str(other))
  699. elif not isinstance(other, SpecifierSet):
  700. return NotImplemented
  701. return self._specs == other._specs
  702. def __len__(self) -> int:
  703. """Returns the number of specifiers in this specifier set."""
  704. return len(self._specs)
  705. def __iter__(self) -> Iterator[Specifier]:
  706. """
  707. Returns an iterator over all the underlying :class:`Specifier` instances
  708. in this specifier set.
  709. >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str)
  710. [<Specifier('!=1.0.1')>, <Specifier('>=1.0.0')>]
  711. """
  712. return iter(self._specs)
  713. def __contains__(self, item: UnparsedVersion) -> bool:
  714. """Return whether or not the item is contained in this specifier.
  715. :param item: The item to check for.
  716. This is used for the ``in`` operator and behaves the same as
  717. :meth:`contains` with no ``prereleases`` argument passed.
  718. >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1")
  719. True
  720. >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1")
  721. True
  722. >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1")
  723. False
  724. >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1")
  725. False
  726. >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)
  727. True
  728. """
  729. return self.contains(item)
  730. def contains(
  731. self,
  732. item: UnparsedVersion,
  733. prereleases: Optional[bool] = None,
  734. installed: Optional[bool] = None,
  735. ) -> bool:
  736. """Return whether or not the item is contained in this SpecifierSet.
  737. :param item:
  738. The item to check for, which can be a version string or a
  739. :class:`Version` instance.
  740. :param prereleases:
  741. Whether or not to match prereleases with this SpecifierSet. If set to
  742. ``None`` (the default), it uses :attr:`prereleases` to determine
  743. whether or not prereleases are allowed.
  744. >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3")
  745. True
  746. >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3"))
  747. True
  748. >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1")
  749. False
  750. >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1")
  751. False
  752. >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True).contains("1.3.0a1")
  753. True
  754. >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True)
  755. True
  756. """
  757. # Ensure that our item is a Version instance.
  758. if not isinstance(item, Version):
  759. item = Version(item)
  760. # Determine if we're forcing a prerelease or not, if we're not forcing
  761. # one for this particular filter call, then we'll use whatever the
  762. # SpecifierSet thinks for whether or not we should support prereleases.
  763. if prereleases is None:
  764. prereleases = self.prereleases
  765. # We can determine if we're going to allow pre-releases by looking to
  766. # see if any of the underlying items supports them. If none of them do
  767. # and this item is a pre-release then we do not allow it and we can
  768. # short circuit that here.
  769. # Note: This means that 1.0.dev1 would not be contained in something
  770. # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
  771. if not prereleases and item.is_prerelease:
  772. return False
  773. if installed and item.is_prerelease:
  774. item = Version(item.base_version)
  775. # We simply dispatch to the underlying specs here to make sure that the
  776. # given version is contained within all of them.
  777. # Note: This use of all() here means that an empty set of specifiers
  778. # will always return True, this is an explicit design decision.
  779. return all(s.contains(item, prereleases=prereleases) for s in self._specs)
  780. def filter(
  781. self, iterable: Iterable[UnparsedVersionVar], prereleases: Optional[bool] = None
  782. ) -> Iterator[UnparsedVersionVar]:
  783. """Filter items in the given iterable, that match the specifiers in this set.
  784. :param iterable:
  785. An iterable that can contain version strings and :class:`Version` instances.
  786. The items in the iterable will be filtered according to the specifier.
  787. :param prereleases:
  788. Whether or not to allow prereleases in the returned iterator. If set to
  789. ``None`` (the default), it will be intelligently decide whether to allow
  790. prereleases or not (based on the :attr:`prereleases` attribute, and
  791. whether the only versions matching are prereleases).
  792. This method is smarter than just ``filter(SpecifierSet(...).contains, [...])``
  793. because it implements the rule from :pep:`440` that a prerelease item
  794. SHOULD be accepted if no other versions match the given specifier.
  795. >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
  796. ['1.3']
  797. >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")]))
  798. ['1.3', <Version('1.4')>]
  799. >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"]))
  800. []
  801. >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
  802. ['1.3', '1.5a1']
  803. >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
  804. ['1.3', '1.5a1']
  805. An "empty" SpecifierSet will filter items based on the presence of prerelease
  806. versions in the set.
  807. >>> list(SpecifierSet("").filter(["1.3", "1.5a1"]))
  808. ['1.3']
  809. >>> list(SpecifierSet("").filter(["1.5a1"]))
  810. ['1.5a1']
  811. >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"]))
  812. ['1.3', '1.5a1']
  813. >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True))
  814. ['1.3', '1.5a1']
  815. """
  816. # Determine if we're forcing a prerelease or not, if we're not forcing
  817. # one for this particular filter call, then we'll use whatever the
  818. # SpecifierSet thinks for whether or not we should support prereleases.
  819. if prereleases is None:
  820. prereleases = self.prereleases
  821. # If we have any specifiers, then we want to wrap our iterable in the
  822. # filter method for each one, this will act as a logical AND amongst
  823. # each specifier.
  824. if self._specs:
  825. for spec in self._specs:
  826. iterable = spec.filter(iterable, prereleases=bool(prereleases))
  827. return iter(iterable)
  828. # If we do not have any specifiers, then we need to have a rough filter
  829. # which will filter out any pre-releases, unless there are no final
  830. # releases.
  831. else:
  832. filtered: List[UnparsedVersionVar] = []
  833. found_prereleases: List[UnparsedVersionVar] = []
  834. for item in iterable:
  835. parsed_version = _coerce_version(item)
  836. # Store any item which is a pre-release for later unless we've
  837. # already found a final version or we are accepting prereleases
  838. if parsed_version.is_prerelease and not prereleases:
  839. if not filtered:
  840. found_prereleases.append(item)
  841. else:
  842. filtered.append(item)
  843. # If we've found no items except for pre-releases, then we'll go
  844. # ahead and use the pre-releases
  845. if not filtered and found_prereleases and prereleases is None:
  846. return iter(found_prereleases)
  847. return iter(filtered)