Skip to content
Browse files

Remove SpecItem.

Signed-off-by: Raphaël Barrois <raphael.barrois@polytechnique.org>
  • Loading branch information...
1 parent 8b6a0e4 commit caa1c01858be241bf2a726c780c2f7e8174ecff2 @rbarrois committed May 21, 2012
View
3 README
@@ -40,8 +40,7 @@ Define a simple specification::
Define complex specifications::
- >>> from semantic_version import SpecList
- >>> s = SpecList('>=0.1.1,<0.2.0')
+ >>> s = Spec('>=0.1.1,<0.2.0')
>>> Version('0.1.2') in s
True
>>> Version('0.3.0') in s
View
5 doc/changelog.rst
@@ -1,14 +1,15 @@
ChangeLog
=========
-1.3.0 (Master)
+2.0.0 (Master)
--------------
*Backwards incompatible changes:*
* Removed "loose" specification support
* Cleanup :class:`~semantic_version.Spec` to be more intuitive.
- * Rename Spec to SpecItem and SpecList to Spec.
+ * Merge Spec and SpecList into :class:`~semantic_version.Spec`.
+ * Remove :class:`~semantic_version.django_fields.SpecListField`
1.2.0 (18/05/2012)
------------------
View
8 doc/django.rst
@@ -3,10 +3,9 @@ Interaction with Django
.. module:: semantic_version.django_fields
-The ``python-semanticversion`` package provides three custom fields for Django:
+The ``python-semanticversion`` package provides two custom fields for Django:
- :class:`VersionField`: stores a :class:`semantic_version.Version` object
-- :class:`SpecItemField`: stores a :class:`semantic_version.SpecItem` object
- :class:`SpecField`: stores a :class:`semantic_version.Spec` object
Those fields are :class:`django.db.models.CharField` subclasses,
@@ -22,11 +21,6 @@ with their :attr:`~django.db.models.CharField.max_length` defaulting to 200.
Boolean; whether :attr:`~semantic_version.Version.partial` versions are allowed.
-.. class:: SpecItemField
-
- Stores a :class:`semantic_version.SpecItem` as its string representation.
-
-
.. class:: SpecField
Stores a :class:`semantic_version.Spec` as its comma-separated string representation.
View
62 doc/index.rst
@@ -82,9 +82,9 @@ Obviously, :class:`Versions <Version>` can be compared::
Requirement specification
-------------------------
-The :class:`SpecItem` object describes a range of accepted versions::
+The :class:`Spec` object describes a range of accepted versions::
- >>> s = SpecItem('>=0.1.1') # At least 0.1.1
+ >>> s = Spec('>=0.1.1') # At least 0.1.1
>>> s.match(Version('0.1.1'))
True
>>> s.match(Version('0.1.1-alpha1')) # pre-release satisfy version spec
@@ -94,69 +94,63 @@ The :class:`SpecItem` object describes a range of accepted versions::
Simpler test syntax is also available using the ``in`` keyword::
- >>> s = SpecItem('==0.1.1')
+ >>> s = Spec('==0.1.1')
>>> Version('0.1.1-alpha1') in s
True
>>> Version('0.1.2') in s
False
+Combining specifications can be expressed in two ways:
+
+- Components separated by commas in a single string::
+
+ >>> Spec('>=0.1.1,<0.3.0')
+
+- Components given as different arguments::
+
+ >>> Spec('>=0.1.1', '<0.3.0')
+
+- A mix of both versions::
+
+ >>> Spec('>=0.1.1', '!=0.2.4-alpha,<0.3.0')
+
+
Including pre-release identifiers in specifications
"""""""""""""""""""""""""""""""""""""""""""""""""""
-When testing a :class:`Version` against a :class:`SpecItem`, comparisons are only
-performed for components defined in the :class:`SpecItem`; thus, a pre-release
+When testing a :class:`Version` against a :class:`Spec`, comparisons are only
+performed for components defined in the :class:`Spec`; thus, a pre-release
version (``1.0.0-alpha``), while not strictly equal to the non pre-release
-version (``1.0.0``), satisfies the ``==1.0.0`` :class:`SpecItem`.
+version (``1.0.0``), satisfies the ``==1.0.0`` :class:`Spec`.
-Pre-release identifiers will only be compared if included in the :class:`SpecItem`
+Pre-release identifiers will only be compared if included in the :class:`Spec`
definition or (for the empty pre-release number) if a single dash is appended
(``1.0.0-``)::
- >>> Version('0.1.0-alpha') in SpecItem('>=0.1.0') # No pre-release identifier
+ >>> Version('0.1.0-alpha') in Spec('>=0.1.0') # No pre-release identifier
True
- >>> Version('0.1.0-alpha') in SpecItem('>=0.1.0-') # Include pre-release in checks
+ >>> Version('0.1.0-alpha') in Spec('>=0.1.0-') # Include pre-release in checks
False
Including build identifiers in specifications
"""""""""""""""""""""""""""""""""""""""""""""
The same rule applies for the build identifier: comparisons will include it only
-if it was included in the :class:`SpecItem` definition, or - for the unnumbered build
+if it was included in the :class:`Spec` definition, or - for the unnumbered build
version - if a single + is appended to the definition(``1.0.0+``, ``1.0.0-alpha+``)::
- >>> Version('1.0.0+build2') in SpecItem('<=1.0.0') # Build identifier ignored
+ >>> Version('1.0.0+build2') in Spec('<=1.0.0') # Build identifier ignored
True
- >>> Version('1.0.0+build2') in SpecItem('<=1.0.0+') # Include build in checks
- False
-
-
-Combining requirements
-======================
-
-In order to express complex version specifications, use the :class:`Spec` class::
-
- >>> # At least 0.1.1, not 0.2.0, avoid broken 0.1.5-alpha.
- >>> sl = Spec('>=0.1.1,<0.2.0,!=0.1.5-alpha')
- >>> sl.match(Version('0.1.1'))
- True
- >>> Version('0.1.1-rc1') in sl
- True
- >>> Version('0.1.2') in sl
- True
- >>> Version('0.2.0-alpha') in sl
- False
- >>> Version('0.1.5-alpha') in sl
- False
- >>> Version('0.1.5-alpha+build2') in sl
+ >>> Version('1.0.0+build2') in Spec('<=1.0.0+') # Include build in checks
False
Using with Django
=================
The :mod:`semantic_version.django_fields` module provides django fields to
-store :class:`Version`, :class:`SpecItem` or :class:`Spec` objects.
+store :class:`Version` or :class:`Spec` objects.
More documentation is available in the :doc:`django` section.
View
221 doc/reference.rst
@@ -189,7 +189,7 @@ Representing a version (the Version class)
:rtype: (major, minor, patch, prerelease, build)
-Version specifications (the SpecItem class)
+Version specifications (the Spec class)
-------------------------------------------
@@ -215,13 +215,13 @@ In order to have version specification behave naturally, the rules are the follo
This means that::
- >>> Version('1.1.1-rc1') in SpecItem('<1.1.1')
+ >>> Version('1.1.1-rc1') in Spec('<1.1.1')
False
- >>> Version('1.1.1-rc1') in SpecItem('<1.1.1-rc4')
+ >>> Version('1.1.1-rc1') in Spec('<1.1.1-rc4')
True
- >>> Version('1.1.1-rc1+build4') in SpecItem('<=1.1.1-rc1')
+ >>> Version('1.1.1-rc1+build4') in Spec('<=1.1.1-rc1')
True
- >>> Version('1.1.1-rc1+build4') in SpecItem('<=1.1.1-rc1+build2')
+ >>> Version('1.1.1-rc1+build4') in Spec('<=1.1.1-rc1+build2')
False
In order to force matches to *strictly* compare version numbers, these additional
@@ -230,21 +230,114 @@ rules apply:
* Setting a pre-release separator without a pre-release identifier (``<=1.1.1-``)
forces match to take into account pre-release version::
- >>> Version('1.1.1-rc1') in SpecItem('<1.1.1')
+ >>> Version('1.1.1-rc1') in Spec('<1.1.1')
False
- >>> Version('1.1.1-rc1') in SpecItem('<1.1.1-')
+ >>> Version('1.1.1-rc1') in Spec('<1.1.1-')
True
* Setting a build separator without a build identifier (``>1.1.1+``) forces
satisfaction tests to include both prerelease and build identifiers::
- >>> Version('1.1.1+build2') in SpecItem('>1.1.1')
+ >>> Version('1.1.1+build2') in Spec('>1.1.1')
False
- >>> Version('1.1.1+build2') in SpecItem('>1.1.1+')
+ >>> Version('1.1.1+build2') in Spec('>1.1.1+')
True
+.. class:: Spec(spec_string[, spec_string[, ...]])
+
+ Stores a list of :class:`SpecItem` and matches any :class:`Version` against all
+ contained :class:`specs <SpecItem>`.
+
+ It is build from a comma-separated list of version specifications::
+
+ >>> Spec('>=1.0.0,<1.2.0,!=1.1.4')
+ <Spec: (
+ <SpecItem: >= <~SemVer: 1 0 0 None None>>,
+ <SpecItem: < <~SemVer: 1 2 0 None None>>,
+ <SpecItem: != <~SemVer: 1 1 4 None None>>
+ )>
+
+ Version specifications may also be passed in separated arguments::
+
+ >>> Spec('>=1.0.0', '<1.2.0', '!=1.1.4,!=1.1.13')
+ <Spec: (
+ <SpecItem: >= <~SemVer: 1 0 0 None None>>,
+ <SpecItem: < <SemVer: 1 2 0 None None>>,
+ <SpecItem: != <~SemVer: 1 1 4 None None>>
+ <SpecItem: != <~SemVer: 1 1 13 None None>>
+ )>
+
+
+ .. rubric:: Attributes
+
+
+ .. attribute:: specs
+
+ Tuple of :class:`SpecItem`, the included specifications.
+
+
+ .. rubric:: Methods
+
+
+ .. method:: match(self, version)
+
+ Test whether a given :class:`Version` matches all included :class:`SpecItem`::
+
+ >>> Spec('>=1.1.0,<1.1.2').match(Version('1.1.1'))
+ True
+
+ :param version: The version to test against the specs
+ :type version: :class:`Version`
+ :rtype: ``bool``
+
+ .. method:: __contains__(self, version)
+
+ Alias of the :func:`match` method;
+ allows the use of the ``version in speclist`` syntax::
+
+ >>> Version('1.1.1-alpha') in Spec('>=1.1.0,<1.1.1')
+ True
+
+
+ .. method:: __str__(self)
+
+ Converting a :class:`Spec` returns the initial description string::
+
+ >>> str(Spec('>=0.1.1,!=0.1.2'))
+ '>=0.1.1,!=0.1.2'
+
+ .. method:: __iter__(self)
+
+ Returns an iterator over the contained specs::
+
+ >>> for spec in Spec('>=0.1.1,!=0.1.2'):
+ ... print spec
+ >=0.1.1
+ !=0.1.2
+
+ .. method:: __hash__(self)
+
+ Provides a hash based solely on the hash of contained specs.
+
+ Allows using a :class:`Spec` as a dictionary key.
+
+
+ .. rubric:: Class methods
+
+
+ .. classmethod:: parse(self, specs_string)
+
+ Retrieve a ``(*specs)`` tuple from a string.
+
+ :param str requirement_string: The textual description of the specifications
+ :raises: :exc:`ValueError`: if the ``requirement_string`` is invalid.
+ :rtype: ``(*spec)`` tuple
+
+
.. class:: SpecItem(spec_string)
+ .. note:: This class belong to the private python-semanticversion API.
+
Stores a version specification, defined from a string::
>>> SpecItem('>=0.1.1')
@@ -310,15 +403,6 @@ rules apply:
:rtype: ``bool``
- .. method:: __contains__(self, version)
-
- Alias of the :func:`match` method;
- allows the use of the ``version in spec`` syntax::
-
- >>> Version('1.1.1') in SpecItem('<=1.1.2')
- True
-
-
.. method:: __str__(self)
Converting a :class:`SpecItem` to a string returns the initial description string::
@@ -383,105 +467,4 @@ rules apply:
-
-Combining version specifications (the Spec class)
--------------------------------------------------
-
-It may be useful to define a rule such as
-"Accept any version between the first 1.0.0 (incl. pre-release) and strictly before 1.2.0; ecluding 1.1.4 which was broken.".
-
-This is possible with the :class:`Spec` class.
-
-
-.. class:: Spec(spec_string[, spec_string[, ...]])
-
- Stores a list of :class:`SpecItem` and matches any :class:`Version` against all
- contained :class:`specs <SpecItem>`.
-
- It is build from a comma-separated list of version specifications::
-
- >>> Spec('>=1.0.0,<1.2.0,!=1.1.4')
- <Spec: (
- <SpecItem: >= <~SemVer: 1 0 0 None None>>,
- <SpecItem: < <~SemVer: 1 2 0 None None>>,
- <SpecItem: != <~SemVer: 1 1 4 None None>>
- )>
-
- Version specifications may also be passed in separated arguments::
-
- >>> Spec('>=1.0.0', '<1.2.0', '!=1.1.4,!=1.1.13')
- <Spec: (
- <SpecItem: >= <~SemVer: 1 0 0 None None>>,
- <SpecItem: < <SemVer: 1 2 0 None None>>,
- <SpecItem: != <~SemVer: 1 1 4 None None>>
- <SpecItem: != <~SemVer: 1 1 13 None None>>
- )>
-
-
- .. rubric:: Attributes
-
-
- .. attribute:: specs
-
- Tuple of :class:`SpecItem`, the included specifications.
-
-
- .. rubric:: Methods
-
-
- .. method:: match(self, version)
-
- Test whether a given :class:`Version` matches all included :class:`SpecItem`::
-
- >>> Spec('>=1.1.0,<1.1.2').match(Version('1.1.1'))
- True
-
- :param version: The version to test against the specs
- :type version: :class:`Version`
- :rtype: ``bool``
-
- .. method:: __contains__(self, version)
-
- Alias of the :func:`match` method;
- allows the use of the ``version in speclist`` syntax::
-
- >>> Version('1.1.1-alpha') in Spec('>=1.1.0,<1.1.1')
- True
-
-
- .. method:: __str__(self)
-
- Converting a :class:`Spec` returns the initial description string::
-
- >>> str(Spec('>=0.1.1,!=0.1.2'))
- '>=0.1.1,!=0.1.2'
-
- .. method:: __iter__(self)
-
- Returns an iterator over the contained specs::
-
- >>> for spec in Spec('>=0.1.1,!=0.1.2'):
- ... print spec
- >=0.1.1
- !=0.1.2
-
- .. method:: __hash__(self)
-
- Provides a hash based solely on the hash of contained specs.
-
- Allows using a :class:`Spec` as a dictionary key.
-
-
- .. rubric:: Class methods
-
-
- .. classmethod:: parse(self, specs_string)
-
- Retrieve a ``(*specs)`` tuple from a string.
-
- :param str requirement_string: The textual description of the specifications
- :raises: :exc:`ValueError`: if the ``requirement_string`` is invalid.
- :rtype: ``(*spec)`` tuple
-
-
.. _SemVer: http://semver.org/
View
2 src/semantic_version/__init__.py
@@ -5,4 +5,4 @@
__version__ = '1.3.0-alpha'
-from .base import compare, match, Version, Spec, SpecItem
+from .base import compare, match, Version, Spec
View
17 src/semantic_version/base.py
@@ -88,16 +88,8 @@ def parse(cls, version_string, partial=False):
major, minor, patch, prerelease, build = match.groups()
major = int(major)
-
- if minor is None:
- return (major, None, None, None, None)
- else:
- minor = int(minor)
-
- if patch is None:
- return (major, minor, None, None, None)
- else:
- patch = int(patch)
+ minor = int(minor)
+ patch = int(patch)
if prerelease is None:
if partial and (build is None):
@@ -290,11 +282,6 @@ def match(self, version):
else: # pragma: no cover
raise ValueError('Unexpected match kind: %r' % self.kind)
- def __contains__(self, version):
- if isinstance(version, Version):
- return self.match(version)
- return False
-
def __str__(self):
return '%s%s' % (self.kind, self.spec)
View
15 src/semantic_version/django_fields.py
@@ -46,21 +46,6 @@ def to_python(self, value):
return base.Version(value, partial=self.partial)
-class SpecItemField(BaseSemVerField):
- default_error_messages = {
- 'invalid': _(u"Enter a valid version number spec in ==X.Y.Z format."),
- }
- description = _(u"Version specification")
-
- def to_python(self, value):
- """Converts any value to a base.SpecItem field."""
- if value is None or value == '':
- return value
- if isinstance(value, base.SpecItem):
- return value
- return base.SpecItem(value)
-
-
class SpecField(BaseSemVerField):
default_error_messages = {
'invalid': _(u"Enter a valid version number spec list in ==X.Y.Z,>=A.B.C format."),
View
7 tests/django_test_app/models.py
@@ -7,13 +7,10 @@
class VersionModel(models.Model):
version = semver_fields.VersionField(verbose_name='my version')
- spec = semver_fields.SpecItemField(verbose_name='my spec')
- speclist = semver_fields.SpecField(verbose_name='my spec list')
+ spec = semver_fields.SpecField(verbose_name='my spec')
class PartialVersionModel(models.Model):
partial = semver_fields.VersionField(partial=True, verbose_name='partial version')
optional = semver_fields.VersionField(verbose_name='optional version', blank=True, null=True)
- optional_spec = semver_fields.SpecItemField(verbose_name='optional spec', blank=True, null=True)
- optional_speclist = semver_fields.SpecField(verbose_name='optional spec list',
- blank=True, null=True)
+ optional_spec = semver_fields.SpecField(verbose_name='optional spec', blank=True, null=True)
View
3 tests/test_base.py
@@ -249,13 +249,10 @@ def test_matches(self):
for version_text in matching:
version = base.Version(version_text)
- self.assertTrue(version in spec, "%r should be in %r" % (version, spec))
self.assertTrue(spec.match(version), "%r should match %r" % (version, spec))
for version_text in failing:
version = base.Version(version_text)
- self.assertFalse(version in spec,
- "%r should not be in %r" % (version, spec))
self.assertFalse(spec.match(version),
"%r should not match %r" % (version, spec))
View
31 tests/test_django.py
@@ -35,56 +35,49 @@
@unittest.skipIf(not django_loaded, "Django not installed")
class DjangoFieldTestCase(unittest.TestCase):
def test_version(self):
- obj = models.VersionModel(version='0.1.1', spec='>0.1.0', speclist='==0.1.1,!=0.1.1-alpha')
+ obj = models.VersionModel(version='0.1.1', spec='==0.1.1,!=0.1.1-alpha')
self.assertEqual(semantic_version.Version('0.1.1'), obj.version)
- self.assertEqual(semantic_version.SpecItem('>0.1.0'), obj.spec)
- self.assertEqual(semantic_version.Spec('==0.1.1,!=0.1.1-alpha'), obj.speclist)
+ self.assertEqual(semantic_version.Spec('==0.1.1,!=0.1.1-alpha'), obj.spec)
- alt_obj = models.VersionModel(version=obj.version, spec=obj.spec, speclist=obj.speclist)
+ alt_obj = models.VersionModel(version=obj.version, spec=obj.spec)
self.assertEqual(semantic_version.Version('0.1.1'), alt_obj.version)
- self.assertEqual(semantic_version.SpecItem('>0.1.0'), alt_obj.spec)
- self.assertEqual(semantic_version.Spec('==0.1.1,!=0.1.1-alpha'), alt_obj.speclist)
+ self.assertEqual(semantic_version.Spec('==0.1.1,!=0.1.1-alpha'), alt_obj.spec)
self.assertEqual(obj.spec, alt_obj.spec)
self.assertEqual(obj.version, alt_obj.version)
- self.assertEqual(obj.speclist, alt_obj.speclist)
def test_invalid_input(self):
self.assertRaises(ValueError, models.VersionModel,
- version='0.1.1', spec='blah', speclist='==0.1.1,!=0.1.1-alpha')
+ version='0.1.1', spec='blah')
self.assertRaises(ValueError, models.VersionModel,
- version='0.1', spec='>0.1.1', speclist='==0.1.1,!=0.1.1-alpha')
+ version='0.1', spec='==0.1.1,!=0.1.1-alpha')
self.assertRaises(ValueError, models.VersionModel,
- version='0.1.1', spec='>0.1.1', speclist='==0,!=0.2')
+ version='0.1.1', spec='==0,!=0.2')
def test_partial(self):
obj = models.PartialVersionModel(partial='0.1.0')
self.assertEqual(semantic_version.Version('0.1.0', partial=True), obj.partial)
self.assertIsNone(obj.optional)
self.assertIsNone(obj.optional_spec)
- self.assertIsNone(obj.optional_speclist)
# Copy values to another model
alt_obj = models.PartialVersionModel(
partial=obj.partial,
optional=obj.optional,
optional_spec=obj.optional_spec,
- optional_speclist=obj.optional_speclist,
)
self.assertEqual(semantic_version.Version('0.1.0', partial=True), alt_obj.partial)
self.assertEqual(obj.partial, alt_obj.partial)
self.assertIsNone(obj.optional)
self.assertIsNone(obj.optional_spec)
- self.assertIsNone(obj.optional_speclist)
def test_serialization(self):
- o1 = models.VersionModel(version='0.1.1', spec='<0.2.4-rc42',
- speclist='==0.1.1,!=0.1.1-alpha')
- o2 = models.VersionModel(version='0.4.3-rc3+build3', spec='==0.4.3',
- speclist='<=0.1.1-rc2,!=0.1.1-rc1')
+ o1 = models.VersionModel(version='0.1.1', spec='==0.1.1,!=0.1.1-alpha')
+ o2 = models.VersionModel(version='0.4.3-rc3+build3',
+ spec='<=0.1.1-rc2,!=0.1.1-rc1')
data = serializers.serialize('json', [o1, o2])
@@ -94,9 +87,9 @@ def test_serialization(self):
def test_serialization_partial(self):
o1 = models.PartialVersionModel(partial='0.1.1', optional='0.2.4-rc42',
- optional_spec=None, optional_speclist=None)
+ optional_spec=None)
o2 = models.PartialVersionModel(partial='0.4.3-rc3+build3', optional='',
- optional_spec='==1.1.0', optional_speclist='==0.1.1,!=0.1.1-alpha')
+ optional_spec='==0.1.1,!=0.1.1-alpha')
data = serializers.serialize('json', [o1, o2])

0 comments on commit caa1c01

Please sign in to comment.
Something went wrong with that request. Please try again.