omdev 0.0.0.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omdev/__about__.py +35 -0
- omdev/__init__.py +0 -0
- omdev/amalg/__init__.py +0 -0
- omdev/amalg/__main__.py +4 -0
- omdev/amalg/amalg.py +513 -0
- omdev/classdot.py +61 -0
- omdev/cmake.py +164 -0
- omdev/exts/__init__.py +0 -0
- omdev/exts/_distutils/__init__.py +10 -0
- omdev/exts/_distutils/build_ext.py +367 -0
- omdev/exts/_distutils/compilers/__init__.py +3 -0
- omdev/exts/_distutils/compilers/ccompiler.py +1032 -0
- omdev/exts/_distutils/compilers/options.py +80 -0
- omdev/exts/_distutils/compilers/unixccompiler.py +385 -0
- omdev/exts/_distutils/dir_util.py +76 -0
- omdev/exts/_distutils/errors.py +62 -0
- omdev/exts/_distutils/extension.py +107 -0
- omdev/exts/_distutils/file_util.py +216 -0
- omdev/exts/_distutils/modified.py +47 -0
- omdev/exts/_distutils/spawn.py +103 -0
- omdev/exts/_distutils/sysconfig.py +349 -0
- omdev/exts/_distutils/util.py +201 -0
- omdev/exts/_distutils/version.py +308 -0
- omdev/exts/build.py +43 -0
- omdev/exts/cmake.py +195 -0
- omdev/exts/importhook.py +88 -0
- omdev/exts/scan.py +74 -0
- omdev/interp/__init__.py +1 -0
- omdev/interp/__main__.py +4 -0
- omdev/interp/cli.py +63 -0
- omdev/interp/inspect.py +105 -0
- omdev/interp/providers.py +67 -0
- omdev/interp/pyenv.py +353 -0
- omdev/interp/resolvers.py +76 -0
- omdev/interp/standalone.py +187 -0
- omdev/interp/system.py +125 -0
- omdev/interp/types.py +92 -0
- omdev/mypy/__init__.py +0 -0
- omdev/mypy/debug.py +86 -0
- omdev/pyproject/__init__.py +1 -0
- omdev/pyproject/__main__.py +4 -0
- omdev/pyproject/cli.py +319 -0
- omdev/pyproject/configs.py +97 -0
- omdev/pyproject/ext.py +107 -0
- omdev/pyproject/pkg.py +196 -0
- omdev/scripts/__init__.py +0 -0
- omdev/scripts/execrss.py +19 -0
- omdev/scripts/findimports.py +62 -0
- omdev/scripts/findmagic.py +70 -0
- omdev/scripts/interp.py +2118 -0
- omdev/scripts/pyproject.py +3584 -0
- omdev/scripts/traceimport.py +502 -0
- omdev/tokens.py +42 -0
- omdev/toml/__init__.py +1 -0
- omdev/toml/parser.py +823 -0
- omdev/toml/writer.py +104 -0
- omdev/tools/__init__.py +0 -0
- omdev/tools/dockertools.py +81 -0
- omdev/tools/sqlrepl.py +193 -0
- omdev/versioning/__init__.py +1 -0
- omdev/versioning/specifiers.py +531 -0
- omdev/versioning/versions.py +416 -0
- omdev-0.0.0.dev7.dist-info/LICENSE +21 -0
- omdev-0.0.0.dev7.dist-info/METADATA +24 -0
- omdev-0.0.0.dev7.dist-info/RECORD +67 -0
- omdev-0.0.0.dev7.dist-info/WHEEL +5 -0
- omdev-0.0.0.dev7.dist-info/top_level.txt +1 -0
omdev/pyproject/cli.py
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# @omdev-amalg ../scripts/pyproject.py
|
|
3
|
+
# ruff: noqa: UP006 UP007
|
|
4
|
+
"""
|
|
5
|
+
TODO:
|
|
6
|
+
- check / tests, src dir sets
|
|
7
|
+
- ci
|
|
8
|
+
- build / package / publish / version roll
|
|
9
|
+
- {pkg_name: [src_dirs]}, default excludes, generate MANIFST.in, ...
|
|
10
|
+
- env vars - PYTHONPATH
|
|
11
|
+
|
|
12
|
+
lookit:
|
|
13
|
+
- https://pdm-project.org/en/latest/
|
|
14
|
+
- https://rye.astral.sh/philosophy/
|
|
15
|
+
- https://github.com/indygreg/python-build-standalone/blob/main/pythonbuild/cpython.py
|
|
16
|
+
- https://astral.sh/blog/uv
|
|
17
|
+
- https://github.com/jazzband/pip-tools
|
|
18
|
+
- https://github.com/Osiris-Team/1JPM
|
|
19
|
+
- https://github.com/brettcannon/microvenv
|
|
20
|
+
- https://github.com/pypa/pipx
|
|
21
|
+
- https://github.com/tox-dev/tox/
|
|
22
|
+
"""
|
|
23
|
+
import argparse
|
|
24
|
+
import dataclasses as dc
|
|
25
|
+
import glob
|
|
26
|
+
import itertools
|
|
27
|
+
import os.path
|
|
28
|
+
import shlex
|
|
29
|
+
import shutil
|
|
30
|
+
import sys
|
|
31
|
+
import typing as ta
|
|
32
|
+
|
|
33
|
+
from omlish.lite.cached import cached_nullary
|
|
34
|
+
from omlish.lite.check import check_not
|
|
35
|
+
from omlish.lite.check import check_not_none
|
|
36
|
+
from omlish.lite.logs import configure_standard_logging
|
|
37
|
+
from omlish.lite.logs import log
|
|
38
|
+
from omlish.lite.runtime import check_runtime_version
|
|
39
|
+
from omlish.lite.subprocesses import subprocess_check_call
|
|
40
|
+
|
|
41
|
+
from ..interp.resolvers import DEFAULT_INTERP_RESOLVER
|
|
42
|
+
from ..interp.types import InterpSpecifier
|
|
43
|
+
from ..toml.parser import toml_loads
|
|
44
|
+
from .configs import PyprojectConfig
|
|
45
|
+
from .configs import PyprojectConfigPreparer
|
|
46
|
+
from .configs import VenvConfig
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dc.dataclass(frozen=True)
|
|
53
|
+
class VersionsFile:
|
|
54
|
+
name: ta.Optional[str] = '.versions'
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def parse(s: str) -> ta.Mapping[str, str]:
|
|
58
|
+
return {
|
|
59
|
+
k: v
|
|
60
|
+
for l in s.splitlines()
|
|
61
|
+
if (sl := l.split('#')[0].strip())
|
|
62
|
+
for k, _, v in (sl.partition('='),)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@cached_nullary
|
|
66
|
+
def contents(self) -> ta.Mapping[str, str]:
|
|
67
|
+
if not self.name or not os.path.exists(self.name):
|
|
68
|
+
return {}
|
|
69
|
+
with open(self.name) as f:
|
|
70
|
+
s = f.read()
|
|
71
|
+
return self.parse(s)
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def get_pythons(d: ta.Mapping[str, str]) -> ta.Mapping[str, str]:
|
|
75
|
+
pfx = 'PYTHON_'
|
|
76
|
+
return {k[len(pfx):].lower(): v for k, v in d.items() if k.startswith(pfx)}
|
|
77
|
+
|
|
78
|
+
@cached_nullary
|
|
79
|
+
def pythons(self) -> ta.Mapping[str, str]:
|
|
80
|
+
return self.get_pythons(self.contents())
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@cached_nullary
|
|
87
|
+
def _script_rel_path() -> str:
|
|
88
|
+
cwd = os.getcwd()
|
|
89
|
+
if not (f := __file__).startswith(cwd):
|
|
90
|
+
raise OSError(f'file {f} not in {cwd}')
|
|
91
|
+
return f[len(cwd):].lstrip(os.sep)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Venv:
|
|
98
|
+
def __init__(
|
|
99
|
+
self,
|
|
100
|
+
name: str,
|
|
101
|
+
cfg: VenvConfig,
|
|
102
|
+
) -> None:
|
|
103
|
+
super().__init__()
|
|
104
|
+
self._name = name
|
|
105
|
+
self._cfg = cfg
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def cfg(self) -> VenvConfig:
|
|
109
|
+
return self._cfg
|
|
110
|
+
|
|
111
|
+
DIR_NAME = '.venvs'
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def dir_name(self) -> str:
|
|
115
|
+
return os.path.join(self.DIR_NAME, self._name)
|
|
116
|
+
|
|
117
|
+
@cached_nullary
|
|
118
|
+
def interp_exe(self) -> str:
|
|
119
|
+
i = InterpSpecifier.parse(check_not_none(self._cfg.interp))
|
|
120
|
+
return DEFAULT_INTERP_RESOLVER.resolve(i).exe
|
|
121
|
+
|
|
122
|
+
@cached_nullary
|
|
123
|
+
def exe(self) -> str:
|
|
124
|
+
ve = os.path.join(self.dir_name, 'bin/python')
|
|
125
|
+
if not os.path.isfile(ve):
|
|
126
|
+
raise Exception(f'venv exe {ve} does not exist or is not a file!')
|
|
127
|
+
return ve
|
|
128
|
+
|
|
129
|
+
@cached_nullary
|
|
130
|
+
def create(self) -> bool:
|
|
131
|
+
if os.path.exists(dn := self.dir_name):
|
|
132
|
+
if not os.path.isdir(dn):
|
|
133
|
+
raise Exception(f'{dn} exists but is not a directory!')
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
log.info('Using interpreter %s', (ie := self.interp_exe()))
|
|
137
|
+
subprocess_check_call(ie, '-m', 'venv', dn)
|
|
138
|
+
|
|
139
|
+
ve = self.exe()
|
|
140
|
+
|
|
141
|
+
subprocess_check_call(
|
|
142
|
+
ve,
|
|
143
|
+
'-m', 'pip',
|
|
144
|
+
'install', '-v', '--upgrade',
|
|
145
|
+
'pip',
|
|
146
|
+
'setuptools',
|
|
147
|
+
'wheel',
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if (sr := self._cfg.requires):
|
|
151
|
+
subprocess_check_call(
|
|
152
|
+
ve,
|
|
153
|
+
'-m', 'pip',
|
|
154
|
+
'install', '-v',
|
|
155
|
+
*sr,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
return True
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def _resolve_srcs(raw: ta.List[str]) -> ta.List[str]:
|
|
162
|
+
out: list[str] = []
|
|
163
|
+
seen: ta.Set[str] = set()
|
|
164
|
+
for r in raw:
|
|
165
|
+
es: list[str]
|
|
166
|
+
if any(c in r for c in '*?'):
|
|
167
|
+
es = list(glob.glob(r, recursive=True))
|
|
168
|
+
else:
|
|
169
|
+
es = [r]
|
|
170
|
+
for e in es:
|
|
171
|
+
if e not in seen:
|
|
172
|
+
seen.add(e)
|
|
173
|
+
out.append(e)
|
|
174
|
+
return out
|
|
175
|
+
|
|
176
|
+
@cached_nullary
|
|
177
|
+
def srcs(self) -> ta.Sequence[str]:
|
|
178
|
+
return self._resolve_srcs(self._cfg.srcs or [])
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
##
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class Run:
|
|
185
|
+
def __init__(
|
|
186
|
+
self,
|
|
187
|
+
*,
|
|
188
|
+
raw_cfg: ta.Union[ta.Mapping[str, ta.Any], str, None] = None,
|
|
189
|
+
) -> None:
|
|
190
|
+
super().__init__()
|
|
191
|
+
|
|
192
|
+
self._raw_cfg = raw_cfg
|
|
193
|
+
|
|
194
|
+
@cached_nullary
|
|
195
|
+
def raw_cfg(self) -> ta.Mapping[str, ta.Any]:
|
|
196
|
+
if self._raw_cfg is None:
|
|
197
|
+
with open('pyproject.toml') as f:
|
|
198
|
+
buf = f.read()
|
|
199
|
+
elif isinstance(self._raw_cfg, str):
|
|
200
|
+
buf = self._raw_cfg
|
|
201
|
+
else:
|
|
202
|
+
return self._raw_cfg
|
|
203
|
+
return toml_loads(buf)
|
|
204
|
+
|
|
205
|
+
@cached_nullary
|
|
206
|
+
def cfg(self) -> PyprojectConfig:
|
|
207
|
+
dct = self.raw_cfg()['tool']['omlish']['pyproject']
|
|
208
|
+
return PyprojectConfigPreparer(
|
|
209
|
+
python_versions=VersionsFile().pythons(),
|
|
210
|
+
).prepare_config(dct)
|
|
211
|
+
|
|
212
|
+
@cached_nullary
|
|
213
|
+
def venvs(self) -> ta.Mapping[str, Venv]:
|
|
214
|
+
return {
|
|
215
|
+
n: Venv(n, c)
|
|
216
|
+
for n, c in self.cfg().venvs.items()
|
|
217
|
+
if not n.startswith('_')
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
##
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _venv_cmd(args) -> None:
|
|
225
|
+
venv = Run().venvs()[args.name]
|
|
226
|
+
if (sd := venv.cfg.docker) is not None and sd != (cd := args._docker_container): # noqa
|
|
227
|
+
script = ' '.join([
|
|
228
|
+
'python3',
|
|
229
|
+
shlex.quote(_script_rel_path()),
|
|
230
|
+
f'--_docker_container={shlex.quote(sd)}',
|
|
231
|
+
*map(shlex.quote, sys.argv[1:]),
|
|
232
|
+
])
|
|
233
|
+
subprocess_check_call(
|
|
234
|
+
'docker',
|
|
235
|
+
'compose',
|
|
236
|
+
'-f', 'docker/compose.yml',
|
|
237
|
+
'exec',
|
|
238
|
+
*itertools.chain.from_iterable(
|
|
239
|
+
('-e', f'{e}={os.environ.get(e, "")}' if '=' not in e else e)
|
|
240
|
+
for e in (args.docker_env or [])
|
|
241
|
+
),
|
|
242
|
+
'-it', sd,
|
|
243
|
+
'bash', '--login', '-c', script,
|
|
244
|
+
)
|
|
245
|
+
return
|
|
246
|
+
|
|
247
|
+
venv.create()
|
|
248
|
+
|
|
249
|
+
cmd = args.cmd
|
|
250
|
+
if not cmd:
|
|
251
|
+
pass
|
|
252
|
+
|
|
253
|
+
elif cmd == 'python':
|
|
254
|
+
os.execl(
|
|
255
|
+
(exe := venv.exe()),
|
|
256
|
+
exe,
|
|
257
|
+
*args.args,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
elif cmd == 'exe':
|
|
261
|
+
check_not(args.args)
|
|
262
|
+
print(venv.exe())
|
|
263
|
+
|
|
264
|
+
elif cmd == 'run':
|
|
265
|
+
sh = check_not_none(shutil.which('bash'))
|
|
266
|
+
script = ' '.join(args.args)
|
|
267
|
+
if not script:
|
|
268
|
+
script = sh
|
|
269
|
+
os.execl(
|
|
270
|
+
(bash := check_not_none(sh)),
|
|
271
|
+
bash,
|
|
272
|
+
'-c',
|
|
273
|
+
f'. {venv.dir_name}/bin/activate && ' + script,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
elif cmd == 'srcs':
|
|
277
|
+
check_not(args.args)
|
|
278
|
+
print('\n'.join(venv.srcs()))
|
|
279
|
+
|
|
280
|
+
elif cmd == 'test':
|
|
281
|
+
subprocess_check_call(venv.exe(), '-m', 'pytest', *(args.args or []), *venv.srcs())
|
|
282
|
+
|
|
283
|
+
else:
|
|
284
|
+
raise Exception(f'unknown subcommand: {cmd}')
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
##
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
291
|
+
parser = argparse.ArgumentParser()
|
|
292
|
+
parser.add_argument('--_docker_container', help=argparse.SUPPRESS)
|
|
293
|
+
|
|
294
|
+
subparsers = parser.add_subparsers()
|
|
295
|
+
|
|
296
|
+
parser_resolve = subparsers.add_parser('venv')
|
|
297
|
+
parser_resolve.add_argument('name')
|
|
298
|
+
parser_resolve.add_argument('-e', '--docker-env', action='append')
|
|
299
|
+
parser_resolve.add_argument('cmd', nargs='?')
|
|
300
|
+
parser_resolve.add_argument('args', nargs=argparse.REMAINDER)
|
|
301
|
+
parser_resolve.set_defaults(func=_venv_cmd)
|
|
302
|
+
|
|
303
|
+
return parser
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
|
307
|
+
check_runtime_version()
|
|
308
|
+
configure_standard_logging()
|
|
309
|
+
|
|
310
|
+
parser = _build_parser()
|
|
311
|
+
args = parser.parse_args(argv)
|
|
312
|
+
if not getattr(args, 'func', None):
|
|
313
|
+
parser.print_help()
|
|
314
|
+
else:
|
|
315
|
+
args.func(args)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
if __name__ == '__main__':
|
|
319
|
+
_main()
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
import dataclasses as dc
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from omlish.lite.marshal import unmarshal_obj
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dc.dataclass(frozen=True)
|
|
9
|
+
class VenvConfig:
|
|
10
|
+
inherits: ta.Optional[ta.Sequence[str]] = None
|
|
11
|
+
interp: ta.Optional[str] = None
|
|
12
|
+
requires: ta.Optional[ta.List[str]] = None
|
|
13
|
+
docker: ta.Optional[str] = None
|
|
14
|
+
srcs: ta.Optional[ta.List[str]] = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dc.dataclass(frozen=True)
|
|
18
|
+
class PyprojectConfig:
|
|
19
|
+
srcs: ta.Mapping[str, ta.Sequence[str]]
|
|
20
|
+
venvs: ta.Mapping[str, VenvConfig]
|
|
21
|
+
|
|
22
|
+
venvs_dir: str = '.venvs'
|
|
23
|
+
versions_file: ta.Optional[str] = '.versions'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PyprojectConfigPreparer:
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
*,
|
|
30
|
+
python_versions: ta.Optional[ta.Mapping[str, str]] = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__()
|
|
33
|
+
|
|
34
|
+
self._python_versions = python_versions or {}
|
|
35
|
+
|
|
36
|
+
def _inherit_venvs(self, m: ta.Mapping[str, VenvConfig]) -> ta.Mapping[str, VenvConfig]:
|
|
37
|
+
done: ta.Dict[str, VenvConfig] = {}
|
|
38
|
+
|
|
39
|
+
def rec(k):
|
|
40
|
+
try:
|
|
41
|
+
return done[k]
|
|
42
|
+
except KeyError:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
c = m[k]
|
|
46
|
+
kw = dc.asdict(c)
|
|
47
|
+
for i in c.inherits or ():
|
|
48
|
+
ic = rec(i)
|
|
49
|
+
kw.update({k: v for k, v in dc.asdict(ic).items() if v is not None and kw.get(k) is None})
|
|
50
|
+
del kw['inherits']
|
|
51
|
+
|
|
52
|
+
d = done[k] = VenvConfig(**kw)
|
|
53
|
+
return d
|
|
54
|
+
|
|
55
|
+
for k in m:
|
|
56
|
+
rec(k)
|
|
57
|
+
return done
|
|
58
|
+
|
|
59
|
+
def _resolve_srcs(
|
|
60
|
+
self,
|
|
61
|
+
lst: ta.Sequence[str],
|
|
62
|
+
aliases: ta.Mapping[str, ta.Sequence[str]],
|
|
63
|
+
) -> ta.List[str]:
|
|
64
|
+
todo = list(reversed(lst))
|
|
65
|
+
raw: ta.List[str] = []
|
|
66
|
+
seen: ta.Set[str] = set()
|
|
67
|
+
|
|
68
|
+
while todo:
|
|
69
|
+
cur = todo.pop()
|
|
70
|
+
if cur in seen:
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
seen.add(cur)
|
|
74
|
+
if not cur.startswith('@'):
|
|
75
|
+
raw.append(cur)
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
todo.extend(aliases[cur[1:]][::-1])
|
|
79
|
+
|
|
80
|
+
return raw
|
|
81
|
+
|
|
82
|
+
def _fixup_interp(self, s: ta.Optional[str]) -> ta.Optional[str]:
|
|
83
|
+
if not s or not s.startswith('@'):
|
|
84
|
+
return s
|
|
85
|
+
return self._python_versions[s[1:]]
|
|
86
|
+
|
|
87
|
+
def prepare_config(self, dct: ta.Mapping[str, ta.Any]) -> PyprojectConfig:
|
|
88
|
+
pcfg: PyprojectConfig = unmarshal_obj(dct, PyprojectConfig)
|
|
89
|
+
|
|
90
|
+
ivs = dict(self._inherit_venvs(pcfg.venvs or {}))
|
|
91
|
+
for k, v in ivs.items():
|
|
92
|
+
v = dc.replace(v, srcs=self._resolve_srcs(v.srcs or [], pcfg.srcs or {}))
|
|
93
|
+
v = dc.replace(v, interp=self._fixup_interp(v.interp))
|
|
94
|
+
ivs[k] = v
|
|
95
|
+
|
|
96
|
+
pcfg = dc.replace(pcfg, venvs=ivs)
|
|
97
|
+
return pcfg
|
omdev/pyproject/ext.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
import dataclasses as dc
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
# https://setuptools.pypa.io/en/latest/userguide/ext_modules.html#extension-api-reference
|
|
8
|
+
|
|
9
|
+
name (str) -
|
|
10
|
+
the full name of the extension, including any packages - ie. not a filename or pathname, but Python dotted name
|
|
11
|
+
|
|
12
|
+
sources (list[str]) -
|
|
13
|
+
list of source filenames, relative to the distribution root (where the setup script lives), in Unix form
|
|
14
|
+
(slash-separated) for portability. Source files may be C, C++, SWIG (.i), platform-specific resource files, or
|
|
15
|
+
whatever else is recognized by the “build_ext” command as source for a Python extension.
|
|
16
|
+
|
|
17
|
+
include_dirs (list[str]) -
|
|
18
|
+
list of directories to search for C/C++ header files (in Unix form for portability)
|
|
19
|
+
|
|
20
|
+
define_macros (list[tuple[str, str|None]]) -
|
|
21
|
+
list of macros to define; each macro is defined using a 2-tuple: the first item corresponding to the name of the
|
|
22
|
+
macro and the second item either a string with its value or None to define it without a particular value (equivalent
|
|
23
|
+
of “#define FOO” in source or -DFOO on Unix C compiler command line)
|
|
24
|
+
|
|
25
|
+
undef_macros (list[str]) -
|
|
26
|
+
list of macros to undefine explicitly
|
|
27
|
+
|
|
28
|
+
library_dirs (list[str]) -
|
|
29
|
+
list of directories to search for C/C++ libraries at link time
|
|
30
|
+
|
|
31
|
+
libraries (list[str]) -
|
|
32
|
+
list of library names (not filenames or paths) to link against
|
|
33
|
+
|
|
34
|
+
runtime_library_dirs (list[str]) -
|
|
35
|
+
list of directories to search for C/C++ libraries at run time (for shared extensions, this is when the extension is
|
|
36
|
+
loaded). Setting this will cause an exception during build on Windows platforms.
|
|
37
|
+
|
|
38
|
+
extra_objects (list[str]) -
|
|
39
|
+
list of extra files to link with (eg. object files not implied by 'sources', static library that must be explicitly
|
|
40
|
+
specified, binary resource files, etc.)
|
|
41
|
+
|
|
42
|
+
extra_compile_args (list[str]) -
|
|
43
|
+
any extra platform- and compiler-specific information to use when compiling the source files in 'sources'. For
|
|
44
|
+
platforms and compilers where “command line” makes sense, this is typically a list of command-line arguments, but
|
|
45
|
+
for other platforms it could be anything.
|
|
46
|
+
|
|
47
|
+
extra_link_args (list[str]) -
|
|
48
|
+
any extra platform- and compiler-specific information to use when linking object files together to create the
|
|
49
|
+
extension (or to create a new static Python interpreter). Similar interpretation as for 'extra_compile_args'.
|
|
50
|
+
|
|
51
|
+
export_symbols (list[str]) -
|
|
52
|
+
list of symbols to be exported from a shared extension. Not used on all platforms, and not generally necessary for
|
|
53
|
+
Python extensions, which typically export exactly one symbol: “init” + extension_name.
|
|
54
|
+
|
|
55
|
+
swig_opts (list[str]) -
|
|
56
|
+
any extra options to pass to SWIG if a source file has the .i extension.
|
|
57
|
+
|
|
58
|
+
depends (list[str]) -
|
|
59
|
+
list of files that the extension depends on
|
|
60
|
+
|
|
61
|
+
language (str) -
|
|
62
|
+
extension language (i.e. “c”, “c++”, “objc”). Will be detected from the source extensions if not provided.
|
|
63
|
+
|
|
64
|
+
optional (bool) -
|
|
65
|
+
specifies that a build failure in the extension should not abort the build process, but simply not install the
|
|
66
|
+
failing extension.
|
|
67
|
+
|
|
68
|
+
py_limited_api (bool) -
|
|
69
|
+
opt-in flag for the usage of Python's limited API.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
SETUP_PY_TMPL = """
|
|
74
|
+
import setuptools as st
|
|
75
|
+
|
|
76
|
+
st.setup(
|
|
77
|
+
ext_modules=[
|
|
78
|
+
st.Extension(
|
|
79
|
+
'{mod_name}',
|
|
80
|
+
[{mod_srcs}],
|
|
81
|
+
include_dirs=['lib'],
|
|
82
|
+
py_limited_api=True
|
|
83
|
+
),
|
|
84
|
+
],
|
|
85
|
+
)
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dc.dataclass(frozen=True)
|
|
90
|
+
class ExtModule:
|
|
91
|
+
name: str
|
|
92
|
+
sources: ta.List[str]
|
|
93
|
+
include_dirs: ta.Optional[ta.List[str]] = None
|
|
94
|
+
define_macros: ta.Optional[ta.List[ta.Tuple[str, ta.Optional[str]]]] = None
|
|
95
|
+
undef_macros: ta.Optional[ta.List[str]] = None
|
|
96
|
+
library_dirs: ta.Optional[ta.List[str]] = None
|
|
97
|
+
libraries: ta.Optional[ta.List[str]] = None
|
|
98
|
+
runtime_library_dirs: ta.Optional[ta.List[str]] = None
|
|
99
|
+
extra_objects: ta.Optional[ta.List[str]] = None
|
|
100
|
+
extra_compile_args: ta.Optional[ta.List[str]] = None
|
|
101
|
+
extra_link_args: ta.Optional[ta.List[str]] = None
|
|
102
|
+
export_symbols: ta.Optional[ta.List[str]] = None
|
|
103
|
+
swig_opts: ta.Optional[ta.List[str]] = None
|
|
104
|
+
depends: ta.Optional[ta.List[str]] = None
|
|
105
|
+
language: ta.Optional[str] = None
|
|
106
|
+
optional: ta.Optional[bool] = None
|
|
107
|
+
py_limited_api: ta.Optional[bool] = None
|