base.py 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) The python-semanticversion project
  3. # This code is distributed under the two-clause BSD License.
  4. import functools
  5. import re
  6. import warnings
  7. def _has_leading_zero(value):
  8. return (value
  9. and value[0] == '0'
  10. and value.isdigit()
  11. and value != '0')
  12. class MaxIdentifier(object):
  13. __slots__ = []
  14. def __repr__(self):
  15. return 'MaxIdentifier()'
  16. def __eq__(self, other):
  17. return isinstance(other, self.__class__)
  18. @functools.total_ordering
  19. class NumericIdentifier(object):
  20. __slots__ = ['value']
  21. def __init__(self, value):
  22. self.value = int(value)
  23. def __repr__(self):
  24. return 'NumericIdentifier(%r)' % self.value
  25. def __eq__(self, other):
  26. if isinstance(other, NumericIdentifier):
  27. return self.value == other.value
  28. return NotImplemented
  29. def __lt__(self, other):
  30. if isinstance(other, MaxIdentifier):
  31. return True
  32. elif isinstance(other, AlphaIdentifier):
  33. return True
  34. elif isinstance(other, NumericIdentifier):
  35. return self.value < other.value
  36. else:
  37. return NotImplemented
  38. @functools.total_ordering
  39. class AlphaIdentifier(object):
  40. __slots__ = ['value']
  41. def __init__(self, value):
  42. self.value = value.encode('ascii')
  43. def __repr__(self):
  44. return 'AlphaIdentifier(%r)' % self.value
  45. def __eq__(self, other):
  46. if isinstance(other, AlphaIdentifier):
  47. return self.value == other.value
  48. return NotImplemented
  49. def __lt__(self, other):
  50. if isinstance(other, MaxIdentifier):
  51. return True
  52. elif isinstance(other, NumericIdentifier):
  53. return False
  54. elif isinstance(other, AlphaIdentifier):
  55. return self.value < other.value
  56. else:
  57. return NotImplemented
  58. class Version(object):
  59. version_re = re.compile(r'^(\d+)\.(\d+)\.(\d+)(?:-([0-9a-zA-Z.-]+))?(?:\+([0-9a-zA-Z.-]+))?$')
  60. partial_version_re = re.compile(r'^(\d+)(?:\.(\d+)(?:\.(\d+))?)?(?:-([0-9a-zA-Z.-]*))?(?:\+([0-9a-zA-Z.-]*))?$')
  61. def __init__(
  62. self,
  63. version_string=None,
  64. major=None,
  65. minor=None,
  66. patch=None,
  67. prerelease=None,
  68. build=None,
  69. partial=False):
  70. if partial:
  71. warnings.warn(
  72. "Partial versions will be removed in 3.0; use SimpleSpec('1.x.x') instead.",
  73. DeprecationWarning,
  74. stacklevel=2,
  75. )
  76. has_text = version_string is not None
  77. has_parts = not (major is minor is patch is prerelease is build is None)
  78. if not has_text ^ has_parts:
  79. raise ValueError("Call either Version('1.2.3') or Version(major=1, ...).")
  80. if has_text:
  81. major, minor, patch, prerelease, build = self.parse(version_string, partial)
  82. else:
  83. # Convenience: allow to omit prerelease/build.
  84. prerelease = tuple(prerelease or ())
  85. if not partial:
  86. build = tuple(build or ())
  87. self._validate_kwargs(major, minor, patch, prerelease, build, partial)
  88. self.major = major
  89. self.minor = minor
  90. self.patch = patch
  91. self.prerelease = prerelease
  92. self.build = build
  93. self.partial = partial
  94. @classmethod
  95. def _coerce(cls, value, allow_none=False):
  96. if value is None and allow_none:
  97. return value
  98. return int(value)
  99. def next_major(self):
  100. if self.prerelease and self.minor == self.patch == 0:
  101. return Version(
  102. major=self.major,
  103. minor=0,
  104. patch=0,
  105. partial=self.partial,
  106. )
  107. else:
  108. return Version(
  109. major=self.major + 1,
  110. minor=0,
  111. patch=0,
  112. partial=self.partial,
  113. )
  114. def next_minor(self):
  115. if self.prerelease and self.patch == 0:
  116. return Version(
  117. major=self.major,
  118. minor=self.minor,
  119. patch=0,
  120. partial=self.partial,
  121. )
  122. else:
  123. return Version(
  124. major=self.major,
  125. minor=self.minor + 1,
  126. patch=0,
  127. partial=self.partial,
  128. )
  129. def next_patch(self):
  130. if self.prerelease:
  131. return Version(
  132. major=self.major,
  133. minor=self.minor,
  134. patch=self.patch,
  135. partial=self.partial,
  136. )
  137. else:
  138. return Version(
  139. major=self.major,
  140. minor=self.minor,
  141. patch=self.patch + 1,
  142. partial=self.partial,
  143. )
  144. def truncate(self, level='patch'):
  145. """Return a new Version object, truncated up to the selected level."""
  146. if level == 'build':
  147. return self
  148. elif level == 'prerelease':
  149. return Version(
  150. major=self.major,
  151. minor=self.minor,
  152. patch=self.patch,
  153. prerelease=self.prerelease,
  154. partial=self.partial,
  155. )
  156. elif level == 'patch':
  157. return Version(
  158. major=self.major,
  159. minor=self.minor,
  160. patch=self.patch,
  161. partial=self.partial,
  162. )
  163. elif level == 'minor':
  164. return Version(
  165. major=self.major,
  166. minor=self.minor,
  167. patch=None if self.partial else 0,
  168. partial=self.partial,
  169. )
  170. elif level == 'major':
  171. return Version(
  172. major=self.major,
  173. minor=None if self.partial else 0,
  174. patch=None if self.partial else 0,
  175. partial=self.partial,
  176. )
  177. else:
  178. raise ValueError("Invalid truncation level `%s`." % level)
  179. @classmethod
  180. def coerce(cls, version_string, partial=False):
  181. """Coerce an arbitrary version string into a semver-compatible one.
  182. The rule is:
  183. - If not enough components, fill minor/patch with zeroes; unless
  184. partial=True
  185. - If more than 3 dot-separated components, extra components are "build"
  186. data. If some "build" data already appeared, append it to the
  187. extra components
  188. Examples:
  189. >>> Version.coerce('0.1')
  190. Version(0, 1, 0)
  191. >>> Version.coerce('0.1.2.3')
  192. Version(0, 1, 2, (), ('3',))
  193. >>> Version.coerce('0.1.2.3+4')
  194. Version(0, 1, 2, (), ('3', '4'))
  195. >>> Version.coerce('0.1+2-3+4_5')
  196. Version(0, 1, 0, (), ('2-3', '4-5'))
  197. """
  198. base_re = re.compile(r'^\d+(?:\.\d+(?:\.\d+)?)?')
  199. match = base_re.match(version_string)
  200. if not match:
  201. raise ValueError(
  202. "Version string lacks a numerical component: %r"
  203. % version_string
  204. )
  205. version = version_string[:match.end()]
  206. if not partial:
  207. # We need a not-partial version.
  208. while version.count('.') < 2:
  209. version += '.0'
  210. # Strip leading zeros in components
  211. # Version is of the form nn, nn.pp or nn.pp.qq
  212. version = '.'.join(
  213. # If the part was '0', we end up with an empty string.
  214. part.lstrip('0') or '0'
  215. for part in version.split('.')
  216. )
  217. if match.end() == len(version_string):
  218. return Version(version, partial=partial)
  219. rest = version_string[match.end():]
  220. # Cleanup the 'rest'
  221. rest = re.sub(r'[^a-zA-Z0-9+.-]', '-', rest)
  222. if rest[0] == '+':
  223. # A 'build' component
  224. prerelease = ''
  225. build = rest[1:]
  226. elif rest[0] == '.':
  227. # An extra version component, probably 'build'
  228. prerelease = ''
  229. build = rest[1:]
  230. elif rest[0] == '-':
  231. rest = rest[1:]
  232. if '+' in rest:
  233. prerelease, build = rest.split('+', 1)
  234. else:
  235. prerelease, build = rest, ''
  236. elif '+' in rest:
  237. prerelease, build = rest.split('+', 1)
  238. else:
  239. prerelease, build = rest, ''
  240. build = build.replace('+', '.')
  241. if prerelease:
  242. version = '%s-%s' % (version, prerelease)
  243. if build:
  244. version = '%s+%s' % (version, build)
  245. return cls(version, partial=partial)
  246. @classmethod
  247. def parse(cls, version_string, partial=False, coerce=False):
  248. """Parse a version string into a Version() object.
  249. Args:
  250. version_string (str), the version string to parse
  251. partial (bool), whether to accept incomplete input
  252. coerce (bool), whether to try to map the passed in string into a
  253. valid Version.
  254. """
  255. if not version_string:
  256. raise ValueError('Invalid empty version string: %r' % version_string)
  257. if partial:
  258. version_re = cls.partial_version_re
  259. else:
  260. version_re = cls.version_re
  261. match = version_re.match(version_string)
  262. if not match:
  263. raise ValueError('Invalid version string: %r' % version_string)
  264. major, minor, patch, prerelease, build = match.groups()
  265. if _has_leading_zero(major):
  266. raise ValueError("Invalid leading zero in major: %r" % version_string)
  267. if _has_leading_zero(minor):
  268. raise ValueError("Invalid leading zero in minor: %r" % version_string)
  269. if _has_leading_zero(patch):
  270. raise ValueError("Invalid leading zero in patch: %r" % version_string)
  271. major = int(major)
  272. minor = cls._coerce(minor, partial)
  273. patch = cls._coerce(patch, partial)
  274. if prerelease is None:
  275. if partial and (build is None):
  276. # No build info, strip here
  277. return (major, minor, patch, None, None)
  278. else:
  279. prerelease = ()
  280. elif prerelease == '':
  281. prerelease = ()
  282. else:
  283. prerelease = tuple(prerelease.split('.'))
  284. cls._validate_identifiers(prerelease, allow_leading_zeroes=False)
  285. if build is None:
  286. if partial:
  287. build = None
  288. else:
  289. build = ()
  290. elif build == '':
  291. build = ()
  292. else:
  293. build = tuple(build.split('.'))
  294. cls._validate_identifiers(build, allow_leading_zeroes=True)
  295. return (major, minor, patch, prerelease, build)
  296. @classmethod
  297. def _validate_identifiers(cls, identifiers, allow_leading_zeroes=False):
  298. for item in identifiers:
  299. if not item:
  300. raise ValueError(
  301. "Invalid empty identifier %r in %r"
  302. % (item, '.'.join(identifiers))
  303. )
  304. if item[0] == '0' and item.isdigit() and item != '0' and not allow_leading_zeroes:
  305. raise ValueError("Invalid leading zero in identifier %r" % item)
  306. @classmethod
  307. def _validate_kwargs(cls, major, minor, patch, prerelease, build, partial):
  308. if (
  309. major != int(major)
  310. or minor != cls._coerce(minor, partial)
  311. or patch != cls._coerce(patch, partial)
  312. or prerelease is None and not partial
  313. or build is None and not partial
  314. ):
  315. raise ValueError(
  316. "Invalid kwargs to Version(major=%r, minor=%r, patch=%r, "
  317. "prerelease=%r, build=%r, partial=%r" % (
  318. major, minor, patch, prerelease, build, partial
  319. ))
  320. if prerelease is not None:
  321. cls._validate_identifiers(prerelease, allow_leading_zeroes=False)
  322. if build is not None:
  323. cls._validate_identifiers(build, allow_leading_zeroes=True)
  324. def __iter__(self):
  325. return iter((self.major, self.minor, self.patch, self.prerelease, self.build))
  326. def __str__(self):
  327. version = '%d' % self.major
  328. if self.minor is not None:
  329. version = '%s.%d' % (version, self.minor)
  330. if self.patch is not None:
  331. version = '%s.%d' % (version, self.patch)
  332. if self.prerelease or (self.partial and self.prerelease == () and self.build is None):
  333. version = '%s-%s' % (version, '.'.join(self.prerelease))
  334. if self.build or (self.partial and self.build == ()):
  335. version = '%s+%s' % (version, '.'.join(self.build))
  336. return version
  337. def __repr__(self):
  338. return '%s(%r%s)' % (
  339. self.__class__.__name__,
  340. str(self),
  341. ', partial=True' if self.partial else '',
  342. )
  343. def __hash__(self):
  344. # We don't include 'partial', since this is strictly equivalent to having
  345. # at least a field being `None`.
  346. return hash((self.major, self.minor, self.patch, self.prerelease, self.build))
  347. @property
  348. def precedence_key(self):
  349. if self.prerelease:
  350. prerelease_key = tuple(
  351. NumericIdentifier(part) if re.match(r'^[0-9]+$', part) else AlphaIdentifier(part)
  352. for part in self.prerelease
  353. )
  354. else:
  355. prerelease_key = (
  356. MaxIdentifier(),
  357. )
  358. return (
  359. self.major,
  360. self.minor,
  361. self.patch,
  362. prerelease_key,
  363. )
  364. def __cmp__(self, other):
  365. if not isinstance(other, self.__class__):
  366. return NotImplemented
  367. if self < other:
  368. return -1
  369. elif self > other:
  370. return 1
  371. elif self == other:
  372. return 0
  373. else:
  374. return NotImplemented
  375. def __eq__(self, other):
  376. if not isinstance(other, self.__class__):
  377. return NotImplemented
  378. return (
  379. self.major == other.major
  380. and self.minor == other.minor
  381. and self.patch == other.patch
  382. and (self.prerelease or ()) == (other.prerelease or ())
  383. and (self.build or ()) == (other.build or ())
  384. )
  385. def __ne__(self, other):
  386. if not isinstance(other, self.__class__):
  387. return NotImplemented
  388. return tuple(self) != tuple(other)
  389. def __lt__(self, other):
  390. if not isinstance(other, self.__class__):
  391. return NotImplemented
  392. return self.precedence_key < other.precedence_key
  393. def __le__(self, other):
  394. if not isinstance(other, self.__class__):
  395. return NotImplemented
  396. return self.precedence_key <= other.precedence_key
  397. def __gt__(self, other):
  398. if not isinstance(other, self.__class__):
  399. return NotImplemented
  400. return self.precedence_key > other.precedence_key
  401. def __ge__(self, other):
  402. if not isinstance(other, self.__class__):
  403. return NotImplemented
  404. return self.precedence_key >= other.precedence_key
  405. class SpecItem(object):
  406. """A requirement specification."""
  407. KIND_ANY = '*'
  408. KIND_LT = '<'
  409. KIND_LTE = '<='
  410. KIND_EQUAL = '=='
  411. KIND_SHORTEQ = '='
  412. KIND_EMPTY = ''
  413. KIND_GTE = '>='
  414. KIND_GT = '>'
  415. KIND_NEQ = '!='
  416. KIND_CARET = '^'
  417. KIND_TILDE = '~'
  418. KIND_COMPATIBLE = '~='
  419. # Map a kind alias to its full version
  420. KIND_ALIASES = {
  421. KIND_SHORTEQ: KIND_EQUAL,
  422. KIND_EMPTY: KIND_EQUAL,
  423. }
  424. re_spec = re.compile(r'^(<|<=||=|==|>=|>|!=|\^|~|~=)(\d.*)$')
  425. def __init__(self, requirement_string, _warn=True):
  426. if _warn:
  427. warnings.warn(
  428. "The `SpecItem` class will be removed in 3.0.",
  429. DeprecationWarning,
  430. stacklevel=2,
  431. )
  432. kind, spec = self.parse(requirement_string)
  433. self.kind = kind
  434. self.spec = spec
  435. self._clause = Spec(requirement_string).clause
  436. @classmethod
  437. def parse(cls, requirement_string):
  438. if not requirement_string:
  439. raise ValueError("Invalid empty requirement specification: %r" % requirement_string)
  440. # Special case: the 'any' version spec.
  441. if requirement_string == '*':
  442. return (cls.KIND_ANY, '')
  443. match = cls.re_spec.match(requirement_string)
  444. if not match:
  445. raise ValueError("Invalid requirement specification: %r" % requirement_string)
  446. kind, version = match.groups()
  447. if kind in cls.KIND_ALIASES:
  448. kind = cls.KIND_ALIASES[kind]
  449. spec = Version(version, partial=True)
  450. if spec.build is not None and kind not in (cls.KIND_EQUAL, cls.KIND_NEQ):
  451. raise ValueError(
  452. "Invalid requirement specification %r: build numbers have no ordering."
  453. % requirement_string
  454. )
  455. return (kind, spec)
  456. @classmethod
  457. def from_matcher(cls, matcher):
  458. if matcher == Always():
  459. return cls('*', _warn=False)
  460. elif matcher == Never():
  461. return cls('<0.0.0-', _warn=False)
  462. elif isinstance(matcher, Range):
  463. return cls('%s%s' % (matcher.operator, matcher.target), _warn=False)
  464. def match(self, version):
  465. return self._clause.match(version)
  466. def __str__(self):
  467. return '%s%s' % (self.kind, self.spec)
  468. def __repr__(self):
  469. return '<SpecItem: %s %r>' % (self.kind, self.spec)
  470. def __eq__(self, other):
  471. if not isinstance(other, SpecItem):
  472. return NotImplemented
  473. return self.kind == other.kind and self.spec == other.spec
  474. def __hash__(self):
  475. return hash((self.kind, self.spec))
  476. def compare(v1, v2):
  477. return Version(v1).__cmp__(Version(v2))
  478. def match(spec, version):
  479. return Spec(spec).match(Version(version))
  480. def validate(version_string):
  481. """Validates a version string againt the SemVer specification."""
  482. try:
  483. Version.parse(version_string)
  484. return True
  485. except ValueError:
  486. return False
  487. DEFAULT_SYNTAX = 'simple'
  488. class BaseSpec(object):
  489. """A specification of compatible versions.
  490. Usage:
  491. >>> Spec('>=1.0.0', syntax='npm')
  492. A version matches a specification if it matches any
  493. of the clauses of that specification.
  494. Internally, a Spec is AnyOf(
  495. AllOf(Matcher, Matcher, Matcher),
  496. AllOf(...),
  497. )
  498. """
  499. SYNTAXES = {}
  500. @classmethod
  501. def register_syntax(cls, subclass):
  502. syntax = subclass.SYNTAX
  503. if syntax is None:
  504. raise ValueError("A Spec needs its SYNTAX field to be set.")
  505. elif syntax in cls.SYNTAXES:
  506. raise ValueError(
  507. "Duplicate syntax for %s: %r, %r"
  508. % (syntax, cls.SYNTAXES[syntax], subclass)
  509. )
  510. cls.SYNTAXES[syntax] = subclass
  511. return subclass
  512. def __init__(self, expression):
  513. super(BaseSpec, self).__init__()
  514. self.expression = expression
  515. self.clause = self._parse_to_clause(expression)
  516. @classmethod
  517. def parse(cls, expression, syntax=DEFAULT_SYNTAX):
  518. """Convert a syntax-specific expression into a BaseSpec instance."""
  519. return cls.SYNTAXES[syntax](expression)
  520. @classmethod
  521. def _parse_to_clause(cls, expression):
  522. """Converts an expression to a clause."""
  523. raise NotImplementedError()
  524. def filter(self, versions):
  525. """Filter an iterable of versions satisfying the Spec."""
  526. for version in versions:
  527. if self.match(version):
  528. yield version
  529. def match(self, version):
  530. """Check whether a Version satisfies the Spec."""
  531. return self.clause.match(version)
  532. def select(self, versions):
  533. """Select the best compatible version among an iterable of options."""
  534. options = list(self.filter(versions))
  535. if options:
  536. return max(options)
  537. return None
  538. def __contains__(self, version):
  539. """Whether `version in self`."""
  540. if isinstance(version, Version):
  541. return self.match(version)
  542. return False
  543. def __eq__(self, other):
  544. if not isinstance(other, self.__class__):
  545. return NotImplemented
  546. return self.clause == other.clause
  547. def __hash__(self):
  548. return hash(self.clause)
  549. def __str__(self):
  550. return self.expression
  551. def __repr__(self):
  552. return '<%s: %r>' % (self.__class__.__name__, self.expression)
  553. class Clause(object):
  554. __slots__ = []
  555. def match(self, version):
  556. raise NotImplementedError()
  557. def __and__(self, other):
  558. raise NotImplementedError()
  559. def __or__(self, other):
  560. raise NotImplementedError()
  561. def __eq__(self, other):
  562. raise NotImplementedError()
  563. def prettyprint(self, indent='\t'):
  564. """Pretty-print the clause.
  565. """
  566. return '\n'.join(self._pretty()).replace('\t', indent)
  567. def _pretty(self):
  568. """Actual pretty-printing logic.
  569. Yields:
  570. A list of string. Indentation is performed with \t.
  571. """
  572. yield repr(self)
  573. def __ne__(self, other):
  574. return not self == other
  575. def simplify(self):
  576. return self
  577. class AnyOf(Clause):
  578. __slots__ = ['clauses']
  579. def __init__(self, *clauses):
  580. super(AnyOf, self).__init__()
  581. self.clauses = frozenset(clauses)
  582. def match(self, version):
  583. return any(c.match(version) for c in self.clauses)
  584. def simplify(self):
  585. subclauses = set()
  586. for clause in self.clauses:
  587. simplified = clause.simplify()
  588. if isinstance(simplified, AnyOf):
  589. subclauses |= simplified.clauses
  590. elif simplified == Never():
  591. continue
  592. else:
  593. subclauses.add(simplified)
  594. if len(subclauses) == 1:
  595. return subclauses.pop()
  596. return AnyOf(*subclauses)
  597. def __hash__(self):
  598. return hash((AnyOf, self.clauses))
  599. def __iter__(self):
  600. return iter(self.clauses)
  601. def __eq__(self, other):
  602. return isinstance(other, self.__class__) and self.clauses == other.clauses
  603. def __and__(self, other):
  604. if isinstance(other, AllOf):
  605. return other & self
  606. elif isinstance(other, Matcher) or isinstance(other, AnyOf):
  607. return AllOf(self, other)
  608. else:
  609. return NotImplemented
  610. def __or__(self, other):
  611. if isinstance(other, AnyOf):
  612. clauses = list(self.clauses | other.clauses)
  613. elif isinstance(other, Matcher) or isinstance(other, AllOf):
  614. clauses = list(self.clauses | set([other]))
  615. else:
  616. return NotImplemented
  617. return AnyOf(*clauses)
  618. def __repr__(self):
  619. return 'AnyOf(%s)' % ', '.join(sorted(repr(c) for c in self.clauses))
  620. def _pretty(self):
  621. yield 'AnyOF('
  622. for clause in self.clauses:
  623. lines = list(clause._pretty())
  624. for line in lines[:-1]:
  625. yield '\t' + line
  626. yield '\t' + lines[-1] + ','
  627. yield ')'
  628. class AllOf(Clause):
  629. __slots__ = ['clauses']
  630. def __init__(self, *clauses):
  631. super(AllOf, self).__init__()
  632. self.clauses = frozenset(clauses)
  633. def match(self, version):
  634. return all(clause.match(version) for clause in self.clauses)
  635. def simplify(self):
  636. subclauses = set()
  637. for clause in self.clauses:
  638. simplified = clause.simplify()
  639. if isinstance(simplified, AllOf):
  640. subclauses |= simplified.clauses
  641. elif simplified == Always():
  642. continue
  643. else:
  644. subclauses.add(simplified)
  645. if len(subclauses) == 1:
  646. return subclauses.pop()
  647. return AllOf(*subclauses)
  648. def __hash__(self):
  649. return hash((AllOf, self.clauses))
  650. def __iter__(self):
  651. return iter(self.clauses)
  652. def __eq__(self, other):
  653. return isinstance(other, self.__class__) and self.clauses == other.clauses
  654. def __and__(self, other):
  655. if isinstance(other, Matcher) or isinstance(other, AnyOf):
  656. clauses = list(self.clauses | set([other]))
  657. elif isinstance(other, AllOf):
  658. clauses = list(self.clauses | other.clauses)
  659. else:
  660. return NotImplemented
  661. return AllOf(*clauses)
  662. def __or__(self, other):
  663. if isinstance(other, AnyOf):
  664. return other | self
  665. elif isinstance(other, Matcher):
  666. return AnyOf(self, AllOf(other))
  667. elif isinstance(other, AllOf):
  668. return AnyOf(self, other)
  669. else:
  670. return NotImplemented
  671. def __repr__(self):
  672. return 'AllOf(%s)' % ', '.join(sorted(repr(c) for c in self.clauses))
  673. def _pretty(self):
  674. yield 'AllOF('
  675. for clause in self.clauses:
  676. lines = list(clause._pretty())
  677. for line in lines[:-1]:
  678. yield '\t' + line
  679. yield '\t' + lines[-1] + ','
  680. yield ')'
  681. class Matcher(Clause):
  682. __slots__ = []
  683. def __and__(self, other):
  684. if isinstance(other, AllOf):
  685. return other & self
  686. elif isinstance(other, Matcher) or isinstance(other, AnyOf):
  687. return AllOf(self, other)
  688. else:
  689. return NotImplemented
  690. def __or__(self, other):
  691. if isinstance(other, AnyOf):
  692. return other | self
  693. elif isinstance(other, Matcher) or isinstance(other, AllOf):
  694. return AnyOf(self, other)
  695. else:
  696. return NotImplemented
  697. class Never(Matcher):
  698. __slots__ = []
  699. def match(self, version):
  700. return False
  701. def __hash__(self):
  702. return hash((Never,))
  703. def __eq__(self, other):
  704. return isinstance(other, self.__class__)
  705. def __and__(self, other):
  706. return self
  707. def __or__(self, other):
  708. return other
  709. def __repr__(self):
  710. return 'Never()'
  711. class Always(Matcher):
  712. __slots__ = []
  713. def match(self, version):
  714. return True
  715. def __hash__(self):
  716. return hash((Always,))
  717. def __eq__(self, other):
  718. return isinstance(other, self.__class__)
  719. def __and__(self, other):
  720. return other
  721. def __or__(self, other):
  722. return self
  723. def __repr__(self):
  724. return 'Always()'
  725. class Range(Matcher):
  726. OP_EQ = '=='
  727. OP_GT = '>'
  728. OP_GTE = '>='
  729. OP_LT = '<'
  730. OP_LTE = '<='
  731. OP_NEQ = '!='
  732. # <1.2.3 matches 1.2.3-a1
  733. PRERELEASE_ALWAYS = 'always'
  734. # <1.2.3 does not match 1.2.3-a1
  735. PRERELEASE_NATURAL = 'natural'
  736. # 1.2.3-a1 is only considered if target == 1.2.3-xxx
  737. PRERELEASE_SAMEPATCH = 'same-patch'
  738. # 1.2.3 matches 1.2.3+*
  739. BUILD_IMPLICIT = 'implicit'
  740. # 1.2.3 matches only 1.2.3, not 1.2.3+4
  741. BUILD_STRICT = 'strict'
  742. __slots__ = ['operator', 'target', 'prerelease_policy', 'build_policy']
  743. def __init__(self, operator, target, prerelease_policy=PRERELEASE_NATURAL, build_policy=BUILD_IMPLICIT):
  744. super(Range, self).__init__()
  745. if target.build and operator not in (self.OP_EQ, self.OP_NEQ):
  746. raise ValueError(
  747. "Invalid range %s%s: build numbers have no ordering."
  748. % (operator, target))
  749. self.operator = operator
  750. self.target = target
  751. self.prerelease_policy = prerelease_policy
  752. self.build_policy = self.BUILD_STRICT if target.build else build_policy
  753. def match(self, version):
  754. if self.build_policy != self.BUILD_STRICT:
  755. version = version.truncate('prerelease')
  756. if version.prerelease:
  757. same_patch = self.target.truncate() == version.truncate()
  758. if self.prerelease_policy == self.PRERELEASE_SAMEPATCH and not same_patch:
  759. return False
  760. if self.operator == self.OP_EQ:
  761. if self.build_policy == self.BUILD_STRICT:
  762. return (
  763. self.target.truncate('prerelease') == version.truncate('prerelease')
  764. and version.build == self.target.build
  765. )
  766. return version == self.target
  767. elif self.operator == self.OP_GT:
  768. return version > self.target
  769. elif self.operator == self.OP_GTE:
  770. return version >= self.target
  771. elif self.operator == self.OP_LT:
  772. if (
  773. version.prerelease
  774. and self.prerelease_policy == self.PRERELEASE_NATURAL
  775. and version.truncate() == self.target.truncate()
  776. and not self.target.prerelease
  777. ):
  778. return False
  779. return version < self.target
  780. elif self.operator == self.OP_LTE:
  781. return version <= self.target
  782. else:
  783. assert self.operator == self.OP_NEQ
  784. if self.build_policy == self.BUILD_STRICT:
  785. return not (
  786. self.target.truncate('prerelease') == version.truncate('prerelease')
  787. and version.build == self.target.build
  788. )
  789. if (
  790. version.prerelease
  791. and self.prerelease_policy == self.PRERELEASE_NATURAL
  792. and version.truncate() == self.target.truncate()
  793. and not self.target.prerelease
  794. ):
  795. return False
  796. return version != self.target
  797. def __hash__(self):
  798. return hash((Range, self.operator, self.target, self.prerelease_policy))
  799. def __eq__(self, other):
  800. return (
  801. isinstance(other, self.__class__)
  802. and self.operator == other.operator
  803. and self.target == other.target
  804. and self.prerelease_policy == other.prerelease_policy
  805. )
  806. def __str__(self):
  807. return '%s%s' % (self.operator, self.target)
  808. def __repr__(self):
  809. policy_part = (
  810. '' if self.prerelease_policy == self.PRERELEASE_NATURAL
  811. else ', prerelease_policy=%r' % self.prerelease_policy
  812. ) + (
  813. '' if self.build_policy == self.BUILD_IMPLICIT
  814. else ', build_policy=%r' % self.build_policy
  815. )
  816. return 'Range(%r, %r%s)' % (
  817. self.operator,
  818. self.target,
  819. policy_part,
  820. )
  821. @BaseSpec.register_syntax
  822. class SimpleSpec(BaseSpec):
  823. SYNTAX = 'simple'
  824. @classmethod
  825. def _parse_to_clause(cls, expression):
  826. return cls.Parser.parse(expression)
  827. class Parser:
  828. NUMBER = r'\*|0|[1-9][0-9]*'
  829. NAIVE_SPEC = re.compile(r"""^
  830. (?P<op><|<=||=|==|>=|>|!=|\^|~|~=)
  831. (?P<major>{nb})(?:\.(?P<minor>{nb})(?:\.(?P<patch>{nb}))?)?
  832. (?:-(?P<prerel>[a-z0-9A-Z.-]*))?
  833. (?:\+(?P<build>[a-z0-9A-Z.-]*))?
  834. $
  835. """.format(nb=NUMBER),
  836. re.VERBOSE,
  837. )
  838. @classmethod
  839. def parse(cls, expression):
  840. blocks = expression.split(',')
  841. clause = Always()
  842. for block in blocks:
  843. if not cls.NAIVE_SPEC.match(block):
  844. raise ValueError("Invalid simple block %r" % block)
  845. clause &= cls.parse_block(block)
  846. return clause
  847. PREFIX_CARET = '^'
  848. PREFIX_TILDE = '~'
  849. PREFIX_COMPATIBLE = '~='
  850. PREFIX_EQ = '=='
  851. PREFIX_NEQ = '!='
  852. PREFIX_GT = '>'
  853. PREFIX_GTE = '>='
  854. PREFIX_LT = '<'
  855. PREFIX_LTE = '<='
  856. PREFIX_ALIASES = {
  857. '=': PREFIX_EQ,
  858. '': PREFIX_EQ,
  859. }
  860. EMPTY_VALUES = ['*', 'x', 'X', None]
  861. @classmethod
  862. def parse_block(cls, expr):
  863. if not cls.NAIVE_SPEC.match(expr):
  864. raise ValueError("Invalid simple spec component: %r" % expr)
  865. prefix, major_t, minor_t, patch_t, prerel, build = cls.NAIVE_SPEC.match(expr).groups()
  866. prefix = cls.PREFIX_ALIASES.get(prefix, prefix)
  867. major = None if major_t in cls.EMPTY_VALUES else int(major_t)
  868. minor = None if minor_t in cls.EMPTY_VALUES else int(minor_t)
  869. patch = None if patch_t in cls.EMPTY_VALUES else int(patch_t)
  870. if major is None: # '*'
  871. target = Version(major=0, minor=0, patch=0)
  872. if prefix not in (cls.PREFIX_EQ, cls.PREFIX_GTE):
  873. raise ValueError("Invalid simple spec: %r" % expr)
  874. elif minor is None:
  875. target = Version(major=major, minor=0, patch=0)
  876. elif patch is None:
  877. target = Version(major=major, minor=minor, patch=0)
  878. else:
  879. target = Version(
  880. major=major,
  881. minor=minor,
  882. patch=patch,
  883. prerelease=prerel.split('.') if prerel else (),
  884. build=build.split('.') if build else (),
  885. )
  886. if (major is None or minor is None or patch is None) and (prerel or build):
  887. raise ValueError("Invalid simple spec: %r" % expr)
  888. if build is not None and prefix not in (cls.PREFIX_EQ, cls.PREFIX_NEQ):
  889. raise ValueError("Invalid simple spec: %r" % expr)
  890. if prefix == cls.PREFIX_CARET:
  891. # Accept anything with the same most-significant digit
  892. if target.major:
  893. high = target.next_major()
  894. elif target.minor:
  895. high = target.next_minor()
  896. else:
  897. high = target.next_patch()
  898. return Range(Range.OP_GTE, target) & Range(Range.OP_LT, high)
  899. elif prefix == cls.PREFIX_TILDE:
  900. assert major is not None
  901. # Accept any higher patch in the same minor
  902. # Might go higher if the initial version was a partial
  903. if minor is None:
  904. high = target.next_major()
  905. else:
  906. high = target.next_minor()
  907. return Range(Range.OP_GTE, target) & Range(Range.OP_LT, high)
  908. elif prefix == cls.PREFIX_COMPATIBLE:
  909. assert major is not None
  910. # ~1 is 1.0.0..2.0.0; ~=2.2 is 2.2.0..3.0.0; ~=1.4.5 is 1.4.5..1.5.0
  911. if minor is None or patch is None:
  912. # We got a partial version
  913. high = target.next_major()
  914. else:
  915. high = target.next_minor()
  916. return Range(Range.OP_GTE, target) & Range(Range.OP_LT, high)
  917. elif prefix == cls.PREFIX_EQ:
  918. if major is None:
  919. return Range(Range.OP_GTE, target)
  920. elif minor is None:
  921. return Range(Range.OP_GTE, target) & Range(Range.OP_LT, target.next_major())
  922. elif patch is None:
  923. return Range(Range.OP_GTE, target) & Range(Range.OP_LT, target.next_minor())
  924. elif build == '':
  925. return Range(Range.OP_EQ, target, build_policy=Range.BUILD_STRICT)
  926. else:
  927. return Range(Range.OP_EQ, target)
  928. elif prefix == cls.PREFIX_NEQ:
  929. assert major is not None
  930. if minor is None:
  931. # !=1.x => <1.0.0 || >=2.0.0
  932. return Range(Range.OP_LT, target) | Range(Range.OP_GTE, target.next_major())
  933. elif patch is None:
  934. # !=1.2.x => <1.2.0 || >=1.3.0
  935. return Range(Range.OP_LT, target) | Range(Range.OP_GTE, target.next_minor())
  936. elif prerel == '':
  937. # !=1.2.3-
  938. return Range(Range.OP_NEQ, target, prerelease_policy=Range.PRERELEASE_ALWAYS)
  939. elif build == '':
  940. # !=1.2.3+ or !=1.2.3-a2+
  941. return Range(Range.OP_NEQ, target, build_policy=Range.BUILD_STRICT)
  942. else:
  943. return Range(Range.OP_NEQ, target)
  944. elif prefix == cls.PREFIX_GT:
  945. assert major is not None
  946. if minor is None:
  947. # >1.x => >=2.0
  948. return Range(Range.OP_GTE, target.next_major())
  949. elif patch is None:
  950. return Range(Range.OP_GTE, target.next_minor())
  951. else:
  952. return Range(Range.OP_GT, target)
  953. elif prefix == cls.PREFIX_GTE:
  954. return Range(Range.OP_GTE, target)
  955. elif prefix == cls.PREFIX_LT:
  956. assert major is not None
  957. if prerel == '':
  958. # <1.2.3-
  959. return Range(Range.OP_LT, target, prerelease_policy=Range.PRERELEASE_ALWAYS)
  960. return Range(Range.OP_LT, target)
  961. else:
  962. assert prefix == cls.PREFIX_LTE
  963. assert major is not None
  964. if minor is None:
  965. # <=1.x => <2.0
  966. return Range(Range.OP_LT, target.next_major())
  967. elif patch is None:
  968. return Range(Range.OP_LT, target.next_minor())
  969. else:
  970. return Range(Range.OP_LTE, target)
  971. class LegacySpec(SimpleSpec):
  972. def __init__(self, *expressions):
  973. warnings.warn(
  974. "The Spec() class will be removed in 3.1; use SimpleSpec() instead.",
  975. PendingDeprecationWarning,
  976. stacklevel=2,
  977. )
  978. if len(expressions) > 1:
  979. warnings.warn(
  980. "Passing 2+ arguments to SimpleSpec will be removed in 3.0; concatenate them with ',' instead.",
  981. DeprecationWarning,
  982. stacklevel=2,
  983. )
  984. expression = ','.join(expressions)
  985. super(LegacySpec, self).__init__(expression)
  986. @property
  987. def specs(self):
  988. return list(self)
  989. def __iter__(self):
  990. warnings.warn(
  991. "Iterating over the components of a SimpleSpec object will be removed in 3.0.",
  992. DeprecationWarning,
  993. stacklevel=2,
  994. )
  995. try:
  996. clauses = list(self.clause)
  997. except TypeError: # Not an iterable
  998. clauses = [self.clause]
  999. for clause in clauses:
  1000. yield SpecItem.from_matcher(clause)
  1001. Spec = LegacySpec
  1002. @BaseSpec.register_syntax
  1003. class NpmSpec(BaseSpec):
  1004. SYNTAX = 'npm'
  1005. @classmethod
  1006. def _parse_to_clause(cls, expression):
  1007. return cls.Parser.parse(expression)
  1008. class Parser:
  1009. JOINER = '||'
  1010. HYPHEN = ' - '
  1011. NUMBER = r'x|X|\*|0|[1-9][0-9]*'
  1012. PART = r'[a-zA-Z0-9.-]*'
  1013. NPM_SPEC_BLOCK = re.compile(r"""
  1014. ^(?:v)? # Strip optional initial v
  1015. (?P<op><|<=|>=|>|=|\^|~|) # Operator, can be empty
  1016. (?P<major>{nb})(?:\.(?P<minor>{nb})(?:\.(?P<patch>{nb}))?)?
  1017. (?:-(?P<prerel>{part}))? # Optional re-release
  1018. (?:\+(?P<build>{part}))? # Optional build
  1019. $""".format(nb=NUMBER, part=PART),
  1020. re.VERBOSE,
  1021. )
  1022. @classmethod
  1023. def range(cls, operator, target):
  1024. return Range(operator, target, prerelease_policy=Range.PRERELEASE_SAMEPATCH)
  1025. @classmethod
  1026. def parse(cls, expression):
  1027. result = Never()
  1028. groups = expression.split(cls.JOINER)
  1029. for group in groups:
  1030. group = group.strip()
  1031. if not group:
  1032. group = '>=0.0.0'
  1033. subclauses = []
  1034. if cls.HYPHEN in group:
  1035. low, high = group.split(cls.HYPHEN, 2)
  1036. subclauses = cls.parse_simple('>=' + low) + cls.parse_simple('<=' + high)
  1037. else:
  1038. blocks = group.split(' ')
  1039. for block in blocks:
  1040. if not cls.NPM_SPEC_BLOCK.match(block):
  1041. raise ValueError("Invalid NPM block in %r: %r" % (expression, block))
  1042. subclauses.extend(cls.parse_simple(block))
  1043. prerelease_clauses = []
  1044. non_prerel_clauses = []
  1045. for clause in subclauses:
  1046. if clause.target.prerelease:
  1047. if clause.operator in (Range.OP_GT, Range.OP_GTE):
  1048. prerelease_clauses.append(Range(
  1049. operator=Range.OP_LT,
  1050. target=Version(
  1051. major=clause.target.major,
  1052. minor=clause.target.minor,
  1053. patch=clause.target.patch + 1,
  1054. ),
  1055. prerelease_policy=Range.PRERELEASE_ALWAYS,
  1056. ))
  1057. elif clause.operator in (Range.OP_LT, Range.OP_LTE):
  1058. prerelease_clauses.append(Range(
  1059. operator=Range.OP_GTE,
  1060. target=Version(
  1061. major=clause.target.major,
  1062. minor=clause.target.minor,
  1063. patch=0,
  1064. prerelease=(),
  1065. ),
  1066. prerelease_policy=Range.PRERELEASE_ALWAYS,
  1067. ))
  1068. prerelease_clauses.append(clause)
  1069. non_prerel_clauses.append(cls.range(
  1070. operator=clause.operator,
  1071. target=clause.target.truncate(),
  1072. ))
  1073. else:
  1074. non_prerel_clauses.append(clause)
  1075. if prerelease_clauses:
  1076. result |= AllOf(*prerelease_clauses)
  1077. result |= AllOf(*non_prerel_clauses)
  1078. return result
  1079. PREFIX_CARET = '^'
  1080. PREFIX_TILDE = '~'
  1081. PREFIX_EQ = '='
  1082. PREFIX_GT = '>'
  1083. PREFIX_GTE = '>='
  1084. PREFIX_LT = '<'
  1085. PREFIX_LTE = '<='
  1086. PREFIX_ALIASES = {
  1087. '': PREFIX_EQ,
  1088. }
  1089. PREFIX_TO_OPERATOR = {
  1090. PREFIX_EQ: Range.OP_EQ,
  1091. PREFIX_LT: Range.OP_LT,
  1092. PREFIX_LTE: Range.OP_LTE,
  1093. PREFIX_GTE: Range.OP_GTE,
  1094. PREFIX_GT: Range.OP_GT,
  1095. }
  1096. EMPTY_VALUES = ['*', 'x', 'X', None]
  1097. @classmethod
  1098. def parse_simple(cls, simple):
  1099. match = cls.NPM_SPEC_BLOCK.match(simple)
  1100. prefix, major_t, minor_t, patch_t, prerel, build = match.groups()
  1101. prefix = cls.PREFIX_ALIASES.get(prefix, prefix)
  1102. major = None if major_t in cls.EMPTY_VALUES else int(major_t)
  1103. minor = None if minor_t in cls.EMPTY_VALUES else int(minor_t)
  1104. patch = None if patch_t in cls.EMPTY_VALUES else int(patch_t)
  1105. if build is not None and prefix not in [cls.PREFIX_EQ]:
  1106. # Ignore the 'build' part when not comparing to a specific part.
  1107. build = None
  1108. if major is None: # '*', 'x', 'X'
  1109. target = Version(major=0, minor=0, patch=0)
  1110. if prefix not in [cls.PREFIX_EQ, cls.PREFIX_GTE]:
  1111. raise ValueError("Invalid expression %r" % simple)
  1112. prefix = cls.PREFIX_GTE
  1113. elif minor is None:
  1114. target = Version(major=major, minor=0, patch=0)
  1115. elif patch is None:
  1116. target = Version(major=major, minor=minor, patch=0)
  1117. else:
  1118. target = Version(
  1119. major=major,
  1120. minor=minor,
  1121. patch=patch,
  1122. prerelease=prerel.split('.') if prerel else (),
  1123. build=build.split('.') if build else (),
  1124. )
  1125. if (major is None or minor is None or patch is None) and (prerel or build):
  1126. raise ValueError("Invalid NPM spec: %r" % simple)
  1127. if prefix == cls.PREFIX_CARET:
  1128. if target.major: # ^1.2.4 => >=1.2.4 <2.0.0 ; ^1.x => >=1.0.0 <2.0.0
  1129. high = target.truncate().next_major()
  1130. elif target.minor: # ^0.1.2 => >=0.1.2 <0.2.0
  1131. high = target.truncate().next_minor()
  1132. elif minor is None: # ^0.x => >=0.0.0 <1.0.0
  1133. high = target.truncate().next_major()
  1134. elif patch is None: # ^0.2.x => >=0.2.0 <0.3.0
  1135. high = target.truncate().next_minor()
  1136. else: # ^0.0.1 => >=0.0.1 <0.0.2
  1137. high = target.truncate().next_patch()
  1138. return [cls.range(Range.OP_GTE, target), cls.range(Range.OP_LT, high)]
  1139. elif prefix == cls.PREFIX_TILDE:
  1140. assert major is not None
  1141. if minor is None: # ~1.x => >=1.0.0 <2.0.0
  1142. high = target.next_major()
  1143. else: # ~1.2.x => >=1.2.0 <1.3.0; ~1.2.3 => >=1.2.3 <1.3.0
  1144. high = target.next_minor()
  1145. return [cls.range(Range.OP_GTE, target), cls.range(Range.OP_LT, high)]
  1146. elif prefix == cls.PREFIX_EQ:
  1147. if major is None:
  1148. return [cls.range(Range.OP_GTE, target)]
  1149. elif minor is None:
  1150. return [cls.range(Range.OP_GTE, target), cls.range(Range.OP_LT, target.next_major())]
  1151. elif patch is None:
  1152. return [cls.range(Range.OP_GTE, target), cls.range(Range.OP_LT, target.next_minor())]
  1153. else:
  1154. return [cls.range(Range.OP_EQ, target)]
  1155. elif prefix == cls.PREFIX_GT:
  1156. assert major is not None
  1157. if minor is None: # >1.x
  1158. return [cls.range(Range.OP_GTE, target.next_major())]
  1159. elif patch is None: # >1.2.x => >=1.3.0
  1160. return [cls.range(Range.OP_GTE, target.next_minor())]
  1161. else:
  1162. return [cls.range(Range.OP_GT, target)]
  1163. elif prefix == cls.PREFIX_GTE:
  1164. return [cls.range(Range.OP_GTE, target)]
  1165. elif prefix == cls.PREFIX_LT:
  1166. assert major is not None
  1167. return [cls.range(Range.OP_LT, target)]
  1168. else:
  1169. assert prefix == cls.PREFIX_LTE
  1170. assert major is not None
  1171. if minor is None: # <=1.x => <2.0.0
  1172. return [cls.range(Range.OP_LT, target.next_major())]
  1173. elif patch is None: # <=1.2.x => <1.3.0
  1174. return [cls.range(Range.OP_LT, target.next_minor())]
  1175. else:
  1176. return [cls.range(Range.OP_LTE, target)]