77from __future__ import annotations
88
99import ctypes
10+ import importlib .metadata
1011import os
1112import platform
1213import sys
1314from ctypes .util import find_library
15+ from pathlib import Path
1416
15- # the current working directory of this file
16- _cwd = os . path . abspath ( os . path . expanduser ( os . path . dirname ( __file__ )) )
17+ _cwd = Path ( __file__ ). parent
18+ _sys_prefix = Path ( sys . prefix )
1719
1820# generate a bunch of candidate locations where the
1921# libspatialindex shared library *might* be hanging out
20- _candidates = [
21- os .environ .get ("SPATIALINDEX_C_LIBRARY" , None ),
22- os .path .join (_cwd , "lib" ),
23- _cwd ,
24- "" ,
25- ]
22+ _candidates = []
23+ if "SPATIALINDEX_C_LIBRARY" in os .environ :
24+ _candidates .append (Path (os .environ ["SPATIALINDEX_C_LIBRARY" ]))
25+ _candidates += [_cwd / "lib" , _cwd , Path ("" )]
2626
2727
2828def load () -> ctypes .CDLL :
@@ -39,29 +39,26 @@ def load() -> ctypes.CDLL:
3939 lib_name = f"spatialindex_c-{ arch } .dll"
4040
4141 # add search paths for conda installs
42- if (
43- os .path .exists (os .path .join (sys .prefix , "conda-meta" ))
44- or "conda" in sys .version
45- ):
46- _candidates .append (os .path .join (sys .prefix , "Library" , "bin" ))
42+ if (_sys_prefix / "conda-meta" ).exists () or "conda" in sys .version :
43+ _candidates .append (_sys_prefix / "Library" / "bin" )
4744
4845 # get the current PATH
4946 oldenv = os .environ .get ("PATH" , "" ).strip ().rstrip (";" )
5047 # run through our list of candidate locations
5148 for path in _candidates :
52- if not path or not os . path . exists (path ):
49+ if not path . exists ():
5350 continue
5451 # temporarily add the path to the PATH environment variable
5552 # so Windows can find additional DLL dependencies.
56- os .environ ["PATH" ] = ";" .join ([path , oldenv ])
53+ os .environ ["PATH" ] = ";" .join ([str ( path ) , oldenv ])
5754 try :
58- rt = ctypes .cdll .LoadLibrary (os . path . join (path , lib_name ))
55+ rt = ctypes .cdll .LoadLibrary (str (path / lib_name ))
5956 if rt is not None :
6057 return rt
6158 except OSError :
6259 pass
63- except BaseException as E :
64- print (f"rtree.finder unexpected error: { E !s} " )
60+ except BaseException as err :
61+ print (f"rtree.finder unexpected error: { err !s} " , file = sys . stderr )
6562 finally :
6663 os .environ ["PATH" ] = oldenv
6764 raise OSError (f"could not find or load { lib_name } " )
@@ -73,8 +70,6 @@ def load() -> ctypes.CDLL:
7370 # macos shared libraries are `.dylib`
7471 lib_name = "libspatialindex_c.dylib"
7572 else :
76- import importlib .metadata
77-
7873 # linux shared libraries are `.so`
7974 lib_name = "libspatialindex_c.so"
8075
@@ -88,49 +83,91 @@ def load() -> ctypes.CDLL:
8883 and file .stem .startswith ("libspatialindex" )
8984 and ".so" in file .suffixes
9085 ):
91- _candidates .insert (1 , os . path . join ( str ( file .locate () )))
86+ _candidates .insert (1 , Path ( file .locate ()))
9287 break
9388 except importlib .metadata .PackageNotFoundError :
9489 pass
9590
9691 # get the starting working directory
9792 cwd = os .getcwd ()
9893 for cand in _candidates :
99- if cand is None :
100- continue
101- elif os .path .isdir (cand ):
94+ if cand .is_dir ():
10295 # if our candidate is a directory use best guess
10396 path = cand
104- target = os . path . join ( cand , lib_name )
105- elif os . path . isfile ( cand ):
97+ target = cand / lib_name
98+ elif cand . is_file ( ):
10699 # if candidate is just a file use that
107- path = os . path . split ( cand )[ 0 ]
100+ path = cand . parent
108101 target = cand
109102 else :
110103 continue
111104
112- if not os . path . exists (target ):
105+ if not target . exists ():
113106 continue
114107
115108 try :
116109 # move to the location we're checking
117110 os .chdir (path )
118111 # try loading the target file candidate
119- rt = ctypes .cdll .LoadLibrary (target )
112+ rt = ctypes .cdll .LoadLibrary (str ( target ) )
120113 if rt is not None :
121114 return rt
122- except BaseException as E :
123- print (f"rtree.finder ({ target } ) unexpected error: { E !s} " )
115+ except BaseException as err :
116+ print (
117+ f"rtree.finder ({ target } ) unexpected error: { err !s} " ,
118+ file = sys .stderr ,
119+ )
124120 finally :
125121 os .chdir (cwd )
126122
127123 try :
128124 # try loading library using LD path search
129- path = find_library ("spatialindex_c" )
130- if path is not None :
131- return ctypes .cdll .LoadLibrary (path )
125+ pth = find_library ("spatialindex_c" )
126+ if pth is not None :
127+ return ctypes .cdll .LoadLibrary (pth )
132128
133129 except BaseException :
134130 pass
135131
136132 raise OSError ("Could not load libspatialindex_c library" )
133+
134+
135+ def get_include () -> str :
136+ """Return the directory that contains the spatialindex \\ *.h files.
137+
138+ :returns: Path to include directory or "" if not found.
139+ """
140+ # check if was bundled with a binary wheel
141+ try :
142+ pkg_files = importlib .metadata .files ("rtree" )
143+ if pkg_files is not None :
144+ for path in pkg_files : # type: ignore
145+ if path .name == "SpatialIndex.h" :
146+ return str (Path (path .locate ()).parent .parent )
147+ except importlib .metadata .PackageNotFoundError :
148+ pass
149+
150+ # look for this header file in a few directories
151+ path_to_spatialindex_h = Path ("include/spatialindex/SpatialIndex.h" )
152+
153+ # check sys.prefix, e.g. conda's libspatialindex package
154+ if os .name == "nt" :
155+ file = _sys_prefix / "Library" / path_to_spatialindex_h
156+ else :
157+ file = _sys_prefix / path_to_spatialindex_h
158+ if file .is_file ():
159+ return str (file .parent .parent )
160+
161+ # check if relative to lib
162+ libdir = Path (load ()._name ).parent
163+ file = libdir .parent / path_to_spatialindex_h
164+ if file .is_file ():
165+ return str (file .parent .parent )
166+
167+ # check system install
168+ file = Path ("/usr" ) / path_to_spatialindex_h
169+ if file .is_file ():
170+ return str (file .parent .parent )
171+
172+ # not found
173+ return ""
0 commit comments