File: setup.py

package info (click to toggle)
python-shapely 2.1.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,528 kB
  • sloc: python: 18,648; ansic: 6,615; makefile: 88; sh: 62
file content (204 lines) | stat: -rw-r--r-- 6,144 bytes parent folder | download | duplicates (2)
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
"""Setuptools build."""

import logging
import os
import subprocess
import sys
from pathlib import Path

from setuptools import Extension, setup

# ensure the current directory is on sys.path so versioneer can be imported
# when pip uses PEP 517/518 build rules.
# https://github.com/python-versioneer/python-versioneer/issues/193
sys.path.insert(0, os.path.dirname(__file__))
import versioneer

# Skip Cython build if not available
try:
    import cython
    from Cython.Build import cythonize
except ImportError:
    cythonize = None


log = logging.getLogger(__name__)
ch = logging.StreamHandler()
log.addHandler(ch)

MIN_GEOS_VERSION = "3.9"

if "all" in sys.warnoptions:
    # show GEOS messages in console with: python -W all
    log.setLevel(logging.DEBUG)


def get_geos_config(option):
    """Get configuration option from the `geos-config` development utility.

    The PATH environment variable should include the path where geos-config is
    located, or the GEOS_CONFIG environment variable should point to the
    executable.
    """
    cmd = os.environ.get("GEOS_CONFIG", "geos-config")
    try:
        proc = subprocess.run([cmd, option], capture_output=True, text=True, check=True)
    except OSError:
        return
    if proc.stderr and not proc.stdout:
        log.warning("geos-config %s returned '%s'", option, proc.stderr.strip())
        return
    result = proc.stdout.strip()
    log.debug("geos-config %s returned '%s'", option, result)
    return result


def get_ext_options():
    """Get Extension options to build using GEOS and NumPy C API.

    First the presence of the GEOS_INCLUDE_PATH and GEOS_INCLUDE_PATH environment
    variables is checked. If they are both present, these are taken.

    If one of the two paths was not present, geos-config is called (it should be on the
    PATH variable). geos-config provides all the paths.

    If geos-config was not found, no additional paths are provided to the extension.
    It is still possible to compile in this case using custom arguments to setup.py.
    """
    import numpy

    opts = {
        "define_macros": [
            # avoid accidental use of non-reentrant functions
            ("GEOS_USE_ONLY_R_API", None),
            # silence warnings
            ("NPY_NO_DEPRECATED_API", "0"),
            # minimum numpy version
            ("NPY_TARGET_VERSION", "NPY_1_20_API_VERSION"),
        ],
        "include_dirs": ["./src"],
        "library_dirs": [],
        "extra_link_args": [],
        "libraries": [],
    }

    if include_dir := numpy.get_include():
        opts["include_dirs"].append(include_dir)

    # Without geos-config (e.g. MSVC), specify these two vars
    include_dir = os.environ.get("GEOS_INCLUDE_PATH")
    library_dir = os.environ.get("GEOS_LIBRARY_PATH")
    if include_dir and library_dir:
        opts["include_dirs"].append(include_dir)
        opts["library_dirs"].append(library_dir)
        opts["libraries"].append("geos_c")
        return opts

    geos_version = get_geos_config("--version")
    if not geos_version:
        log.warning(
            "Could not find geos-config executable. Either append the path to "
            "geos-config to PATH or manually provide the include_dirs, library_dirs, "
            "libraries and other link args for compiling against a GEOS version >=%s.",
            MIN_GEOS_VERSION,
        )
        return {}

    def version_tuple(ver):
        return tuple(int(itm) if itm.isnumeric() else itm for itm in ver.split("."))

    if version_tuple(geos_version) < version_tuple(MIN_GEOS_VERSION):
        raise ImportError(
            f"GEOS version should be >={MIN_GEOS_VERSION}, found {geos_version}"
        )

    for item in get_geos_config("--cflags").split():
        if item.startswith("-I"):
            opts["include_dirs"].extend(item[2:].split(":"))

    for item in get_geos_config("--clibs").split():
        if item.startswith("-L"):
            opts["library_dirs"].extend(item[2:].split(":"))
        elif item.startswith("-l"):
            opts["libraries"].append(item[2:])
        else:
            opts["extra_link_args"].append(item)

    return opts


ext_modules = []

if "clean" in sys.argv:
    # delete any previously Cythonized or compiled files in pygeos
    p = Path(".")
    for pattern in [
        "build/lib.*/shapely/*.so",
        "shapely/*.c",
        "shapely/*.so",
        "shapely/*.pyd",
    ]:
        for filename in p.glob(pattern):
            print(f"removing '{filename}'")
            filename.unlink()
elif "sdist" in sys.argv:
    if Path("LICENSE_GEOS").exists() or Path("LICENSE_win32").exists():
        raise FileExistsError(
            "Source distributions should not pack LICENSE_GEOS or LICENSE_win32. "
            "Please remove the files."
        )
else:
    ext_options = get_ext_options()

    ext_modules = [
        Extension(
            "shapely.lib",
            sources=[
                "src/c_api.c",
                "src/coords.c",
                "src/geos.c",
                "src/lib.c",
                "src/pygeom.c",
                "src/pygeos.c",
                "src/strtree.c",
                "src/ufuncs.c",
                "src/vector.c",
            ],
            **ext_options,
        )
    ]

    # Cython is required
    if not cythonize:
        sys.exit("ERROR: Cython is required to build shapely from source.")

    cython_modules = [
        Extension(
            "shapely._geometry_helpers",
            ["shapely/_geometry_helpers.pyx"],
            **ext_options,
        ),
        Extension(
            "shapely._geos",
            ["shapely/_geos.pyx"],
            **ext_options,
        ),
    ]
    compiler_directives = {"language_level": "3"}
    if cython.__version__ >= "3.1.0":
        compiler_directives.update({"freethreading_compatible": True})
    ext_modules += cythonize(
        cython_modules,
        compiler_directives=compiler_directives,
    )


cmdclass = versioneer.get_cmdclass()


# see pyproject.toml for static project metadata
setup(
    version=versioneer.get_version(),
    ext_modules=ext_modules,
    cmdclass=cmdclass,
)