diff options
author | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2013-03-20 02:02:26 +0100 |
---|---|---|
committer | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2013-03-20 02:02:26 +0100 |
commit | 712d74f87c07c60f2e1d27b44915d5d4bb941fe7 (patch) | |
tree | c0263f7f74b56895fb6b36fd89316a61238cd795 /src | |
parent | f84d754af1ae86aaa9a891445d6ae5be36668a85 (diff) | |
download | semantic-version-712d74f87c07c60f2e1d27b44915d5d4bb941fe7.tar.gz |
Add Version.coerce.
Some people don't use semver yet...
Diffstat (limited to 'src')
-rw-r--r-- | src/semantic_version/base.py | 80 | ||||
-rw-r--r-- | src/semantic_version/django_fields.py | 11 |
2 files changed, 88 insertions, 3 deletions
diff --git a/src/semantic_version/base.py b/src/semantic_version/base.py index b8e7fcf..b52c671 100644 --- a/src/semantic_version/base.py +++ b/src/semantic_version/base.py @@ -78,7 +78,85 @@ class Version(object): return int(value) @classmethod - def parse(cls, version_string, partial=False): + def coerce(cls, version_string, partial=False): + """Coerce an arbitrary version string into a semver-compatible one. + + The rule is: + - If not enough components, fill minor/patch with zeroes; unless + partial=True + - If more than 3 dot-separated components, extra components are "build" + data. If some "build" data already appeared, append it to the + extra components + + Examples: + >>> Version.coerce('0.1') + Version(0, 1, 0) + >>> Version.coerce('0.1.2.3') + Version(0, 1, 2, (), ('3',)) + >>> Version.coerce('0.1.2.3+4') + Version(0, 1, 2, (), ('3', '4')) + >>> Version.coerce('0.1+2-3+4_5') + Version(0, 1, 0, (), ('2-3', '4-5')) + """ + base_re = re.compile(r'^\d+(?:\.\d+(?:\.\d+)?)?') + + match = base_re.match(version_string) + if not match: + raise ValueError("Version string lacks a numerical component: %r" + % version_string) + + version = version_string[:match.end()] + if not partial: + # We need a not-partial version. + while version.count('.') < 2: + version += '.0' + + if match.end() == len(version_string): + return Version(version, partial=partial) + + rest = version_string[match.end():] + + # Cleanup the 'rest' + rest = re.sub(r'[^a-zA-Z0-9+.-]', '-', rest) + + if rest[0] == '+': + # A 'build' component + prerelease = '' + build = rest[1:] + elif rest[0] == '.': + # An extra version component, probably 'build' + prerelease = '' + build = rest[1:] + elif rest[0] == '-': + rest = rest[1:] + if '+' in rest: + prerelease, build = rest.split('+', 1) + else: + prerelease, build = rest, '' + elif '+' in rest: + prerelease, build = rest.split('+', 1) + else: + prerelease, build = rest, '' + + build = build.replace('+', '.') + + if prerelease: + version = '%s-%s' % (version, prerelease) + if build: + version = '%s+%s' % (version, build) + + return cls(version, partial=partial) + + @classmethod + def parse(cls, version_string, partial=False, coerce=False): + """Parse a version string into a Version() object. + + Args: + version_string (str), the version string to parse + partial (bool), whether to accept incomplete input + coerce (bool), whether to try to map the passed in string into a + valid Version. + """ if not version_string: raise ValueError('Invalid empty version string: %r' % version_string) diff --git a/src/semantic_version/django_fields.py b/src/semantic_version/django_fields.py index ecc0a8f..eaf668a 100644 --- a/src/semantic_version/django_fields.py +++ b/src/semantic_version/django_fields.py @@ -38,6 +38,7 @@ class VersionField(BaseSemVerField): def __init__(self, *args, **kwargs): self.partial = kwargs.pop('partial', False) + self.coerce = kwargs.pop('coerce', False) super(VersionField, self).__init__(*args, **kwargs) def to_python(self, value): @@ -46,7 +47,10 @@ class VersionField(BaseSemVerField): return value if isinstance(value, base.Version): return value - return base.Version(value, partial=self.partial) + if self.coerce: + return base.Version.coerce(value, partial=self.partial) + else: + return base.Version(value, partial=self.partial) class SpecField(BaseSemVerField): @@ -71,7 +75,10 @@ def add_south_rules(): ( (VersionField,), [], - {'partial': ('partial', {'default': False})}, + { + 'partial': ('partial', {'default': False}), + 'coerce': ('coerce', {'default': False}), + }, ), ], ["semantic_version\.django_fields"]) |