Skip to content

Commit b80609f

Browse files
authored
Merge pull request #12162 from dbaston/python-osr-spatialref-ctor
Python bindings: Accept CRS definition in osr.SpatialReference constructor
2 parents e3945eb + e85c224 commit b80609f

File tree

3 files changed

+224
-1
lines changed

3 files changed

+224
-1
lines changed

autotest/osr/osr_basic.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,3 +2489,179 @@ def test_osr_basic_GetAuthorityListFromDatabase():
24892489
ret = osr.GetAuthorityListFromDatabase()
24902490
assert "EPSG" in ret
24912491
assert "PROJ" in ret
2492+
2493+
2494+
###############################################################################
2495+
2496+
2497+
@pytest.mark.parametrize(
2498+
"args,kwargs",
2499+
(
2500+
pytest.param([], {"epsg": 4326}, id="epsg"),
2501+
pytest.param(["+proj=utm +zone=18 +datum=WGS84"], {}, id="proj4"),
2502+
pytest.param(
2503+
[
2504+
'PROJCS["NAD83 / Vermont (ftUS)",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",42.5],PARAMETER["central_meridian",-72.5],PARAMETER["scale_factor",0.999964286],PARAMETER["false_easting",1640416.6667],PARAMETER["false_northing",0],UNIT["US survey foot",0.304800609601219,AUTHORITY["EPSG","9003"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","5646"]]'
2505+
],
2506+
{},
2507+
id="wkt",
2508+
),
2509+
pytest.param(
2510+
[
2511+
'{\n "$schema": "https://proj.org/schemas/v0.7/projjson.schema.json",\n "type": "ProjectedCRS",\n "name": "NAD83 / Vermont (ftUS)",\n "base_crs": {\n "name": "NAD83",\n "datum": {\n "type": "GeodeticReferenceFrame",\n "name": "North American Datum 1983",\n "ellipsoid": {\n "name": "GRS 1980",\n "semi_major_axis": 6378137,\n "inverse_flattening": 298.257222101\n }\n },\n "coordinate_system": {\n "subtype": "ellipsoidal",\n "axis": [\n {\n "name": "Geodetic latitude",\n "abbreviation": "Lat",\n "direction": "north",\n "unit": "degree"\n },\n {\n "name": "Geodetic longitude",\n "abbreviation": "Lon",\n "direction": "east",\n "unit": "degree"\n }\n ]\n },\n "id": {\n "authority": "EPSG",\n "code": 4269\n }\n },\n "conversion": {\n "name": "SPCS83 Vermont zone (US survey foot)",\n "method": {\n "name": "Transverse Mercator",\n "id": {\n "authority": "EPSG",\n "code": 9807\n }\n },\n "parameters": [\n {\n "name": "Latitude of natural origin",\n "value": 42.5,\n "unit": "degree",\n "id": {\n "authority": "EPSG",\n "code": 8801\n }\n },\n {\n "name": "Longitude of natural origin",\n "value": -72.5,\n "unit": "degree",\n "id": {\n "authority": "EPSG",\n "code": 8802\n }\n },\n {\n "name": "Scale factor at natural origin",\n "value": 0.999964286,\n "unit": "unity",\n "id": {\n "authority": "EPSG",\n "code": 8805\n }\n },\n {\n "name": "False easting",\n "value": 1640416.6667,\n "unit": {\n "type": "LinearUnit",\n "name": "US survey foot",\n "conversion_factor": 0.304800609601219\n },\n "id": {\n "authority": "EPSG",\n "code": 8806\n }\n },\n {\n "name": "False northing",\n "value": 0,\n "unit": {\n "type": "LinearUnit",\n "name": "US survey foot",\n "conversion_factor": 0.304800609601219\n },\n "id": {\n "authority": "EPSG",\n "code": 8807\n }\n }\n ]\n },\n "coordinate_system": {\n "subtype": "Cartesian",\n "axis": [\n {\n "name": "Easting",\n "abbreviation": "X",\n "direction": "east",\n "unit": {\n "type": "LinearUnit",\n "name": "US survey foot",\n "conversion_factor": 0.304800609601219\n }\n },\n {\n "name": "Northing",\n "abbreviation": "Y",\n "direction": "north",\n "unit": {\n "type": "LinearUnit",\n "name": "US survey foot",\n "conversion_factor": 0.304800609601219\n }\n }\n ]\n },\n "scope": "Engineering survey, topographic mapping.",\n "area": "United States (USA) - Vermont - counties of Addison; Bennington; Caledonia; Chittenden; Essex; Franklin; Grand Isle; Lamoille; Orange; Orleans; Rutland; Washington; Windham; Windsor.",\n "bbox": {\n "south_latitude": 42.72,\n "west_longitude": -73.44,\n "north_latitude": 45.03,\n "east_longitude": -71.5\n },\n "id": {\n "authority": "EPSG",\n "code": 5646\n }\n}'
2512+
],
2513+
{},
2514+
id="projjson text",
2515+
),
2516+
pytest.param(
2517+
[
2518+
{
2519+
"$schema": "https://proj.org/schemas/v0.7/projjson.schema.json",
2520+
"type": "ProjectedCRS",
2521+
"name": "NAD83 / Vermont (ftUS)",
2522+
"base_crs": {
2523+
"name": "NAD83",
2524+
"datum": {
2525+
"type": "GeodeticReferenceFrame",
2526+
"name": "North American Datum 1983",
2527+
"ellipsoid": {
2528+
"name": "GRS 1980",
2529+
"semi_major_axis": 6378137,
2530+
"inverse_flattening": 298.257222101,
2531+
},
2532+
},
2533+
"coordinate_system": {
2534+
"subtype": "ellipsoidal",
2535+
"axis": [
2536+
{
2537+
"name": "Geodetic latitude",
2538+
"abbreviation": "Lat",
2539+
"direction": "north",
2540+
"unit": "degree",
2541+
},
2542+
{
2543+
"name": "Geodetic longitude",
2544+
"abbreviation": "Lon",
2545+
"direction": "east",
2546+
"unit": "degree",
2547+
},
2548+
],
2549+
},
2550+
"id": {"authority": "EPSG", "code": 4269},
2551+
},
2552+
"conversion": {
2553+
"name": "SPCS83 Vermont zone (US survey foot)",
2554+
"method": {
2555+
"name": "Transverse Mercator",
2556+
"id": {"authority": "EPSG", "code": 9807},
2557+
},
2558+
"parameters": [
2559+
{
2560+
"name": "Latitude of natural origin",
2561+
"value": 42.5,
2562+
"unit": "degree",
2563+
"id": {"authority": "EPSG", "code": 8801},
2564+
},
2565+
{
2566+
"name": "Longitude of natural origin",
2567+
"value": -72.5,
2568+
"unit": "degree",
2569+
"id": {"authority": "EPSG", "code": 8802},
2570+
},
2571+
{
2572+
"name": "Scale factor at natural origin",
2573+
"value": 0.999964286,
2574+
"unit": "unity",
2575+
"id": {"authority": "EPSG", "code": 8805},
2576+
},
2577+
{
2578+
"name": "False easting",
2579+
"value": 1640416.6667,
2580+
"unit": {
2581+
"type": "LinearUnit",
2582+
"name": "US survey foot",
2583+
"conversion_factor": 0.304800609601219,
2584+
},
2585+
"id": {"authority": "EPSG", "code": 8806},
2586+
},
2587+
{
2588+
"name": "False northing",
2589+
"value": 0,
2590+
"unit": {
2591+
"type": "LinearUnit",
2592+
"name": "US survey foot",
2593+
"conversion_factor": 0.304800609601219,
2594+
},
2595+
"id": {"authority": "EPSG", "code": 8807},
2596+
},
2597+
],
2598+
},
2599+
"coordinate_system": {
2600+
"subtype": "Cartesian",
2601+
"axis": [
2602+
{
2603+
"name": "Easting",
2604+
"abbreviation": "X",
2605+
"direction": "east",
2606+
"unit": {
2607+
"type": "LinearUnit",
2608+
"name": "US survey foot",
2609+
"conversion_factor": 0.304800609601219,
2610+
},
2611+
},
2612+
{
2613+
"name": "Northing",
2614+
"abbreviation": "Y",
2615+
"direction": "north",
2616+
"unit": {
2617+
"type": "LinearUnit",
2618+
"name": "US survey foot",
2619+
"conversion_factor": 0.304800609601219,
2620+
},
2621+
},
2622+
],
2623+
},
2624+
"scope": "Engineering survey, topographic mapping.",
2625+
"area": "United States (USA) - Vermont - counties of Addison; Bennington; Caledonia; Chittenden; Essex; Franklin; Grand Isle; Lamoille; Orange; Orleans; Rutland; Washington; Windham; Windsor.",
2626+
"bbox": {
2627+
"south_latitude": 42.72,
2628+
"west_longitude": -73.44,
2629+
"north_latitude": 45.03,
2630+
"east_longitude": -71.5,
2631+
},
2632+
"id": {"authority": "EPSG", "code": 5646},
2633+
}
2634+
],
2635+
{},
2636+
id="projjson dict",
2637+
),
2638+
),
2639+
)
2640+
def test_osr_basic_constructor(args, kwargs):
2641+
2642+
srs = osr.SpatialReference(*args, **kwargs)
2643+
2644+
assert srs.ExportToWkt() != ""
2645+
2646+
2647+
@pytest.mark.parametrize("arg", ("", None))
2648+
def test_osr_basic_constructor_empty(arg):
2649+
2650+
srs = osr.SpatialReference(arg)
2651+
assert srs is not None
2652+
2653+
2654+
def test_osr_basic_constructor_overspecified():
2655+
2656+
# The arguments provided here don't make any sense.
2657+
# But SpatialReference.SetFromUserInput doesn't seem to complain if we pass it
2658+
# unexpected options, so we have no way to catch this for now.
2659+
2660+
with pytest.raises(ValueError, match="Unexpected argument"):
2661+
osr.SpatialReference(proj4="+proj=utm +zone=18 +datum=WGS84", epsg=4326)
2662+
2663+
2664+
def test_osr_basic_constructor_invalid_kwarg():
2665+
2666+
with pytest.raises(ValueError, match="Unexpected argument"):
2667+
osr.SpatialReference(description="VT State Plane")

swig/include/python/docs/osr_spatialreference_docs.i

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
%feature("docstring") OSRSpatialReferenceShadow "
22
Python proxy of an :cpp:class:`OGRSpatialReference`.
3+
4+
Create a new spatial reference object. An empty object will be created
5+
unless exactly one of the following parameters is provided.
6+
7+
Parameters
8+
----------
9+
name : str / dict, optional
10+
SRS description in a format understood by :py:meth:`SetFromUserInput`.
11+
epsg : int, optional
12+
EPSG CRS code, as understood by :py:meth:`ImportFromEPSG`
13+
wkt : str, optional
14+
WKT CRS string, as understood by :py:meth:`ImportFromWkt`
15+
16+
Examples
17+
--------
18+
>>> osr.SpatialReference(epsg=5646).GetName()
19+
'NAD83 / Vermont (ftUS)'
20+
>>> osr.SpatialReference('+proj=utm +zone=18 +datum=WGS84').GetUTMZone()
21+
18
322
";
423

524
%extend OSRSpatialReferenceShadow {

swig/include/python/osr_python.i

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,34 @@ def _WarnIfUserHasNotSpecifiedIfUsingExceptions():
5353

5454
_WarnIfUserHasNotSpecifiedIfUsingExceptions()
5555

56+
user_input = None
57+
58+
if len(args) + len(kwargs) > 1:
59+
# We could pass additional kwargs as options to SetFromUserInput,
60+
# but that is not commonly needed and limits our ability to
61+
# validate arguments here.
62+
raise ValueError("Unexpected argument to SpatialReference")
63+
64+
if kwargs:
65+
if "wkt" in kwargs:
66+
user_input = kwargs["wkt"]
67+
elif "name" in kwargs:
68+
user_input = kwargs["name"]
69+
elif "epsg" in kwargs:
70+
user_input = f'EPSG:{kwargs["epsg"]}'
71+
else:
72+
raise ValueError("Unexpected argument to SpatialReference")
73+
74+
if args:
75+
if type(args[0]) is dict:
76+
import json
77+
user_input = json.dumps(args[0])
78+
else:
79+
user_input = args[0]
80+
5681
try:
5782
with ExceptionMgr(useExceptions=True):
58-
this = _osr.new_SpatialReference(*args, **kwargs)
83+
this = _osr.new_SpatialReference()
5984
finally:
6085
pass
6186
if hasattr(_osr, "SpatialReference_swiginit"):
@@ -68,6 +93,9 @@ def _WarnIfUserHasNotSpecifiedIfUsingExceptions():
6893
except __builtin__.Exception:
6994
self.this = this
7095

96+
if user_input:
97+
self.SetFromUserInput(user_input)
98+
7199
%}
72100

73101
%feature("shadow") ImportFromCF1 %{

0 commit comments

Comments
 (0)