Code Monkey home page Code Monkey logo

python-semanticversion's Introduction

Introduction

This small python library provides a few tools to handle SemVer in Python. It follows strictly the 2.0.0 version of the SemVer scheme.

image

Latest Version

Supported Python versions

Wheel status

License

Getting started

Install the package from PyPI, using pip:

pip install semantic-version

Or from GitHub:

$ git clone git://github.com/rbarrois/python-semanticversion.git

Import it in your code:

import semantic_version

This module provides classes to handle semantic versions:

  • Version represents a version number (0.1.1-alpha+build.2012-05-15)
  • BaseSpec-derived classes represent requirement specifications (>=0.1.1,<0.3.0):
    • SimpleSpec describes a natural description syntax
    • NpmSpec is used for NPM-style range descriptions.

Versions

Defining a Version is quite simple:

>>> import semantic_version
>>> v = semantic_version.Version('0.1.1')
>>> v.major
0
>>> v.minor
1
>>> v.patch
1
>>> v.prerelease
[]
>>> v.build
[]
>>> list(v)
[0, 1, 1, [], []]

If the provided version string is invalid, a ValueError will be raised:

>>> semantic_version.Version('0.1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/rbarrois/dev/semantic_version/src/semantic_version/base.py", line 64, in __init__
    major, minor, patch, prerelease, build = self.parse(version_string, partial)
  File "/Users/rbarrois/dev/semantic_version/src/semantic_version/base.py", line 86, in parse
    raise ValueError('Invalid version string: %r' % version_string)
ValueError: Invalid version string: '0.1'

One may also create a Version with named components:

>>> semantic_version.Version(major=0, minor=1, patch=2)
Version('0.1.2')

In that case, major, minor and patch are mandatory, and must be integers. prerelease and build, if provided, must be tuples of strings:

>>> semantic_version.Version(major=0, minor=1, patch=2, prerelease=('alpha', '2'))
Version('0.1.2-alpha.2')

Some user-supplied input might not match the semantic version scheme. For such cases, the Version.coerce method will try to convert any version-like string into a valid semver version:

>>> Version.coerce('0')
Version('0.0.0')
>>> Version.coerce('0.1.2.3.4')
Version('0.1.2+3.4')
>>> Version.coerce('0.1.2a3')
Version('0.1.2-a3')

Working with versions

Obviously, versions can be compared:

>>> semantic_version.Version('0.1.1') < semantic_version.Version('0.1.2')
True
>>> semantic_version.Version('0.1.1') > semantic_version.Version('0.1.1-alpha')
True
>>> semantic_version.Version('0.1.1') <= semantic_version.Version('0.1.1-alpha')
False

You can also get a new version that represents a bump in one of the version levels:

>>> v = semantic_version.Version('0.1.1+build')
>>> new_v = v.next_major()
>>> str(new_v)
'1.0.0'
>>> v = semantic_version.Version('1.1.1+build')
>>> new_v = v.next_minor()
>>> str(new_v)
'1.2.0'
>>> v = semantic_version.Version('1.1.1+build')
>>> new_v = v.next_patch()
>>> str(new_v)
'1.1.2'

Requirement specification

python-semanticversion provides a couple of ways to describe a range of accepted versions:

  • The SimpleSpec class provides a simple, easily understood scheme --somewhat inspired from PyPI range notations;
  • The NpmSpec class supports the whole NPM range specification scheme:

    >>> Version('0.1.2') in NpmSpec('0.1.0-alpha.2 .. 0.2.4')
    True
    >>> Version('0.1.2') in NpmSpec('>=0.1.1 <0.1.3 || 2.x')
    True
    >>> Version('2.3.4') in NpmSpec('>=0.1.1 <0.1.3 || 2.x')
    True

The SimpleSpec scheme

Basic usage is simply a comparator and a base version:

>>> s = SimpleSpec('>=0.1.1')  # At least 0.1.1
>>> s.match(Version('0.1.1'))
True
>>> s.match(Version('0.1.1-alpha1'))  # pre-release doesn't satisfy version spec
False
>>> s.match(Version('0.1.0'))
False

Combining specifications can be expressed as follows:

>>> SimpleSpec('>=0.1.1,<0.3.0')

Simpler test syntax is also available using the in keyword:

>>> s = SimpleSpec('==0.1.1')
>>> Version('0.1.1+git7ccc72') in s  # build variants are equivalent to full versions
True
>>> Version('0.1.1-alpha1') in s     # pre-release variants don't match the full version.
False
>>> Version('0.1.2') in s
False

Refer to the full documentation at https://python-semanticversion.readthedocs.io/en/latest/ for more details on the SimpleSpec scheme.

Using a specification

The SimpleSpec.filter method filters an iterable of Version:

>>> s = SimpleSpec('>=0.1.0,<0.4.0')
>>> versions = (Version('0.%d.0' % i) for i in range(6))
>>> for v in s.filter(versions):
...     print v
0.1.0
0.2.0
0.3.0

It is also possible to select the 'best' version from such iterables:

>>> s = SimpleSpec('>=0.1.0,<0.4.0')
>>> versions = (Version('0.%d.0' % i) for i in range(6))
>>> s.select(versions)
Version('0.3.0')

Contributing

In order to contribute to the source code:

When submitting patches or pull requests, you should respect the following rules:

  • Coding conventions are based on 8
  • The whole test suite must pass after adding the changes
  • The test coverage for a new feature must be 100%
  • New features and methods should be documented in the reference section and included in the changelog
  • Include your name in the contributors section

Note

All files should contain the following header:

# -*- encoding: utf-8 -*-
# Copyright (c) The python-semanticversion project

python-semanticversion's People

Contributors

ahogen avatar dankolbman avatar edwardbetts avatar ekmartin avatar hugorodgerbrown avatar jasongraham avatar kgbaird avatar marcelometal avatar mhrivnak avatar minchinweb avatar pombredanne avatar rbarrois avatar rickeyre avatar skwashd avatar tdamsma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-semanticversion's Issues

Version.__repr__ does not respect subclasses

The current __repr__ implementation hard codes Version as the class name. This means any subclasses will be represented with Version instead of their class name. Would it be feasible to change this so the class name was shown instead of the hard coded Version.

I'm willing to work on this, and in fact, already have a commit staged up in a fork, if this change is acceptable.

Issue moving from 2.2.1 to 2.2.2 OSX Mavericks

I was able to install 2.2.1 fine, but had this issue when installing 2.2.2.

  Downloading semantic_version-2.2.2.tar.gz
  Running setup.py egg_info for package semantic-version
    Traceback (most recent call last):
      File "<string>", line 16, in <module>
      File "/private/tmp/pip_build_root/semantic-version/setup.py", line 58, in <module>
        test_suite='tests',
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/distutils/core.py", line 112, in setup
        _setup_distribution = dist = klass(attrs)
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/setuptools/dist.py", line 260, in __init__
        self.fetch_build_eggs(attrs.pop('setup_requires'))
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/setuptools/dist.py", line 284, in fetch_build_eggs
        parse_requirements(requires), installer=self.fetch_build_egg
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/pkg_resources.py", line 569, in resolve
        raise VersionConflict(dist,req) # XXX put more info here
    pkg_resources.VersionConflict: (setuptools 0.6c12dev-r88846 (/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python), Requirement.parse('setuptools>=0.8'))
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 16, in <module>

  File "/private/tmp/pip_build_root/semantic-version/setup.py", line 58, in <module>

    test_suite='tests',

  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/distutils/core.py", line 112, in setup

    _setup_distribution = dist = klass(attrs)

  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/setuptools/dist.py", line 260, in __init__

    self.fetch_build_eggs(attrs.pop('setup_requires'))

  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/setuptools/dist.py", line 284, in fetch_build_eggs

    parse_requirements(requires), installer=self.fetch_build_egg

  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/pkg_resources.py", line 569, in resolve

    raise VersionConflict(dist,req) # XXX put more info here

pkg_resources.VersionConflict: (setuptools 0.6c12dev-r88846 (/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python), Requirement.parse('setuptools>=0.8'))

----------------------------------------
Cleaning up...

What API specification?

What specification of semantic version is valid for your module?
v2.0.0 v2.0.0-rc.2 v2.0.0-rc.1

Thanks for the great project.

Version bump from prereleases not working as expected

I was expecting that a prerelease version, when bumped, would go up to the 'full' or release version without bumping the main version number if not needed.

Probably makes more sense if I give examples.

What I expected:

1.0.0-dev --[major]--> 1.0.0
1.0.1-dev --[major]--> 2.0.0
1.1.0-dev --[major]--> 2.0.0

1.0.0-dev --[minor]--> 1.0.0
1.0.1-dev --[minor]--> 1.1.0
1.1.0-dev --[minor]--> 1.1.0

1.0.0-dev --[patch]--> 1.0.0
1.0.1-dev --[patch]--> 1.0.1
1.1.0-dev --[patch]--> 1.1.0

What currently happens:

1.0.0-dev --[major]--> 2.0.0
1.0.1-dev --[major]--> 2.0.0
1.1.0-dev --[major]--> 2.0.0

1.0.0-dev --[minor]--> 1.1.0
1.0.1-dev --[minor]--> 1.1.0
1.1.0-dev --[minor]--> 1.2.0

1.0.0-dev --[patch]--> 1.0.1
1.0.1-dev --[patch]--> 1.0.2
1.1.0-dev --[patch]--> 1.1.1

If this a bug in the implementation, or have I missed something in the spec? Thanks!

2ed3d39 causes previously working specifications to fail to parse

The fix for #18 (2ed3d39) now causes specifications like: >=1.0.0+somebuild to fail to parse (ValueError: Invalid requirement specification <whatever>: build numbers have no ordering.).

I'd suggest that the correct behaviour would be to treat >=1.0.0+whatever as equivalent to >=1.0.0. For example:

>1.0.0+somebuild would match: 1.0.1, would not match: 1.0.0+somebuild or 1.0.0+somethingelse

>=1.0.0+something would match: 1.0.0, 1.0.0+something and 1.0.0+somethingelse

Construct Version objects from tuples

It would be useful to be able to do the following:

import semantic_version as sv
version = sv.Version((1,0,0))

I would be willing to take on a PR for this feature myself, if it seems reasonable.

Spec doesn't select expected version

Hi, I found that it would be nice to support the following case

In [64]: sv.Spec('>0.8.0').select([sv.Version('0.8.1')])
Out[64]: 
Version('0.8.1')

In [65]: sv.Spec('>0.8').select([sv.Version('0.8.1')])
# Expected to get 0.8.1 but it returns None

I know there is version coercing, maybe we need to do the same coercing to the one in the spec ?

Thanks

next_patch

v1 = semantic_version.Version('1.1.1-pre+build')
v2 = v1.next_patch()
str(v2)
'1.1.1'

semver spec violation for versions with build metadata

According to semver 2.0.0, spec rule number 10, two versions that differ only in build metadata should have the same precedence. However, cmp of two such versions returns non-zero:

$ python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from semantic_version import Version
>>> cmp(Version('1.0.0'), Version('1.0.0+build'))
-1

I almost started working on a fix and pull request, but it looks from pydoc in the code that this might be intentional?

TypeError on matching to Spec('~1')

I can make a specifier with '~1' but when doing a match or select on it, it causes a TypeError. I tried to provide the relevant details below, thanks!

Successfully installed semantic-version-2.6.0
(sv) awc:env$ python3
Python 3.6.8 (default, Jan 27 2019, 09:00:23)
[GCC 8.2.1 20181215 (Red Hat 8.2.1-6)] on linux
Type "help", "copyright", "credits" or "license" for more information.                                  
>>> import semantic_version
>>> v = semantic_version.Version('1.1.2')
>>> s_major = semantic_version.Spec('~1')
>>> s_minor = semantic_version.Spec('~1.1')
>>> s_minor.match(v)
True
>>> s_major.match(v)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/awc/code/env/sv/lib/python3.6/site-packages/semantic_version/base.py", line 515, in match
    return all(spec.match(version) for spec in self.specs)
  File "/home/awc/code/env/sv/lib/python3.6/site-packages/semantic_version/base.py", line 515, in <genexpr>
    return all(spec.match(version) for spec in self.specs)
  File "/home/awc/code/env/sv/lib/python3.6/site-packages/semantic_version/base.py", line 478, in match
    return self.spec <= version < self.spec.next_minor()
  File "/home/awc/code/env/sv/lib/python3.6/site-packages/semantic_version/base.py", line 104, in next_minor
    '.'.join(str(x) for x in [self.major, self.minor + 1, 0]))
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
>>> s_major
<Spec: (<SpecItem: ~ Version('1', partial=True)>,)>

Missing CREDITS file in tarball

I'm packaging python-semanticversion for Fedora, and documentation fails to build due to docs/credits.rst being a symbolic link to CREDITS which is not shipped in 2.3.1 tarball.

It's not critical, but packagers would be grateful if you fix it in the next release :)

Specs are separated using commas instead of spaces

We are currently writing an API for which will be accessed with PHP and/or JS. Both have a semver package that supports ranges, however they split the ranges using spaces rather than spaces, e.g.

>=1.2.3 <2.0.0

and not

>=1.2.3,<2.0.0

AFAIK ranges are not part of semver, but it would be awesome to be compatible.

There are two ways I can think of fixing this:

  • Simply replace the comma with a space which would be backwards incompatible but cleaner, or
  • When instantiating a Spec we check if the string contains a comma and save it in a bool attribute. When parsing the version and serializing back to a string we would inspect the flag and use a comma or space. This approach would be backwards compatible but not as nice :)

I could create a PR if you want, it seems these are the only lines that have to be adjusted:

What do you think?

Related:

Implicit version comparison with strings

This seems like a cool project and I'd like to include it in a project I'm working on. Is there any chance you'd be willing to support implicit comparison of Version and Spec objects with string types? For example, I'd like the following cases to work:

import semantic_version as sv
assert sv.Version('1.0.0') == '1.0.0'

spec = sv.Spec('>=2.0.0')
assert spec.match('2.1.0')

It's less important, but I also think this would be useful with tuples:

assert sv.Version('1.0.0') == (1,0,0)

It doesn't seem like this would be very difficult or unreasonable to support. I'd be willing to submit a PR myself.

Cannot create partial versions

If I pass '2.0' to the Version constructor, I get a ValueError regardless of whether I specified partial=True or not. I suspect that this is because version_re and partial_version_re are completely identical.

If this is intended behavior, then the documentation should be fixed to reflect that.

Select version excluding prerelease

I would like to filter and match 'best' stable version.

Current behavior:

versions = [1.0.0, 1.1.0, 1.2.0-pre]
s = Spec(">=1.0.0")
s.select(versions)
Out: Version('1.2.0-pre')

I would expect pre-releases to be exclude unless explicitly ask for.

Expected behavior:

s = Spec(">=1.0.0-")    # with a '-'
s.select(versions)
Out: Version('1.2.0-pre')

s = Spec(">=1.0.0")
Out: Version('1.1.0')

isValid(version) for public API

catching the ValueError of, let's say Version('we12we.12we.23'), doesn't seem to be very performant
so maybe you could add a similar implementation of the following code to the public API?

def isValid(version):
    try:
        Version(version)
    except ValueError:
        return False
    return True

.x versioning is not supported

According to NPM semver documentation .x behaviour is supposed to act like:

Patch releases: 1.0 or 1.0.x or ~1.0.4
Minor releases: 1 or 1.x or ^1.0.4
Major releases: * or x

However Spec class doesn't parse versions with 'x' instead of a digit

API for bumping versions

What would you think of something like:

version.bump_major()
version.bump_minor()
version.bump_patch()

Each of these would reset any lower levels in the versioning 'hierarchy'. So running version.bump_major() on 1.0.0-prerelease+build would result in 2.0.0.

specify utf-8 encoding in setup.py

When the module is being setup, you are defaulting to system-level encoding, which can sometimes be ascii, which fails when it parses the non-ascii character here: https://github.com/rbarrois/python-semanticversion/blob/master/semantic_version/__init__.py#L6.

Traceback (most recent call last): File "", line 17, in File "/sites/preprod/.virtual_python/build/semantic-version/setup.py", line 31, in version=get_version(PACKAGE), File "/sites/preprod/.virtual_python/build/semantic-version/setup.py", line 19, in get_version for line in f: File "/sites/preprod/.virtual_python/lib/python3.3/encodings/ascii.py", line 26, in decode return codecs.ascii_decode(input, self.errors)[0] UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 167: ordinal not in range(128) Complete output from command python setup.py egg_info: Traceback (most recent call last): File "", line 17, in File "/sites/preprod/.virtual_python/build/semantic-version/setup.py", line 31, in version=get_version(PACKAGE), File "/sites/preprod/.virtual_python/build/semantic-version/setup.py", line 19, in get_version for line in f: File "/sites/preprod/.virtual_python/lib/python3.3/encodings/ascii.py", line 26, in decode return codecs.ascii_decode(input, self.errors)[0] UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 167: ordinal not in range(128)

This is probably what you wanna do before parsing files in setup.py:

import sys
sys.setdefaultencoding("UTF-8")

An alternative fix is to set
LANG="en_us.UTF-8"
in .bashrc of the user that does the pip install

Partial version comparison

Shouldn't partial versions be compared too?
At the moment Version('1.0', partial=True) == Version('1.0.5', partial=True) is True.

django unit tests are broken

It appears that when django 1.7 or newer is installed, some unit tests have errors. I tested with 1.4.20, 1.5.12, and 1.6.11 which all pass.

Examples below are using a fresh python 2.7.9 virtualenv, with the stated django version, and South==1.0.2

On 1.7.8, this happens:

======================================================================
ERROR: setUpClass (tests.test_django.DbInteractingTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/mhrivnak/git/python-semanticversion/tests/test_django.py", line 182, in setUpClass
    cls.old_state = DjangoTestSuiteRunner().setup_databases()
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/test/runner.py", line 109, in setup_databases
    return setup_databases(self.verbosity, self.interactive, **kwargs)
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/test/runner.py", line 299, in setup_databases
    serialize=connection.settings_dict.get("TEST", {}).get("SERIALIZE", True),
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/db/backends/creation.py", line 377, in create_test_db
    test_flush=True,
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 93, in call_command
    app_name = get_commands()[name]
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/utils/lru_cache.py", line 101, in wrapper
    result = user_function(*args, **kwds)
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 73, in get_commands
    for app_config in reversed(list(apps.get_app_configs())):
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 137, in get_app_configs
    self.check_apps_ready()
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 124, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
AppRegistryNotReady: Apps aren't loaded yet.

======================================================================
ERROR: test_serialization (tests.test_django.DjangoFieldTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/mhrivnak/git/python-semanticversion/tests/test_django.py", line 97, in test_serialization
    obj1, obj2 = serializers.deserialize('json', data)
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/json.py", line 81, in Deserializer
    six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/json.py", line 75, in Deserializer
    for obj in PythonDeserializer(objects, **options):
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/python.py", line 93, in Deserializer
    Model = _get_model(d["model"])
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/python.py", line 156, in _get_model
    return apps.get_model(model_identifier)
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 199, in get_model
    self.check_models_ready()
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 131, in check_models_ready
    raise AppRegistryNotReady("Models aren't loaded yet.")
DeserializationError: Models aren't loaded yet.

======================================================================
ERROR: test_serialization_partial (tests.test_django.DjangoFieldTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/mhrivnak/git/python-semanticversion/tests/test_django.py", line 109, in test_serialization_partial
    obj1, obj2 = serializers.deserialize('json', data)
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/json.py", line 81, in Deserializer
    six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/json.py", line 75, in Deserializer
    for obj in PythonDeserializer(objects, **options):
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/python.py", line 93, in Deserializer
    Model = _get_model(d["model"])
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/core/serializers/python.py", line 156, in _get_model
    return apps.get_model(model_identifier)
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 199, in get_model
    self.check_models_ready()
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 131, in check_models_ready
    raise AppRegistryNotReady("Models aren't loaded yet.")
DeserializationError: Models aren't loaded yet.

======================================================================
ERROR: test_freezing_app (tests.test_django.SouthTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/mhrivnak/git/python-semanticversion/tests/test_django.py", line 147, in test_freezing_app
    frozen = south.creator.freezer.freeze_apps('django_test_app')
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/south/creator/freezer.py", line 26, in freeze_apps
    for model in models.get_models(models.get_app(app)):
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/db/models/__init__.py", line 54, in alias
    return getattr(loading, function_name)(*args, **kwargs)
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 372, in get_app
    models_module = self.get_app_config(app_label).models_module
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 146, in get_app_config
    self.check_apps_ready()
  File "/home/mhrivnak/pythons/semver-d17/local/lib/python2.7/site-packages/django/apps/registry.py", line 124, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
AppRegistryNotReady: Apps aren't loaded yet.

----------------------------------------------------------------------
Ran 57 tests in 0.027s

FAILED (errors=4, skipped=1)

And on 1.8.2, this...

$ python setup.py test
running test
running egg_info
writing semantic_version.egg-info/PKG-INFO
writing top-level names to semantic_version.egg-info/top_level.txt
writing dependency_links to semantic_version.egg-info/dependency_links.txt
reading manifest file 'semantic_version.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
no previously-included directories found matching 'docs/_build'
writing manifest file 'semantic_version.egg-info/SOURCES.txt'
running build_ext
Traceback (most recent call last):
  File "setup.py", line 58, in <module>
    test_suite='tests',
  File "/usr/lib/python2.7/distutils/core.py", line 151, in setup
    dist.run_commands()
  File "/usr/lib/python2.7/distutils/dist.py", line 953, in run_commands
    self.run_command(cmd)
  File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/home/mhrivnak/pythons/semver/local/lib/python2.7/site-packages/setuptools/command/test.py", line 142, in run
    self.with_project_on_sys_path(self.run_tests)
  File "/home/mhrivnak/pythons/semver/local/lib/python2.7/site-packages/setuptools/command/test.py", line 122, in with_project_on_sys_path
    func()
  File "/home/mhrivnak/pythons/semver/local/lib/python2.7/site-packages/setuptools/command/test.py", line 163, in run_tests
    testRunner=self._resolve_as_ep(self.test_runner),
  File "/usr/lib/python2.7/unittest/main.py", line 94, in __init__
    self.parseArgs(argv)
  File "/usr/lib/python2.7/unittest/main.py", line 149, in parseArgs
    self.createTests()
  File "/usr/lib/python2.7/unittest/main.py", line 158, in createTests
    self.module)
  File "/usr/lib/python2.7/unittest/loader.py", line 130, in loadTestsFromNames
    suites = [self.loadTestsFromName(name, module) for name in names]
  File "/usr/lib/python2.7/unittest/loader.py", line 103, in loadTestsFromName
    return self.loadTestsFromModule(obj)
  File "/home/mhrivnak/pythons/semver/local/lib/python2.7/site-packages/setuptools/command/test.py", line 37, in loadTestsFromModule
    tests.append(self.loadTestsFromName(submodule))
  File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
    parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'test_django'

The problem on 1.8.2 appears to be the result of this import failing: https://github.com/rbarrois/python-semanticversion/blob/v2.4.1/tests/test_django.py#L176

That class was removed as of django 1.8: https://docs.djangoproject.com/en/1.8/releases/1.8/

If you fix that import to instead use django.test.runner.DiscoverRunner, then the same errors from 1.7.8 appear.

Whitespace in specifications

PEP 0440 states the following:

Whitespace between a conditional operator and the following version identifier is optional, as is the whitespace around the commas.

However, currently the following fails:

Spec('== 1.4.0') # ValueError

Incorrect matching when using `partial` keyword argument in `Version`

Python versions: 3.7.4 and 3.6.9
OS: Windows 10

I've found interesting behavior in version 2.8.1 which I believe is a bug.

>>> # Expected, good
>>> Version("1.0.0") in Spec("==1.0.0")
True
>>> Version("1.0.0") in Spec("!=1.0.0")
False

>>> # Unexpected, probably a bug
>>> # Expected that these would match above without partial
>>> Version("1.0.0", partial=True) in Spec("==1.0.0")
True
>>> Version("1.0.0", partial=True) in Spec("!=1.0.0")
True

>>> # Unexpected, probably a bug
>>> # Expected that these would match above without partial
>>> Version("1", partial=True) in Spec("==1.0.0")
False
>>> Version("1", partial=True) in Spec("!=1.0.0")
True

In version 2.6.0, the partial keyword argument seemed to add missing minor / patch numbers as 0. It seems to be doing something different now.

>>> Version("1.0.0") == Version("1.0.0", partial=True)
True
>>> Version("1.0.0") != Version("1.0.0", partial=True)
True
>>> Version("1.0.0") == Version("1", partial=True)
False

Version comparison bug

Hi,

I created an arbitrary version and have found bug. None of these come to true. I would assume that a>b has an outcome as True

import semantic_version
a = semantic_version.Version.coerce('0.1.2.3.4.3-beta4.5.6.7-alpha')
b = semantic_version.Version('0.1.2')
print(a > b) # False
print(a < b) # False
print(a ==b) # False

Proposal: PEP 440 compatible type

PEP 440 allows version strings like this: 0.1b2.dev3. it would be neat to have the Version class and the validate function would support these when passed an option to parse with regards to that syntax.

[RFE] support for wildcard kind

rust utilizes wildcard in away:

* := >=0.0.0
1.* := >=1.0.0 <2.0.0
1.2.* := >=1.2.0 <1.3.0

it's definitely possible to workaround on my side, but would be very cool enhancement!

And thanks for making this library!

Accept versions with a 'v' prefix

A common convention I have seen across various projects is to prefix the semantic version string with a v (e.g. v1.2.3). I was wondering if there would be interest in supporting it here. I would believe the scope to be fairly limited (allow users to specify strings prefixed with v when instantiating and make the str of the Version class include a v prefix, if appropriate).

I respect this deviates from the semver standards and would understand if you declined the request. I was unsure how you were balancing strictly following the semver standards versus user convenience in this library.

The development team at my employer uses this library a ton and has adapted the current version to accept v prefixes. We would be willing to share our implementation if there was an appetite for supporting this customization, but are, of course, open to other implementations and suggestions.

Thank you again for all of your work on this project. We have found it very useful and use it almost everywhere.

Version 2.7 broke compatibility

Ironically, semver library does not follow semver. For example, removing specs property from Spec broke compatibility with version 2.6. Please, introduce breaking changes with major bump only.

Ordering of Fields in Django Field

Hello

1 - Create a Django model containing a VersionField, and insert values with different versions

2 - Use an order_by clause ordering by the VersionField field

3 - The ordering is done as text, not as version numbers

One example of ordering (this is with reverse ordering): [Version('1.2.3'), Version('1.10.3'), Version('1.0.3')]

Regards

Optional VersionField that is null breaks Django ORM on retrieval

Hi there - running on Django 1.8. I have a model that has an optional VersionField (null=True, blank=True). If I save the model, I can see in the database that the value is stored as the string 'None', which then subsequently fails on rehydration:

Traceback (most recent call last):
  File "/Projects/python-semanticversion/tests/test_django.py", line 56, in test_null_version
    self.assertRaises(ValueError, models.PartialVersionModel.objects.get(id=obj.id))
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/query.py", line 328, in get
    num = len(clone)
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/query.py", line 144, in __len__
    self._fetch_all()
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/query.py", line 965, in _fetch_all
    self._result_cache = list(self.iterator())
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/query.py", line 255, in iterator
    obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end])
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/base.py", line 489, in from_db
    new = cls(*values)
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/base.py", line 410, in __init__
    setattr(self, field.attname, val)
  File "/Users/hugo/.virtualenvs/semver/lib/python2.7/site-packages/django/db/models/fields/subclassing.py", line 44, in __set__
    obj.__dict__[self.field.name] = self.field.to_python(value)
  File "/Users/hugo/Projects/src/github.com/yunojuno/python-semanticversion/semantic_version/django_fields.py", line 61, in to_python
    return base.Version(value, partial=self.partial)
  File "/Users/hugo/Projects/src/github.com/yunojuno/python-semanticversion/semantic_version/base.py", line 75, in __init__
    major, minor, patch, prerelease, build = self.parse(version_string, partial)
  File "/Users/hugo/Projects/src/github.com/yunojuno/python-semanticversion/semantic_version/base.py", line 192, in parse
    raise ValueError('Invalid version string: %r' % version_string)
ValueError: Invalid version string: u'None'

You can test this with the following test:

def test_optional_field(self):
    """Test storing a null value in optional VersionField."""
    obj = models.PartialVersionModel()
    obj.save()
    self.assertIsNone(obj.optional)
    self.assertRaises(ValueError, models.PartialVersionModel.objects.get, id=obj.id)

This makes some sense, as the VersionField.to_python method doesn't check for 'None':

def to_python(self, value):
    """Converts any value to a base.Version field."""
    if value is None or value == '':
        return value
    if isinstance(value, base.Version):
        return value
    if self.coerce:
        return base.Version.coerce(value, partial=self.partial)
    else:
        return base.Version(value, partial=self.partial)

Possibly looking at the BaseSemVerField.get_prep_value method, which just str's the object value:

def get_prep_value(self, obj):
    return str(obj)

This would turn None into 'None'

SubfieldBase will be removed in Django 1.10

Warnings upon launching a Django 1.9.5 project using semantic_version:

/<snipped>/.venv/lib/python3.5/site-packages/semantic_version/django_fields.py:38: RemovedInDjango110Warning: SubfieldBase has been deprecated. Use Field.from_db_value instead.
  str('SemVerField'), (BaseSemVerField, models.CharField), {})

/<snipped>/.venv/lib/python3.5/site-packages/semantic_version/django_fields.py:41: RemovedInDjango110Warning: SubfieldBase has been deprecated. Use Field.from_db_value instead.
  class VersionField(SemVerField):

/<snipped>/.venv/lib/python3.5/site-packages/semantic_version/django_fields.py:64: RemovedInDjango110Warning: SubfieldBase has been deprecated. Use Field.from_db_value instead.
  class SpecField(SemVerField):

It looks like the solution is to remove __metaclass__ and manually define the to/from Python methods: https://stackoverflow.com/questions/35166085/how-to-deal-with-subfieldbase-has-been-deprecated-use-field-from-db-value-inst

Spec(`~=1.1.0`) matches Version(`1.2.0-foobar`)

I would expect this to return False, but when comparing the versions mentioned in the title, I'm getting a True result. Is my interpretation of the rules incorrect, or is this a bug?

Example:

>>> semantic_version.match('~=1.1.0', '1.2.0-foobar')
True

Comparison is broken for partials

I'm getting wrong results comparing versions using partials :

print semantic_version.Version('1.2.0-beta', partial=True) >  semantic_version.Version('1.2.0', partial=True)
print semantic_version.Version('1.2.0-beta', partial=True) <  semantic_version.Version('1.2.0', partial=True)
print semantic_version.Version('1.2.0-beta', partial=True) == semantic_version.Version('1.2.0', partial=True)

print semantic_version.Version('1.2-beta', partial=True) >  semantic_version.Version('1.2', partial=True)
print semantic_version.Version('1.2-beta', partial=True) <  semantic_version.Version('1.2', partial=True)
print semantic_version.Version('1.2-beta', partial=True) == semantic_version.Version('1.2', partial=True)

print semantic_version.Version('1.2.0-beta') >  semantic_version.Version('1.2.0')
print semantic_version.Version('1.2.0-beta') <  semantic_version.Version('1.2.0')
print semantic_version.Version('1.2.0-beta') == semantic_version.Version('1.2.0')

False
False
True

False
False
True

False
True
False

Support npm/composer extensions?

npm and composer support the use of tilde (~) and caret (^) in version requirements. Would you accept a well written and tested patch that implements support for this in comparisons?

bug in pypi package for v2.2.1

I'm not really sure who is responsible for patching packages in pypi so I am going to start by posting the bug here. The semantic_version package for v2.2.1 contained in pypi has a symbolic link from ChangeLog at the top level to doc/changelog.rst but there is no doc/ directory in the package so I get the warning message,

In the tar file /tmp/pip-BEK853-unpack/semantic_version-2.2.1.tar.gz the member semantic_version-2.2.1/ChangeLog is invalid: "linkname 'semantic_version-2.2.1/doc/changelog.rst' not found"

This does not prevent the package from being installed but it would be nice to not have this message displayed.

Carat ^ matching is not compatible with NPM prerelease exclusion

The current carat match algorithm matches pre-release versions (-alpha, -beta). NPM only considers those versions which are not pre-releases. Given that the carat match was added explicitly to mirror the NPM extension, it seems like identical behavior is desired.

For example, search for the "babel" package from semver and then use "^5.0.0" as the search term. None of the 5.0.0-betas are selected. Using python-semanticversion, they would match.

To fix this will require adjusting existing tests -- and therefore potentially breaking existing behavior.

Possibly another breaking change between 2.6.0 and 2.7.0 (not fixed in 2.8.1)

I'm currently investigating a problem in an application of mime which works fine with 2.6.0 and breaks with 2.7.0 and later versions including 2.8.1.
The exception I get is (with 2.8.1):

s1:4: DeprecationWarning: Partial versions will be removed in 3.0; use SimpleSpec('1.x.x') instead.
  version_obj = semantic_version.Version(version, partial=True)
Traceback (most recent call last):
  File "s1", line 5, in <module>
    if version_obj not in supported:
  File "venv/lib64/python3.7/site-packages/semantic_version/base.py", line 642, in __contains__
    return self.match(version)
  File "venv/lib64/python3.7/site-packages/semantic_version/base.py", line 630, in match
    return self.clause.match(version)
  File "venv/lib64/python3.7/site-packages/semantic_version/base.py", line 745, in match
    return all(clause.match(version) for clause in self.clauses)
  File "venv/lib64/python3.7/site-packages/semantic_version/base.py", line 745, in <genexpr>
    return all(clause.match(version) for clause in self.clauses)
  File "venv/lib64/python3.7/site-packages/semantic_version/base.py", line 910, in match
    return version >= self.target
  File "venv/lib64/python3.7/site-packages/semantic_version/base.py", line 467, in __ge__
    return self.precedence_key >= other.precedence_key
TypeError: '>=' not supported between instances of 'NoneType' and 'int'

Here is a code snippet to reproduce the issue:

import semantic_version
supported=semantic_version.Spec('>=1,<2')
version = '1'
version_obj = semantic_version.Version(version, partial=True)
if version_obj not in supported:
  raise RuntimeError('Configuration has unsupported version of "{}".'.format(version))

It obviously has something to do with the partial version specification and it's possible that I'm not using semantic-version correctly.

next_major() bug when minor=0 and patch=0 and prerelease is not none

Hi,

I think there is a bug in next_major() function when certain conditions are met:

In [32]: semantic_version.Version("3.0.0").next_major()
Out[32]: Version('4.0.0') # Correct

In [33]: semantic_version.Version("3.0-slim",partial=True).next_major()
Out[33]: Version('4.0.0') # Correct

In [34]: semantic_version.Version("3.0",partial=True).next_major()
Out[34]: Version('4.0.0') # Correct

In [31]: semantic_version.Version("3.0.0-slim").next_major()
Out[31]: Version('3.0.0') # WRONG - should be 4.0.0

In [35]: v = semantic_version.Version("3.0.0-slim")
In [36]: v.prerelease = None
In [37]: v.next_major()
Out[37]: Version('4.0.0') # Correct

Is it really a bug or am I missing something?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.