Initial Commit
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
# Copyright (c) Twisted Matrix Laboratories.
|
||||
# See LICENSE for details.
|
||||
|
||||
"""
|
||||
Versions for Python packages.
|
||||
|
||||
See L{Version}.
|
||||
"""
|
||||
|
||||
from __future__ import division, absolute_import
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Any, TypeVar, Union, Optional, Dict
|
||||
|
||||
#
|
||||
# Compat functions
|
||||
#
|
||||
|
||||
_T = TypeVar("_T", contravariant=True)
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Literal
|
||||
from distutils.dist import Distribution as _Distribution
|
||||
|
||||
|
||||
else:
|
||||
_Distribution = object
|
||||
|
||||
if sys.version_info > (3,):
|
||||
|
||||
def _cmp(a, b): # type: (Any, Any) -> int
|
||||
"""
|
||||
Compare two objects.
|
||||
|
||||
Returns a negative number if C{a < b}, zero if they are equal, and a
|
||||
positive number if C{a > b}.
|
||||
"""
|
||||
if a < b:
|
||||
return -1
|
||||
elif a == b:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
else:
|
||||
_cmp = cmp # noqa: F821
|
||||
|
||||
|
||||
#
|
||||
# Versioning
|
||||
#
|
||||
|
||||
|
||||
class _Inf(object):
|
||||
"""
|
||||
An object that is bigger than all other objects.
|
||||
"""
|
||||
|
||||
def __cmp__(self, other): # type: (object) -> int
|
||||
"""
|
||||
@param other: Another object.
|
||||
@type other: any
|
||||
|
||||
@return: 0 if other is inf, 1 otherwise.
|
||||
@rtype: C{int}
|
||||
"""
|
||||
if other is _inf:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
|
||||
def __lt__(self, other): # type: (object) -> bool
|
||||
return self.__cmp__(other) < 0
|
||||
|
||||
def __le__(self, other): # type: (object) -> bool
|
||||
return self.__cmp__(other) <= 0
|
||||
|
||||
def __gt__(self, other): # type: (object) -> bool
|
||||
return self.__cmp__(other) > 0
|
||||
|
||||
def __ge__(self, other): # type: (object) -> bool
|
||||
return self.__cmp__(other) >= 0
|
||||
|
||||
|
||||
_inf = _Inf()
|
||||
|
||||
|
||||
class IncomparableVersions(TypeError):
|
||||
"""
|
||||
Two versions could not be compared.
|
||||
"""
|
||||
|
||||
|
||||
class Version(object):
|
||||
"""
|
||||
An encapsulation of a version for a project, with support for outputting
|
||||
PEP-440 compatible version strings.
|
||||
|
||||
This class supports the standard major.minor.micro[rcN] scheme of
|
||||
versioning.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
package, # type: str
|
||||
major, # type: Union[Literal["NEXT"], int]
|
||||
minor, # type: int
|
||||
micro, # type: int
|
||||
release_candidate=None, # type: Optional[int]
|
||||
prerelease=None, # type: Optional[int]
|
||||
post=None, # type: Optional[int]
|
||||
dev=None, # type: Optional[int]
|
||||
):
|
||||
"""
|
||||
@param package: Name of the package that this is a version of.
|
||||
@type package: C{str}
|
||||
@param major: The major version number.
|
||||
@type major: C{int} or C{str} (for the "NEXT" symbol)
|
||||
@param minor: The minor version number.
|
||||
@type minor: C{int}
|
||||
@param micro: The micro version number.
|
||||
@type micro: C{int}
|
||||
@param release_candidate: The release candidate number.
|
||||
@type release_candidate: C{int}
|
||||
@param prerelease: The prerelease number. (Deprecated)
|
||||
@type prerelease: C{int}
|
||||
@param post: The postrelease number.
|
||||
@type post: C{int}
|
||||
@param dev: The development release number.
|
||||
@type dev: C{int}
|
||||
"""
|
||||
if release_candidate and prerelease:
|
||||
raise ValueError("Please only return one of these.")
|
||||
elif prerelease and not release_candidate:
|
||||
release_candidate = prerelease
|
||||
warnings.warn(
|
||||
"Passing prerelease to incremental.Version was "
|
||||
"deprecated in Incremental 16.9.0. Please pass "
|
||||
"release_candidate instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
if major == "NEXT":
|
||||
if minor or micro or release_candidate or post or dev:
|
||||
raise ValueError(
|
||||
"When using NEXT, all other values except Package must be 0."
|
||||
)
|
||||
|
||||
self.package = package
|
||||
self.major = major
|
||||
self.minor = minor
|
||||
self.micro = micro
|
||||
self.release_candidate = release_candidate
|
||||
self.post = post
|
||||
self.dev = dev
|
||||
|
||||
@property
|
||||
def prerelease(self): # type: () -> Optional[int]
|
||||
warnings.warn(
|
||||
"Accessing incremental.Version.prerelease was "
|
||||
"deprecated in Incremental 16.9.0. Use "
|
||||
"Version.release_candidate instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
),
|
||||
return self.release_candidate
|
||||
|
||||
def public(self): # type: () -> str
|
||||
"""
|
||||
Return a PEP440-compatible "public" representation of this L{Version}.
|
||||
|
||||
Examples:
|
||||
|
||||
- 14.4.0
|
||||
- 1.2.3rc1
|
||||
- 14.2.1rc1dev9
|
||||
- 16.04.0dev0
|
||||
"""
|
||||
if self.major == "NEXT":
|
||||
return self.major
|
||||
|
||||
if self.release_candidate is None:
|
||||
rc = ""
|
||||
else:
|
||||
rc = ".rc%s" % (self.release_candidate,)
|
||||
|
||||
if self.post is None:
|
||||
post = ""
|
||||
else:
|
||||
post = ".post%s" % (self.post,)
|
||||
|
||||
if self.dev is None:
|
||||
dev = ""
|
||||
else:
|
||||
dev = ".dev%s" % (self.dev,)
|
||||
|
||||
return "%r.%d.%d%s%s%s" % (self.major, self.minor, self.micro, rc, post, dev)
|
||||
|
||||
base = public
|
||||
short = public
|
||||
local = public
|
||||
|
||||
def __repr__(self): # type: () -> str
|
||||
|
||||
if self.release_candidate is None:
|
||||
release_candidate = ""
|
||||
else:
|
||||
release_candidate = ", release_candidate=%r" % (self.release_candidate,)
|
||||
|
||||
if self.post is None:
|
||||
post = ""
|
||||
else:
|
||||
post = ", post=%r" % (self.post,)
|
||||
|
||||
if self.dev is None:
|
||||
dev = ""
|
||||
else:
|
||||
dev = ", dev=%r" % (self.dev,)
|
||||
|
||||
return "%s(%r, %r, %d, %d%s%s%s)" % (
|
||||
self.__class__.__name__,
|
||||
self.package,
|
||||
self.major,
|
||||
self.minor,
|
||||
self.micro,
|
||||
release_candidate,
|
||||
post,
|
||||
dev,
|
||||
)
|
||||
|
||||
def __str__(self): # type: () -> str
|
||||
return "[%s, version %s]" % (self.package, self.short())
|
||||
|
||||
def __cmp__(self, other): # type: (Version) -> int
|
||||
"""
|
||||
Compare two versions, considering major versions, minor versions, micro
|
||||
versions, then release candidates, then postreleases, then dev
|
||||
releases. Package names are case insensitive.
|
||||
|
||||
A version with a release candidate is always less than a version
|
||||
without a release candidate. If both versions have release candidates,
|
||||
they will be included in the comparison.
|
||||
|
||||
Likewise, a version with a dev release is always less than a version
|
||||
without a dev release. If both versions have dev releases, they will
|
||||
be included in the comparison.
|
||||
|
||||
@param other: Another version.
|
||||
@type other: L{Version}
|
||||
|
||||
@return: NotImplemented when the other object is not a Version, or one
|
||||
of -1, 0, or 1.
|
||||
|
||||
@raise IncomparableVersions: when the package names of the versions
|
||||
differ.
|
||||
"""
|
||||
if not isinstance(other, self.__class__):
|
||||
return NotImplemented
|
||||
if self.package.lower() != other.package.lower():
|
||||
raise IncomparableVersions("%r != %r" % (self.package, other.package))
|
||||
|
||||
if self.major == "NEXT":
|
||||
major = _inf # type: Union[int, _Inf]
|
||||
else:
|
||||
major = self.major
|
||||
|
||||
if self.release_candidate is None:
|
||||
release_candidate = _inf # type: Union[int, _Inf]
|
||||
else:
|
||||
release_candidate = self.release_candidate
|
||||
|
||||
if self.post is None:
|
||||
post = -1
|
||||
else:
|
||||
post = self.post
|
||||
|
||||
if self.dev is None:
|
||||
dev = _inf # type: Union[int, _Inf]
|
||||
else:
|
||||
dev = self.dev
|
||||
|
||||
if other.major == "NEXT":
|
||||
othermajor = _inf # type: Union[int, _Inf]
|
||||
else:
|
||||
othermajor = other.major
|
||||
|
||||
if other.release_candidate is None:
|
||||
otherrc = _inf # type: Union[int, _Inf]
|
||||
else:
|
||||
otherrc = other.release_candidate
|
||||
|
||||
if other.post is None:
|
||||
otherpost = -1
|
||||
else:
|
||||
otherpost = other.post
|
||||
|
||||
if other.dev is None:
|
||||
otherdev = _inf # type: Union[int, _Inf]
|
||||
else:
|
||||
otherdev = other.dev
|
||||
|
||||
x = _cmp(
|
||||
(major, self.minor, self.micro, release_candidate, post, dev),
|
||||
(othermajor, other.minor, other.micro, otherrc, otherpost, otherdev),
|
||||
)
|
||||
return x
|
||||
|
||||
if sys.version_info >= (3,):
|
||||
|
||||
def __eq__(self, other): # type: (Any) -> bool
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c # type: ignore[return-value]
|
||||
return c == 0
|
||||
|
||||
def __ne__(self, other): # type: (Any) -> bool
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c # type: ignore[return-value]
|
||||
return c != 0
|
||||
|
||||
def __lt__(self, other): # type: (Version) -> bool
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c # type: ignore[return-value]
|
||||
return c < 0
|
||||
|
||||
def __le__(self, other): # type: (Version) -> bool
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c # type: ignore[return-value]
|
||||
return c <= 0
|
||||
|
||||
def __gt__(self, other): # type: (Version) -> bool
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c # type: ignore[return-value]
|
||||
return c > 0
|
||||
|
||||
def __ge__(self, other): # type: (Version) -> bool
|
||||
c = self.__cmp__(other)
|
||||
if c is NotImplemented:
|
||||
return c # type: ignore[return-value]
|
||||
return c >= 0
|
||||
|
||||
|
||||
def getVersionString(version): # type: (Version) -> str
|
||||
"""
|
||||
Get a friendly string for the given version object.
|
||||
|
||||
@param version: A L{Version} object.
|
||||
@return: A string containing the package and short version number.
|
||||
"""
|
||||
result = "%s %s" % (version.package, version.short())
|
||||
return result
|
||||
|
||||
|
||||
def _get_version(dist, keyword, value): # type: (_Distribution, object, object) -> None
|
||||
"""
|
||||
Get the version from the package listed in the Distribution.
|
||||
"""
|
||||
if not value:
|
||||
return
|
||||
|
||||
from distutils.command import build_py
|
||||
|
||||
sp_command = build_py.build_py(dist)
|
||||
sp_command.finalize_options()
|
||||
|
||||
for item in sp_command.find_all_modules(): # type: ignore[attr-defined]
|
||||
if item[1] == "_version":
|
||||
version_file = {} # type: Dict[str, Version]
|
||||
|
||||
with open(item[2]) as f:
|
||||
exec(f.read(), version_file)
|
||||
|
||||
dist.metadata.version = version_file["__version__"].public()
|
||||
return None
|
||||
|
||||
raise Exception("No _version.py found.")
|
||||
|
||||
|
||||
from ._version import __version__ # noqa: E402
|
||||
|
||||
|
||||
def _setuptools_version(): # type: () -> str
|
||||
return __version__.public()
|
||||
|
||||
|
||||
__all__ = ["__version__", "Version", "getVersionString"]
|
||||
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Provides Incremental version information.
|
||||
"""
|
||||
|
||||
# This file is auto-generated! Do not edit!
|
||||
# Use `python -m incremental.update Incremental` to change this file.
|
||||
|
||||
from incremental import Version
|
||||
|
||||
__version__ = Version("Incremental", 22, 10, 0)
|
||||
__all__ = ["__version__"]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,552 @@
|
||||
# Copyright (c) Twisted Matrix Laboratories.
|
||||
# See LICENSE for details.
|
||||
|
||||
"""
|
||||
Tests for L{incremental}.
|
||||
"""
|
||||
|
||||
from __future__ import division, absolute_import
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
import operator
|
||||
|
||||
from incremental import getVersionString, IncomparableVersions
|
||||
from incremental import Version, _inf
|
||||
|
||||
from twisted.trial.unittest import TestCase
|
||||
|
||||
|
||||
class VersionsTests(TestCase):
|
||||
def test_localIsShort(self):
|
||||
"""
|
||||
The local version is the same as the short version.
|
||||
"""
|
||||
va = Version("dummy", 1, 0, 0, release_candidate=1, post=2, dev=3)
|
||||
self.assertEqual(va.local(), va.short())
|
||||
|
||||
def test_versionComparison(self):
|
||||
"""
|
||||
Versions can be compared for equality and order.
|
||||
"""
|
||||
va = Version("dummy", 1, 0, 0)
|
||||
vb = Version("dummy", 0, 1, 0)
|
||||
self.assertTrue(va > vb)
|
||||
self.assertTrue(vb < va)
|
||||
self.assertTrue(va >= vb)
|
||||
self.assertTrue(vb <= va)
|
||||
self.assertTrue(va != vb)
|
||||
self.assertTrue(vb == Version("dummy", 0, 1, 0))
|
||||
self.assertTrue(vb == vb)
|
||||
|
||||
@unittest.skipIf(sys.version_info < (3,), "Comparisons do not raise on py2")
|
||||
def test_versionComparisonNonVersion(self):
|
||||
"""
|
||||
Versions can be compared with non-versions.
|
||||
"""
|
||||
v = Version("dummy", 1, 0, 0)
|
||||
o = object()
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
v > o
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
v < o
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
v >= o
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
v <= o
|
||||
|
||||
self.assertFalse(v == o)
|
||||
self.assertTrue(v != o)
|
||||
|
||||
def test_versionComparisonCaseInsensitive(self):
|
||||
"""
|
||||
Version package names are case insensitive.
|
||||
"""
|
||||
va = Version("dummy", 1, 0, 0)
|
||||
vb = Version("DuMmY", 0, 1, 0)
|
||||
self.assertTrue(va > vb)
|
||||
self.assertTrue(vb < va)
|
||||
self.assertTrue(va >= vb)
|
||||
self.assertTrue(vb <= va)
|
||||
self.assertTrue(va != vb)
|
||||
self.assertTrue(vb == Version("dummy", 0, 1, 0))
|
||||
self.assertTrue(vb == vb)
|
||||
|
||||
def test_comparingNEXTReleases(self):
|
||||
"""
|
||||
NEXT releases are always larger than numbered releases.
|
||||
"""
|
||||
va = Version("whatever", "NEXT", 0, 0)
|
||||
vb = Version("whatever", 1, 0, 0)
|
||||
self.assertTrue(va > vb)
|
||||
self.assertFalse(va < vb)
|
||||
self.assertNotEquals(vb, va)
|
||||
|
||||
def test_NEXTMustBeAlone(self):
|
||||
"""
|
||||
NEXT releases must always have the rest of the numbers set to 0.
|
||||
"""
|
||||
with self.assertRaises(ValueError):
|
||||
Version("whatever", "NEXT", 1, 0, release_candidate=0, post=0, dev=0)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
Version("whatever", "NEXT", 0, 1, release_candidate=0, post=0, dev=0)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
Version("whatever", "NEXT", 0, 0, release_candidate=1, post=0, dev=0)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
Version("whatever", "NEXT", 0, 0, release_candidate=0, post=1, dev=0)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
Version("whatever", "NEXT", 0, 0, release_candidate=0, post=0, dev=1)
|
||||
|
||||
def test_comparingNEXTReleasesEqual(self):
|
||||
"""
|
||||
NEXT releases are equal to each other.
|
||||
"""
|
||||
va = Version("whatever", "NEXT", 0, 0)
|
||||
vb = Version("whatever", "NEXT", 0, 0)
|
||||
self.assertEquals(vb, va)
|
||||
|
||||
def test_comparingPrereleasesWithReleases(self):
|
||||
"""
|
||||
Prereleases are always less than versions without prereleases.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, prerelease=1)
|
||||
vb = Version("whatever", 1, 0, 0)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertFalse(va > vb)
|
||||
self.assertNotEquals(vb, va)
|
||||
|
||||
def test_prereleaseDeprecated(self):
|
||||
"""
|
||||
Passing 'prerelease' to Version is deprecated.
|
||||
"""
|
||||
Version("whatever", 1, 0, 0, prerelease=1)
|
||||
warnings = self.flushWarnings([self.test_prereleaseDeprecated])
|
||||
self.assertEqual(len(warnings), 1)
|
||||
self.assertEqual(
|
||||
warnings[0]["message"],
|
||||
"Passing prerelease to incremental.Version was deprecated in "
|
||||
"Incremental 16.9.0. Please pass release_candidate instead.",
|
||||
)
|
||||
|
||||
def test_prereleaseAttributeDeprecated(self):
|
||||
"""
|
||||
Accessing 'prerelease' on a Version is deprecated.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, release_candidate=1)
|
||||
va.prerelease
|
||||
warnings = self.flushWarnings([self.test_prereleaseAttributeDeprecated])
|
||||
self.assertEqual(len(warnings), 1)
|
||||
self.assertEqual(
|
||||
warnings[0]["message"],
|
||||
"Accessing incremental.Version.prerelease was deprecated in "
|
||||
"Incremental 16.9.0. Use Version.release_candidate instead.",
|
||||
)
|
||||
|
||||
def test_comparingReleaseCandidatesWithReleases(self):
|
||||
"""
|
||||
Release Candidates are always less than versions without release
|
||||
candidates.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, release_candidate=1)
|
||||
vb = Version("whatever", 1, 0, 0)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertFalse(va > vb)
|
||||
self.assertNotEquals(vb, va)
|
||||
|
||||
def test_comparingPostReleasesWithReleases(self):
|
||||
"""
|
||||
Post releases are always greater than versions without post
|
||||
releases.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, post=1)
|
||||
vb = Version("whatever", 1, 0, 0)
|
||||
self.assertTrue(va > vb)
|
||||
self.assertFalse(va < vb)
|
||||
self.assertNotEquals(vb, va)
|
||||
|
||||
def test_comparingDevReleasesWithPreviousPostReleases(self):
|
||||
"""
|
||||
Dev releases are always greater than postreleases based on previous
|
||||
releases.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 1, dev=1)
|
||||
vb = Version("whatever", 1, 0, 0, post=1)
|
||||
self.assertTrue(va > vb)
|
||||
self.assertFalse(va < vb)
|
||||
self.assertNotEquals(vb, va)
|
||||
|
||||
def test_comparingDevReleasesWithReleases(self):
|
||||
"""
|
||||
Dev releases are always less than versions without dev releases.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, dev=1)
|
||||
vb = Version("whatever", 1, 0, 0)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertFalse(va > vb)
|
||||
self.assertNotEquals(vb, va)
|
||||
|
||||
def test_rcEqualspre(self):
|
||||
"""
|
||||
Release Candidates are equal to prereleases.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, release_candidate=1)
|
||||
vb = Version("whatever", 1, 0, 0, prerelease=1)
|
||||
self.assertTrue(va == vb)
|
||||
self.assertFalse(va != vb)
|
||||
|
||||
def test_rcOrpreButNotBoth(self):
|
||||
"""
|
||||
Release Candidate and prerelease can't both be given.
|
||||
"""
|
||||
with self.assertRaises(ValueError):
|
||||
Version("whatever", 1, 0, 0, prerelease=1, release_candidate=1)
|
||||
|
||||
def test_comparingReleaseCandidates(self):
|
||||
"""
|
||||
The value specified as the release candidate is used in version
|
||||
comparisons.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, release_candidate=1)
|
||||
vb = Version("whatever", 1, 0, 0, release_candidate=2)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertTrue(vb > va)
|
||||
self.assertTrue(va <= vb)
|
||||
self.assertTrue(vb >= va)
|
||||
self.assertTrue(va != vb)
|
||||
self.assertTrue(vb == Version("whatever", 1, 0, 0, release_candidate=2))
|
||||
self.assertTrue(va == va)
|
||||
|
||||
def test_comparingPost(self):
|
||||
"""
|
||||
The value specified as the postrelease is used in version comparisons.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, post=1)
|
||||
vb = Version("whatever", 1, 0, 0, post=2)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertTrue(vb > va)
|
||||
self.assertTrue(va <= vb)
|
||||
self.assertTrue(vb >= va)
|
||||
self.assertTrue(va != vb)
|
||||
self.assertTrue(vb == Version("whatever", 1, 0, 0, post=2))
|
||||
self.assertTrue(va == va)
|
||||
|
||||
def test_comparingDev(self):
|
||||
"""
|
||||
The value specified as the dev release is used in version comparisons.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, dev=1)
|
||||
vb = Version("whatever", 1, 0, 0, dev=2)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertTrue(vb > va)
|
||||
self.assertTrue(va <= vb)
|
||||
self.assertTrue(vb >= va)
|
||||
self.assertTrue(va != vb)
|
||||
self.assertTrue(vb == Version("whatever", 1, 0, 0, dev=2))
|
||||
self.assertTrue(va == va)
|
||||
|
||||
def test_comparingDevAndRC(self):
|
||||
"""
|
||||
The value specified as the dev release and release candidate is used in
|
||||
version comparisons.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, release_candidate=1, dev=1)
|
||||
vb = Version("whatever", 1, 0, 0, release_candidate=1, dev=2)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertTrue(vb > va)
|
||||
self.assertTrue(va <= vb)
|
||||
self.assertTrue(vb >= va)
|
||||
self.assertTrue(va != vb)
|
||||
self.assertTrue(vb == Version("whatever", 1, 0, 0, release_candidate=1, dev=2))
|
||||
self.assertTrue(va == va)
|
||||
|
||||
def test_comparingDevAndRCDifferent(self):
|
||||
"""
|
||||
The value specified as the dev release and release candidate is used in
|
||||
version comparisons.
|
||||
"""
|
||||
va = Version("whatever", 1, 0, 0, release_candidate=1, dev=1)
|
||||
vb = Version("whatever", 1, 0, 0, release_candidate=2, dev=1)
|
||||
self.assertTrue(va < vb)
|
||||
self.assertTrue(vb > va)
|
||||
self.assertTrue(va <= vb)
|
||||
self.assertTrue(vb >= va)
|
||||
self.assertTrue(va != vb)
|
||||
self.assertTrue(vb == Version("whatever", 1, 0, 0, release_candidate=2, dev=1))
|
||||
self.assertTrue(va == va)
|
||||
|
||||
def test_infComparison(self):
|
||||
"""
|
||||
L{_inf} is equal to L{_inf}.
|
||||
|
||||
This is a regression test.
|
||||
"""
|
||||
o = object()
|
||||
self.assertEqual(_inf, _inf)
|
||||
self.assertTrue(_inf > o)
|
||||
self.assertFalse(_inf < o)
|
||||
self.assertTrue(_inf >= o)
|
||||
self.assertFalse(_inf <= o)
|
||||
self.assertTrue(_inf != o)
|
||||
self.assertFalse(_inf == o)
|
||||
|
||||
def test_disallowBuggyComparisons(self):
|
||||
"""
|
||||
The package names of the Version objects need to be the same.
|
||||
"""
|
||||
self.assertRaises(
|
||||
IncomparableVersions,
|
||||
operator.eq,
|
||||
Version("dummy", 1, 0, 0),
|
||||
Version("dumym", 1, 0, 0),
|
||||
)
|
||||
|
||||
def test_notImplementedComparisons(self):
|
||||
"""
|
||||
Comparing a L{Version} to some other object type results in
|
||||
C{NotImplemented}.
|
||||
"""
|
||||
va = Version("dummy", 1, 0, 0)
|
||||
vb = ("dummy", 1, 0, 0) # a tuple is not a Version object
|
||||
self.assertEqual(va.__cmp__(vb), NotImplemented)
|
||||
|
||||
def test_repr(self):
|
||||
"""
|
||||
Calling C{repr} on a version returns a human-readable string
|
||||
representation of the version.
|
||||
"""
|
||||
self.assertEqual(repr(Version("dummy", 1, 2, 3)), "Version('dummy', 1, 2, 3)")
|
||||
|
||||
def test_reprWithPrerelease(self):
|
||||
"""
|
||||
Calling C{repr} on a version with a prerelease returns a human-readable
|
||||
string representation of the version including the prerelease as a
|
||||
release candidate..
|
||||
"""
|
||||
self.assertEqual(
|
||||
repr(Version("dummy", 1, 2, 3, prerelease=4)),
|
||||
"Version('dummy', 1, 2, 3, release_candidate=4)",
|
||||
)
|
||||
|
||||
def test_reprWithReleaseCandidate(self):
|
||||
"""
|
||||
Calling C{repr} on a version with a release candidate returns a
|
||||
human-readable string representation of the version including the rc.
|
||||
"""
|
||||
self.assertEqual(
|
||||
repr(Version("dummy", 1, 2, 3, release_candidate=4)),
|
||||
"Version('dummy', 1, 2, 3, release_candidate=4)",
|
||||
)
|
||||
|
||||
def test_reprWithPost(self):
|
||||
"""
|
||||
Calling C{repr} on a version with a postrelease returns a
|
||||
human-readable string representation of the version including the
|
||||
postrelease.
|
||||
"""
|
||||
self.assertEqual(
|
||||
repr(Version("dummy", 1, 2, 3, post=4)), "Version('dummy', 1, 2, 3, post=4)"
|
||||
)
|
||||
|
||||
def test_reprWithDev(self):
|
||||
"""
|
||||
Calling C{repr} on a version with a dev release returns a
|
||||
human-readable string representation of the version including the dev
|
||||
release.
|
||||
"""
|
||||
self.assertEqual(
|
||||
repr(Version("dummy", 1, 2, 3, dev=4)), "Version('dummy', 1, 2, 3, dev=4)"
|
||||
)
|
||||
|
||||
def test_str(self):
|
||||
"""
|
||||
Calling C{str} on a version returns a human-readable string
|
||||
representation of the version.
|
||||
"""
|
||||
self.assertEqual(str(Version("dummy", 1, 2, 3)), "[dummy, version 1.2.3]")
|
||||
|
||||
def test_strWithPrerelease(self):
|
||||
"""
|
||||
Calling C{str} on a version with a prerelease includes the prerelease
|
||||
as a release candidate.
|
||||
"""
|
||||
self.assertEqual(
|
||||
str(Version("dummy", 1, 0, 0, prerelease=1)), "[dummy, version 1.0.0.rc1]"
|
||||
)
|
||||
|
||||
def test_strWithReleaseCandidate(self):
|
||||
"""
|
||||
Calling C{str} on a version with a release candidate includes the
|
||||
release candidate.
|
||||
"""
|
||||
self.assertEqual(
|
||||
str(Version("dummy", 1, 0, 0, release_candidate=1)),
|
||||
"[dummy, version 1.0.0.rc1]",
|
||||
)
|
||||
|
||||
def test_strWithPost(self):
|
||||
"""
|
||||
Calling C{str} on a version with a postrelease includes the
|
||||
postrelease.
|
||||
"""
|
||||
self.assertEqual(
|
||||
str(Version("dummy", 1, 0, 0, post=1)), "[dummy, version 1.0.0.post1]"
|
||||
)
|
||||
|
||||
def test_strWithDevAndReleaseCandidate(self):
|
||||
"""
|
||||
Calling C{str} on a version with a release candidate and dev release
|
||||
includes the release candidate and the dev release.
|
||||
"""
|
||||
self.assertEqual(
|
||||
str(Version("dummy", 1, 0, 0, release_candidate=1, dev=2)),
|
||||
"[dummy, version 1.0.0.rc1.dev2]",
|
||||
)
|
||||
|
||||
def test_strWithDev(self):
|
||||
"""
|
||||
Calling C{str} on a version with a dev release includes the dev
|
||||
release.
|
||||
"""
|
||||
self.assertEqual(
|
||||
str(Version("dummy", 1, 0, 0, dev=1)), "[dummy, version 1.0.0.dev1]"
|
||||
)
|
||||
|
||||
def test_strWithDevAndPost(self):
|
||||
"""
|
||||
Calling C{str} on a version with a postrelease and dev release
|
||||
includes the postrelease and the dev release.
|
||||
"""
|
||||
self.assertEqual(
|
||||
str(Version("dummy", 1, 0, 0, post=1, dev=2)),
|
||||
"[dummy, version 1.0.0.post1.dev2]",
|
||||
)
|
||||
|
||||
def testShort(self):
|
||||
self.assertEqual(Version("dummy", 1, 2, 3).short(), "1.2.3")
|
||||
|
||||
def test_getVersionString(self):
|
||||
"""
|
||||
L{getVersionString} returns a string with the package name and the
|
||||
short version number.
|
||||
"""
|
||||
self.assertEqual("Twisted 8.0.0", getVersionString(Version("Twisted", 8, 0, 0)))
|
||||
|
||||
def test_getVersionStringWithPrerelease(self):
|
||||
"""
|
||||
L{getVersionString} includes the prerelease as a release candidate, if
|
||||
any.
|
||||
"""
|
||||
self.assertEqual(
|
||||
getVersionString(Version("whatever", 8, 0, 0, prerelease=1)),
|
||||
"whatever 8.0.0.rc1",
|
||||
)
|
||||
|
||||
def test_getVersionStringWithReleaseCandidate(self):
|
||||
"""
|
||||
L{getVersionString} includes the release candidate, if any.
|
||||
"""
|
||||
self.assertEqual(
|
||||
getVersionString(Version("whatever", 8, 0, 0, release_candidate=1)),
|
||||
"whatever 8.0.0.rc1",
|
||||
)
|
||||
|
||||
def test_getVersionStringWithPost(self):
|
||||
"""
|
||||
L{getVersionString} includes the postrelease, if any.
|
||||
"""
|
||||
self.assertEqual(
|
||||
getVersionString(Version("whatever", 8, 0, 0, post=1)),
|
||||
"whatever 8.0.0.post1",
|
||||
)
|
||||
|
||||
def test_getVersionStringWithDev(self):
|
||||
"""
|
||||
L{getVersionString} includes the dev release, if any.
|
||||
"""
|
||||
self.assertEqual(
|
||||
getVersionString(Version("whatever", 8, 0, 0, dev=1)), "whatever 8.0.0.dev1"
|
||||
)
|
||||
|
||||
def test_getVersionStringWithDevAndRC(self):
|
||||
"""
|
||||
L{getVersionString} includes the dev release and release candidate, if
|
||||
any.
|
||||
"""
|
||||
self.assertEqual(
|
||||
getVersionString(Version("whatever", 8, 0, 0, release_candidate=2, dev=1)),
|
||||
"whatever 8.0.0.rc2.dev1",
|
||||
)
|
||||
|
||||
def test_getVersionStringWithDevAndPost(self):
|
||||
"""
|
||||
L{getVersionString} includes the dev release and postrelease, if
|
||||
any.
|
||||
"""
|
||||
self.assertEqual(
|
||||
getVersionString(Version("whatever", 8, 0, 0, post=2, dev=1)),
|
||||
"whatever 8.0.0.post2.dev1",
|
||||
)
|
||||
|
||||
def test_baseWithNEXT(self):
|
||||
"""
|
||||
The C{base} method returns just "NEXT" when NEXT is the major version.
|
||||
"""
|
||||
self.assertEqual(Version("foo", "NEXT", 0, 0).base(), "NEXT")
|
||||
|
||||
def test_base(self):
|
||||
"""
|
||||
The C{base} method returns a very simple representation of the version.
|
||||
"""
|
||||
self.assertEqual(Version("foo", 1, 0, 0).base(), "1.0.0")
|
||||
|
||||
def test_baseWithPrerelease(self):
|
||||
"""
|
||||
The base version includes 'rcX' for versions with prereleases.
|
||||
"""
|
||||
self.assertEqual(Version("foo", 1, 0, 0, prerelease=8).base(), "1.0.0.rc8")
|
||||
|
||||
def test_baseWithPost(self):
|
||||
"""
|
||||
The base version includes 'postX' for versions with postreleases.
|
||||
"""
|
||||
self.assertEqual(Version("foo", 1, 0, 0, post=8).base(), "1.0.0.post8")
|
||||
|
||||
def test_baseWithDev(self):
|
||||
"""
|
||||
The base version includes 'devX' for versions with dev releases.
|
||||
"""
|
||||
self.assertEqual(Version("foo", 1, 0, 0, dev=8).base(), "1.0.0.dev8")
|
||||
|
||||
def test_baseWithReleaseCandidate(self):
|
||||
"""
|
||||
The base version includes 'rcX' for versions with prereleases.
|
||||
"""
|
||||
self.assertEqual(
|
||||
Version("foo", 1, 0, 0, release_candidate=8).base(), "1.0.0.rc8"
|
||||
)
|
||||
|
||||
def test_baseWithDevAndRC(self):
|
||||
"""
|
||||
The base version includes 'rcXdevX' for versions with dev releases and
|
||||
a release candidate.
|
||||
"""
|
||||
self.assertEqual(
|
||||
Version("foo", 1, 0, 0, release_candidate=2, dev=8).base(), "1.0.0.rc2.dev8"
|
||||
)
|
||||
|
||||
def test_baseWithDevAndPost(self):
|
||||
"""
|
||||
The base version includes 'postXdevX' for versions with dev releases
|
||||
and a postrelease.
|
||||
"""
|
||||
self.assertEqual(
|
||||
Version("foo", 1, 0, 0, post=2, dev=8).base(), "1.0.0.post2.dev8"
|
||||
)
|
||||
@@ -0,0 +1,331 @@
|
||||
# Copyright (c) Twisted Matrix Laboratories.
|
||||
# See LICENSE for details.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import click
|
||||
import os
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING, Dict, Optional, Callable, Iterable
|
||||
|
||||
from incremental import Version
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Protocol
|
||||
|
||||
class _ReadableWritable(Protocol):
|
||||
def read(self): # type: () -> bytes
|
||||
pass
|
||||
|
||||
def write(self, v): # type: (bytes) -> object
|
||||
pass
|
||||
|
||||
def __enter__(self): # type: () -> _ReadableWritable
|
||||
pass
|
||||
|
||||
def __exit__(self, *args, **kwargs): # type: (object, object) -> Optional[bool]
|
||||
pass
|
||||
|
||||
# FilePath is missing type annotations
|
||||
# https://twistedmatrix.com/trac/ticket/10148
|
||||
class FilePath(object):
|
||||
def __init__(self, path): # type: (str) -> None
|
||||
self.path = path
|
||||
|
||||
def child(self, v): # type: (str) -> FilePath
|
||||
pass
|
||||
|
||||
def isdir(self): # type: () -> bool
|
||||
pass
|
||||
|
||||
def isfile(self): # type: () -> bool
|
||||
pass
|
||||
|
||||
def getContent(self): # type: () -> bytes
|
||||
pass
|
||||
|
||||
def open(self, mode): # type: (str) -> _ReadableWritable
|
||||
pass
|
||||
|
||||
def walk(self): # type: () -> Iterable[FilePath]
|
||||
pass
|
||||
|
||||
|
||||
else:
|
||||
from twisted.python.filepath import FilePath
|
||||
|
||||
_VERSIONPY_TEMPLATE = '''"""
|
||||
Provides {package} version information.
|
||||
"""
|
||||
|
||||
# This file is auto-generated! Do not edit!
|
||||
# Use `python -m incremental.update {package}` to change this file.
|
||||
|
||||
from incremental import Version
|
||||
|
||||
__version__ = {version_repr}
|
||||
__all__ = ["__version__"]
|
||||
'''
|
||||
|
||||
_YEAR_START = 2000
|
||||
|
||||
|
||||
def _findPath(path, package): # type: (str, str) -> FilePath
|
||||
|
||||
cwd = FilePath(path)
|
||||
|
||||
src_dir = cwd.child("src").child(package.lower())
|
||||
current_dir = cwd.child(package.lower())
|
||||
|
||||
if src_dir.isdir():
|
||||
return src_dir
|
||||
elif current_dir.isdir():
|
||||
return current_dir
|
||||
else:
|
||||
raise ValueError(
|
||||
"Can't find under `./src` or `./`. Check the "
|
||||
"package name is right (note that we expect your "
|
||||
"package name to be lower cased), or pass it using "
|
||||
"'--path'."
|
||||
)
|
||||
|
||||
|
||||
def _existing_version(path): # type: (FilePath) -> Version
|
||||
version_info = {} # type: Dict[str, Version]
|
||||
|
||||
with path.child("_version.py").open("r") as f:
|
||||
exec(f.read(), version_info)
|
||||
|
||||
return version_info["__version__"]
|
||||
|
||||
|
||||
def _run(
|
||||
package, # type: str
|
||||
path, # type: Optional[str]
|
||||
newversion, # type: Optional[str]
|
||||
patch, # type: bool
|
||||
rc, # type: bool
|
||||
post, # type: bool
|
||||
dev, # type: bool
|
||||
create, # type: bool
|
||||
_date=None, # type: Optional[datetime.date]
|
||||
_getcwd=None, # type: Optional[Callable[[], str]]
|
||||
_print=print, # type: Callable[[object], object]
|
||||
): # type: (...) -> None
|
||||
|
||||
if not _getcwd:
|
||||
_getcwd = os.getcwd
|
||||
|
||||
if not _date:
|
||||
_date = datetime.date.today()
|
||||
|
||||
if type(package) != str:
|
||||
package = package.encode("utf8") # type: ignore[assignment]
|
||||
|
||||
_path = FilePath(path) if path else _findPath(_getcwd(), package)
|
||||
|
||||
if (
|
||||
newversion
|
||||
and patch
|
||||
or newversion
|
||||
and dev
|
||||
or newversion
|
||||
and rc
|
||||
or newversion
|
||||
and post
|
||||
):
|
||||
raise ValueError("Only give --newversion")
|
||||
|
||||
if dev and patch or dev and rc or dev and post:
|
||||
raise ValueError("Only give --dev")
|
||||
|
||||
if (
|
||||
create
|
||||
and dev
|
||||
or create
|
||||
and patch
|
||||
or create
|
||||
and rc
|
||||
or create
|
||||
and post
|
||||
or create
|
||||
and newversion
|
||||
):
|
||||
raise ValueError("Only give --create")
|
||||
|
||||
if newversion:
|
||||
from pkg_resources import parse_version
|
||||
|
||||
existing = _existing_version(_path)
|
||||
st_version = parse_version(newversion)._version # type: ignore[attr-defined]
|
||||
|
||||
release = list(st_version.release)
|
||||
|
||||
minor = 0
|
||||
micro = 0
|
||||
if len(release) == 1:
|
||||
(major,) = release
|
||||
elif len(release) == 2:
|
||||
major, minor = release
|
||||
else:
|
||||
major, minor, micro = release
|
||||
|
||||
v = Version(
|
||||
package,
|
||||
major,
|
||||
minor,
|
||||
micro,
|
||||
release_candidate=st_version.pre[1] if st_version.pre else None,
|
||||
post=st_version.post[1] if st_version.post else None,
|
||||
dev=st_version.dev[1] if st_version.dev else None,
|
||||
)
|
||||
|
||||
elif create:
|
||||
v = Version(package, _date.year - _YEAR_START, _date.month, 0)
|
||||
existing = v
|
||||
|
||||
elif rc and not patch:
|
||||
existing = _existing_version(_path)
|
||||
|
||||
if existing.release_candidate:
|
||||
v = Version(
|
||||
package,
|
||||
existing.major,
|
||||
existing.minor,
|
||||
existing.micro,
|
||||
existing.release_candidate + 1,
|
||||
)
|
||||
else:
|
||||
v = Version(package, _date.year - _YEAR_START, _date.month, 0, 1)
|
||||
|
||||
elif patch:
|
||||
existing = _existing_version(_path)
|
||||
v = Version(
|
||||
package,
|
||||
existing.major,
|
||||
existing.minor,
|
||||
existing.micro + 1,
|
||||
1 if rc else None,
|
||||
)
|
||||
|
||||
elif post:
|
||||
existing = _existing_version(_path)
|
||||
|
||||
if existing.post is None:
|
||||
_post = 0
|
||||
else:
|
||||
_post = existing.post + 1
|
||||
|
||||
v = Version(package, existing.major, existing.minor, existing.micro, post=_post)
|
||||
|
||||
elif dev:
|
||||
existing = _existing_version(_path)
|
||||
|
||||
if existing.dev is None:
|
||||
_dev = 0
|
||||
else:
|
||||
_dev = existing.dev + 1
|
||||
|
||||
v = Version(
|
||||
package,
|
||||
existing.major,
|
||||
existing.minor,
|
||||
existing.micro,
|
||||
existing.release_candidate,
|
||||
dev=_dev,
|
||||
)
|
||||
|
||||
else:
|
||||
existing = _existing_version(_path)
|
||||
|
||||
if existing.release_candidate:
|
||||
v = Version(package, existing.major, existing.minor, existing.micro)
|
||||
else:
|
||||
raise ValueError("You need to issue a rc before updating the major/minor")
|
||||
|
||||
NEXT_repr = repr(Version(package, "NEXT", 0, 0)).split("#")[0].replace("'", '"')
|
||||
NEXT_repr_bytes = NEXT_repr.encode("utf8")
|
||||
|
||||
version_repr = repr(v).split("#")[0].replace("'", '"')
|
||||
version_repr_bytes = version_repr.encode("utf8")
|
||||
|
||||
existing_version_repr = repr(existing).split("#")[0].replace("'", '"')
|
||||
existing_version_repr_bytes = existing_version_repr.encode("utf8")
|
||||
|
||||
_print("Updating codebase to %s" % (v.public()))
|
||||
|
||||
for x in _path.walk():
|
||||
|
||||
if not x.isfile():
|
||||
continue
|
||||
|
||||
original_content = x.getContent()
|
||||
content = original_content
|
||||
|
||||
# Replace previous release_candidate calls to the new one
|
||||
if existing.release_candidate:
|
||||
content = content.replace(existing_version_repr_bytes, version_repr_bytes)
|
||||
content = content.replace(
|
||||
(package.encode("utf8") + b" " + existing.public().encode("utf8")),
|
||||
(package.encode("utf8") + b" " + v.public().encode("utf8")),
|
||||
)
|
||||
|
||||
# Replace NEXT Version calls with the new one
|
||||
content = content.replace(NEXT_repr_bytes, version_repr_bytes)
|
||||
content = content.replace(
|
||||
NEXT_repr_bytes.replace(b"'", b'"'), version_repr_bytes
|
||||
)
|
||||
|
||||
# Replace <package> NEXT with <package> <public>
|
||||
content = content.replace(
|
||||
package.encode("utf8") + b" NEXT",
|
||||
(package.encode("utf8") + b" " + v.public().encode("utf8")),
|
||||
)
|
||||
|
||||
if content != original_content:
|
||||
_print("Updating %s" % (x.path,))
|
||||
with x.open("w") as f:
|
||||
f.write(content)
|
||||
|
||||
_print("Updating %s/_version.py" % (_path.path))
|
||||
with _path.child("_version.py").open("w") as f:
|
||||
f.write(
|
||||
(
|
||||
_VERSIONPY_TEMPLATE.format(package=package, version_repr=version_repr)
|
||||
).encode("utf8")
|
||||
)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("package")
|
||||
@click.option("--path", default=None)
|
||||
@click.option("--newversion", default=None)
|
||||
@click.option("--patch", is_flag=True)
|
||||
@click.option("--rc", is_flag=True)
|
||||
@click.option("--post", is_flag=True)
|
||||
@click.option("--dev", is_flag=True)
|
||||
@click.option("--create", is_flag=True)
|
||||
def run(
|
||||
package, # type: str
|
||||
path, # type: Optional[str]
|
||||
newversion, # type: Optional[str]
|
||||
patch, # type: bool
|
||||
rc, # type: bool
|
||||
post, # type: bool
|
||||
dev, # type: bool
|
||||
create, # type: bool
|
||||
): # type: (...) -> None
|
||||
return _run(
|
||||
package=package,
|
||||
path=path,
|
||||
newversion=newversion,
|
||||
patch=patch,
|
||||
rc=rc,
|
||||
post=post,
|
||||
dev=dev,
|
||||
create=create,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
run()
|
||||
Reference in New Issue
Block a user