Kaydet (Commit) 08bda82c authored tarafından chillaranand's avatar chillaranand Kaydeden (comit) Tim Graham

Fixed #27830 -- Used distutils.version.LooseVersion for version parsing.

üst e7dc39fb
...@@ -11,6 +11,7 @@ from django.core.exceptions import ImproperlyConfigured ...@@ -11,6 +11,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.db.backends.postgresql.operations import DatabaseOperations from django.db.backends.postgresql.operations import DatabaseOperations
from django.db.utils import ProgrammingError from django.db.utils import ProgrammingError
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.version import get_version_tuple
from .adapter import PostGISAdapter from .adapter import PostGISAdapter
from .models import PostGISGeometryColumns, PostGISSpatialRefSys from .models import PostGISGeometryColumns, PostGISSpatialRefSys
...@@ -109,7 +110,6 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations): ...@@ -109,7 +110,6 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
postgis = True postgis = True
geography = True geography = True
geom_func_prefix = 'ST_' geom_func_prefix = 'ST_'
version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
Adapter = PostGISAdapter Adapter = PostGISAdapter
...@@ -353,18 +353,8 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations): ...@@ -353,18 +353,8 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
Return the PostGIS version as a tuple (version string, major, Return the PostGIS version as a tuple (version string, major,
minor, subminor). minor, subminor).
""" """
# Getting the PostGIS version
version = self.postgis_lib_version() version = self.postgis_lib_version()
m = self.version_regex.match(version) return (version,) + get_version_tuple(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)
def proj_version_tuple(self): def proj_version_tuple(self):
""" """
......
...@@ -3,8 +3,6 @@ SQL functions reference lists: ...@@ -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://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 https://www.gaia-gis.it/gaia-sins/spatialite-sql-4.2.1.html
""" """
import re
from django.contrib.gis.db.backends.base.operations import ( from django.contrib.gis.db.backends.base.operations import (
BaseSpatialOperations, BaseSpatialOperations,
) )
...@@ -16,6 +14,7 @@ from django.contrib.gis.measure import Distance ...@@ -16,6 +14,7 @@ from django.contrib.gis.measure import Distance
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db.backends.sqlite3.operations import DatabaseOperations from django.db.backends.sqlite3.operations import DatabaseOperations
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.version import get_version_tuple
class SpatiaLiteDistanceOperator(SpatialOperator): class SpatiaLiteDistanceOperator(SpatialOperator):
...@@ -35,7 +34,6 @@ class SpatiaLiteDistanceOperator(SpatialOperator): ...@@ -35,7 +34,6 @@ class SpatiaLiteDistanceOperator(SpatialOperator):
class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations): class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
name = 'spatialite' name = 'spatialite'
spatialite = True spatialite = True
version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
Adapter = SpatiaLiteAdapter Adapter = SpatiaLiteAdapter
...@@ -189,16 +187,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations): ...@@ -189,16 +187,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
minor, subminor). minor, subminor).
""" """
version = self.spatialite_version() version = self.spatialite_version()
return (version,) + get_version_tuple(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)
def spatial_aggregate_name(self, agg_name): def spatial_aggregate_name(self, agg_name):
""" """
......
...@@ -8,7 +8,7 @@ from ctypes import byref, c_int, c_uint ...@@ -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 import prototypes as capi
from django.contrib.gis.geos.error import GEOSException from django.contrib.gis.geos.error import GEOSException
from django.contrib.gis.geos.geometry import GEOSGeometry, LinearGeometryMixin 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.linestring import LinearRing, LineString
from django.contrib.gis.geos.point import Point from django.contrib.gis.geos.point import Point
from django.contrib.gis.geos.polygon import Polygon from django.contrib.gis.geos.polygon import Polygon
...@@ -115,7 +115,7 @@ class MultiLineString(LinearGeometryMixin, GeometryCollection): ...@@ -115,7 +115,7 @@ class MultiLineString(LinearGeometryMixin, GeometryCollection):
@property @property
def closed(self): 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.") raise GEOSException("MultiLineString.closed requires GEOS >= 3.5.0.")
return super().closed return super().closed
......
...@@ -15,6 +15,7 @@ from ctypes.util import find_library ...@@ -15,6 +15,7 @@ from ctypes.util import find_library
from django.contrib.gis.geos.error import GEOSException from django.contrib.gis.geos.error import GEOSException
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import SimpleLazyObject from django.utils.functional import SimpleLazyObject
from django.utils.version import get_version_tuple
logger = logging.getLogger('django.contrib.gis') logger = logging.getLogger('django.contrib.gis')
...@@ -199,3 +200,8 @@ def geos_version_info(): ...@@ -199,3 +200,8 @@ def geos_version_info():
raise GEOSException('Could not parse version info string "%s"' % ver) raise GEOSException('Could not parse version info string "%s"' % ver)
return {key: m.group(key) for key in ( return {key: m.group(key) for key in (
'version', 'release_candidate', 'capi_version', 'major', 'minor', 'subminor')} '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'])
...@@ -14,6 +14,7 @@ from django.db.backends.base.base import BaseDatabaseWrapper ...@@ -14,6 +14,7 @@ from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.utils import DatabaseError as WrappedDatabaseError from django.db.utils import DatabaseError as WrappedDatabaseError
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.safestring import SafeText from django.utils.safestring import SafeText
from django.utils.version import get_version_tuple
try: try:
import psycopg2 as Database import psycopg2 as Database
...@@ -25,7 +26,7 @@ except ImportError as e: ...@@ -25,7 +26,7 @@ except ImportError as e:
def psycopg2_version(): def psycopg2_version():
version = psycopg2.__version__.split(' ', 1)[0] 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() PSYCOPG2_VERSION = psycopg2_version()
......
...@@ -2,6 +2,7 @@ import datetime ...@@ -2,6 +2,7 @@ import datetime
import functools import functools
import os import os
import subprocess import subprocess
from distutils.version import LooseVersion
def get_version(version=None): def get_version(version=None):
...@@ -77,3 +78,17 @@ def get_git_changeset(): ...@@ -77,3 +78,17 @@ def get_git_changeset():
except ValueError: except ValueError:
return None return None
return timestamp.strftime('%Y%m%d%H%M%S') 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)
...@@ -323,13 +323,12 @@ class PostgreSQLTests(TestCase): ...@@ -323,13 +323,12 @@ class PostgreSQLTests(TestCase):
def test_correct_extraction_psycopg2_version(self): def test_correct_extraction_psycopg2_version(self):
from django.db.backends.postgresql.base import psycopg2_version 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'): with mock.patch('psycopg2.__version__', '4.2.1 (dt dec pq3 ext lo64)'):
self.assertEqual(psycopg2_version(), (2, 6, 9)) self.assertEqual(psycopg2_version(), (4, 2, 1))
with mock.patch(version_path, '2.5.dev0'): with mock.patch('psycopg2.__version__', '4.2b0.dev1 (dt dec pq3 ext lo64)'):
self.assertEqual(psycopg2_version(), (2, 5)) self.assertEqual(psycopg2_version(), (4, 2))
class DateQuotingTest(TestCase): class DateQuotingTest(TestCase):
......
...@@ -12,7 +12,7 @@ from django.contrib.gis.geos import ( ...@@ -12,7 +12,7 @@ from django.contrib.gis.geos import (
MultiLineString, MultiPoint, MultiPolygon, Point, Polygon, fromfile, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon, fromfile,
fromstr, 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.contrib.gis.shortcuts import numpy
from django.template import Context from django.template import Context
from django.template.engine import Engine from django.template.engine import Engine
...@@ -670,11 +670,11 @@ class GEOSTest(SimpleTestCase, TestDataMixin): ...@@ -670,11 +670,11 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
self.assertFalse(ls_not_closed.closed) self.assertFalse(ls_not_closed.closed)
self.assertTrue(ls_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.assertFalse(MultiLineString(ls_closed, ls_not_closed).closed)
self.assertTrue(MultiLineString(ls_closed, ls_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."): with self.assertRaisesMessage(GEOSException, "MultiLineString.closed requires GEOS >= 3.5.0."):
MultiLineString().closed MultiLineString().closed
...@@ -1305,6 +1305,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin): ...@@ -1305,6 +1305,10 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
self.assertEqual(m.group('version'), v_geos) self.assertEqual(m.group('version'), v_geos)
self.assertEqual(m.group('capi_version'), v_capi) 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): def test_from_gml(self):
self.assertEqual( self.assertEqual(
GEOSGeometry('POINT(0 0)'), GEOSGeometry('POINT(0 0)'),
......
...@@ -68,6 +68,12 @@ class TestPostGISVersionCheck(unittest.TestCase): ...@@ -68,6 +68,12 @@ class TestPostGISVersionCheck(unittest.TestCase):
actual = ops.postgis_version_tuple() actual = ops.postgis_version_tuple()
self.assertEqual(expect, actual) 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): def test_valid_version_numbers(self):
versions = [ versions = [
('1.3.0', 1, 3, 0), ('1.3.0', 1, 3, 0),
...@@ -81,15 +87,6 @@ class TestPostGISVersionCheck(unittest.TestCase): ...@@ -81,15 +87,6 @@ class TestPostGISVersionCheck(unittest.TestCase):
actual = ops.spatial_version actual = ops.spatial_version
self.assertEqual(version[1:], actual) 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): def test_no_version_number(self):
ops = FakePostGISOperations() ops = FakePostGISOperations()
with self.assertRaises(ImproperlyConfigured): with self.assertRaises(ImproperlyConfigured):
......
from django import get_version from django import get_version
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.utils.version import get_version_tuple
class VersionTests(SimpleTestCase): class VersionTests(SimpleTestCase):
...@@ -22,3 +23,8 @@ class VersionTests(SimpleTestCase): ...@@ -22,3 +23,8 @@ class VersionTests(SimpleTestCase):
) )
for ver_tuple, ver_string in tuples_to_strings: for ver_tuple, ver_string in tuples_to_strings:
self.assertEqual(get_version(ver_tuple), ver_string) 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))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment