Add support for Django 1.10
Stop coercing fields magically: >>> a = SomeModel() >>> a.version = '0.1.0' >>> a.version '0.1.0' >>> a.full_clean() >>> a.version Version('0.1.0') Closes #43, #45
This commit is contained in:
parent
f514edb523
commit
be455e8998
|
@ -2,9 +2,14 @@ ChangeLog
|
|||
=========
|
||||
|
||||
|
||||
2.5.1 (master)
|
||||
2.6.0 (master)
|
||||
--------------
|
||||
|
||||
*New:*
|
||||
|
||||
* `#43 <https://github.com/rbarrois/python-semanticversion/issues/43>`_:
|
||||
Add support for Django up to 1.10.
|
||||
|
||||
*Bugfix:*
|
||||
|
||||
* `#35 <https://github.com/rbarrois/python-semanticversion/issues/35>`_:
|
||||
|
|
2
Makefile
2
Makefile
|
@ -6,7 +6,7 @@ DOC_DIR=docs
|
|||
COVERAGE = python $(shell which coverage)
|
||||
|
||||
# Dependencies
|
||||
DJANGO_VERSION ?= 1.9
|
||||
DJANGO_VERSION ?= 1.10
|
||||
PYTHON_VERSION := $(shell python --version)
|
||||
NEXT_DJANGO_VERSION=$(shell python -c "v='$(DJANGO_VERSION)'; parts=v.split('.'); parts[-1]=str(int(parts[-1])+1); print('.'.join(parts))")
|
||||
|
||||
|
|
|
@ -4,18 +4,32 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from . import base
|
||||
|
||||
|
||||
class BaseSemVerField(models.CharField):
|
||||
__metaclass__ = models.SubfieldBase
|
||||
class SemVerField(models.CharField):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('max_length', 200)
|
||||
super(BaseSemVerField, self).__init__(*args, **kwargs)
|
||||
super(SemVerField, self).__init__(*args, **kwargs)
|
||||
|
||||
if django.VERSION[:2] < (1, 8):
|
||||
def contribute_to_class(self, cls, name, **kwargs):
|
||||
"""Emulate SubFieldBase for Django < 1.8"""
|
||||
super(SemVerField, self).contribute_to_class(cls, name, **kwargs)
|
||||
from django.db.models.fields import subclassing
|
||||
setattr(cls, self.name, subclassing.Creator(self))
|
||||
|
||||
def from_db_value(self, value, expression, connection, context):
|
||||
"""Convert from the database format.
|
||||
|
||||
This should be the inverse of self.get_prep_value()
|
||||
"""
|
||||
return self.to_python(value)
|
||||
|
||||
def get_prep_value(self, obj):
|
||||
return None if obj is None else str(obj)
|
||||
|
@ -30,12 +44,7 @@ class BaseSemVerField(models.CharField):
|
|||
return str(value)
|
||||
|
||||
def run_validators(self, value):
|
||||
return super(BaseSemVerField, self).run_validators(str(value))
|
||||
|
||||
|
||||
# Py2 and Py3-compatible metaclass
|
||||
SemVerField = models.SubfieldBase(
|
||||
str('SemVerField'), (BaseSemVerField, models.CharField), {})
|
||||
return super(SemVerField, self).run_validators(str(value))
|
||||
|
||||
|
||||
class VersionField(SemVerField):
|
||||
|
|
|
@ -38,23 +38,33 @@ def save_and_refresh(obj):
|
|||
obj = obj.__class__.objects.get(id=obj.id)
|
||||
|
||||
|
||||
Version = semantic_version.Version
|
||||
Spec = semantic_version.Spec
|
||||
|
||||
|
||||
@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.1,!=0.1.1-alpha')
|
||||
obj = models.VersionModel(version=Version('0.1.1'), spec=Spec('==0.1.1,!=0.1.1-alpha'))
|
||||
|
||||
self.assertEqual(semantic_version.Version('0.1.1'), obj.version)
|
||||
self.assertEqual(semantic_version.Spec('==0.1.1,!=0.1.1-alpha'), obj.spec)
|
||||
self.assertEqual(Version('0.1.1'), obj.version)
|
||||
self.assertEqual(Spec('==0.1.1,!=0.1.1-alpha'), obj.spec)
|
||||
|
||||
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.Spec('==0.1.1,!=0.1.1-alpha'), alt_obj.spec)
|
||||
self.assertEqual(Version('0.1.1'), alt_obj.version)
|
||||
self.assertEqual(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)
|
||||
|
||||
def test_version_clean(self):
|
||||
"""Calling .full_clean() should convert str to Version/Spec objects."""
|
||||
obj = models.VersionModel(version='0.1.1', spec='==0.1.1,!=0.1.1-alpha')
|
||||
obj.full_clean()
|
||||
|
||||
self.assertEqual(Version('0.1.1'), obj.version)
|
||||
self.assertEqual(Spec('==0.1.1,!=0.1.1-alpha'), obj.spec)
|
||||
|
||||
def test_version_save(self):
|
||||
"""Test saving object with a VersionField."""
|
||||
# first test with a null value
|
||||
|
@ -66,7 +76,7 @@ class DjangoFieldTestCase(unittest.TestCase):
|
|||
self.assertIsNone(obj.optional_spec)
|
||||
|
||||
# now set to something that is not null
|
||||
spec = semantic_version.Spec('==0,!=0.2')
|
||||
spec = Spec('==0,!=0.2')
|
||||
obj.optional_spec = spec
|
||||
save_and_refresh(obj)
|
||||
self.assertEqual(obj.optional_spec, spec)
|
||||
|
@ -82,35 +92,45 @@ class DjangoFieldTestCase(unittest.TestCase):
|
|||
self.assertIsNone(obj.optional_spec)
|
||||
|
||||
# now set to something that is not null
|
||||
spec = semantic_version.Spec('==0,!=0.2')
|
||||
spec = Spec('==0,!=0.2')
|
||||
obj.optional_spec = spec
|
||||
save_and_refresh(obj)
|
||||
self.assertEqual(obj.optional_spec, spec)
|
||||
|
||||
def test_partial_spec(self):
|
||||
def test_partial_spec_clean(self):
|
||||
obj = models.VersionModel(version='0.1.1', spec='==0,!=0.2')
|
||||
self.assertEqual(semantic_version.Version('0.1.1'), obj.version)
|
||||
self.assertEqual(semantic_version.Spec('==0,!=0.2'), obj.spec)
|
||||
obj.full_clean()
|
||||
self.assertEqual(Version('0.1.1'), obj.version)
|
||||
self.assertEqual(Spec('==0,!=0.2'), obj.spec)
|
||||
|
||||
def test_coerce(self):
|
||||
def test_coerce_clean(self):
|
||||
obj = models.CoerceVersionModel(version='0.1.1a+2', partial='23')
|
||||
self.assertEqual(semantic_version.Version('0.1.1-a+2'), obj.version)
|
||||
self.assertEqual(semantic_version.Version('23', partial=True), obj.partial)
|
||||
obj.full_clean()
|
||||
self.assertEqual(Version('0.1.1-a+2'), obj.version)
|
||||
self.assertEqual(Version('23', partial=True), obj.partial)
|
||||
|
||||
obj2 = models.CoerceVersionModel(version='23', partial='0.1.2.3.4.5/6')
|
||||
self.assertEqual(semantic_version.Version('23.0.0'), obj2.version)
|
||||
self.assertEqual(semantic_version.Version('0.1.2+3.4.5-6', partial=True), obj2.partial)
|
||||
obj2.full_clean()
|
||||
self.assertEqual(Version('23.0.0'), obj2.version)
|
||||
self.assertEqual(Version('0.1.2+3.4.5-6', partial=True), obj2.partial)
|
||||
|
||||
@unittest.skipIf(django.VERSION[:2] < (1, 8), "Django<1.8 casts values on setattr")
|
||||
def test_invalid_input(self):
|
||||
self.assertRaises(ValueError, models.VersionModel,
|
||||
version='0.1.1', spec='blah')
|
||||
self.assertRaises(ValueError, models.VersionModel,
|
||||
version='0.1', spec='==0.1.1,!=0.1.1-alpha')
|
||||
v = models.VersionModel(version='0.1.1', spec='blah')
|
||||
self.assertRaises(ValueError, v.full_clean)
|
||||
|
||||
v2 = models.VersionModel(version='0.1', spec='==0.1.1,!=0.1.1-alpha')
|
||||
self.assertRaises(ValueError, v2.full_clean)
|
||||
|
||||
@unittest.skipUnless(django.VERSION[:2] < (1, 8), "Django>=1.8 doesn't mangle setattr")
|
||||
def test_invalid_input_full_clean(self):
|
||||
self.assertRaises(ValueError, models.VersionModel, version='0.1.1', spec='blah')
|
||||
self.assertRaises(ValueError, models.VersionModel, version='0.1', spec='==0.1.1,!=0.1.1-alpha')
|
||||
|
||||
def test_partial(self):
|
||||
obj = models.PartialVersionModel(partial='0.1.0')
|
||||
obj = models.PartialVersionModel(partial=Version('0.1.0'))
|
||||
|
||||
self.assertEqual(semantic_version.Version('0.1.0', partial=True), obj.partial)
|
||||
self.assertEqual(Version('0.1.0', partial=True), obj.partial)
|
||||
self.assertIsNone(obj.optional)
|
||||
self.assertIsNone(obj.optional_spec)
|
||||
|
||||
|
@ -121,17 +141,18 @@ class DjangoFieldTestCase(unittest.TestCase):
|
|||
optional_spec=obj.optional_spec,
|
||||
)
|
||||
|
||||
self.assertEqual(semantic_version.Version('0.1.0', partial=True), alt_obj.partial)
|
||||
self.assertEqual(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)
|
||||
|
||||
# Validation should be fine
|
||||
obj.full_clean()
|
||||
|
||||
def test_serialization(self):
|
||||
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')
|
||||
o1 = models.VersionModel(version=Version('0.1.1'), spec=Spec('==0.1.1,!=0.1.1-alpha'))
|
||||
o2 = models.VersionModel(version=Version('0.4.3-rc3+build3'),
|
||||
spec=Spec('<=0.1.1-rc2,!=0.1.1-rc1'))
|
||||
|
||||
data = serializers.serialize('json', [o1, o2])
|
||||
|
||||
|
@ -142,10 +163,16 @@ class DjangoFieldTestCase(unittest.TestCase):
|
|||
self.assertEqual(o2.spec, obj2.object.spec)
|
||||
|
||||
def test_serialization_partial(self):
|
||||
o1 = models.PartialVersionModel(partial='0.1.1', optional='0.2.4-rc42',
|
||||
optional_spec=None)
|
||||
o2 = models.PartialVersionModel(partial='0.4.3-rc3+build3', optional='',
|
||||
optional_spec='==0.1.1,!=0.1.1-alpha')
|
||||
o1 = models.PartialVersionModel(
|
||||
partial=Version('0.1.1', partial=True),
|
||||
optional=Version('0.2.4-rc42', partial=True),
|
||||
optional_spec=None,
|
||||
)
|
||||
o2 = models.PartialVersionModel(
|
||||
partial=Version('0.4.3-rc3+build3', partial=True),
|
||||
optional='',
|
||||
optional_spec=Spec('==0.1.1,!=0.1.1-alpha'),
|
||||
)
|
||||
|
||||
data = serializers.serialize('json', [o1, o2])
|
||||
|
||||
|
@ -234,8 +261,8 @@ if django_loaded:
|
|||
TestRunner().teardown_databases(cls.old_state)
|
||||
|
||||
def test_db_interaction(self):
|
||||
o1 = models.VersionModel(version='0.1.1', spec='<0.2.4-rc42')
|
||||
o2 = models.VersionModel(version='0.4.3-rc3+build3', spec='==0.4.3')
|
||||
o1 = models.VersionModel(version=Version('0.1.1'), spec=Spec('<0.2.4-rc42'))
|
||||
o2 = models.VersionModel(version=Version('0.4.3-rc3+build3'), spec=Spec('==0.4.3'))
|
||||
|
||||
o1.save()
|
||||
o2.save()
|
||||
|
|
Loading…
Reference in New Issue