From 490b6143eb994d9c2b64cdb84ddd476e5d76ecf5 Mon Sep 17 00:00:00 2001 From: snowman2 Date: Sat, 4 Jun 2022 20:50:50 -0500 Subject: [PATCH] REF: use regex to process PROJ strings in CRS.to_dict() --- docs/history.rst | 1 + pyproj/crs/crs.py | 34 ++++++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/docs/history.rst b/docs/history.rst index ffab8a210..c36b1d4d9 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -7,6 +7,7 @@ Latest - BUG: Fix transformer list for 3D transformations in :class:`pyproj.transformer.TransformerGroup` (discussion #1072) - ENH: Added authority, accuracy, and allow_ballpark kwargs to :class:`pyproj.transformer.TransformerGroup` (pull #1076) - CLN: Remove deprecated `skip_equivalent` kwarg from transformers and `errcheck` kwarg from :meth:`pyproj.crs.CRS.from_cf` (pull #1077) +- REF: use regex to process PROJ strings in :meth:`pyproj.crs.CRS.to_dict()`(pull #1086) 3.3.1 ------- diff --git a/pyproj/crs/crs.py b/pyproj/crs/crs.py index 6bda8eff1..fad6cfa9c 100644 --- a/pyproj/crs/crs.py +++ b/pyproj/crs/crs.py @@ -37,6 +37,17 @@ from pyproj.exceptions import CRSError from pyproj.geod import Geod +_RE_PROJ_PARAM = re.compile( + r""" + \+ # parameter starts with '+' character + (?P\w+) # capture parameter name + \=? # match both key only and key-value parameters + (?P\S+)? # capture all characters up to next space (None if no value) + \s*? # consume remaining whitespace, if any +""", + re.X, +) + class CRSLocal(threading.local): """ @@ -573,7 +584,11 @@ def to_dict(self) -> dict: """ - def parse(val): + proj_string = self.to_proj4() + if proj_string is None: + return {} + + def _parse(val): if val.lower() == "true": return True if val.lower() == "false": @@ -588,16 +603,15 @@ def parse(val): pass return _try_list_if_string(val) - proj_string = self.to_proj4() - if proj_string is None: - return {} - - items = map( - lambda kv: len(kv) == 2 and (kv[0], parse(kv[1])) or (kv[0], None), - (part.lstrip("+").split("=", 1) for part in proj_string.strip().split()), - ) + proj_dict = {} + for param in _RE_PROJ_PARAM.finditer(proj_string): + key, value = param.groups() + if value is not None: + value = _parse(value) + if value is not False: + proj_dict[key] = value - return {key: value for key, value in items if value is not False} + return proj_dict def to_cf( self,