diff --git a/pyproj/_crs.pyx b/pyproj/_crs.pyx index 7a13c5b5b..cefaee2e6 100644 --- a/pyproj/_crs.pyx +++ b/pyproj/_crs.pyx @@ -1288,13 +1288,13 @@ _DATUM_TYPE_MAP = { } _PJ_DATUM_TYPE_MAP = { + DatumType.DATUM_ENSEMBLE: PJ_TYPE_DATUM_ENSEMBLE, DatumType.GEODETIC_REFERENCE_FRAME: PJ_TYPE_GEODETIC_REFERENCE_FRAME, DatumType.DYNAMIC_GEODETIC_REFERENCE_FRAME: PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME, DatumType.VERTICAL_REFERENCE_FRAME: PJ_TYPE_VERTICAL_REFERENCE_FRAME, DatumType.DYNAMIC_VERTICAL_REFERENCE_FRAME: PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME, - DatumType.DATUM_ENSEMBLE: PJ_TYPE_DATUM_ENSEMBLE, } @@ -1329,7 +1329,7 @@ cdef class Datum(_CRSParts): return datum @staticmethod - def from_authority(auth_name, code): + def _from_authority(auth_name, code, PJ_CATEGORY category): """ Create a Datum from an authority code. @@ -1350,7 +1350,7 @@ cdef class Datum(_CRSParts): context, cstrencode(str(auth_name)), cstrencode(str(code)), - PJ_CATEGORY_DATUM, + category, False, NULL, ) @@ -1361,6 +1361,27 @@ cdef class Datum(_CRSParts): CRSError.clear() return Datum.create(context, datum_pj) + @staticmethod + def from_authority(auth_name, code): + """ + Create a Datum from an authority code. + + Parameters + ---------- + auth_name: str + Name ot the authority. + code: str or int + The code used by the authority. + + Returns + ------- + Datum + """ + try: + return Datum._from_authority(auth_name, code, PJ_CATEGORY_DATUM_ENSEMBLE) + except CRSError: + return Datum._from_authority(auth_name, code, PJ_CATEGORY_DATUM) + @staticmethod def from_epsg(code): """ diff --git a/pyproj/proj.pxi b/pyproj/proj.pxi index 848f5fb20..d1e3855cd 100644 --- a/pyproj/proj.pxi +++ b/pyproj/proj.pxi @@ -1,4 +1,25 @@ -# PROJ.4 API Defnition +# PROJ API Definition + +IF CTE_PROJ_VERSION_MAJOR >= 8: + cdef extern from "proj.h": + ctypedef enum PJ_CATEGORY: + PJ_CATEGORY_ELLIPSOID + PJ_CATEGORY_PRIME_MERIDIAN + PJ_CATEGORY_DATUM + PJ_CATEGORY_CRS + PJ_CATEGORY_COORDINATE_OPERATION + PJ_CATEGORY_DATUM_ENSEMBLE +ELSE: + cdef extern from "proj.h": + ctypedef enum PJ_CATEGORY: + PJ_CATEGORY_ELLIPSOID + PJ_CATEGORY_PRIME_MERIDIAN + PJ_CATEGORY_DATUM + PJ_CATEGORY_CRS + PJ_CATEGORY_COORDINATE_OPERATION + cdef int PJ_CATEGORY_DATUM_ENSEMBLE = PJ_CATEGORY_DATUM + + cdef extern from "proj.h": cdef int PROJ_VERSION_MAJOR cdef int PROJ_VERSION_MINOR @@ -397,20 +418,12 @@ cdef extern from "proj.h": PJ *proj_concatoperation_get_step(PJ_CONTEXT *ctx, const PJ *concatoperation, int i_step) - - ctypedef enum PJ_CATEGORY: - PJ_CATEGORY_ELLIPSOID - PJ_CATEGORY_PRIME_MERIDIAN - PJ_CATEGORY_DATUM - PJ_CATEGORY_CRS - PJ_CATEGORY_COORDINATE_OPERATION PJ *proj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name, const char *code, PJ_CATEGORY category, int usePROJAlternativeGridNames, const char* const *options) - PJ_OBJ_LIST *proj_create_from_name(PJ_CONTEXT *ctx, const char *auth_name, const char *searchedName, diff --git a/setup.py b/setup.py index 3b48cd35f..89b104275 100644 --- a/setup.py +++ b/setup.py @@ -14,23 +14,26 @@ INTERNAL_PROJ_DIR = CURRENT_FILE_PATH / "pyproj" / BASE_INTERNAL_PROJ_DIR -def check_proj_version(proj_dir: Path): - """checks that the PROJ library meets the minimum version""" +def get_proj_version(proj_dir: Path) -> str: + proj_version = os.environ.get("PROJ_VERSION") + if proj_version: + return proj_version proj = proj_dir / "bin" / "proj" - proj_ver_bytes = subprocess.check_output( - str(proj), stderr=subprocess.STDOUT - ).decode("ascii") - proj_ver_bytes = (proj_ver_bytes.split()[1]).strip(",") - proj_version = parse_version(proj_ver_bytes) - if proj_version < PROJ_MIN_VERSION: + proj_ver = subprocess.check_output(str(proj), stderr=subprocess.STDOUT).decode( + "ascii" + ) + return (proj_ver.split()[1]).strip(",") + + +def check_proj_version(proj_version: str) -> None: + """checks that the PROJ library meets the minimum version""" + if parse_version(proj_version) < PROJ_MIN_VERSION: raise SystemExit( f"ERROR: Minimum supported proj version is {PROJ_MIN_VERSION}, installed " f"version is {proj_version}. For more information see: " "https://pyproj4.github.io/pyproj/stable/installation.html" ) - return proj_version - def get_proj_dir() -> Path: """ @@ -58,9 +61,6 @@ def get_proj_dir() -> Path: print("PROJ_DIR is set, using existing proj4 installation..\n") else: raise SystemExit(f"ERROR: Invalid path for PROJ_DIR {proj_dir}") - - # check_proj_version - check_proj_version(proj_dir) return proj_dir @@ -152,6 +152,10 @@ def get_extension_modules(): library_dirs = get_proj_libdirs(proj_dir) include_dirs = get_proj_incdirs(proj_dir) + proj_version = get_proj_version(proj_dir) + check_proj_version(proj_version) + proj_version_major, proj_version_minor, proj_version_patch = proj_version.split(".") + # setup extension options ext_options = { "include_dirs": include_dirs, @@ -175,6 +179,11 @@ def get_extension_modules(): Extension("pyproj._sync", ["pyproj/_sync.pyx"], **ext_options), ], quiet=True, + compile_time_env={ + "CTE_PROJ_VERSION_MAJOR": int(proj_version_major), + "CTE_PROJ_VERSION_MINOR": int(proj_version_minor), + "CTE_PROJ_VERSION_PATCH": int(proj_version_patch), + }, **get_cythonize_options(), ) diff --git a/test/conftest.py b/test/conftest.py index 69106a666..0a1a2d996 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,5 +1,6 @@ import os from contextlib import contextmanager +from distutils.version import LooseVersion from pathlib import Path import pyproj @@ -70,3 +71,9 @@ def grids_available(*grid_names, check_network=True, check_all=False): if check_all: return all(available) return any(available) + + +def get_wgs84_datum_name(): + if LooseVersion(pyproj.__proj_version__) < LooseVersion("8.0"): + return "World Geodetic System 1984" + return "World Geodetic System 1984 ensemble" diff --git a/test/crs/test_crs.py b/test/crs/test_crs.py index 9d2bbf0fa..dc59bfe59 100644 --- a/test/crs/test_crs.py +++ b/test/crs/test_crs.py @@ -1,9 +1,10 @@ import json +from distutils.version import LooseVersion import numpy import pytest -from pyproj import CRS +from pyproj import CRS, __proj_version__ from pyproj.crs import ( CoordinateOperation, CoordinateSystem, @@ -15,7 +16,7 @@ from pyproj.enums import ProjVersion, WktVersion from pyproj.exceptions import CRSError from pyproj.transformer import TransformerGroup -from test.conftest import grids_available +from test.conftest import get_wgs84_datum_name, grids_available class CustomCRS(object): @@ -201,7 +202,7 @@ def test_repr(): "Area of Use:\n" "- name: World.\n" "- bounds: (-180.0, -90.0, 180.0, 90.0)\n" - "Datum: World Geodetic System 1984\n" + f"Datum: {get_wgs84_datum_name()}\n" "- Ellipsoid: WGS 84\n" "- Prime Meridian: Greenwich\n" ) @@ -219,7 +220,7 @@ def test_repr__long(): "Area of Use:\n" "- name: World.\n" "- bounds: (-180.0, -90.0, 180.0, 90.0)\n" - "Datum: World Geodetic System 1984\n" + f"Datum: {get_wgs84_datum_name()}\n" "- Ellipsoid: WGS 84\n" "- Prime Meridian: Greenwich\n" ) @@ -235,7 +236,7 @@ def test_repr_epsg(): "Area of Use:\n" "- name: World.\n" "- bounds: (-180.0, -90.0, 180.0, 90.0)\n" - "Datum: World Geodetic System 1984\n" + f"Datum: {get_wgs84_datum_name()}\n" "- Ellipsoid: WGS 84\n" "- Prime Meridian: Greenwich\n" ) @@ -309,9 +310,13 @@ def test_epsg(): def test_datum(): datum = CRS.from_epsg(4326).datum - assert repr(datum).startswith('DATUM["World Geodetic System 1984"') assert "\n" in repr(datum) - assert datum.to_wkt().startswith('DATUM["World Geodetic System 1984"') + if LooseVersion(__proj_version__) < LooseVersion("8.0"): + datum_wkt = 'DATUM["World Geodetic System 1984"' + else: + datum_wkt = 'ENSEMBLE["World Geodetic System 1984"' + assert repr(datum).startswith(datum_wkt) + assert datum.to_wkt().startswith(datum_wkt) assert datum == datum assert datum.is_exact_same(datum) @@ -871,7 +876,7 @@ def test_datum_equals(): ) def test_datum__from_string(input_str): dd = Datum.from_string(input_str) - assert dd.name == "World Geodetic System 1984" + assert dd.name == get_wgs84_datum_name() assert dd.type_name == "Geodetic Reference Frame" diff --git a/test/crs/test_crs_cf.py b/test/crs/test_crs_cf.py index 2bc98eaf6..40658863e 100644 --- a/test/crs/test_crs_cf.py +++ b/test/crs/test_crs_cf.py @@ -16,6 +16,7 @@ VerticalPerspectiveConversion, ) from pyproj.exceptions import CRSError +from test.conftest import get_wgs84_datum_name def _to_dict(operation): @@ -240,7 +241,7 @@ def test_cf_from_utm(): "longitude_of_prime_meridian": 0.0, "prime_meridian_name": "Greenwich", "geographic_crs_name": "WGS 84", - "horizontal_datum_name": "World Geodetic System 1984", + "horizontal_datum_name": get_wgs84_datum_name(), "projected_crs_name": "WGS 84 / UTM zone 15N", "grid_mapping_name": "transverse_mercator", "latitude_of_projection_origin": 0.0,