Skip to content

Commit e77dad7

Browse files
authored
Merge pull request #213 from snowman2/pyproj_data
Update data directory functionality
2 parents 64e15b1 + e8c74c3 commit e77dad7

File tree

11 files changed

+243
-98
lines changed

11 files changed

+243
-98
lines changed

appveyor.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,12 @@ after_test:
123123
# If tests are successful, create binary packages for the project.
124124
- mkdir pyproj\proj_dir\share\proj
125125
- copy %PROJ_LIB%\* pyproj\proj_dir\share\proj
126-
- mkdir pyproj\proj_dir\lib
127-
- copy %PROJ_DIR%\lib\* pyproj\proj_dir\lib
128-
- copy c:\tools\vcpkg\installed\"%platform%"-windows\bin\sqlite3.dll pyproj\proj_dir\lib
129-
- set PROJ_LIBDIR=proj_dir\lib
126+
- mkdir pyproj\.lib
127+
- mkdir .lib
128+
- copy %PROJ_DIR%\lib\* pyproj\.lib
129+
- copy %PROJ_DIR%\lib\* .lib
130+
- copy c:\tools\vcpkg\installed\"%platform%"-windows\bin\sqlite3.dll pyproj\.lib
131+
- set PROJ_LIBDIR=.lib
130132
- set PROJ_WHEEL=true
131133
- "%CMD_IN_ENV% python setup.py bdist_wheel"
132134
# - "%CMD_IN_ENV% python setup.py bdist_wininst"

pyproj/_crs.pyx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pyproj.compat import cstrencode, pystrdecode
2-
from pyproj.datadir import get_data_dir
2+
from pyproj._datadir cimport get_pyproj_context
33
from pyproj.exceptions import CRSError
44

55
def is_wkt(proj_string):
@@ -303,12 +303,7 @@ cdef class _CRS:
303303
self._area_of_use = None
304304
self._prime_meridian = None
305305
# setup the context
306-
self.projctx = proj_context_create()
307-
py_data_dir = cstrencode(get_data_dir())
308-
cdef const char* data_dir = py_data_dir
309-
proj_context_set_search_paths(self.projctx, 1, &data_dir)
310-
proj_context_use_proj4_init_rules(self.projctx, 1)
311-
306+
self.projctx = get_pyproj_context()
312307
# setup proj initialization string.
313308
if not is_wkt(projstring) \
314309
and not projstring.lower().startswith("epsg")\

pyproj/_datadir.pxd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include "proj.pxi"
2+
3+
4+
cdef PJ_CONTEXT* get_pyproj_context()

pyproj/_datadir.pyx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
from libc.stdlib cimport malloc, free
3+
4+
from pyproj.compat import cstrencode
5+
from pyproj.datadir import get_data_dir
6+
7+
8+
cdef PJ_CONTEXT* get_pyproj_context():
9+
data_dir = get_data_dir()
10+
data_dir_list = data_dir.split(";")
11+
cdef PJ_CONTEXT* pyproj_context = NULL
12+
cdef char **c_data_dir = <char **>malloc(len(data_dir_list) * sizeof(char*))
13+
try:
14+
pyproj_context = proj_context_create()
15+
for iii in range(len(data_dir_list)):
16+
b_data_dir = cstrencode(data_dir_list[iii])
17+
c_data_dir[iii] = b_data_dir
18+
proj_context_set_search_paths(pyproj_context, len(data_dir_list), c_data_dir)
19+
proj_context_use_proj4_init_rules(pyproj_context, 1)
20+
except:
21+
if pyproj_context != NULL:
22+
proj_context_destroy(pyproj_context)
23+
raise
24+
finally:
25+
free(c_data_dir)
26+
return pyproj_context

pyproj/_proj.pyx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
include "base.pxi"
22

33
from pyproj.compat import cstrencode, pystrdecode
4-
from pyproj.datadir import get_data_dir
4+
from pyproj._datadir cimport get_pyproj_context
55
from pyproj.exceptions import ProjError
66

77

@@ -20,11 +20,7 @@ cdef class Proj:
2020
def __init__(self, const char *projstring):
2121
self.srs = pystrdecode(projstring)
2222
# setup the context
23-
self.projctx = proj_context_create()
24-
py_data_dir = cstrencode(get_data_dir())
25-
cdef const char* data_dir = py_data_dir
26-
proj_context_set_search_paths(self.projctx, 1, &data_dir)
27-
proj_context_use_proj4_init_rules(self.projctx, 1)
23+
self.projctx = get_pyproj_context()
2824
# initialize projection
2925
self.projpj = proj_create(self.projctx, projstring)
3026
if self.projpj is NULL:

pyproj/_transformer.pyx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ include "base.pxi"
33
from pyproj.crs import CRS
44
from pyproj.proj import Proj
55
from pyproj.compat import cstrencode, pystrdecode
6-
from pyproj.datadir import get_data_dir
6+
from pyproj._datadir cimport get_pyproj_context
77
from pyproj.exceptions import ProjError
88

99
cdef class _Transformer:
@@ -21,11 +21,7 @@ cdef class _Transformer:
2121

2222
def __init__(self):
2323
# set up the context
24-
self.projctx = proj_context_create()
25-
py_data_dir = cstrencode(get_data_dir())
26-
cdef const char* data_dir = py_data_dir
27-
proj_context_set_search_paths(self.projctx, 1, &data_dir)
28-
proj_context_use_proj4_init_rules(self.projctx, 1)
24+
self.projctx = get_pyproj_context()
2925

3026
def __dealloc__(self):
3127
"""destroy projection definition"""

pyproj/datadir.py

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
Set the datadir path to the local data directory
33
"""
44
import os
5+
from distutils.spawn import find_executable
56

67
from pyproj.exceptions import DataDirError
78

89
_USER_PROJ_DATA = None
10+
_VALIDATED_PROJ_DATA = None
911

1012

1113
def set_data_dir(proj_data_dir):
@@ -18,7 +20,22 @@ def set_data_dir(proj_data_dir):
1820
The path to rhe PROJ.4 data directory.
1921
"""
2022
global _USER_PROJ_DATA
23+
global _VALIDATED_PROJ_DATA
2124
_USER_PROJ_DATA = proj_data_dir
25+
# set to none to re-validate
26+
_VALIDATED_PROJ_DATA = None
27+
28+
29+
def append_data_dir(proj_data_dir):
30+
"""
31+
Add an additional data directory for PROJ.4 to use.
32+
33+
Parameters
34+
----------
35+
proj_data_dir: str
36+
The path to rhe PROJ.4 data directory.
37+
"""
38+
set_data_dir(";".join([get_data_dir(), proj_data_dir]))
2239

2340

2441
def get_data_dir():
@@ -27,17 +44,24 @@ def get_data_dir():
2744
2845
1. The one set by pyproj.datadir.set_data_dir (if exists & valid)
2946
2. The internal proj directory (if exists & valid)
30-
3. The directory in PROJ_LIB
47+
3. The directory in PROJ_LIB (if exists & valid)
48+
4. The directory on the PATH (if exists & valid)
3149
3250
Returns
3351
-------
3452
str: The valid data directory.
3553
3654
"""
55+
# to avoid re-validating
56+
global _VALIDATED_PROJ_DATA
57+
if _VALIDATED_PROJ_DATA is not None:
58+
return _VALIDATED_PROJ_DATA
59+
3760
global _USER_PROJ_DATA
3861
internal_datadir = os.path.join(
3962
os.path.dirname(os.path.abspath(__file__)), "proj_dir", "share", "proj"
4063
)
64+
proj_lib_dirs = os.environ.get("PROJ_LIB", "")
4165

4266
def valid_data_dir(potential_data_dir):
4367
if potential_data_dir is not None and os.path.exists(
@@ -46,21 +70,34 @@ def valid_data_dir(potential_data_dir):
4670
return True
4771
return False
4872

49-
proj_data_dir = None
50-
if valid_data_dir(_USER_PROJ_DATA):
51-
proj_data_dir = _USER_PROJ_DATA
73+
def valid_data_dirs(potential_data_dirs):
74+
if potential_data_dirs is None:
75+
return False
76+
for proj_data_dir in potential_data_dirs.split(";"):
77+
if valid_data_dir(proj_data_dir):
78+
return True
79+
break
80+
return None
81+
82+
if valid_data_dirs(_USER_PROJ_DATA):
83+
_VALIDATED_PROJ_DATA = _USER_PROJ_DATA
5284
elif valid_data_dir(internal_datadir):
53-
proj_data_dir = internal_datadir
85+
_VALIDATED_PROJ_DATA = internal_datadir
86+
elif valid_data_dirs(proj_lib_dirs):
87+
_VALIDATED_PROJ_DATA = proj_lib_dirs
5488
else:
55-
proj_lib_dirs = os.environ.get("PROJ_LIB", "")
56-
for proj_lib_dir in proj_lib_dirs.split(";"):
57-
if valid_data_dir(proj_lib_dir):
58-
proj_data_dir = proj_lib_dir
59-
break
60-
if proj_data_dir is None:
89+
proj_exe = find_executable("proj")
90+
if proj_exe is not None:
91+
system_proj_dir = os.path.join(
92+
os.path.dirname(os.path.dirname(proj_exe)), "share", "proj"
93+
)
94+
if valid_data_dir(system_proj_dir):
95+
_VALIDATED_PROJ_DATA = system_proj_dir
96+
97+
if _VALIDATED_PROJ_DATA is None:
6198
raise DataDirError(
6299
"Valid PROJ.4 data directory not found."
63100
"Either set the path using the environmental variable PROJ_LIB or "
64101
"with `pyproj.datadir.set_data_dir`."
65102
)
66-
return proj_data_dir
103+
return _VALIDATED_PROJ_DATA

0 commit comments

Comments
 (0)