Skip to content

Commit 72ca7b2

Browse files
committed
BLD/RFC: use Cython templating instead of compile-time conditionals
1 parent 94891d7 commit 72ca7b2

8 files changed

Lines changed: 71 additions & 49 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pyproj/proj_dir/
2+
pyproj/_compat.p*
23
pyproj/*.c
34
pyproj/*/*.c
45
pyproj/*/*.html

MANIFEST.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ include pyproj/*.pyi
1313
include test/sample.out
1414
include test/*.py
1515
include test/*/*.py
16+
17+
# exclude generated files
18+
exclude pyproj/_compat.pxd
19+
exclude pyproj/_compat.pyx
1620
exclude pyproj/*.c
21+
1722
recursive-include docs *
1823
prune docs/_build
1924
prune pyproj/proj_dir

docs/history.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Latest
1616
- BUG: Clear CONTEXT_THREAD_KEY when destroying PJ_CONTEXT (pull #1541)
1717
- BUG: Default skew angle for CF grid mapping oblique mercator to 90 (issue #1506)
1818
- BLD: update build-time dependencies
19+
- BLD/RFC: use Cython templating instead of compile-time conditionals (issue #1142)
1920

2021
3.7.2
2122
-----

pyproj/_compat.pxd

Lines changed: 0 additions & 10 deletions
This file was deleted.

pyproj/_compat.pyx

Lines changed: 0 additions & 31 deletions
This file was deleted.

pyproj/_compat.templ.pxd

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cdef str cstrdecode(const char *instring)
2+
cpdef bytes cstrencode(str pystr)
3+
4+
### {{if IS_CPYTHON}}
5+
from cpython cimport array
6+
cdef array.array empty_array(int npts)
7+
### {{else}}
8+
# https://github.com/pyproj4/pyproj/issues/854
9+
cdef empty_array(int npts)
10+
### {{endif}}

pyproj/_compat.templ.pyx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import array
2+
3+
4+
cpdef bytes cstrencode(str pystr):
5+
"""
6+
Encode a string into bytes.
7+
"""
8+
try:
9+
return pystr.encode("utf-8")
10+
except UnicodeDecodeError:
11+
return pystr.decode("utf-8").encode("utf-8")
12+
13+
14+
cdef str cstrdecode(const char *instring):
15+
if instring != NULL:
16+
return instring
17+
return None
18+
19+
20+
### {{if IS_CPYTHON}}
21+
from cpython cimport array
22+
23+
cdef array.array _ARRAY_TEMPLATE = array.array("d", [])
24+
25+
cdef array.array empty_array(int npts):
26+
return array.clone(_ARRAY_TEMPLATE, npts, zero=False)
27+
### {{else}}
28+
# https://github.com/pyproj4/pyproj/issues/854
29+
cdef empty_array(int npts):
30+
return array.array("d", [float("NaN")] * npts)
31+
### {{endif}}

setup.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import shutil
55
import subprocess
66
import sys
7+
from importlib.util import find_spec
78
from pathlib import Path
89

910
from setuptools import Extension, setup
@@ -173,13 +174,11 @@ def get_extension_modules():
173174
return None
174175

175176
# make sure cython is available
176-
try:
177-
from Cython.Build import cythonize
178-
except ImportError as error:
179-
raise SystemExit(
180-
"ERROR: Cython.Build.cythonize not found. "
181-
"Cython is required to build pyproj."
182-
) from error
177+
if find_spec("Cython") is None:
178+
raise SystemExit("ERROR: Cython not found. Cython is required to build pyproj.")
179+
180+
import Cython.Tempita as tempita
181+
from Cython.Build import cythonize
183182

184183
# By default we'll try to get options PROJ_DIR or the local version of proj
185184
proj_dir = get_proj_dir()
@@ -199,6 +198,23 @@ def get_extension_modules():
199198
),
200199
"libraries": get_libraries(library_dirs),
201200
}
201+
# apply substitutions
202+
templated_sources = ["_compat.pxd", "_compat.pyx"]
203+
templ_config = {
204+
"IS_CPYTHON": platform.python_implementation() == "CPython",
205+
}
206+
for tsrc in templated_sources:
207+
target = CURRENT_FILE_PATH / "pyproj" / tsrc
208+
templ = target.with_suffix(f".templ{target.suffix}")
209+
if target.is_file():
210+
current_text = target.read_text()
211+
else:
212+
current_text = ""
213+
214+
new_text = tempita.sub(templ.read_text(), **templ_config)
215+
if new_text != current_text:
216+
target.write_text(new_text, "utf-8")
217+
202218
# setup cythonized modules
203219
return cythonize(
204220
[
@@ -220,7 +236,6 @@ def get_extension_modules():
220236
"CTE_PROJ_VERSION_MAJOR": proj_version_major,
221237
"CTE_PROJ_VERSION_MINOR": proj_version_minor,
222238
"CTE_PROJ_VERSION_PATCH": proj_version_patch,
223-
"CTE_PYTHON_IMPLEMENTATION": platform.python_implementation(),
224239
},
225240
**get_cythonize_options(),
226241
)

0 commit comments

Comments
 (0)