From 5fa936514ad901f532ebd03e2da4436611f4358e Mon Sep 17 00:00:00 2001 From: Ian Dees Date: Sat, 22 Aug 2026 07:40:07 -0500 Subject: [PATCH] fix axis order for shapefile/GML sources with an explicit srs tag --- openaddr/conform.py | 4 +++ openaddr/tests/conform.py | 25 ++++++++++++++++-- openaddr/tests/conforms/lake-man-epsg4269.dbf | Bin 0 -> 7759 bytes .../tests/conforms/lake-man-epsg4269.json | 20 ++++++++++++++ openaddr/tests/conforms/lake-man-epsg4269.shp | Bin 0 -> 268 bytes openaddr/tests/conforms/lake-man-epsg4269.shx | Bin 0 -> 148 bytes 6 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 openaddr/tests/conforms/lake-man-epsg4269.dbf create mode 100644 openaddr/tests/conforms/lake-man-epsg4269.json create mode 100644 openaddr/tests/conforms/lake-man-epsg4269.shp create mode 100644 openaddr/tests/conforms/lake-man-epsg4269.shx diff --git a/openaddr/conform.py b/openaddr/conform.py index 80f73e7a..cc24f95b 100644 --- a/openaddr/conform.py +++ b/openaddr/conform.py @@ -550,6 +550,10 @@ def ogr_source_to_csv(source_config, source_path, dest_path): _L.debug("SRS tag found specifying %s", srs) inSpatialRef = osr.SpatialReference() inSpatialRef.ImportFromEPSG(int(srs[5:])) + + if int(osgeo.__version__[0]) >= 3: + # GDAL 3 changes axis order: https://github.com/OSGeo/gdal/issues/1546 + inSpatialRef.SetAxisMappingStrategy(osgeo.osr.OAMS_TRADITIONAL_GIS_ORDER) else: # OGR is capable of doing more than EPSG, but so far we don't need it. raise Exception("Bad SRS. Can only handle EPSG, the SRS tag is %s", srs) diff --git a/openaddr/tests/conform.py b/openaddr/tests/conform.py index bec50520..2cf9a474 100644 --- a/openaddr/tests/conform.py +++ b/openaddr/tests/conform.py @@ -1894,6 +1894,24 @@ def test_lake_man_shp_noprj_epsg26943(self): self.assertAlmostEqual(-122.2592497, rows[0]['geometry']['coordinates'][0], places=4) self.assertAlmostEqual(37.8026126, rows[0]['geometry']['coordinates'][1], places=4) + def test_lake_man_shp_epsg4269_axis_order(self): + # Regression test for https://github.com/openaddresses/batch-machine/issues/26 + # A shapefile with an explicit geographic "srs" tag (here EPSG:4269, NAD83) + # must not have its coordinates flipped by GDAL 3's authority-compliant + # (lat, lon) axis order. The underlying shapefile geometry is stored in + # ordinary (lon, lat) order, same coordinates as the plain lake-man.shp + # fixture used by test_lake_man, so the expected output here matches that + # test's expected values. Before the fix, this source's coordinates come + # out as (lat, lon) instead of (lon, lat). + rc, dest_path = self._run_conform_on_source('lake-man-epsg4269', 'shp') + self.assertEqual(0, rc) + + with open(dest_path) as fp: + rows = list(map(json.loads, list(fp))) + self.assertEqual('Point', rows[0]['geometry']['type']) + self.assertAlmostEqual(-122.2592497, rows[0]['geometry']['coordinates'][0], places=4) + self.assertAlmostEqual(37.8026126, rows[0]['geometry']['coordinates'][1], places=4) + # TODO: add tests for non-ESRI GeoJSON sources def test_lake_man_split2(self): @@ -1973,8 +1991,11 @@ def test_lake_man_gml(self): with open(dest_path) as fp: rows = list(map(json.loads, list(fp))) self.assertEqual(6, len(rows)) - self.assertAlmostEqual(37.8026126, rows[0]['geometry']['coordinates'][0], places=4) - self.assertAlmostEqual(-122.2592497, rows[0]['geometry']['coordinates'][1], places=4) + # GeoJSON coordinates are always [lon, lat]. This source has an + # explicit "srs": "EPSG:4326" tag; see + # https://github.com/openaddresses/batch-machine/issues/26. + self.assertAlmostEqual(-122.2592497, rows[0]['geometry']['coordinates'][0], places=4) + self.assertAlmostEqual(37.8026126, rows[0]['geometry']['coordinates'][1], places=4) self.assertEqual(rows[0]['properties']['number'], '5115') self.assertEqual(rows[0]['properties']['street'], 'FRUITED PLAINS LN') diff --git a/openaddr/tests/conforms/lake-man-epsg4269.dbf b/openaddr/tests/conforms/lake-man-epsg4269.dbf new file mode 100644 index 0000000000000000000000000000000000000000..a710e002e1d4f5099286bb94435379a38d064777 GIT binary patch literal 7759 zcmeHL-D<)x6fWD?V6Ye1m2Y5wY;7;AsS;>wNn3}z5kcn$4#D|4yV#qqZJgLc9M~k1 zi}u2La&o@&lbnwv?$F8M%8d!{yx@cXhS~>#uG9thKHpp z0eT-H5~OJf!L%RvY49ID38tuUQKB;ON8w~bs81$-oJWIzPGIU^@iAhi-XCUoTDfQY zk9-{BczixSln`ppwlB2vY?hQ$*!cyqAN}KhbX1?QKY*XbM`=Ey^<(-kmjBNKQ$NUY zh-d+r`aH%Ng=fe2u{>zcAg(AR3Q19@+LIlH)8uoh0;eETEL4@xoYk1^DnmzN&}I zmuz9ZS-tH$i`^$T5CD)xPTmPQxsD;9oJ>knEjfV&ZX$x_Y64NS5sjyMw}X6D54W~f zO@!UY`dtP)Ng^lj^yK7uS2#IYR#n!PoSN(|U;~;9XfGE<+Yl8&Nc#>fH|VRXtqp^{qbZHmfx^5CD)w zPOf`OPWCm(iQaIvTn?d7AQ@d&y+hHF|J^Hn`iK}C6AEtZ0yDwtodboitI literal 0 HcmV?d00001 diff --git a/openaddr/tests/conforms/lake-man-epsg4269.json b/openaddr/tests/conforms/lake-man-epsg4269.json new file mode 100644 index 00000000..4e591ef6 --- /dev/null +++ b/openaddr/tests/conforms/lake-man-epsg4269.json @@ -0,0 +1,20 @@ +{ + "schema": 2, + "layers": { + "addresses": [{ + "name": "default", + "data": "http://fake-web/lake-man-epsg4269.zip", + "cache": "http://fake-cache/lake-man-epsg4269.zip", + "protocol": "http", + "compression": "zip", + "conform": { + "lon": "X", + "lat": "Y", + "number": "NUMBER", + "street": "STRNAME", + "format": "shapefile", + "srs": "EPSG:4269" + } + }] + } +} diff --git a/openaddr/tests/conforms/lake-man-epsg4269.shp b/openaddr/tests/conforms/lake-man-epsg4269.shp new file mode 100644 index 0000000000000000000000000000000000000000..6963b4fba95f8451deb08afedc7da5581c7bd9f7 GIT binary patch literal 268 zcmZQzQ0HR64%%KYGcYhh2>kXHE`4A%Q#~f4BQ&>#q<#L=|olWDFOw zS!+I=V%h`I%Y-BcHaDw(t@Tcb9MA<2egFUemuv#s$>UhQ_Bce21ttfie@z0)F$Rh} WtAog~BFVigM0GnGlAK;Gl0N`XH#&g; literal 0 HcmV?d00001 diff --git a/openaddr/tests/conforms/lake-man-epsg4269.shx b/openaddr/tests/conforms/lake-man-epsg4269.shx new file mode 100644 index 0000000000000000000000000000000000000000..f7808d6696700972ca91fedae1887287b647aa68 GIT binary patch literal 148 zcmZQzQ0HR64!mA4GcYhh2>kXHE`4A%Q#~f4BQ&>#q<#L=|q*2q*=z S#{o+FLFpJModu;UKr{gI<`F^w literal 0 HcmV?d00001