File: finder.py

package info (click to toggle)
python-rtree 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 444 kB
  • sloc: python: 3,434; makefile: 97; sh: 52
file content (167 lines) | stat: -rw-r--r-- 5,583 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"""
Locate `libspatialindex` shared library and header files.
"""

from __future__ import annotations

import ctypes
import importlib.metadata
import os
import platform
import sys
from ctypes.util import find_library
from pathlib import Path

_cwd = Path(__file__).parent
_sys_prefix = Path(sys.prefix)

# generate a bunch of candidate locations where the
# libspatialindex shared library *might* be hanging out
_candidates = []
if "SPATIALINDEX_C_LIBRARY" in os.environ:
    _candidates.append(Path(os.environ["SPATIALINDEX_C_LIBRARY"]))
_candidates += [_cwd / "lib", _cwd, Path("")]


def load() -> ctypes.CDLL:
    """Load the `libspatialindex` shared library.

    :returns: Loaded shared library
    """
    if os.name == "nt":
        # check the platform architecture
        if "64" in platform.architecture()[0]:
            arch = "64"
        else:
            arch = "32"
        lib_name = f"spatialindex_c-{arch}.dll"

        # add search paths for conda installs
        if (_sys_prefix / "conda-meta").exists() or "conda" in sys.version:
            _candidates.append(_sys_prefix / "Library" / "bin")

        # get the current PATH
        oldenv = os.environ.get("PATH", "").strip().rstrip(";")
        # run through our list of candidate locations
        for path in _candidates:
            if not path.exists():
                continue
            # temporarily add the path to the PATH environment variable
            # so Windows can find additional DLL dependencies.
            os.environ["PATH"] = ";".join([str(path), oldenv])
            try:
                rt = ctypes.cdll.LoadLibrary(str(path / lib_name))
                if rt is not None:
                    return rt
            except OSError:
                pass
            except BaseException as err:
                print(f"rtree.finder unexpected error: {err!s}", file=sys.stderr)
            finally:
                os.environ["PATH"] = oldenv
        raise OSError(f"could not find or load {lib_name}")

    elif os.name == "posix":
        # posix includes both mac and linux
        # use the extension for the specific platform
        if platform.system() == "Darwin":
            # macos shared libraries are `.dylib`
            lib_name = "libspatialindex_c.dylib"
        else:
            # linux shared libraries are `.so`
            lib_name = "libspatialindex_c.so"

            # add path for binary wheel prepared with cibuildwheel/auditwheel
            try:
                pkg_files = importlib.metadata.files("rtree")
                if pkg_files is not None:
                    for file in pkg_files:  # type: ignore
                        if (
                            file.parent.name == "rtree.libs"
                            and file.stem.startswith("libspatialindex")
                            and ".so" in file.suffixes
                        ):
                            _candidates.insert(1, Path(file.locate()))
                            break
            except importlib.metadata.PackageNotFoundError:
                pass

        for cand in _candidates:
            if cand.is_dir():
                # if our candidate is a directory use best guess
                path = cand
                target = cand / lib_name
            elif cand.is_file():
                # if candidate is just a file use that
                path = cand.parent
                target = cand
            else:
                continue

            if not target.exists():
                continue

            try:
                # try loading the target file candidate
                # These should be fully specified paths to
                # files
                rt = ctypes.cdll.LoadLibrary(str(target))
                if rt is not None:
                    return rt
            except BaseException as err:
                print(
                    f"rtree.finder ({target}) unexpected error: {err!s}",
                    file=sys.stderr,
                )

    try:
        # try loading library using LD path search
        pth = find_library("spatialindex_c")
        if pth is not None:
            return ctypes.cdll.LoadLibrary(pth)

    except BaseException:
        pass

    raise OSError("Could not load libspatialindex_c library")


def get_include() -> str:
    """Return the directory that contains the spatialindex \\*.h files.

    :returns: Path to include directory or "" if not found.
    """
    # check if was bundled with a binary wheel
    try:
        pkg_files = importlib.metadata.files("rtree")
        if pkg_files is not None:
            for path in pkg_files:  # type: ignore
                if path.name == "SpatialIndex.h":
                    return str(Path(path.locate()).parent.parent)
    except importlib.metadata.PackageNotFoundError:
        pass

    # look for this header file in a few directories
    path_to_spatialindex_h = Path("include/spatialindex/SpatialIndex.h")

    # check sys.prefix, e.g. conda's libspatialindex package
    if os.name == "nt":
        file = _sys_prefix / "Library" / path_to_spatialindex_h
    else:
        file = _sys_prefix / path_to_spatialindex_h
    if file.is_file():
        return str(file.parent.parent)

    # check if relative to lib
    libdir = Path(load()._name).parent
    file = libdir.parent / path_to_spatialindex_h
    if file.is_file():
        return str(file.parent.parent)

    # check system install
    file = Path("/usr") / path_to_spatialindex_h
    if file.is_file():
        return str(file.parent.parent)

    # not found
    return ""