Skip to content

Commit

Permalink
create PROJError and raise it in custom error handler
Browse files Browse the repository at this point in the history
This handler, `log_func`, is registered in `__init__`. It simply throws 
when the level is at error, and ignores otherwise. Based on 
pyproj4/pyproj#215.
  • Loading branch information
visr committed Nov 17, 2019
1 parent 7bc9048 commit 889239a
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 16 deletions.
26 changes: 15 additions & 11 deletions src/Proj4.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,11 @@ if !isfile(depsjl_path)
end
include(depsjl_path)

const PROJ_LIB = Ref{String}()

# Module initialization function
function __init__()
# Always check your dependencies from `deps.jl`
check_deps()

PROJ_LIB[] = abspath(@__DIR__, "..", "deps", "usr", "share", "proj")
proj_context_set_search_paths(1, [PROJ_LIB[]])
end

include("projection_codes.jl") # ESRI and EPSG projection strings
include("proj_capi.jl") # low-level C-facing functions (corresponding to src/proj_api.h)
include("proj_common.jl")
include("proj_c.jl")
include("error.jl")

function _version()
m = match(r"(\d+).(\d+).(\d+),.+", _get_release())
Expand Down Expand Up @@ -71,5 +61,19 @@ function unsafe_loadstringlist(ptr::Ptr{Cstring})
strings
end

const PROJ_LIB = Ref{String}()

# Module initialization function
function __init__()
# Always check your dependencies from `deps.jl`
check_deps()

# register custom error handler
funcptr = @cfunction(log_func, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Cstring))
proj_log_func(C_NULL, funcptr)

PROJ_LIB[] = abspath(@__DIR__, "..", "deps", "usr", "share", "proj")
proj_context_set_search_paths(1, [PROJ_LIB[]])
end

end # module
22 changes: 22 additions & 0 deletions src/error.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"Exception type based on PROJ error handling"
struct PROJError <: Exception
msg::String
# reset PROJ's error stack on construction
function PROJError(msg)
proj_errno_reset(C_NULL)
new(msg)
end
end

function Base.showerror(io::IO, err::PROJError)
err = string("PROJError: ", err.msg)
println(io, err)
end

"Custom error handler, automatically set with `proj_log_func`"
function log_func(user_data::Ptr{Cvoid}, level::Cint, msg::Cstring)
if level == PJ_LOG_ERROR
throw(PROJError(unsafe_string(msg)))
end
return C_NULL
end
27 changes: 24 additions & 3 deletions test/proj6api.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
using Test
import Proj4

@testset "Error handling" begin
@test_throws ArgumentError Proj4.proj_errno_string(0)
@test Proj4.proj_errno_string(1) == "Operation not permitted"
@test Proj4.proj_errno_string(2) == "No such file or directory"

# this throws an internal error that is handled by our log_func
@test_throws Proj4.PROJError Proj4.proj_create("+proj=bobbyjoe")
# ensure we have reset the error state
@test Proj4.proj_context_errno() == 0

end

@testset "Database" begin
crs = Proj4.proj_create_from_database("EPSG", "4326", Proj4.PJ_CATEGORY_CRS, false, C_NULL)
Proj4.proj_errno(crs)
Proj4.proj_get_id_code(crs, 0)
# The following is wrong, but unfortunately segfaults. How to fix other than adding
# a null check before the ccall in this and other functions?
# Proj4.proj_get_id_code(C_NULL, 0)
end

@testset "New tests" begin

pj_latlon = Proj4.proj_create("EPSG:4326")
Expand All @@ -15,8 +36,8 @@ end

@testset "Transformation between CRS" begin
# taken from http://osgeo-org.1560.x6.nabble.com/PROJ-PROJ-6-0-0-proj-create-operation-factory-context-behavior-td5403470.html
src = Proj4.proj_create("IGNF:REUN47GAUSSL") # area : 55.17,-21.42,55.92,-20.76
tgt = Proj4.proj_create("IGNF:RGAF09UTM20") # area : -63.2,14.25,-60.73,18.2
src = Proj4.proj_create("IGNF:REUN47GAUSSL") # area : 55.17,-21.42,55.92,-20.76
tgt = Proj4.proj_create("IGNF:RGAF09UTM20") # area : -63.2,14.25,-60.73,18.2
factory = Proj4.proj_create_operation_factory_context(C_NULL)
@test factory != C_NULL
@test Proj4.proj_context_errno() == 0
Expand Down Expand Up @@ -49,4 +70,4 @@ end
Proj4.proj_destroy(src)
Proj4.proj_destroy(tgt)
# proj_context_destroy(c)
end
end
4 changes: 2 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using Proj4
using Test

include("proj6api.jl")

@testset "Proj4" begin

println("""
C library version: $(Proj4.version) [\"$(Proj4._get_release())\"]
geodesic support: $(Proj4.has_geodesic_support)
""")

include("proj6api.jl")

# Some very basic sanity checking
wgs84 = Projection("+proj=longlat +datum=WGS84 +no_defs")
utm56 = Projection("+proj=utm +zone=56 +south +datum=WGS84 +units=m +no_defs")
Expand Down

0 comments on commit 889239a

Please sign in to comment.