specifiers.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  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. from __future__ import absolute_import, division, print_function
  5. import abc
  6. import functools
  7. import itertools
  8. import re
  9. import warnings
  10. from ._compat import string_types, with_metaclass
  11. from ._typing import TYPE_CHECKING
  12. from .utils import canonicalize_version
  13. from .version import Version, LegacyVersion, parse
  14. if TYPE_CHECKING: # pragma: no cover
  15. from typing import List, Dict, Union, Iterable, Iterator, Optional, Callable, Tuple
  16. ParsedVersion = Union[Version, LegacyVersion]
  17. UnparsedVersion = Union[Version, LegacyVersion, str]
  18. CallableOperator = Callable[[ParsedVersion, str], bool]
  19. class InvalidSpecifier(ValueError):
  20. """
  21. An invalid specifier was found, users should refer to PEP 440.
  22. """
  23. class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): # type: ignore
  24. @abc.abstractmethod
  25. def __str__(self):
  26. # type: () -> str
  27. """
  28. Returns the str representation of this Specifier like object. This
  29. should be representative of the Specifier itself.
  30. """
  31. @abc.abstractmethod
  32. def __hash__(self):
  33. # type: () -> int
  34. """
  35. Returns a hash value for this Specifier like object.
  36. """
  37. @abc.abstractmethod
  38. def __eq__(self, other):
  39. # type: (object) -> bool
  40. """
  41. Returns a boolean representing whether or not the two Specifier like
  42. objects are equal.
  43. """
  44. @abc.abstractmethod
  45. def __ne__(self, other):
  46. # type: (object) -> bool
  47. """
  48. Returns a boolean representing whether or not the two Specifier like
  49. objects are not equal.
  50. """
  51. @abc.abstractproperty
  52. def prereleases(self):
  53. # type: () -> Optional[bool]
  54. """
  55. Returns whether or not pre-releases as a whole are allowed by this
  56. specifier.
  57. """
  58. @prereleases.setter
  59. def prereleases(self, value):
  60. # type: (bool) -> None
  61. """
  62. Sets whether or not pre-releases as a whole are allowed by this
  63. specifier.
  64. """
  65. @abc.abstractmethod
  66. def contains(self, item, prereleases=None):
  67. # type: (str, Optional[bool]) -> bool
  68. """
  69. Determines if the given item is contained within this specifier.
  70. """
  71. @abc.abstractmethod
  72. def filter(self, iterable, prereleases=None):
  73. # type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion]
  74. """
  75. Takes an iterable of items and filters them so that only items which
  76. are contained within this specifier are allowed in it.
  77. """
  78. class _IndividualSpecifier(BaseSpecifier):
  79. _operators = {} # type: Dict[str, str]
  80. def __init__(self, spec="", prereleases=None):
  81. # type: (str, Optional[bool]) -> None
  82. match = self._regex.search(spec)
  83. if not match:
  84. raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
  85. self._spec = (
  86. match.group("operator").strip(),
  87. match.group("version").strip(),
  88. ) # type: Tuple[str, str]
  89. # Store whether or not this Specifier should accept prereleases
  90. self._prereleases = prereleases
  91. def __repr__(self):
  92. # type: () -> str
  93. pre = (
  94. ", prereleases={0!r}".format(self.prereleases)
  95. if self._prereleases is not None
  96. else ""
  97. )
  98. return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
  99. def __str__(self):
  100. # type: () -> str
  101. return "{0}{1}".format(*self._spec)
  102. @property
  103. def _canonical_spec(self):
  104. # type: () -> Tuple[str, Union[Version, str]]
  105. return self._spec[0], canonicalize_version(self._spec[1])
  106. def __hash__(self):
  107. # type: () -> int
  108. return hash(self._canonical_spec)
  109. def __eq__(self, other):
  110. # type: (object) -> bool
  111. if isinstance(other, string_types):
  112. try:
  113. other = self.__class__(str(other))
  114. except InvalidSpecifier:
  115. return NotImplemented
  116. elif not isinstance(other, self.__class__):
  117. return NotImplemented
  118. return self._canonical_spec == other._canonical_spec
  119. def __ne__(self, other):
  120. # type: (object) -> bool
  121. if isinstance(other, string_types):
  122. try:
  123. other = self.__class__(str(other))
  124. except InvalidSpecifier:
  125. return NotImplemented
  126. elif not isinstance(other, self.__class__):
  127. return NotImplemented
  128. return self._spec != other._spec
  129. def _get_operator(self, op):
  130. # type: (str) -> CallableOperator
  131. operator_callable = getattr(
  132. self, "_compare_{0}".format(self._operators[op])
  133. ) # type: CallableOperator
  134. return operator_callable
  135. def _coerce_version(self, version):
  136. # type: (UnparsedVersion) -> ParsedVersion
  137. if not isinstance(version, (LegacyVersion, Version)):
  138. version = parse(version)
  139. return version
  140. @property
  141. def operator(self):
  142. # type: () -> str
  143. return self._spec[0]
  144. @property
  145. def version(self):
  146. # type: () -> str
  147. return self._spec[1]
  148. @property
  149. def prereleases(self):
  150. # type: () -> Optional[bool]
  151. return self._prereleases
  152. @prereleases.setter
  153. def prereleases(self, value):
  154. # type: (bool) -> None
  155. self._prereleases = value
  156. def __contains__(self, item):
  157. # type: (str) -> bool
  158. return self.contains(item)
  159. def contains(self, item, prereleases=None):
  160. # type: (UnparsedVersion, Optional[bool]) -> bool
  161. # Determine if prereleases are to be allowed or not.
  162. if prereleases is None:
  163. prereleases = self.prereleases
  164. # Normalize item to a Version or LegacyVersion, this allows us to have
  165. # a shortcut for ``"2.0" in Specifier(">=2")
  166. normalized_item = self._coerce_version(item)
  167. # Determine if we should be supporting prereleases in this specifier
  168. # or not, if we do not support prereleases than we can short circuit
  169. # logic if this version is a prereleases.
  170. if normalized_item.is_prerelease and not prereleases:
  171. return False
  172. # Actually do the comparison to determine if this item is contained
  173. # within this Specifier or not.
  174. operator_callable = self._get_operator(self.operator) # type: CallableOperator
  175. return operator_callable(normalized_item, self.version)
  176. def filter(self, iterable, prereleases=None):
  177. # type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion]
  178. yielded = False
  179. found_prereleases = []
  180. kw = {"prereleases": prereleases if prereleases is not None else True}
  181. # Attempt to iterate over all the values in the iterable and if any of
  182. # them match, yield them.
  183. for version in iterable:
  184. parsed_version = self._coerce_version(version)
  185. if self.contains(parsed_version, **kw):
  186. # If our version is a prerelease, and we were not set to allow
  187. # prereleases, then we'll store it for later incase nothing
  188. # else matches this specifier.
  189. if parsed_version.is_prerelease and not (
  190. prereleases or self.prereleases
  191. ):
  192. found_prereleases.append(version)
  193. # Either this is not a prerelease, or we should have been
  194. # accepting prereleases from the beginning.
  195. else:
  196. yielded = True
  197. yield version
  198. # Now that we've iterated over everything, determine if we've yielded
  199. # any values, and if we have not and we have any prereleases stored up
  200. # then we will go ahead and yield the prereleases.
  201. if not yielded and found_prereleases:
  202. for version in found_prereleases:
  203. yield version
  204. class LegacySpecifier(_IndividualSpecifier):
  205. _regex_str = r"""
  206. (?P<operator>(==|!=|<=|>=|<|>))
  207. \s*
  208. (?P<version>
  209. [^,;\s)]* # Since this is a "legacy" specifier, and the version
  210. # string can be just about anything, we match everything
  211. # except for whitespace, a semi-colon for marker support,
  212. # a closing paren since versions can be enclosed in
  213. # them, and a comma since it's a version separator.
  214. )
  215. """
  216. _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
  217. _operators = {
  218. "==": "equal",
  219. "!=": "not_equal",
  220. "<=": "less_than_equal",
  221. ">=": "greater_than_equal",
  222. "<": "less_than",
  223. ">": "greater_than",
  224. }
  225. def __init__(self, spec="", prereleases=None):
  226. # type: (str, Optional[bool]) -> None
  227. super(LegacySpecifier, self).__init__(spec, prereleases)
  228. warnings.warn(
  229. "Creating a LegacyVersion has been deprecated and will be "
  230. "removed in the next major release",
  231. DeprecationWarning,
  232. )
  233. def _coerce_version(self, version):
  234. # type: (Union[ParsedVersion, str]) -> LegacyVersion
  235. if not isinstance(version, LegacyVersion):
  236. version = LegacyVersion(str(version))
  237. return version
  238. def _compare_equal(self, prospective, spec):
  239. # type: (LegacyVersion, str) -> bool
  240. return prospective == self._coerce_version(spec)
  241. def _compare_not_equal(self, prospective, spec):
  242. # type: (LegacyVersion, str) -> bool
  243. return prospective != self._coerce_version(spec)
  244. def _compare_less_than_equal(self, prospective, spec):
  245. # type: (LegacyVersion, str) -> bool
  246. return prospective <= self._coerce_version(spec)
  247. def _compare_greater_than_equal(self, prospective, spec):
  248. # type: (LegacyVersion, str) -> bool
  249. return prospective >= self._coerce_version(spec)
  250. def _compare_less_than(self, prospective, spec):
  251. # type: (LegacyVersion, str) -> bool
  252. return prospective < self._coerce_version(spec)
  253. def _compare_greater_than(self, prospective, spec):
  254. # type: (LegacyVersion, str) -> bool
  255. return prospective > self._coerce_version(spec)
  256. def _require_version_compare(
  257. fn, # type: (Callable[[Specifier, ParsedVersion, str], bool])
  258. ):
  259. # type: (...) -> Callable[[Specifier, ParsedVersion, str], bool]
  260. @functools.wraps(fn)
  261. def wrapped(self, prospective, spec):
  262. # type: (Specifier, ParsedVersion, str) -> bool
  263. if not isinstance(prospective, Version):
  264. return False
  265. return fn(self, prospective, spec)
  266. return wrapped
  267. class Specifier(_IndividualSpecifier):
  268. _regex_str = r"""
  269. (?P<operator>(~=|==|!=|<=|>=|<|>|===))
  270. (?P<version>
  271. (?:
  272. # The identity operators allow for an escape hatch that will
  273. # do an exact string match of the version you wish to install.
  274. # This will not be parsed by PEP 440 and we cannot determine
  275. # any semantic meaning from it. This operator is discouraged
  276. # but included entirely as an escape hatch.
  277. (?<====) # Only match for the identity operator
  278. \s*
  279. [^\s]* # We just match everything, except for whitespace
  280. # since we are only testing for strict identity.
  281. )
  282. |
  283. (?:
  284. # The (non)equality operators allow for wild card and local
  285. # versions to be specified so we have to define these two
  286. # operators separately to enable that.
  287. (?<===|!=) # Only match for equals and not equals
  288. \s*
  289. v?
  290. (?:[0-9]+!)? # epoch
  291. [0-9]+(?:\.[0-9]+)* # release
  292. (?: # pre release
  293. [-_\.]?
  294. (a|b|c|rc|alpha|beta|pre|preview)
  295. [-_\.]?
  296. [0-9]*
  297. )?
  298. (?: # post release
  299. (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
  300. )?
  301. # You cannot use a wild card and a dev or local version
  302. # together so group them with a | and make them optional.
  303. (?:
  304. (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
  305. (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
  306. |
  307. \.\* # Wild card syntax of .*
  308. )?
  309. )
  310. |
  311. (?:
  312. # The compatible operator requires at least two digits in the
  313. # release segment.
  314. (?<=~=) # Only match for the compatible operator
  315. \s*
  316. v?
  317. (?:[0-9]+!)? # epoch
  318. [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
  319. (?: # pre release
  320. [-_\.]?
  321. (a|b|c|rc|alpha|beta|pre|preview)
  322. [-_\.]?
  323. [0-9]*
  324. )?
  325. (?: # post release
  326. (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
  327. )?
  328. (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
  329. )
  330. |
  331. (?:
  332. # All other operators only allow a sub set of what the
  333. # (non)equality operators do. Specifically they do not allow
  334. # local versions to be specified nor do they allow the prefix
  335. # matching wild cards.
  336. (?<!==|!=|~=) # We have special cases for these
  337. # operators so we want to make sure they
  338. # don't match here.
  339. \s*
  340. v?
  341. (?:[0-9]+!)? # epoch
  342. [0-9]+(?:\.[0-9]+)* # release
  343. (?: # pre release
  344. [-_\.]?
  345. (a|b|c|rc|alpha|beta|pre|preview)
  346. [-_\.]?
  347. [0-9]*
  348. )?
  349. (?: # post release
  350. (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
  351. )?
  352. (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
  353. )
  354. )
  355. """
  356. _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
  357. _operators = {
  358. "~=": "compatible",
  359. "==": "equal",
  360. "!=": "not_equal",
  361. "<=": "less_than_equal",
  362. ">=": "greater_than_equal",
  363. "<": "less_than",
  364. ">": "greater_than",
  365. "===": "arbitrary",
  366. }
  367. @_require_version_compare
  368. def _compare_compatible(self, prospective, spec):
  369. # type: (ParsedVersion, str) -> bool
  370. # Compatible releases have an equivalent combination of >= and ==. That
  371. # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
  372. # implement this in terms of the other specifiers instead of
  373. # implementing it ourselves. The only thing we need to do is construct
  374. # the other specifiers.
  375. # We want everything but the last item in the version, but we want to
  376. # ignore post and dev releases and we want to treat the pre-release as
  377. # it's own separate segment.
  378. prefix = ".".join(
  379. list(
  380. itertools.takewhile(
  381. lambda x: (not x.startswith("post") and not x.startswith("dev")),
  382. _version_split(spec),
  383. )
  384. )[:-1]
  385. )
  386. # Add the prefix notation to the end of our string
  387. prefix += ".*"
  388. return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
  389. prospective, prefix
  390. )
  391. @_require_version_compare
  392. def _compare_equal(self, prospective, spec):
  393. # type: (ParsedVersion, str) -> bool
  394. # We need special logic to handle prefix matching
  395. if spec.endswith(".*"):
  396. # In the case of prefix matching we want to ignore local segment.
  397. prospective = Version(prospective.public)
  398. # Split the spec out by dots, and pretend that there is an implicit
  399. # dot in between a release segment and a pre-release segment.
  400. split_spec = _version_split(spec[:-2]) # Remove the trailing .*
  401. # Split the prospective version out by dots, and pretend that there
  402. # is an implicit dot in between a release segment and a pre-release
  403. # segment.
  404. split_prospective = _version_split(str(prospective))
  405. # Shorten the prospective version to be the same length as the spec
  406. # so that we can determine if the specifier is a prefix of the
  407. # prospective version or not.
  408. shortened_prospective = split_prospective[: len(split_spec)]
  409. # Pad out our two sides with zeros so that they both equal the same
  410. # length.
  411. padded_spec, padded_prospective = _pad_version(
  412. split_spec, shortened_prospective
  413. )
  414. return padded_prospective == padded_spec
  415. else:
  416. # Convert our spec string into a Version
  417. spec_version = Version(spec)
  418. # If the specifier does not have a local segment, then we want to
  419. # act as if the prospective version also does not have a local
  420. # segment.
  421. if not spec_version.local:
  422. prospective = Version(prospective.public)
  423. return prospective == spec_version
  424. @_require_version_compare
  425. def _compare_not_equal(self, prospective, spec):
  426. # type: (ParsedVersion, str) -> bool
  427. return not self._compare_equal(prospective, spec)
  428. @_require_version_compare
  429. def _compare_less_than_equal(self, prospective, spec):
  430. # type: (ParsedVersion, str) -> bool
  431. # NB: Local version identifiers are NOT permitted in the version
  432. # specifier, so local version labels can be universally removed from
  433. # the prospective version.
  434. return Version(prospective.public) <= Version(spec)
  435. @_require_version_compare
  436. def _compare_greater_than_equal(self, prospective, spec):
  437. # type: (ParsedVersion, str) -> bool
  438. # NB: Local version identifiers are NOT permitted in the version
  439. # specifier, so local version labels can be universally removed from
  440. # the prospective version.
  441. return Version(prospective.public) >= Version(spec)
  442. @_require_version_compare
  443. def _compare_less_than(self, prospective, spec_str):
  444. # type: (ParsedVersion, str) -> bool
  445. # Convert our spec to a Version instance, since we'll want to work with
  446. # it as a version.
  447. spec = Version(spec_str)
  448. # Check to see if the prospective version is less than the spec
  449. # version. If it's not we can short circuit and just return False now
  450. # instead of doing extra unneeded work.
  451. if not prospective < spec:
  452. return False
  453. # This special case is here so that, unless the specifier itself
  454. # includes is a pre-release version, that we do not accept pre-release
  455. # versions for the version mentioned in the specifier (e.g. <3.1 should
  456. # not match 3.1.dev0, but should match 3.0.dev0).
  457. if not spec.is_prerelease and prospective.is_prerelease:
  458. if Version(prospective.base_version) == Version(spec.base_version):
  459. return False
  460. # If we've gotten to here, it means that prospective version is both
  461. # less than the spec version *and* it's not a pre-release of the same
  462. # version in the spec.
  463. return True
  464. @_require_version_compare
  465. def _compare_greater_than(self, prospective, spec_str):
  466. # type: (ParsedVersion, str) -> bool
  467. # Convert our spec to a Version instance, since we'll want to work with
  468. # it as a version.
  469. spec = Version(spec_str)
  470. # Check to see if the prospective version is greater than the spec
  471. # version. If it's not we can short circuit and just return False now
  472. # instead of doing extra unneeded work.
  473. if not prospective > spec:
  474. return False
  475. # This special case is here so that, unless the specifier itself
  476. # includes is a post-release version, that we do not accept
  477. # post-release versions for the version mentioned in the specifier
  478. # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
  479. if not spec.is_postrelease and prospective.is_postrelease:
  480. if Version(prospective.base_version) == Version(spec.base_version):
  481. return False
  482. # Ensure that we do not allow a local version of the version mentioned
  483. # in the specifier, which is technically greater than, to match.
  484. if prospective.local is not None:
  485. if Version(prospective.base_version) == Version(spec.base_version):
  486. return False
  487. # If we've gotten to here, it means that prospective version is both
  488. # greater than the spec version *and* it's not a pre-release of the
  489. # same version in the spec.
  490. return True
  491. def _compare_arbitrary(self, prospective, spec):
  492. # type: (Version, str) -> bool
  493. return str(prospective).lower() == str(spec).lower()
  494. @property
  495. def prereleases(self):
  496. # type: () -> bool
  497. # If there is an explicit prereleases set for this, then we'll just
  498. # blindly use that.
  499. if self._prereleases is not None:
  500. return self._prereleases
  501. # Look at all of our specifiers and determine if they are inclusive
  502. # operators, and if they are if they are including an explicit
  503. # prerelease.
  504. operator, version = self._spec
  505. if operator in ["==", ">=", "<=", "~=", "==="]:
  506. # The == specifier can include a trailing .*, if it does we
  507. # want to remove before parsing.
  508. if operator == "==" and version.endswith(".*"):
  509. version = version[:-2]
  510. # Parse the version, and if it is a pre-release than this
  511. # specifier allows pre-releases.
  512. if parse(version).is_prerelease:
  513. return True
  514. return False
  515. @prereleases.setter
  516. def prereleases(self, value):
  517. # type: (bool) -> None
  518. self._prereleases = value
  519. _prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
  520. def _version_split(version):
  521. # type: (str) -> List[str]
  522. result = [] # type: List[str]
  523. for item in version.split("."):
  524. match = _prefix_regex.search(item)
  525. if match:
  526. result.extend(match.groups())
  527. else:
  528. result.append(item)
  529. return result
  530. def _pad_version(left, right):
  531. # type: (List[str], List[str]) -> Tuple[List[str], List[str]]
  532. left_split, right_split = [], []
  533. # Get the release segment of our versions
  534. left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
  535. right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
  536. # Get the rest of our versions
  537. left_split.append(left[len(left_split[0]) :])
  538. right_split.append(right[len(right_split[0]) :])
  539. # Insert our padding
  540. left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
  541. right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
  542. return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
  543. class SpecifierSet(BaseSpecifier):
  544. def __init__(self, specifiers="", prereleases=None):
  545. # type: (str, Optional[bool]) -> None
  546. # Split on , to break each individual specifier into it's own item, and
  547. # strip each item to remove leading/trailing whitespace.
  548. split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
  549. # Parsed each individual specifier, attempting first to make it a
  550. # Specifier and falling back to a LegacySpecifier.
  551. parsed = set()
  552. for specifier in split_specifiers:
  553. try:
  554. parsed.add(Specifier(specifier))
  555. except InvalidSpecifier:
  556. parsed.add(LegacySpecifier(specifier))
  557. # Turn our parsed specifiers into a frozen set and save them for later.
  558. self._specs = frozenset(parsed)
  559. # Store our prereleases value so we can use it later to determine if
  560. # we accept prereleases or not.
  561. self._prereleases = prereleases
  562. def __repr__(self):
  563. # type: () -> str
  564. pre = (
  565. ", prereleases={0!r}".format(self.prereleases)
  566. if self._prereleases is not None
  567. else ""
  568. )
  569. return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
  570. def __str__(self):
  571. # type: () -> str
  572. return ",".join(sorted(str(s) for s in self._specs))
  573. def __hash__(self):
  574. # type: () -> int
  575. return hash(self._specs)
  576. def __and__(self, other):
  577. # type: (Union[SpecifierSet, str]) -> SpecifierSet
  578. if isinstance(other, string_types):
  579. other = SpecifierSet(other)
  580. elif not isinstance(other, SpecifierSet):
  581. return NotImplemented
  582. specifier = SpecifierSet()
  583. specifier._specs = frozenset(self._specs | other._specs)
  584. if self._prereleases is None and other._prereleases is not None:
  585. specifier._prereleases = other._prereleases
  586. elif self._prereleases is not None and other._prereleases is None:
  587. specifier._prereleases = self._prereleases
  588. elif self._prereleases == other._prereleases:
  589. specifier._prereleases = self._prereleases
  590. else:
  591. raise ValueError(
  592. "Cannot combine SpecifierSets with True and False prerelease "
  593. "overrides."
  594. )
  595. return specifier
  596. def __eq__(self, other):
  597. # type: (object) -> bool
  598. if isinstance(other, (string_types, _IndividualSpecifier)):
  599. other = SpecifierSet(str(other))
  600. elif not isinstance(other, SpecifierSet):
  601. return NotImplemented
  602. return self._specs == other._specs
  603. def __ne__(self, other):
  604. # type: (object) -> bool
  605. if isinstance(other, (string_types, _IndividualSpecifier)):
  606. other = SpecifierSet(str(other))
  607. elif not isinstance(other, SpecifierSet):
  608. return NotImplemented
  609. return self._specs != other._specs
  610. def __len__(self):
  611. # type: () -> int
  612. return len(self._specs)
  613. def __iter__(self):
  614. # type: () -> Iterator[_IndividualSpecifier]
  615. return iter(self._specs)
  616. @property
  617. def prereleases(self):
  618. # type: () -> Optional[bool]
  619. # If we have been given an explicit prerelease modifier, then we'll
  620. # pass that through here.
  621. if self._prereleases is not None:
  622. return self._prereleases
  623. # If we don't have any specifiers, and we don't have a forced value,
  624. # then we'll just return None since we don't know if this should have
  625. # pre-releases or not.
  626. if not self._specs:
  627. return None
  628. # Otherwise we'll see if any of the given specifiers accept
  629. # prereleases, if any of them do we'll return True, otherwise False.
  630. return any(s.prereleases for s in self._specs)
  631. @prereleases.setter
  632. def prereleases(self, value):
  633. # type: (bool) -> None
  634. self._prereleases = value
  635. def __contains__(self, item):
  636. # type: (Union[ParsedVersion, str]) -> bool
  637. return self.contains(item)
  638. def contains(self, item, prereleases=None):
  639. # type: (Union[ParsedVersion, str], Optional[bool]) -> bool
  640. # Ensure that our item is a Version or LegacyVersion instance.
  641. if not isinstance(item, (LegacyVersion, Version)):
  642. item = parse(item)
  643. # Determine if we're forcing a prerelease or not, if we're not forcing
  644. # one for this particular filter call, then we'll use whatever the
  645. # SpecifierSet thinks for whether or not we should support prereleases.
  646. if prereleases is None:
  647. prereleases = self.prereleases
  648. # We can determine if we're going to allow pre-releases by looking to
  649. # see if any of the underlying items supports them. If none of them do
  650. # and this item is a pre-release then we do not allow it and we can
  651. # short circuit that here.
  652. # Note: This means that 1.0.dev1 would not be contained in something
  653. # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
  654. if not prereleases and item.is_prerelease:
  655. return False
  656. # We simply dispatch to the underlying specs here to make sure that the
  657. # given version is contained within all of them.
  658. # Note: This use of all() here means that an empty set of specifiers
  659. # will always return True, this is an explicit design decision.
  660. return all(s.contains(item, prereleases=prereleases) for s in self._specs)
  661. def filter(
  662. self,
  663. iterable, # type: Iterable[Union[ParsedVersion, str]]
  664. prereleases=None, # type: Optional[bool]
  665. ):
  666. # type: (...) -> Iterable[Union[ParsedVersion, str]]
  667. # Determine if we're forcing a prerelease or not, if we're not forcing
  668. # one for this particular filter call, then we'll use whatever the
  669. # SpecifierSet thinks for whether or not we should support prereleases.
  670. if prereleases is None:
  671. prereleases = self.prereleases
  672. # If we have any specifiers, then we want to wrap our iterable in the
  673. # filter method for each one, this will act as a logical AND amongst
  674. # each specifier.
  675. if self._specs:
  676. for spec in self._specs:
  677. iterable = spec.filter(iterable, prereleases=bool(prereleases))
  678. return iterable
  679. # If we do not have any specifiers, then we need to have a rough filter
  680. # which will filter out any pre-releases, unless there are no final
  681. # releases, and which will filter out LegacyVersion in general.
  682. else:
  683. filtered = [] # type: List[Union[ParsedVersion, str]]
  684. found_prereleases = [] # type: List[Union[ParsedVersion, str]]
  685. for item in iterable:
  686. # Ensure that we some kind of Version class for this item.
  687. if not isinstance(item, (LegacyVersion, Version)):
  688. parsed_version = parse(item)
  689. else:
  690. parsed_version = item
  691. # Filter out any item which is parsed as a LegacyVersion
  692. if isinstance(parsed_version, LegacyVersion):
  693. continue
  694. # Store any item which is a pre-release for later unless we've
  695. # already found a final version or we are accepting prereleases
  696. if parsed_version.is_prerelease and not prereleases:
  697. if not filtered:
  698. found_prereleases.append(item)
  699. else:
  700. filtered.append(item)
  701. # If we've found no items except for pre-releases, then we'll go
  702. # ahead and use the pre-releases
  703. if not filtered and found_prereleases and prereleases is None:
  704. return found_prereleases
  705. return filtered