summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchillaranand <anand21nanda@gmail.com>2017-02-15 21:44:21 +0530
committerTim Graham <timograham@gmail.com>2017-06-13 10:53:39 -0400
commit08bda82c237b9ad071538c2386b8bfc62fef7f7f (patch)
tree7dd489feef529e00a27ff8b6c085aedf2fbdd765
parente7dc39fb65e51d7613c941f7e5768b621dea4e76 (diff)
Fixed #27830 -- Used distutils.version.LooseVersion for version parsing.
-rw-r--r--django/contrib/gis/db/backends/postgis/operations.py14
-rw-r--r--django/contrib/gis/db/backends/spatialite/operations.py15
-rw-r--r--django/contrib/gis/geos/collections.py4
-rw-r--r--django/contrib/gis/geos/libgeos.py6
-rw-r--r--django/db/backends/postgresql/base.py3
-rw-r--r--django/utils/version.py15
-rw-r--r--tests/backends/tests.py9
-rw-r--r--tests/gis_tests/geos_tests/test_geos.py10
-rw-r--r--tests/gis_tests/tests.py15
-rw-r--r--tests/version/tests.py6
10 files changed, 52 insertions, 45 deletions
diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py
index ef443c47d6..da673312db 100644
--- a/django/contrib/gis/db/backends/postgis/operations.py
+++ b/django/contrib/gis/db/backends/postgis/operations.py
@@ -11,6 +11,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.db.backends.postgresql.operations import DatabaseOperations
from django.db.utils import ProgrammingError
from django.utils.functional import cached_property
+from django.utils.version import get_version_tuple
from .adapter import PostGISAdapter
from .models import PostGISGeometryColumns, PostGISSpatialRefSys
@@ -109,7 +110,6 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
postgis = True
geography = True
geom_func_prefix = 'ST_'
- version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
Adapter = PostGISAdapter
@@ -353,18 +353,8 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
Return the PostGIS version as a tuple (version string, major,
minor, subminor).
"""
- # Getting the PostGIS version
version = self.postgis_lib_version()
- m = self.version_regex.match(version)
-
- if m:
- major = int(m.group('major'))
- minor1 = int(m.group('minor1'))
- minor2 = int(m.group('minor2'))
- else:
- raise Exception('Could not parse PostGIS version string: %s' % version)
-
- return (version, major, minor1, minor2)
+ return (version,) + get_version_tuple(version)
def proj_version_tuple(self):
"""
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
index 3458239bed..5575164f91 100644
--- a/django/contrib/gis/db/backends/spatialite/operations.py
+++ b/django/contrib/gis/db/backends/spatialite/operations.py
@@ -3,8 +3,6 @@ SQL functions reference lists:
https://web.archive.org/web/20130407175746/https://www.gaia-gis.it/gaia-sins/spatialite-sql-4.0.0.html
https://www.gaia-gis.it/gaia-sins/spatialite-sql-4.2.1.html
"""
-import re
-
from django.contrib.gis.db.backends.base.operations import (
BaseSpatialOperations,
)
@@ -16,6 +14,7 @@ from django.contrib.gis.measure import Distance
from django.core.exceptions import ImproperlyConfigured
from django.db.backends.sqlite3.operations import DatabaseOperations
from django.utils.functional import cached_property
+from django.utils.version import get_version_tuple
class SpatiaLiteDistanceOperator(SpatialOperator):
@@ -35,7 +34,6 @@ class SpatiaLiteDistanceOperator(SpatialOperator):
class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
name = 'spatialite'
spatialite = True
- version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
Adapter = SpatiaLiteAdapter
@@ -189,16 +187,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
minor, subminor).
"""
version = self.spatialite_version()
-
- m = self.version_regex.match(version)
- if m:
- major = int(m.group('major'))
- minor1 = int(m.group('minor1'))
- minor2 = int(m.group('minor2'))
- else:
- raise Exception('Could not parse SpatiaLite version string: %s' % version)
-
- return (version, major, minor1, minor2)
+ return (version,) + get_version_tuple(version)
def spatial_aggregate_name(self, agg_name):
"""
diff --git a/django/contrib/gis/geos/collections.py b/django/contrib/gis/geos/collections.py
index c3904774dd..83df035b07 100644
--- a/django/contrib/gis/geos/collections.py
+++ b/django/contrib/gis/geos/collections.py
@@ -8,7 +8,7 @@ from ctypes import byref, c_int, c_uint
from django.contrib.gis.geos import prototypes as capi
from django.contrib.gis.geos.error import GEOSException
from django.contrib.gis.geos.geometry import GEOSGeometry, LinearGeometryMixin
-from django.contrib.gis.geos.libgeos import geos_version_info, get_pointer_arr
+from django.contrib.gis.geos.libgeos import geos_version_tuple, get_pointer_arr
from django.contrib.gis.geos.linestring import LinearRing, LineString
from django.contrib.gis.geos.point import Point
from django.contrib.gis.geos.polygon import Polygon
@@ -115,7 +115,7 @@ class MultiLineString(LinearGeometryMixin, GeometryCollection):
@property
def closed(self):
- if geos_version_info()['version'] < '3.5':
+ if geos_version_tuple() < (3, 5):
raise GEOSException("MultiLineString.closed requires GEOS >= 3.5.0.")
return super().closed
diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py
index d3fd674918..810161ffeb 100644
--- a/django/contrib/gis/geos/libgeos.py
+++ b/django/contrib/gis/geos/libgeos.py
@@ -15,6 +15,7 @@ from ctypes.util import find_library
from django.contrib.gis.geos.error import GEOSException
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import SimpleLazyObject
+from django.utils.version import get_version_tuple
logger = logging.getLogger('django.contrib.gis')
@@ -199,3 +200,8 @@ def geos_version_info():
raise GEOSException('Could not parse version info string "%s"' % ver)
return {key: m.group(key) for key in (
'version', 'release_candidate', 'capi_version', 'major', 'minor', 'subminor')}
+
+
+def geos_version_tuple():
+ """Return the GEOS version as a tuple (major, minor, subminor)."""
+ return get_version_tuple(geos_version_info()['version'])
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index 15adb0282e..ad1fd0fd0b 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -14,6 +14,7 @@ from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.utils import DatabaseError as WrappedDatabaseError
from django.utils.functional import cached_property
from django.utils.safestring import SafeText
+from django.utils.version import get_version_tuple
try:
import psycopg2 as Database
@@ -25,7 +26,7 @@ except ImportError as e:
def psycopg2_version():
version = psycopg2.__version__.split(' ', 1)[0]
- return tuple(int(v) for v in version.split('.') if v.isdigit())
+ return get_version_tuple(version)
PSYCOPG2_VERSION = psycopg2_version()
diff --git a/django/utils/version.py b/django/utils/version.py
index 790a68c19c..4569abb608 100644
--- a/django/utils/version.py
+++ b/django/utils/version.py
@@ -2,6 +2,7 @@ import datetime
import functools
import os
import subprocess
+from distutils.version import LooseVersion
def get_version(version=None):
@@ -77,3 +78,17 @@ def get_git_changeset():
except ValueError:
return None
return timestamp.strftime('%Y%m%d%H%M%S')
+
+
+def get_version_tuple(version):
+ """
+ Return a tuple of version numbers (e.g. (1, 2, 3)) from the version
+ string (e.g. '1.2.3').
+ """
+ loose_version = LooseVersion(version)
+ version_numbers = []
+ for item in loose_version.version:
+ if not isinstance(item, int):
+ break
+ version_numbers.append(item)
+ return tuple(version_numbers)
diff --git a/tests/backends/tests.py b/tests/backends/tests.py
index 5e7c6ae99c..8847b178ef 100644
--- a/tests/backends/tests.py
+++ b/tests/backends/tests.py
@@ -323,13 +323,12 @@ class PostgreSQLTests(TestCase):
def test_correct_extraction_psycopg2_version(self):
from django.db.backends.postgresql.base import psycopg2_version
- version_path = 'django.db.backends.postgresql.base.Database.__version__'
- with mock.patch(version_path, '2.6.9'):
- self.assertEqual(psycopg2_version(), (2, 6, 9))
+ with mock.patch('psycopg2.__version__', '4.2.1 (dt dec pq3 ext lo64)'):
+ self.assertEqual(psycopg2_version(), (4, 2, 1))
- with mock.patch(version_path, '2.5.dev0'):
- self.assertEqual(psycopg2_version(), (2, 5))
+ with mock.patch('psycopg2.__version__', '4.2b0.dev1 (dt dec pq3 ext lo64)'):
+ self.assertEqual(psycopg2_version(), (4, 2))
class DateQuotingTest(TestCase):
diff --git a/tests/gis_tests/geos_tests/test_geos.py b/tests/gis_tests/geos_tests/test_geos.py
index 602c37503d..c75ef31d70 100644
--- a/tests/gis_tests/geos_tests/test_geos.py
+++ b/tests/gis_tests/geos_tests/test_geos.py
@@ -12,7 +12,7 @@ from django.contrib.gis.geos import (
MultiLineString, MultiPoint, MultiPolygon, Point, Polygon, fromfile,
fromstr,
)
-from django.contrib.gis.geos.libgeos import geos_version_info
+from django.contrib.gis.geos.libgeos import geos_version_tuple
from django.contrib.gis.shortcuts import numpy
from django.template import Context
from django.template.engine import Engine
@@ -670,11 +670,11 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
self.assertFalse(ls_not_closed.closed)
self.assertTrue(ls_closed.closed)
- if geos_version_info()['version'] >= '3.5':
+ if geos_version_tuple() >= (3, 5):
self.assertFalse(MultiLineString(ls_closed, ls_not_closed).closed)
self.assertTrue(MultiLineString(ls_closed, ls_closed).closed)
- with mock.patch('django.contrib.gis.geos.collections.geos_version_info', lambda: {'version': '3.4.9'}):
+ with mock.patch('django.contrib.gis.geos.libgeos.geos_version_info', lambda: {'version': '3.4.9'}):
with self.assertRaisesMessage(GEOSException, "MultiLineString.closed requires GEOS >= 3.5.0."):
MultiLineString().closed
@@ -1305,6 +1305,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
self.assertEqual(m.group('version'), v_geos)
self.assertEqual(m.group('capi_version'), v_capi)
+ def test_geos_version_tuple(self):
+ with mock.patch('django.contrib.gis.geos.libgeos.geos_version_info', lambda: {'version': '3.4.9'}):
+ self.assertEqual(geos_version_tuple(), (3, 4, 9))
+
def test_from_gml(self):
self.assertEqual(
GEOSGeometry('POINT(0 0)'),
diff --git a/tests/gis_tests/tests.py b/tests/gis_tests/tests.py
index 6b42384203..2f55406f56 100644
--- a/tests/gis_tests/tests.py
+++ b/tests/gis_tests/tests.py
@@ -68,6 +68,12 @@ class TestPostGISVersionCheck(unittest.TestCase):
actual = ops.postgis_version_tuple()
self.assertEqual(expect, actual)
+ def test_version_loose_tuple(self):
+ expect = ('1.2.3b1.dev0', 1, 2, 3)
+ ops = FakePostGISOperations(expect[0])
+ actual = ops.postgis_version_tuple()
+ self.assertEqual(expect, actual)
+
def test_valid_version_numbers(self):
versions = [
('1.3.0', 1, 3, 0),
@@ -81,15 +87,6 @@ class TestPostGISVersionCheck(unittest.TestCase):
actual = ops.spatial_version
self.assertEqual(version[1:], actual)
- def test_invalid_version_numbers(self):
- versions = ['nope', '123']
-
- for version in versions:
- with self.subTest(version=version):
- ops = FakePostGISOperations(version)
- with self.assertRaises(Exception):
- ops.spatial_version
-
def test_no_version_number(self):
ops = FakePostGISOperations()
with self.assertRaises(ImproperlyConfigured):
diff --git a/tests/version/tests.py b/tests/version/tests.py
index b9541cd31a..c0075744bc 100644
--- a/tests/version/tests.py
+++ b/tests/version/tests.py
@@ -1,5 +1,6 @@
from django import get_version
from django.test import SimpleTestCase
+from django.utils.version import get_version_tuple
class VersionTests(SimpleTestCase):
@@ -22,3 +23,8 @@ class VersionTests(SimpleTestCase):
)
for ver_tuple, ver_string in tuples_to_strings:
self.assertEqual(get_version(ver_tuple), ver_string)
+
+ def test_get_version_tuple(self):
+ self.assertEqual(get_version_tuple('1.2.3'), (1, 2, 3))
+ self.assertEqual(get_version_tuple('1.2.3b2'), (1, 2, 3))
+ self.assertEqual(get_version_tuple('1.2.3b2.dev0'), (1, 2, 3))