Skip to content

Commit 2abfe4f

Browse files
authored
Merge pull request #215 from snowman2/exceptions
add proj error message to exceptions
2 parents e77dad7 + 8cdf277 commit 2abfe4f

File tree

5 files changed

+53
-7
lines changed

5 files changed

+53
-7
lines changed

pyproj/_datadir.pxd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
include "proj.pxi"
22

3-
43
cdef PJ_CONTEXT* get_pyproj_context()

pyproj/_datadir.pyx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11

22
from libc.stdlib cimport malloc, free
33

4-
from pyproj.compat import cstrencode
4+
from pyproj.compat import cstrencode, pystrdecode
55
from pyproj.datadir import get_data_dir
6+
from pyproj.exceptions import ProjError
7+
8+
cdef void pyproj_log_function(void *user_data, int level, const char *error_msg):
9+
"""
10+
Log function for proj.4 errors with CRS class.
11+
"""
12+
if level == PJ_LOG_ERROR:
13+
ProjError.internal_proj_error = pystrdecode(error_msg)
614

715

816
cdef PJ_CONTEXT* get_pyproj_context():
@@ -16,11 +24,13 @@ cdef PJ_CONTEXT* get_pyproj_context():
1624
b_data_dir = cstrencode(data_dir_list[iii])
1725
c_data_dir[iii] = b_data_dir
1826
proj_context_set_search_paths(pyproj_context, len(data_dir_list), c_data_dir)
19-
proj_context_use_proj4_init_rules(pyproj_context, 1)
2027
except:
2128
if pyproj_context != NULL:
2229
proj_context_destroy(pyproj_context)
2330
raise
2431
finally:
2532
free(c_data_dir)
33+
proj_context_use_proj4_init_rules(pyproj_context, 1)
34+
proj_log_func(pyproj_context, NULL, pyproj_log_function)
35+
2636
return pyproj_context

pyproj/exceptions.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,26 @@
44
"""
55

66

7-
class CRSError(RuntimeError):
8-
"""Raised when a CRS error occurs."""
9-
10-
117
class ProjError(RuntimeError):
128
"""Raised when a Proj error occurs."""
139

10+
internal_proj_error = None
11+
12+
def __init__(self, error_message):
13+
if self.internal_proj_error is not None:
14+
error_message = (
15+
"{error_message}: (Internal Proj Error: {internal_proj_error})"
16+
).format(
17+
error_message=error_message,
18+
internal_proj_error=self.internal_proj_error,
19+
)
20+
self.internal_proj_error = None
21+
super(ProjError, self).__init__(error_message)
22+
23+
24+
class CRSError(ProjError):
25+
"""Raised when a CRS error occurs."""
26+
1427

1528
class GeodError(RuntimeError):
1629
"""Raised when a Geod error occurs."""

pyproj/proj.pxi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ cdef extern from "proj.h":
2424
ctypedef struct PJ_CONTEXT
2525
PJ_CONTEXT *proj_context_create ()
2626
PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx)
27+
28+
ctypedef enum PJ_LOG_LEVEL:
29+
PJ_LOG_NONE = 0
30+
PJ_LOG_ERROR = 1
31+
PJ_LOG_DEBUG = 2
32+
PJ_LOG_TRACE = 3
33+
PJ_LOG_TELL = 4
34+
ctypedef void (*PJ_LOG_FUNCTION)(void *, int, const char *)
35+
void proj_log_func (PJ_CONTEXT *ctx, void *app_data, PJ_LOG_FUNCTION logf)
36+
2737
int proj_errno (const PJ *P)
2838
int proj_context_errno (PJ_CONTEXT *ctx)
2939
const char * proj_errno_string (int err)

unittest/test_exception_logging.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import pytest
2+
3+
from pyproj import CRS, Proj
4+
from pyproj.exceptions import CRSError, ProjError
5+
6+
7+
def test_proj_exception():
8+
with pytest.raises(ProjError, match="Internal Proj Error"):
9+
Proj("+proj=bobbyjoe")
10+
11+
12+
def test_crs_exception():
13+
with pytest.raises(CRSError, match="Internal Proj Error"):
14+
CRS("+proj=bobbyjoe")

0 commit comments

Comments
 (0)