summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphaël Barrois <raphael.barrois@polyconseil.fr>2012-05-15 16:42:40 +0200
committerRaphaël Barrois <raphael.barrois@polyconseil.fr>2012-05-15 16:42:40 +0200
commit6713f3071764e1438fb7e07cf51bacde8fd97394 (patch)
tree41bb5fcf99bbb143ca6cc5ad95523e7b79e71fd6
parent48f7cc1c811cdfb807615931a0fa3d102aa1fa90 (diff)
downloadsemantic-version-6713f3071764e1438fb7e07cf51bacde8fd97394.tar.gz
Add django fields for SemanticVersion and Spec.
Signed-off-by: Raphaël Barrois <raphael.barrois@polyconseil.fr>
-rw-r--r--.gitignore1
-rw-r--r--src/semantic_version/django_fields.py74
-rw-r--r--tests/django_test_app/__init__.py0
-rw-r--r--tests/django_test_app/models.py16
-rw-r--r--tests/test_django.py117
5 files changed, 208 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index d9a4ff7..addc6dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
.*.swp
.coverage
htmlcov/
+tests/db/
diff --git a/src/semantic_version/django_fields.py b/src/semantic_version/django_fields.py
new file mode 100644
index 0000000..17184bc
--- /dev/null
+++ b/src/semantic_version/django_fields.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012 Raphaël Barrois
+
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from . import base
+
+
+class VersionField(models.CharField):
+ default_error_messages = {
+ 'invalid': _(u"Enter a valid version number in X.Y.Z format."),
+ }
+ description = _(u"Version")
+
+ __metaclass__ = models.SubfieldBase
+
+ def __init__(self, *args, **kwargs):
+ self.partial = kwargs.pop('partial', False)
+ kwargs.setdefault('max_length', 40)
+ super(VersionField, self).__init__(*args, **kwargs)
+
+ def to_python(self, value):
+ """Converts any value to a base.SemanticVersion field."""
+ if value is None or value == '':
+ return value
+ if isinstance(value, base.SemanticVersion):
+ return value
+ return base.SemanticVersion(value, partial=self.partial)
+
+ def get_prep_value(self, obj):
+ return str(obj)
+
+ def get_db_prep_value(self, value, connection, prepared=False):
+ if not prepared:
+ value = self.get_prep_value(value)
+ return value
+
+ def value_to_string(self, obj):
+ value = self.to_python(self._get_val_from_obj(obj))
+ return str(value)
+
+
+class SpecField(models.CharField):
+ default_error_messages = {
+ 'invalid': _(u"Enter a valid version number spec in ==X.Y.Z format."),
+ }
+ description = _(u"Version specification")
+
+ __metaclass__ = models.SubfieldBase
+
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('max_length', 42)
+ return super(SpecField, self).__init__(*args, **kwargs)
+
+ def to_python(self, value):
+ """Converts any value to a base.SemanticVersion field."""
+ if value is None or value == '':
+ return value
+ if isinstance(value, base.Spec):
+ return value
+ return base.Spec(value)
+
+ def get_prep_value(self, obj):
+ return str(obj)
+
+ def get_db_prep_value(self, value, connection, prepared=False):
+ if not prepared:
+ value = self.get_prep_value(value)
+ return value
+
+ def value_to_string(self, obj):
+ value = self.to_python(self._get_val_from_obj(obj))
+ return str(value)
diff --git a/tests/django_test_app/__init__.py b/tests/django_test_app/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/django_test_app/__init__.py
diff --git a/tests/django_test_app/models.py b/tests/django_test_app/models.py
new file mode 100644
index 0000000..53ed874
--- /dev/null
+++ b/tests/django_test_app/models.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012 Raphaël Barrois
+
+from django.db import models
+from semantic_version import django_fields as semver_fields
+
+
+class VersionModel(models.Model):
+ version = semver_fields.VersionField(verbose_name='my version')
+ 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.SpecField(verbose_name='optional spec', blank=True, null=True)
diff --git a/tests/test_django.py b/tests/test_django.py
new file mode 100644
index 0000000..72f7964
--- /dev/null
+++ b/tests/test_django.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012 Raphaël Barrois
+
+try: # pragma: no cover
+ import unittest2 as unittest
+except ImportError: # pragma: no cover
+ import unittest
+
+import semantic_version
+
+try: # pragma: no cover
+ from django.conf import settings
+ django_loaded = True
+except ImportError: # pragma: no cover
+ django_loaded = False
+
+if django_loaded: # pragma: no cover
+ if not settings.configured:
+ settings.configure(
+ DATABASES={
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': 'tests/db/test.sqlite',
+ }
+ },
+ INSTALLED_APPS=[
+ 'tests.django_test_app',
+ ]
+ )
+ from django_test_app import models
+ from django.core import serializers
+
+
+@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')
+
+ self.assertEqual(semantic_version.SemanticVersion('0.1.1'), obj.version)
+ self.assertEqual(semantic_version.Spec('>0.1.0'), obj.spec)
+
+ alt_obj = models.VersionModel(version=obj.version, spec=obj.spec)
+
+ self.assertEqual(semantic_version.SemanticVersion('0.1.1'), alt_obj.version)
+ self.assertEqual(semantic_version.Spec('>0.1.0'), alt_obj.spec)
+ self.assertEqual(obj.spec, alt_obj.spec)
+ self.assertEqual(obj.version, alt_obj.version)
+
+ 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')
+
+ def test_partial(self):
+ obj = models.PartialVersionModel(partial='0.1')
+
+ self.assertEqual(semantic_version.SemanticVersion('0.1', partial=True), obj.partial)
+ self.assertIsNone(obj.optional)
+ self.assertIsNone(obj.optional_spec)
+
+ alt_obj = models.PartialVersionModel(partial=obj.partial, optional=obj.optional,
+ optional_spec=obj.optional_spec)
+ self.assertEqual(semantic_version.SemanticVersion('0.1', partial=True), alt_obj.partial)
+ self.assertEqual(obj.partial, alt_obj.partial)
+ self.assertIsNone(obj.optional)
+ self.assertIsNone(obj.optional_spec)
+
+ def test_serialization(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')
+
+ data = serializers.serialize('json', [o1, o2])
+
+ obj1, obj2 = serializers.deserialize('json', data)
+ self.assertEqual(o1, obj1.object)
+ self.assertEqual(o2, obj2.object)
+
+ 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='~1.1')
+
+ data = serializers.serialize('json', [o1, o2])
+
+ obj1, obj2 = serializers.deserialize('json', data)
+ self.assertEqual(o1, obj1.object)
+ self.assertEqual(o2, obj2.object)
+
+
+if django_loaded:
+ from django.test import TestCase
+ from django.test.simple import DjangoTestSuiteRunner
+
+ class DbInteractingTestCase(TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.old_state = DjangoTestSuiteRunner().setup_databases()
+
+ @classmethod
+ def tearDownClass(cls):
+ DjangoTestSuiteRunner().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')
+
+ o1.save()
+ o2.save()
+
+ obj1 = models.VersionModel.objects.get(pk=o1.pk)
+ self.assertEqual(o1.version, obj1.version)
+
+ obj2 = models.VersionModel.objects.get(pk=o2.pk)
+ self.assertEqual(o2.version, obj2.version)
+
+else: # pragma: no cover
+ pass