diff --git a/django/contrib/gis/gdal/__init__.py b/django/contrib/gis/gdal/__init__.py
index de41df9..c33fbcb 100644
a
|
b
|
|
37 | 37 | try: |
38 | 38 | from django.contrib.gis.gdal.driver import Driver |
39 | 39 | from django.contrib.gis.gdal.datasource import DataSource |
40 | | from django.contrib.gis.gdal.libgdal import gdal_version, gdal_full_version, gdal_release_date, GDAL_VERSION |
| 40 | from django.contrib.gis.gdal.libgdal import gdal_version, gdal_full_version, GDAL_VERSION |
41 | 41 | from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform |
42 | 42 | from django.contrib.gis.gdal.geometries import OGRGeometry |
43 | 43 | HAS_GDAL = True |
diff --git a/django/contrib/gis/gdal/libgdal.py b/django/contrib/gis/gdal/libgdal.py
index 0d2889d..7c6b128 100644
a
|
b
|
|
1 | 1 | from __future__ import unicode_literals |
2 | 2 | |
| 3 | import logging |
3 | 4 | import os |
4 | 5 | import re |
5 | | from ctypes import c_char_p, CDLL |
| 6 | from ctypes import c_char_p, c_int, CDLL, CFUNCTYPE |
6 | 7 | from ctypes.util import find_library |
| 8 | |
7 | 9 | from django.contrib.gis.gdal.error import OGRException |
8 | 10 | |
| 11 | |
| 12 | logger = logging.getLogger('django.contrib.gis') |
| 13 | |
9 | 14 | # Custom library path set? |
10 | 15 | try: |
11 | 16 | from django.conf import settings |
… |
… |
def gdal_full_version():
|
73 | 78 | "Returns the full GDAL version information." |
74 | 79 | return _version_info('') |
75 | 80 | |
76 | | def gdal_release_date(date=False): |
77 | | """ |
78 | | Returns the release date in a string format, e.g, "2007/06/27". |
79 | | If the date keyword argument is set to True, a Python datetime object |
80 | | will be returned instead. |
81 | | """ |
82 | | from datetime import date as date_type |
83 | | rel = _version_info('RELEASE_DATE') |
84 | | yy, mm, dd = map(int, (rel[0:4], rel[4:6], rel[6:8])) |
85 | | d = date_type(yy, mm, dd) |
86 | | if date: return d |
87 | | else: return d.strftime('%Y/%m/%d') |
88 | | |
89 | 81 | version_regex = re.compile(r'^(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<subminor>\d+))?') |
90 | 82 | def gdal_version_info(): |
91 | 83 | ver = gdal_version().decode() |
… |
… |
GDAL_MINOR_VERSION = int(_verinfo['minor'])
|
99 | 91 | GDAL_SUBMINOR_VERSION = _verinfo['subminor'] and int(_verinfo['subminor']) |
100 | 92 | GDAL_VERSION = (GDAL_MAJOR_VERSION, GDAL_MINOR_VERSION, GDAL_SUBMINOR_VERSION) |
101 | 93 | del _verinfo |
| 94 | |
| 95 | # Set library error handling so as errors are logged |
| 96 | CPLErrorHandler = CFUNCTYPE(None, c_int, c_int, c_char_p) |
| 97 | def err_handler(error_class, error_number, message): |
| 98 | logger.error('GDAL_ERROR %d: %s' % (error_number, message)) |
| 99 | err_handler = CPLErrorHandler(err_handler) |
| 100 | |
| 101 | def function(name, args, restype): |
| 102 | func = std_call(name) |
| 103 | func.argtypes = args |
| 104 | func.restype = restype |
| 105 | return func |
| 106 | |
| 107 | set_error_handler = function('CPLSetErrorHandler', [CPLErrorHandler], CPLErrorHandler) |
| 108 | set_error_handler(err_handler) |
diff --git a/django/contrib/gis/gdal/tests/test_ds.py b/django/contrib/gis/gdal/tests/test_ds.py
index 094f65b..69e3054 100644
a
|
b
|
from django.contrib.gis.gdal import DataSource, Envelope, OGRGeometry, OGRExcept
|
4 | 4 | from django.contrib.gis.gdal.field import OFTReal, OFTInteger, OFTString |
5 | 5 | from django.contrib.gis.geometry.test_data import get_ds_file, TestDS, TEST_DATA |
6 | 6 | |
| 7 | |
7 | 8 | # List of acceptable data sources. |
8 | 9 | ds_list = (TestDS('test_point', nfeat=5, nfld=3, geom='POINT', gtype=1, driver='ESRI Shapefile', |
9 | 10 | fields={'dbl' : OFTReal, 'int' : OFTInteger, 'str' : OFTString,}, |
… |
… |
class DataSourceTest(unittest.TestCase):
|
59 | 60 | |
60 | 61 | def test03a_layers(self): |
61 | 62 | "Testing Data Source Layers." |
62 | | print("\nBEGIN - expecting out of range feature id error; safe to ignore.\n") |
63 | 63 | for source in ds_list: |
64 | 64 | ds = DataSource(source.ds) |
65 | 65 | |
… |
… |
class DataSourceTest(unittest.TestCase):
|
108 | 108 | # the feature values here while in this loop. |
109 | 109 | for fld_name in fld_names: |
110 | 110 | self.assertEqual(source.field_values[fld_name][i], feat.get(fld_name)) |
111 | | print("\nEND - expecting out of range feature id error; safe to ignore.") |
112 | 111 | |
113 | 112 | def test03b_layer_slice(self): |
114 | 113 | "Test indexing and slicing on Layers." |
diff --git a/django/contrib/gis/gdal/tests/test_geom.py b/django/contrib/gis/gdal/tests/test_geom.py
index b22bb62..9b8ae6a 100644
a
|
b
|
class OGRGeomTest(unittest.TestCase, TestDataMixin):
|
235 | 235 | # Both rings in this geometry are not closed. |
236 | 236 | poly = OGRGeometry('POLYGON((0 0, 5 0, 5 5, 0 5), (1 1, 2 1, 2 2, 2 1))') |
237 | 237 | self.assertEqual(8, poly.point_count) |
238 | | print("\nBEGIN - expecting IllegalArgumentException; safe to ignore.\n") |
239 | | try: |
240 | | c = poly.centroid |
241 | | except OGRException: |
242 | | # Should raise an OGR exception, rings are not closed |
243 | | pass |
244 | | else: |
245 | | self.fail('Should have raised an OGRException!') |
246 | | print("\nEND - expecting IllegalArgumentException; safe to ignore.\n") |
| 238 | with self.assertRaises(OGRException): |
| 239 | _ = poly.centroid |
247 | 240 | |
248 | 241 | poly.close_rings() |
249 | 242 | self.assertEqual(10, poly.point_count) # Two closing points should've been added |
diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py
index b31a795..d19644a 100644
a
|
b
|
|
6 | 6 | This module also houses GEOS Pointer utilities, including |
7 | 7 | get_pointer_arr(), and GEOM_PTR. |
8 | 8 | """ |
| 9 | import logging |
9 | 10 | import os |
10 | 11 | import re |
11 | | import sys |
12 | 12 | from ctypes import c_char_p, Structure, CDLL, CFUNCTYPE, POINTER |
13 | 13 | from ctypes.util import find_library |
| 14 | |
14 | 15 | from django.contrib.gis.geos.error import GEOSException |
15 | 16 | |
| 17 | |
| 18 | logger = logging.getLogger('django.contrib.gis') |
| 19 | |
16 | 20 | # Custom library path set? |
17 | 21 | try: |
18 | 22 | from django.conf import settings |
… |
… |
lgeos = CDLL(lib_path)
|
56 | 60 | # Supposed to mimic the GEOS message handler (C below): |
57 | 61 | # typedef void (*GEOSMessageHandler)(const char *fmt, ...); |
58 | 62 | NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p) |
59 | | def notice_h(fmt, lst, output_h=sys.stdout): |
| 63 | def notice_h(fmt, lst): |
60 | 64 | fmt, lst = fmt.decode(), lst.decode() |
61 | 65 | try: |
62 | 66 | warn_msg = fmt % lst |
63 | 67 | except: |
64 | 68 | warn_msg = fmt |
65 | | output_h.write('GEOS_NOTICE: %s\n' % warn_msg) |
| 69 | logger.warn('GEOS_NOTICE: %s\n' % warn_msg) |
66 | 70 | notice_h = NOTICEFUNC(notice_h) |
67 | 71 | |
68 | 72 | ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p) |
69 | | def error_h(fmt, lst, output_h=sys.stderr): |
| 73 | def error_h(fmt, lst): |
70 | 74 | fmt, lst = fmt.decode(), lst.decode() |
71 | 75 | try: |
72 | 76 | err_msg = fmt % lst |
73 | 77 | except: |
74 | 78 | err_msg = fmt |
75 | | output_h.write('GEOS_ERROR: %s\n' % err_msg) |
| 79 | logger.error('GEOS_ERROR: %s\n' % err_msg) |
76 | 80 | error_h = ERRORFUNC(error_h) |
77 | 81 | |
78 | 82 | #### GEOS Geometry C data structures, and utility functions. #### |
diff --git a/django/contrib/gis/geos/tests/test_geos.py b/django/contrib/gis/geos/tests/test_geos.py
index cbe5136..283daa4 100644
a
|
b
|
class GEOSTest(unittest.TestCase, TestDataMixin):
|
147 | 147 | def test_errors(self): |
148 | 148 | "Testing the Error handlers." |
149 | 149 | # string-based |
150 | | print("\nBEGIN - expecting GEOS_ERROR; safe to ignore.\n") |
151 | 150 | for err in self.geometries.errors: |
152 | | try: |
153 | | g = fromstr(err.wkt) |
154 | | except (GEOSException, ValueError): |
155 | | pass |
| 151 | with self.assertRaises((GEOSException, ValueError)): |
| 152 | _ = fromstr(err.wkt) |
156 | 153 | |
157 | 154 | # Bad WKB |
158 | 155 | self.assertRaises(GEOSException, GEOSGeometry, memoryview(b'0')) |
159 | 156 | |
160 | | print("\nEND - expecting GEOS_ERROR; safe to ignore.\n") |
161 | | |
162 | 157 | class NotAGeometry(object): |
163 | 158 | pass |
164 | 159 | |
… |
… |
class GEOSTest(unittest.TestCase, TestDataMixin):
|
458 | 453 | |
459 | 454 | def test_multipolygons(self): |
460 | 455 | "Testing MultiPolygon objects." |
461 | | print("\nBEGIN - expecting GEOS_NOTICE; safe to ignore.\n") |
462 | 456 | prev = fromstr('POINT (0 0)') |
463 | 457 | for mp in self.geometries.multipolygons: |
464 | 458 | mpoly = fromstr(mp.wkt) |
… |
… |
class GEOSTest(unittest.TestCase, TestDataMixin):
|
477 | 471 | self.assertEqual(p.valid, True) |
478 | 472 | self.assertEqual(mpoly.wkt, MultiPolygon(*tuple(poly.clone() for poly in mpoly)).wkt) |
479 | 473 | |
480 | | print("\nEND - expecting GEOS_NOTICE; safe to ignore.\n") |
481 | | |
482 | 474 | def test_memory_hijinks(self): |
483 | 475 | "Testing Geometry __del__() on rings and polygons." |
484 | 476 | #### Memory issues with rings and polygons |
… |
… |
class GEOSTest(unittest.TestCase, TestDataMixin):
|
1025 | 1017 | |
1026 | 1018 | g = GEOSGeometry("POINT(0 0)") |
1027 | 1019 | self.assertTrue(g.valid) |
1028 | | self.assertTrue(isinstance(g.valid_reason, six.string_types)) |
| 1020 | self.assertIsInstance(g.valid_reason, six.string_types) |
1029 | 1021 | self.assertEqual(g.valid_reason, "Valid Geometry") |
1030 | 1022 | |
1031 | | print("\nBEGIN - expecting GEOS_NOTICE; safe to ignore.\n") |
1032 | | |
1033 | 1023 | g = GEOSGeometry("LINESTRING(0 0, 0 0)") |
1034 | 1024 | |
1035 | | self.assertTrue(not g.valid) |
1036 | | self.assertTrue(isinstance(g.valid_reason, six.string_types)) |
| 1025 | self.assertFalse(g.valid) |
| 1026 | self.assertIsInstance(g.valid_reason, six.string_types) |
1037 | 1027 | self.assertTrue(g.valid_reason.startswith("Too few points in geometry component")) |
1038 | 1028 | |
1039 | | print("\nEND - expecting GEOS_NOTICE; safe to ignore.\n") |
1040 | | |
1041 | 1029 | @unittest.skipUnless(geos_version_info()['version'] >= '3.2.0', "geos >= 3.2.0 is required") |
1042 | 1030 | def test_linearref(self): |
1043 | 1031 | "Testing linear referencing" |