omdev 0.0.0.dev19__py3-none-any.whl → 0.0.0.dev21__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.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- omdev/__about__.py +4 -0
- omdev/interp/cli.py +2 -1
- omdev/interp/providers.py +1 -0
- omdev/interp/pyenv.py +49 -15
- omdev/interp/resolvers.py +36 -5
- omdev/interp/types.py +3 -0
- omdev/pyproject/cli.py +13 -4
- omdev/pyproject/configs.py +1 -0
- omdev/pyproject/pkg.py +1 -1
- omdev/pyproject/reqs.py +78 -0
- omdev/{tools/revisions.py → revisions.py} +1 -1
- omdev/scripts/__init__.py +1 -0
- omdev/scripts/bumpversion.py +43 -0
- omdev/scripts/interp.py +91 -23
- omdev/scripts/pyproject.py +186 -29
- omdev/tools/__init__.py +1 -0
- omdev/tools/rst.py +44 -0
- {omdev-0.0.0.dev19.dist-info → omdev-0.0.0.dev21.dist-info}/METADATA +5 -2
- {omdev-0.0.0.dev19.dist-info → omdev-0.0.0.dev21.dist-info}/RECORD +22 -19
- {omdev-0.0.0.dev19.dist-info → omdev-0.0.0.dev21.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev19.dist-info → omdev-0.0.0.dev21.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev19.dist-info → omdev-0.0.0.dev21.dist-info}/top_level.txt +0 -0
omdev/__about__.py
CHANGED
omdev/interp/cli.py
CHANGED
|
@@ -10,6 +10,7 @@ TODO:
|
|
|
10
10
|
import argparse
|
|
11
11
|
import typing as ta
|
|
12
12
|
|
|
13
|
+
from omlish.lite.check import check_not_none
|
|
13
14
|
from omlish.lite.logs import configure_standard_logging
|
|
14
15
|
from omlish.lite.runtime import check_runtime_version
|
|
15
16
|
|
|
@@ -26,7 +27,7 @@ def _list_cmd(args) -> None:
|
|
|
26
27
|
def _resolve_cmd(args) -> None:
|
|
27
28
|
r = DEFAULT_INTERP_RESOLVER
|
|
28
29
|
s = InterpSpecifier.parse(args.version)
|
|
29
|
-
print(r.resolve(s).exe)
|
|
30
|
+
print(check_not_none(r.resolve(s)).exe)
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
def _build_parser() -> argparse.ArgumentParser:
|
omdev/interp/providers.py
CHANGED
omdev/interp/pyenv.py
CHANGED
|
@@ -116,6 +116,7 @@ class PyenvInstallOpts:
|
|
|
116
116
|
|
|
117
117
|
DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-s', '-v'])
|
|
118
118
|
DEBUG_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-g'])
|
|
119
|
+
THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
|
|
119
120
|
|
|
120
121
|
|
|
121
122
|
#
|
|
@@ -176,19 +177,19 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
176
177
|
f"--with-tcltk-libs='-L{tcl_tk_prefix}/lib -ltcl{tcl_tk_ver} -ltk{tcl_tk_ver}'",
|
|
177
178
|
])
|
|
178
179
|
|
|
179
|
-
@cached_nullary
|
|
180
|
-
def brew_ssl_opts(self) -> PyenvInstallOpts:
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
180
|
+
# @cached_nullary
|
|
181
|
+
# def brew_ssl_opts(self) -> PyenvInstallOpts:
|
|
182
|
+
# pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
|
|
183
|
+
# if 'PKG_CONFIG_PATH' in os.environ:
|
|
184
|
+
# pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
|
|
185
|
+
# return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
|
|
185
186
|
|
|
186
187
|
def opts(self) -> PyenvInstallOpts:
|
|
187
188
|
return PyenvInstallOpts().merge(
|
|
188
189
|
self.framework_opts(),
|
|
189
190
|
self.brew_deps_opts(),
|
|
190
191
|
self.brew_tcl_opts(),
|
|
191
|
-
self.brew_ssl_opts(),
|
|
192
|
+
# self.brew_ssl_opts(),
|
|
192
193
|
)
|
|
193
194
|
|
|
194
195
|
|
|
@@ -202,27 +203,39 @@ PLATFORM_PYENV_INSTALL_OPTS: ta.Dict[str, PyenvInstallOptsProvider] = {
|
|
|
202
203
|
|
|
203
204
|
|
|
204
205
|
class PyenvVersionInstaller:
|
|
206
|
+
"""
|
|
207
|
+
Messy: can install freethreaded build with a 't' suffixed version str _or_ by THREADED_PYENV_INSTALL_OPTS - need
|
|
208
|
+
latter to build custom interp with ft, need former to use canned / blessed interps. Muh.
|
|
209
|
+
"""
|
|
205
210
|
|
|
206
211
|
def __init__(
|
|
207
212
|
self,
|
|
208
213
|
version: str,
|
|
209
214
|
opts: ta.Optional[PyenvInstallOpts] = None,
|
|
215
|
+
interp_opts: InterpOpts = InterpOpts(),
|
|
210
216
|
*,
|
|
211
|
-
|
|
217
|
+
no_default_opts: bool = False,
|
|
212
218
|
pyenv: Pyenv = Pyenv(),
|
|
213
219
|
) -> None:
|
|
214
220
|
super().__init__()
|
|
215
221
|
|
|
216
|
-
if
|
|
217
|
-
|
|
218
|
-
|
|
222
|
+
if no_default_opts:
|
|
223
|
+
if opts is None:
|
|
224
|
+
opts = PyenvInstallOpts()
|
|
225
|
+
else:
|
|
226
|
+
lst = [opts if opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
|
|
227
|
+
if interp_opts.debug:
|
|
219
228
|
lst.append(DEBUG_PYENV_INSTALL_OPTS)
|
|
229
|
+
if interp_opts.threaded:
|
|
230
|
+
lst.append(THREADED_PYENV_INSTALL_OPTS)
|
|
220
231
|
lst.append(PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
|
|
221
232
|
opts = PyenvInstallOpts().merge(*lst)
|
|
222
233
|
|
|
223
234
|
self._version = version
|
|
224
235
|
self._opts = opts
|
|
225
|
-
self.
|
|
236
|
+
self._interp_opts = interp_opts
|
|
237
|
+
|
|
238
|
+
self._no_default_opts = no_default_opts
|
|
226
239
|
self._pyenv = pyenv
|
|
227
240
|
|
|
228
241
|
@property
|
|
@@ -235,7 +248,7 @@ class PyenvVersionInstaller:
|
|
|
235
248
|
|
|
236
249
|
@cached_nullary
|
|
237
250
|
def install_name(self) -> str:
|
|
238
|
-
return self._version + ('-debug' if self.
|
|
251
|
+
return self._version + ('-debug' if self._interp_opts.debug else '')
|
|
239
252
|
|
|
240
253
|
@cached_nullary
|
|
241
254
|
def install_dir(self) -> str:
|
|
@@ -243,7 +256,7 @@ class PyenvVersionInstaller:
|
|
|
243
256
|
|
|
244
257
|
@cached_nullary
|
|
245
258
|
def install(self) -> str:
|
|
246
|
-
env =
|
|
259
|
+
env = {**os.environ, **self._opts.env}
|
|
247
260
|
for k, l in [
|
|
248
261
|
('CFLAGS', self._opts.cflags),
|
|
249
262
|
('LDFLAGS', self._opts.ldflags),
|
|
@@ -254,7 +267,13 @@ class PyenvVersionInstaller:
|
|
|
254
267
|
v += ' ' + os.environ[k]
|
|
255
268
|
env[k] = v
|
|
256
269
|
|
|
257
|
-
subprocess_check_call(
|
|
270
|
+
subprocess_check_call(
|
|
271
|
+
self._pyenv.exe(),
|
|
272
|
+
'install',
|
|
273
|
+
*self._opts.opts,
|
|
274
|
+
self._version,
|
|
275
|
+
env=env,
|
|
276
|
+
)
|
|
258
277
|
|
|
259
278
|
exe = os.path.join(self.install_dir(), 'bin', 'python')
|
|
260
279
|
if not os.path.isfile(exe):
|
|
@@ -355,3 +374,18 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
355
374
|
for d in [False, True]:
|
|
356
375
|
lst.append(dc.replace(iv, opts=dc.replace(iv.opts, debug=d)))
|
|
357
376
|
return lst
|
|
377
|
+
|
|
378
|
+
def install_version(self, version: InterpVersion) -> Interp:
|
|
379
|
+
inst_version = str(version.version)
|
|
380
|
+
inst_opts = version.opts
|
|
381
|
+
if inst_opts.threaded:
|
|
382
|
+
inst_version += 't'
|
|
383
|
+
inst_opts = dc.replace(inst_opts, threaded=False)
|
|
384
|
+
|
|
385
|
+
installer = PyenvVersionInstaller(
|
|
386
|
+
inst_version,
|
|
387
|
+
interp_opts=inst_opts,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
exe = installer.install()
|
|
391
|
+
return Interp(exe, version)
|
omdev/interp/resolvers.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ruff: noqa: UP006
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
2
|
import abc
|
|
3
3
|
import collections
|
|
4
4
|
import typing as ta
|
|
@@ -11,6 +11,7 @@ from .pyenv import PyenvInterpProvider
|
|
|
11
11
|
from .system import SystemInterpProvider
|
|
12
12
|
from .types import Interp
|
|
13
13
|
from .types import InterpSpecifier
|
|
14
|
+
from .types import InterpVersion
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
INTERP_PROVIDER_TYPES_BY_NAME: ta.Mapping[str, ta.Type[InterpProvider]] = {
|
|
@@ -26,17 +27,47 @@ class InterpResolver:
|
|
|
26
27
|
super().__init__()
|
|
27
28
|
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
|
|
28
29
|
|
|
29
|
-
def
|
|
30
|
+
def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
|
30
31
|
lst = [
|
|
31
32
|
(i, si)
|
|
32
33
|
for i, p in enumerate(self._providers.values())
|
|
33
34
|
for si in p.get_installed_versions(spec)
|
|
34
35
|
if spec.contains(si)
|
|
35
36
|
]
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
slst = sorted(lst, key=lambda t: (-t[0], t[1]))
|
|
39
|
+
if not slst:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
bi, bv = slst[-1]
|
|
38
43
|
bp = list(self._providers.values())[bi]
|
|
39
|
-
return bp
|
|
44
|
+
return (bp, bv)
|
|
45
|
+
|
|
46
|
+
def resolve(
|
|
47
|
+
self,
|
|
48
|
+
spec: InterpSpecifier,
|
|
49
|
+
*,
|
|
50
|
+
install: bool = False,
|
|
51
|
+
) -> ta.Optional[Interp]:
|
|
52
|
+
tup = self._resolve_installed(spec)
|
|
53
|
+
if tup is not None:
|
|
54
|
+
bp, bv = tup
|
|
55
|
+
return bp.get_installed_version(bv)
|
|
56
|
+
|
|
57
|
+
if not install:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
tp = list(self._providers.values())[0] # noqa
|
|
61
|
+
|
|
62
|
+
sv = sorted(
|
|
63
|
+
[s for s in tp.get_installable_versions(spec) if s in spec],
|
|
64
|
+
key=lambda s: s.version,
|
|
65
|
+
)
|
|
66
|
+
if not sv:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
bv = sv[-1]
|
|
70
|
+
return tp.install_version(bv)
|
|
40
71
|
|
|
41
72
|
def list(self, spec: InterpSpecifier) -> None:
|
|
42
73
|
print('installed:')
|
omdev/interp/types.py
CHANGED
|
@@ -85,6 +85,9 @@ class InterpSpecifier:
|
|
|
85
85
|
def contains(self, iv: InterpVersion) -> bool:
|
|
86
86
|
return self.specifier.contains(iv.version) and self.opts == iv.opts
|
|
87
87
|
|
|
88
|
+
def __contains__(self, iv: InterpVersion) -> bool:
|
|
89
|
+
return self.contains(iv)
|
|
90
|
+
|
|
88
91
|
|
|
89
92
|
@dc.dataclass(frozen=True)
|
|
90
93
|
class Interp:
|
omdev/pyproject/cli.py
CHANGED
|
@@ -8,6 +8,7 @@ TODO:
|
|
|
8
8
|
- build / package / publish / version roll
|
|
9
9
|
- {pkg_name: [src_dirs]}, default excludes, generate MANIFST.in, ...
|
|
10
10
|
- env vars - PYTHONPATH
|
|
11
|
+
- optional uv backend
|
|
11
12
|
|
|
12
13
|
lookit:
|
|
13
14
|
- https://pdm-project.org/en/latest/
|
|
@@ -48,6 +49,7 @@ from .configs import PyprojectConfig
|
|
|
48
49
|
from .configs import PyprojectConfigPreparer
|
|
49
50
|
from .configs import VenvConfig
|
|
50
51
|
from .pkg import PyprojectPackageGenerator
|
|
52
|
+
from .reqs import RequirementsRewriter
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
##
|
|
@@ -121,7 +123,7 @@ class Venv:
|
|
|
121
123
|
@cached_nullary
|
|
122
124
|
def interp_exe(self) -> str:
|
|
123
125
|
i = InterpSpecifier.parse(check_not_none(self._cfg.interp))
|
|
124
|
-
return DEFAULT_INTERP_RESOLVER.resolve(i).exe
|
|
126
|
+
return check_not_none(DEFAULT_INTERP_RESOLVER.resolve(i, install=True)).exe
|
|
125
127
|
|
|
126
128
|
@cached_nullary
|
|
127
129
|
def exe(self) -> str:
|
|
@@ -141,6 +143,7 @@ class Venv:
|
|
|
141
143
|
subprocess_check_call(ie, '-m', 'venv', dn)
|
|
142
144
|
|
|
143
145
|
ve = self.exe()
|
|
146
|
+
uv = self._cfg.use_uv
|
|
144
147
|
|
|
145
148
|
subprocess_check_call(
|
|
146
149
|
ve,
|
|
@@ -149,14 +152,20 @@ class Venv:
|
|
|
149
152
|
'pip',
|
|
150
153
|
'setuptools',
|
|
151
154
|
'wheel',
|
|
155
|
+
*(['uv'] if uv else []),
|
|
152
156
|
)
|
|
153
157
|
|
|
154
158
|
if (sr := self._cfg.requires):
|
|
159
|
+
rr = RequirementsRewriter(self._name)
|
|
160
|
+
reqs = [rr.rewrite(req) for req in sr]
|
|
155
161
|
subprocess_check_call(
|
|
156
162
|
ve,
|
|
157
|
-
'-m',
|
|
158
|
-
'
|
|
159
|
-
|
|
163
|
+
'-m',
|
|
164
|
+
*(['uv'] if uv else []),
|
|
165
|
+
'pip',
|
|
166
|
+
'install',
|
|
167
|
+
*([] if uv else ['-v']),
|
|
168
|
+
*reqs,
|
|
160
169
|
)
|
|
161
170
|
|
|
162
171
|
return True
|
omdev/pyproject/configs.py
CHANGED
omdev/pyproject/pkg.py
CHANGED
|
@@ -40,8 +40,8 @@ from omlish.lite.logs import log
|
|
|
40
40
|
|
|
41
41
|
from ..cexts.magic import CextMagic
|
|
42
42
|
from ..findmagic import find_magic
|
|
43
|
+
from ..revisions import GitRevisionAdder
|
|
43
44
|
from ..toml.writer import TomlWriter
|
|
44
|
-
from ..tools.revisions import GitRevisionAdder
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
#
|
omdev/pyproject/reqs.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- embed pip._internal.req.parse_requirements, add additional env stuff? breaks compat with raw pip
|
|
4
|
+
"""
|
|
5
|
+
# ruff: noqa: UP007
|
|
6
|
+
import os.path
|
|
7
|
+
import tempfile
|
|
8
|
+
import typing as ta
|
|
9
|
+
|
|
10
|
+
from omlish.lite.cached import cached_nullary
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RequirementsRewriter:
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
venv: ta.Optional[str] = None,
|
|
17
|
+
) -> None:
|
|
18
|
+
super().__init__()
|
|
19
|
+
self._venv = venv
|
|
20
|
+
|
|
21
|
+
@cached_nullary
|
|
22
|
+
def _tmp_dir(self) -> str:
|
|
23
|
+
return tempfile.mkdtemp('-omlish-reqs')
|
|
24
|
+
|
|
25
|
+
VENV_MAGIC = '# @omdev-venv'
|
|
26
|
+
|
|
27
|
+
def rewrite_file(self, in_file: str) -> str:
|
|
28
|
+
with open(in_file) as f:
|
|
29
|
+
src = f.read()
|
|
30
|
+
|
|
31
|
+
in_lines = src.splitlines(keepends=True)
|
|
32
|
+
out_lines = []
|
|
33
|
+
|
|
34
|
+
for l in in_lines:
|
|
35
|
+
if self.VENV_MAGIC in l:
|
|
36
|
+
lp, _, rp = l.partition(self.VENV_MAGIC)
|
|
37
|
+
rp = rp.partition('#')[0]
|
|
38
|
+
omit = False
|
|
39
|
+
for v in rp.split():
|
|
40
|
+
if v[0] == '!':
|
|
41
|
+
if self._venv is not None and self._venv == v[1:]:
|
|
42
|
+
omit = True
|
|
43
|
+
break
|
|
44
|
+
else:
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
|
|
47
|
+
if omit:
|
|
48
|
+
out_lines.append('# OMITTED: ' + l)
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
out_req = self.rewrite(l.rstrip('\n'), for_file=True)
|
|
52
|
+
out_lines.append(out_req + '\n')
|
|
53
|
+
|
|
54
|
+
out_file = os.path.join(self._tmp_dir(), os.path.basename(in_file))
|
|
55
|
+
if os.path.exists(out_file):
|
|
56
|
+
raise Exception(f'file exists: {out_file}')
|
|
57
|
+
|
|
58
|
+
with open(out_file, 'w') as f:
|
|
59
|
+
f.write(''.join(out_lines))
|
|
60
|
+
return out_file
|
|
61
|
+
|
|
62
|
+
def rewrite(self, in_req: str, *, for_file: bool = False) -> str:
|
|
63
|
+
if in_req.strip().startswith('-r'):
|
|
64
|
+
l = in_req.strip()
|
|
65
|
+
lp, _, rp = l.partition(' ')
|
|
66
|
+
if lp == '-r':
|
|
67
|
+
inc_in_file, _, rest = rp.partition(' ')
|
|
68
|
+
else:
|
|
69
|
+
inc_in_file, rest = lp[2:], rp
|
|
70
|
+
|
|
71
|
+
inc_out_file = self.rewrite_file(inc_in_file)
|
|
72
|
+
if for_file:
|
|
73
|
+
return ' '.join(['-r ', inc_out_file, rest])
|
|
74
|
+
else:
|
|
75
|
+
return '-r' + inc_out_file
|
|
76
|
+
|
|
77
|
+
else:
|
|
78
|
+
return in_req
|
omdev/scripts/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Depless, self-contained scripts with no reason to be imported from any other module."""
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
# @omlish-script
|
|
4
|
+
import argparse
|
|
5
|
+
import re
|
|
6
|
+
import string
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_VERSION_PAT = re.compile(r"__version__ = '(?P<version>[^\']+)'")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _main() -> None:
|
|
13
|
+
parser = argparse.ArgumentParser()
|
|
14
|
+
|
|
15
|
+
parser.add_argument('file')
|
|
16
|
+
parser.add_argument('-w', '--write', action='store_true')
|
|
17
|
+
args = parser.parse_args()
|
|
18
|
+
|
|
19
|
+
with open(args.file) as f:
|
|
20
|
+
src = f.read()
|
|
21
|
+
|
|
22
|
+
lines = src.splitlines(keepends=True)
|
|
23
|
+
for i, l in enumerate(lines):
|
|
24
|
+
if (m := _VERSION_PAT.fullmatch(l.strip())) is None:
|
|
25
|
+
continue
|
|
26
|
+
parts = m.groupdict()['version'].split('.')
|
|
27
|
+
rp = parts[-1]
|
|
28
|
+
ni = [i for i in range(len(rp)) if rp[i] not in string.digits][-1] + 1
|
|
29
|
+
tp, np = rp[:ni], rp[ni:]
|
|
30
|
+
n = int(np)
|
|
31
|
+
nv = '.'.join([*parts[:-1], tp + str(n + 1)])
|
|
32
|
+
lines[i] = f"__version__ = '{nv}'\n"
|
|
33
|
+
new_src = ''.join(lines)
|
|
34
|
+
|
|
35
|
+
if args.write:
|
|
36
|
+
with open(args.file, 'w') as f:
|
|
37
|
+
f.write(new_src)
|
|
38
|
+
else:
|
|
39
|
+
print(new_src)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == '__main__':
|
|
43
|
+
_main()
|
omdev/scripts/interp.py
CHANGED
|
@@ -1206,8 +1206,8 @@ class JsonLogFormatter(logging.Formatter):
|
|
|
1206
1206
|
STANDARD_LOG_FORMAT_PARTS = [
|
|
1207
1207
|
('asctime', '%(asctime)-15s'),
|
|
1208
1208
|
('process', 'pid=%(process)-6s'),
|
|
1209
|
-
('thread', 'tid=%(thread)
|
|
1210
|
-
('levelname', '%(levelname)
|
|
1209
|
+
('thread', 'tid=%(thread)x'),
|
|
1210
|
+
('levelname', '%(levelname)s'),
|
|
1211
1211
|
('name', '%(name)s'),
|
|
1212
1212
|
('separator', '::'),
|
|
1213
1213
|
('message', '%(message)s'),
|
|
@@ -1358,6 +1358,9 @@ class InterpSpecifier:
|
|
|
1358
1358
|
def contains(self, iv: InterpVersion) -> bool:
|
|
1359
1359
|
return self.specifier.contains(iv.version) and self.opts == iv.opts
|
|
1360
1360
|
|
|
1361
|
+
def __contains__(self, iv: InterpVersion) -> bool:
|
|
1362
|
+
return self.contains(iv)
|
|
1363
|
+
|
|
1361
1364
|
|
|
1362
1365
|
@dc.dataclass(frozen=True)
|
|
1363
1366
|
class Interp:
|
|
@@ -1576,6 +1579,7 @@ TODO:
|
|
|
1576
1579
|
- backends
|
|
1577
1580
|
- local builds
|
|
1578
1581
|
- deadsnakes?
|
|
1582
|
+
- uv
|
|
1579
1583
|
- loose versions
|
|
1580
1584
|
"""
|
|
1581
1585
|
|
|
@@ -1725,6 +1729,7 @@ class PyenvInstallOpts:
|
|
|
1725
1729
|
|
|
1726
1730
|
DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-s', '-v'])
|
|
1727
1731
|
DEBUG_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-g'])
|
|
1732
|
+
THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
|
|
1728
1733
|
|
|
1729
1734
|
|
|
1730
1735
|
#
|
|
@@ -1785,19 +1790,19 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
1785
1790
|
f"--with-tcltk-libs='-L{tcl_tk_prefix}/lib -ltcl{tcl_tk_ver} -ltk{tcl_tk_ver}'",
|
|
1786
1791
|
])
|
|
1787
1792
|
|
|
1788
|
-
@cached_nullary
|
|
1789
|
-
def brew_ssl_opts(self) -> PyenvInstallOpts:
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1793
|
+
# @cached_nullary
|
|
1794
|
+
# def brew_ssl_opts(self) -> PyenvInstallOpts:
|
|
1795
|
+
# pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
|
|
1796
|
+
# if 'PKG_CONFIG_PATH' in os.environ:
|
|
1797
|
+
# pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
|
|
1798
|
+
# return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
|
|
1794
1799
|
|
|
1795
1800
|
def opts(self) -> PyenvInstallOpts:
|
|
1796
1801
|
return PyenvInstallOpts().merge(
|
|
1797
1802
|
self.framework_opts(),
|
|
1798
1803
|
self.brew_deps_opts(),
|
|
1799
1804
|
self.brew_tcl_opts(),
|
|
1800
|
-
self.brew_ssl_opts(),
|
|
1805
|
+
# self.brew_ssl_opts(),
|
|
1801
1806
|
)
|
|
1802
1807
|
|
|
1803
1808
|
|
|
@@ -1811,27 +1816,39 @@ PLATFORM_PYENV_INSTALL_OPTS: ta.Dict[str, PyenvInstallOptsProvider] = {
|
|
|
1811
1816
|
|
|
1812
1817
|
|
|
1813
1818
|
class PyenvVersionInstaller:
|
|
1819
|
+
"""
|
|
1820
|
+
Messy: can install freethreaded build with a 't' suffixed version str _or_ by THREADED_PYENV_INSTALL_OPTS - need
|
|
1821
|
+
latter to build custom interp with ft, need former to use canned / blessed interps. Muh.
|
|
1822
|
+
"""
|
|
1814
1823
|
|
|
1815
1824
|
def __init__(
|
|
1816
1825
|
self,
|
|
1817
1826
|
version: str,
|
|
1818
1827
|
opts: ta.Optional[PyenvInstallOpts] = None,
|
|
1828
|
+
interp_opts: InterpOpts = InterpOpts(),
|
|
1819
1829
|
*,
|
|
1820
|
-
|
|
1830
|
+
no_default_opts: bool = False,
|
|
1821
1831
|
pyenv: Pyenv = Pyenv(),
|
|
1822
1832
|
) -> None:
|
|
1823
1833
|
super().__init__()
|
|
1824
1834
|
|
|
1825
|
-
if
|
|
1826
|
-
|
|
1827
|
-
|
|
1835
|
+
if no_default_opts:
|
|
1836
|
+
if opts is None:
|
|
1837
|
+
opts = PyenvInstallOpts()
|
|
1838
|
+
else:
|
|
1839
|
+
lst = [opts if opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
|
|
1840
|
+
if interp_opts.debug:
|
|
1828
1841
|
lst.append(DEBUG_PYENV_INSTALL_OPTS)
|
|
1842
|
+
if interp_opts.threaded:
|
|
1843
|
+
lst.append(THREADED_PYENV_INSTALL_OPTS)
|
|
1829
1844
|
lst.append(PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
|
|
1830
1845
|
opts = PyenvInstallOpts().merge(*lst)
|
|
1831
1846
|
|
|
1832
1847
|
self._version = version
|
|
1833
1848
|
self._opts = opts
|
|
1834
|
-
self.
|
|
1849
|
+
self._interp_opts = interp_opts
|
|
1850
|
+
|
|
1851
|
+
self._no_default_opts = no_default_opts
|
|
1835
1852
|
self._pyenv = pyenv
|
|
1836
1853
|
|
|
1837
1854
|
@property
|
|
@@ -1844,7 +1861,7 @@ class PyenvVersionInstaller:
|
|
|
1844
1861
|
|
|
1845
1862
|
@cached_nullary
|
|
1846
1863
|
def install_name(self) -> str:
|
|
1847
|
-
return self._version + ('-debug' if self.
|
|
1864
|
+
return self._version + ('-debug' if self._interp_opts.debug else '')
|
|
1848
1865
|
|
|
1849
1866
|
@cached_nullary
|
|
1850
1867
|
def install_dir(self) -> str:
|
|
@@ -1852,7 +1869,7 @@ class PyenvVersionInstaller:
|
|
|
1852
1869
|
|
|
1853
1870
|
@cached_nullary
|
|
1854
1871
|
def install(self) -> str:
|
|
1855
|
-
env =
|
|
1872
|
+
env = {**os.environ, **self._opts.env}
|
|
1856
1873
|
for k, l in [
|
|
1857
1874
|
('CFLAGS', self._opts.cflags),
|
|
1858
1875
|
('LDFLAGS', self._opts.ldflags),
|
|
@@ -1863,7 +1880,13 @@ class PyenvVersionInstaller:
|
|
|
1863
1880
|
v += ' ' + os.environ[k]
|
|
1864
1881
|
env[k] = v
|
|
1865
1882
|
|
|
1866
|
-
subprocess_check_call(
|
|
1883
|
+
subprocess_check_call(
|
|
1884
|
+
self._pyenv.exe(),
|
|
1885
|
+
'install',
|
|
1886
|
+
*self._opts.opts,
|
|
1887
|
+
self._version,
|
|
1888
|
+
env=env,
|
|
1889
|
+
)
|
|
1867
1890
|
|
|
1868
1891
|
exe = os.path.join(self.install_dir(), 'bin', 'python')
|
|
1869
1892
|
if not os.path.isfile(exe):
|
|
@@ -1965,6 +1988,21 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
1965
1988
|
lst.append(dc.replace(iv, opts=dc.replace(iv.opts, debug=d)))
|
|
1966
1989
|
return lst
|
|
1967
1990
|
|
|
1991
|
+
def install_version(self, version: InterpVersion) -> Interp:
|
|
1992
|
+
inst_version = str(version.version)
|
|
1993
|
+
inst_opts = version.opts
|
|
1994
|
+
if inst_opts.threaded:
|
|
1995
|
+
inst_version += 't'
|
|
1996
|
+
inst_opts = dc.replace(inst_opts, threaded=False)
|
|
1997
|
+
|
|
1998
|
+
installer = PyenvVersionInstaller(
|
|
1999
|
+
inst_version,
|
|
2000
|
+
interp_opts=inst_opts,
|
|
2001
|
+
)
|
|
2002
|
+
|
|
2003
|
+
exe = installer.install()
|
|
2004
|
+
return Interp(exe, version)
|
|
2005
|
+
|
|
1968
2006
|
|
|
1969
2007
|
########################################
|
|
1970
2008
|
# ../system.py
|
|
@@ -2082,7 +2120,7 @@ class SystemInterpProvider(InterpProvider):
|
|
|
2082
2120
|
|
|
2083
2121
|
########################################
|
|
2084
2122
|
# ../resolvers.py
|
|
2085
|
-
# ruff: noqa: UP006
|
|
2123
|
+
# ruff: noqa: UP006 UP007
|
|
2086
2124
|
|
|
2087
2125
|
|
|
2088
2126
|
INTERP_PROVIDER_TYPES_BY_NAME: ta.Mapping[str, ta.Type[InterpProvider]] = {
|
|
@@ -2098,17 +2136,47 @@ class InterpResolver:
|
|
|
2098
2136
|
super().__init__()
|
|
2099
2137
|
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
|
|
2100
2138
|
|
|
2101
|
-
def
|
|
2139
|
+
def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
|
2102
2140
|
lst = [
|
|
2103
2141
|
(i, si)
|
|
2104
2142
|
for i, p in enumerate(self._providers.values())
|
|
2105
2143
|
for si in p.get_installed_versions(spec)
|
|
2106
2144
|
if spec.contains(si)
|
|
2107
2145
|
]
|
|
2108
|
-
|
|
2109
|
-
|
|
2146
|
+
|
|
2147
|
+
slst = sorted(lst, key=lambda t: (-t[0], t[1]))
|
|
2148
|
+
if not slst:
|
|
2149
|
+
return None
|
|
2150
|
+
|
|
2151
|
+
bi, bv = slst[-1]
|
|
2110
2152
|
bp = list(self._providers.values())[bi]
|
|
2111
|
-
return bp
|
|
2153
|
+
return (bp, bv)
|
|
2154
|
+
|
|
2155
|
+
def resolve(
|
|
2156
|
+
self,
|
|
2157
|
+
spec: InterpSpecifier,
|
|
2158
|
+
*,
|
|
2159
|
+
install: bool = False,
|
|
2160
|
+
) -> ta.Optional[Interp]:
|
|
2161
|
+
tup = self._resolve_installed(spec)
|
|
2162
|
+
if tup is not None:
|
|
2163
|
+
bp, bv = tup
|
|
2164
|
+
return bp.get_installed_version(bv)
|
|
2165
|
+
|
|
2166
|
+
if not install:
|
|
2167
|
+
return None
|
|
2168
|
+
|
|
2169
|
+
tp = list(self._providers.values())[0] # noqa
|
|
2170
|
+
|
|
2171
|
+
sv = sorted(
|
|
2172
|
+
[s for s in tp.get_installable_versions(spec) if s in spec],
|
|
2173
|
+
key=lambda s: s.version,
|
|
2174
|
+
)
|
|
2175
|
+
if not sv:
|
|
2176
|
+
return None
|
|
2177
|
+
|
|
2178
|
+
bv = sv[-1]
|
|
2179
|
+
return tp.install_version(bv)
|
|
2112
2180
|
|
|
2113
2181
|
def list(self, spec: InterpSpecifier) -> None:
|
|
2114
2182
|
print('installed:')
|
|
@@ -2161,7 +2229,7 @@ def _list_cmd(args) -> None:
|
|
|
2161
2229
|
def _resolve_cmd(args) -> None:
|
|
2162
2230
|
r = DEFAULT_INTERP_RESOLVER
|
|
2163
2231
|
s = InterpSpecifier.parse(args.version)
|
|
2164
|
-
print(r.resolve(s).exe)
|
|
2232
|
+
print(check_not_none(r.resolve(s)).exe)
|
|
2165
2233
|
|
|
2166
2234
|
|
|
2167
2235
|
def _build_parser() -> argparse.ArgumentParser:
|
omdev/scripts/pyproject.py
CHANGED
|
@@ -11,6 +11,7 @@ TODO:
|
|
|
11
11
|
- build / package / publish / version roll
|
|
12
12
|
- {pkg_name: [src_dirs]}, default excludes, generate MANIFST.in, ...
|
|
13
13
|
- env vars - PYTHONPATH
|
|
14
|
+
- optional uv backend
|
|
14
15
|
|
|
15
16
|
lookit:
|
|
16
17
|
- https://pdm-project.org/en/latest/
|
|
@@ -55,6 +56,7 @@ import string
|
|
|
55
56
|
import subprocess
|
|
56
57
|
import sys
|
|
57
58
|
import tarfile
|
|
59
|
+
import tempfile
|
|
58
60
|
import threading
|
|
59
61
|
import time
|
|
60
62
|
import types
|
|
@@ -1883,6 +1885,83 @@ def is_sunder(name: str) -> bool:
|
|
|
1883
1885
|
)
|
|
1884
1886
|
|
|
1885
1887
|
|
|
1888
|
+
########################################
|
|
1889
|
+
# ../reqs.py
|
|
1890
|
+
"""
|
|
1891
|
+
TODO:
|
|
1892
|
+
- embed pip._internal.req.parse_requirements, add additional env stuff? breaks compat with raw pip
|
|
1893
|
+
"""
|
|
1894
|
+
# ruff: noqa: UP007
|
|
1895
|
+
|
|
1896
|
+
|
|
1897
|
+
class RequirementsRewriter:
|
|
1898
|
+
def __init__(
|
|
1899
|
+
self,
|
|
1900
|
+
venv: ta.Optional[str] = None,
|
|
1901
|
+
) -> None:
|
|
1902
|
+
super().__init__()
|
|
1903
|
+
self._venv = venv
|
|
1904
|
+
|
|
1905
|
+
@cached_nullary
|
|
1906
|
+
def _tmp_dir(self) -> str:
|
|
1907
|
+
return tempfile.mkdtemp('-omlish-reqs')
|
|
1908
|
+
|
|
1909
|
+
VENV_MAGIC = '# @omdev-venv'
|
|
1910
|
+
|
|
1911
|
+
def rewrite_file(self, in_file: str) -> str:
|
|
1912
|
+
with open(in_file) as f:
|
|
1913
|
+
src = f.read()
|
|
1914
|
+
|
|
1915
|
+
in_lines = src.splitlines(keepends=True)
|
|
1916
|
+
out_lines = []
|
|
1917
|
+
|
|
1918
|
+
for l in in_lines:
|
|
1919
|
+
if self.VENV_MAGIC in l:
|
|
1920
|
+
lp, _, rp = l.partition(self.VENV_MAGIC)
|
|
1921
|
+
rp = rp.partition('#')[0]
|
|
1922
|
+
omit = False
|
|
1923
|
+
for v in rp.split():
|
|
1924
|
+
if v[0] == '!':
|
|
1925
|
+
if self._venv is not None and self._venv == v[1:]:
|
|
1926
|
+
omit = True
|
|
1927
|
+
break
|
|
1928
|
+
else:
|
|
1929
|
+
raise NotImplementedError
|
|
1930
|
+
|
|
1931
|
+
if omit:
|
|
1932
|
+
out_lines.append('# OMITTED: ' + l)
|
|
1933
|
+
continue
|
|
1934
|
+
|
|
1935
|
+
out_req = self.rewrite(l.rstrip('\n'), for_file=True)
|
|
1936
|
+
out_lines.append(out_req + '\n')
|
|
1937
|
+
|
|
1938
|
+
out_file = os.path.join(self._tmp_dir(), os.path.basename(in_file))
|
|
1939
|
+
if os.path.exists(out_file):
|
|
1940
|
+
raise Exception(f'file exists: {out_file}')
|
|
1941
|
+
|
|
1942
|
+
with open(out_file, 'w') as f:
|
|
1943
|
+
f.write(''.join(out_lines))
|
|
1944
|
+
return out_file
|
|
1945
|
+
|
|
1946
|
+
def rewrite(self, in_req: str, *, for_file: bool = False) -> str:
|
|
1947
|
+
if in_req.strip().startswith('-r'):
|
|
1948
|
+
l = in_req.strip()
|
|
1949
|
+
lp, _, rp = l.partition(' ')
|
|
1950
|
+
if lp == '-r':
|
|
1951
|
+
inc_in_file, _, rest = rp.partition(' ')
|
|
1952
|
+
else:
|
|
1953
|
+
inc_in_file, rest = lp[2:], rp
|
|
1954
|
+
|
|
1955
|
+
inc_out_file = self.rewrite_file(inc_in_file)
|
|
1956
|
+
if for_file:
|
|
1957
|
+
return ' '.join(['-r ', inc_out_file, rest])
|
|
1958
|
+
else:
|
|
1959
|
+
return '-r' + inc_out_file
|
|
1960
|
+
|
|
1961
|
+
else:
|
|
1962
|
+
return in_req
|
|
1963
|
+
|
|
1964
|
+
|
|
1886
1965
|
########################################
|
|
1887
1966
|
# ../../versioning/specifiers.py
|
|
1888
1967
|
# Copyright (c) Donald Stufft and individual contributors.
|
|
@@ -2473,8 +2552,8 @@ class JsonLogFormatter(logging.Formatter):
|
|
|
2473
2552
|
STANDARD_LOG_FORMAT_PARTS = [
|
|
2474
2553
|
('asctime', '%(asctime)-15s'),
|
|
2475
2554
|
('process', 'pid=%(process)-6s'),
|
|
2476
|
-
('thread', 'tid=%(thread)
|
|
2477
|
-
('levelname', '%(levelname)
|
|
2555
|
+
('thread', 'tid=%(thread)x'),
|
|
2556
|
+
('levelname', '%(levelname)s'),
|
|
2478
2557
|
('name', '%(name)s'),
|
|
2479
2558
|
('separator', '::'),
|
|
2480
2559
|
('message', '%(message)s'),
|
|
@@ -2740,8 +2819,10 @@ _OBJ_MARSHALER_GENERIC_MAPPING_TYPES: ta.Dict[ta.Any, type] = {
|
|
|
2740
2819
|
|
|
2741
2820
|
_OBJ_MARSHALER_GENERIC_ITERABLE_TYPES: ta.Dict[ta.Any, type] = {
|
|
2742
2821
|
**{t: t for t in (list, tuple, set, frozenset)},
|
|
2743
|
-
|
|
2744
|
-
|
|
2822
|
+
collections.abc.Set: frozenset,
|
|
2823
|
+
collections.abc.MutableSet: set,
|
|
2824
|
+
collections.abc.Sequence: tuple,
|
|
2825
|
+
collections.abc.MutableSequence: list,
|
|
2745
2826
|
}
|
|
2746
2827
|
|
|
2747
2828
|
|
|
@@ -2926,6 +3007,9 @@ class InterpSpecifier:
|
|
|
2926
3007
|
def contains(self, iv: InterpVersion) -> bool:
|
|
2927
3008
|
return self.specifier.contains(iv.version) and self.opts == iv.opts
|
|
2928
3009
|
|
|
3010
|
+
def __contains__(self, iv: InterpVersion) -> bool:
|
|
3011
|
+
return self.contains(iv)
|
|
3012
|
+
|
|
2929
3013
|
|
|
2930
3014
|
@dc.dataclass(frozen=True)
|
|
2931
3015
|
class Interp:
|
|
@@ -2945,6 +3029,7 @@ class VenvConfig:
|
|
|
2945
3029
|
requires: ta.Optional[ta.List[str]] = None
|
|
2946
3030
|
docker: ta.Optional[str] = None
|
|
2947
3031
|
srcs: ta.Optional[ta.List[str]] = None
|
|
3032
|
+
use_uv: ta.Optional[bool] = None
|
|
2948
3033
|
|
|
2949
3034
|
|
|
2950
3035
|
@dc.dataclass(frozen=True)
|
|
@@ -3032,7 +3117,7 @@ class PyprojectConfigPreparer:
|
|
|
3032
3117
|
|
|
3033
3118
|
|
|
3034
3119
|
########################################
|
|
3035
|
-
# ../../
|
|
3120
|
+
# ../../revisions.py
|
|
3036
3121
|
"""
|
|
3037
3122
|
TODO:
|
|
3038
3123
|
- omlish-lite, move to pyproject/
|
|
@@ -3762,6 +3847,7 @@ TODO:
|
|
|
3762
3847
|
- backends
|
|
3763
3848
|
- local builds
|
|
3764
3849
|
- deadsnakes?
|
|
3850
|
+
- uv
|
|
3765
3851
|
- loose versions
|
|
3766
3852
|
"""
|
|
3767
3853
|
|
|
@@ -3911,6 +3997,7 @@ class PyenvInstallOpts:
|
|
|
3911
3997
|
|
|
3912
3998
|
DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-s', '-v'])
|
|
3913
3999
|
DEBUG_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-g'])
|
|
4000
|
+
THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
|
|
3914
4001
|
|
|
3915
4002
|
|
|
3916
4003
|
#
|
|
@@ -3971,19 +4058,19 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
|
|
3971
4058
|
f"--with-tcltk-libs='-L{tcl_tk_prefix}/lib -ltcl{tcl_tk_ver} -ltk{tcl_tk_ver}'",
|
|
3972
4059
|
])
|
|
3973
4060
|
|
|
3974
|
-
@cached_nullary
|
|
3975
|
-
def brew_ssl_opts(self) -> PyenvInstallOpts:
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
4061
|
+
# @cached_nullary
|
|
4062
|
+
# def brew_ssl_opts(self) -> PyenvInstallOpts:
|
|
4063
|
+
# pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
|
|
4064
|
+
# if 'PKG_CONFIG_PATH' in os.environ:
|
|
4065
|
+
# pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
|
|
4066
|
+
# return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
|
|
3980
4067
|
|
|
3981
4068
|
def opts(self) -> PyenvInstallOpts:
|
|
3982
4069
|
return PyenvInstallOpts().merge(
|
|
3983
4070
|
self.framework_opts(),
|
|
3984
4071
|
self.brew_deps_opts(),
|
|
3985
4072
|
self.brew_tcl_opts(),
|
|
3986
|
-
self.brew_ssl_opts(),
|
|
4073
|
+
# self.brew_ssl_opts(),
|
|
3987
4074
|
)
|
|
3988
4075
|
|
|
3989
4076
|
|
|
@@ -3997,27 +4084,39 @@ PLATFORM_PYENV_INSTALL_OPTS: ta.Dict[str, PyenvInstallOptsProvider] = {
|
|
|
3997
4084
|
|
|
3998
4085
|
|
|
3999
4086
|
class PyenvVersionInstaller:
|
|
4087
|
+
"""
|
|
4088
|
+
Messy: can install freethreaded build with a 't' suffixed version str _or_ by THREADED_PYENV_INSTALL_OPTS - need
|
|
4089
|
+
latter to build custom interp with ft, need former to use canned / blessed interps. Muh.
|
|
4090
|
+
"""
|
|
4000
4091
|
|
|
4001
4092
|
def __init__(
|
|
4002
4093
|
self,
|
|
4003
4094
|
version: str,
|
|
4004
4095
|
opts: ta.Optional[PyenvInstallOpts] = None,
|
|
4096
|
+
interp_opts: InterpOpts = InterpOpts(),
|
|
4005
4097
|
*,
|
|
4006
|
-
|
|
4098
|
+
no_default_opts: bool = False,
|
|
4007
4099
|
pyenv: Pyenv = Pyenv(),
|
|
4008
4100
|
) -> None:
|
|
4009
4101
|
super().__init__()
|
|
4010
4102
|
|
|
4011
|
-
if
|
|
4012
|
-
|
|
4013
|
-
|
|
4103
|
+
if no_default_opts:
|
|
4104
|
+
if opts is None:
|
|
4105
|
+
opts = PyenvInstallOpts()
|
|
4106
|
+
else:
|
|
4107
|
+
lst = [opts if opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
|
|
4108
|
+
if interp_opts.debug:
|
|
4014
4109
|
lst.append(DEBUG_PYENV_INSTALL_OPTS)
|
|
4110
|
+
if interp_opts.threaded:
|
|
4111
|
+
lst.append(THREADED_PYENV_INSTALL_OPTS)
|
|
4015
4112
|
lst.append(PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
|
|
4016
4113
|
opts = PyenvInstallOpts().merge(*lst)
|
|
4017
4114
|
|
|
4018
4115
|
self._version = version
|
|
4019
4116
|
self._opts = opts
|
|
4020
|
-
self.
|
|
4117
|
+
self._interp_opts = interp_opts
|
|
4118
|
+
|
|
4119
|
+
self._no_default_opts = no_default_opts
|
|
4021
4120
|
self._pyenv = pyenv
|
|
4022
4121
|
|
|
4023
4122
|
@property
|
|
@@ -4030,7 +4129,7 @@ class PyenvVersionInstaller:
|
|
|
4030
4129
|
|
|
4031
4130
|
@cached_nullary
|
|
4032
4131
|
def install_name(self) -> str:
|
|
4033
|
-
return self._version + ('-debug' if self.
|
|
4132
|
+
return self._version + ('-debug' if self._interp_opts.debug else '')
|
|
4034
4133
|
|
|
4035
4134
|
@cached_nullary
|
|
4036
4135
|
def install_dir(self) -> str:
|
|
@@ -4038,7 +4137,7 @@ class PyenvVersionInstaller:
|
|
|
4038
4137
|
|
|
4039
4138
|
@cached_nullary
|
|
4040
4139
|
def install(self) -> str:
|
|
4041
|
-
env =
|
|
4140
|
+
env = {**os.environ, **self._opts.env}
|
|
4042
4141
|
for k, l in [
|
|
4043
4142
|
('CFLAGS', self._opts.cflags),
|
|
4044
4143
|
('LDFLAGS', self._opts.ldflags),
|
|
@@ -4049,7 +4148,13 @@ class PyenvVersionInstaller:
|
|
|
4049
4148
|
v += ' ' + os.environ[k]
|
|
4050
4149
|
env[k] = v
|
|
4051
4150
|
|
|
4052
|
-
subprocess_check_call(
|
|
4151
|
+
subprocess_check_call(
|
|
4152
|
+
self._pyenv.exe(),
|
|
4153
|
+
'install',
|
|
4154
|
+
*self._opts.opts,
|
|
4155
|
+
self._version,
|
|
4156
|
+
env=env,
|
|
4157
|
+
)
|
|
4053
4158
|
|
|
4054
4159
|
exe = os.path.join(self.install_dir(), 'bin', 'python')
|
|
4055
4160
|
if not os.path.isfile(exe):
|
|
@@ -4151,6 +4256,21 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
4151
4256
|
lst.append(dc.replace(iv, opts=dc.replace(iv.opts, debug=d)))
|
|
4152
4257
|
return lst
|
|
4153
4258
|
|
|
4259
|
+
def install_version(self, version: InterpVersion) -> Interp:
|
|
4260
|
+
inst_version = str(version.version)
|
|
4261
|
+
inst_opts = version.opts
|
|
4262
|
+
if inst_opts.threaded:
|
|
4263
|
+
inst_version += 't'
|
|
4264
|
+
inst_opts = dc.replace(inst_opts, threaded=False)
|
|
4265
|
+
|
|
4266
|
+
installer = PyenvVersionInstaller(
|
|
4267
|
+
inst_version,
|
|
4268
|
+
interp_opts=inst_opts,
|
|
4269
|
+
)
|
|
4270
|
+
|
|
4271
|
+
exe = installer.install()
|
|
4272
|
+
return Interp(exe, version)
|
|
4273
|
+
|
|
4154
4274
|
|
|
4155
4275
|
########################################
|
|
4156
4276
|
# ../../interp/system.py
|
|
@@ -4268,7 +4388,7 @@ class SystemInterpProvider(InterpProvider):
|
|
|
4268
4388
|
|
|
4269
4389
|
########################################
|
|
4270
4390
|
# ../../interp/resolvers.py
|
|
4271
|
-
# ruff: noqa: UP006
|
|
4391
|
+
# ruff: noqa: UP006 UP007
|
|
4272
4392
|
|
|
4273
4393
|
|
|
4274
4394
|
INTERP_PROVIDER_TYPES_BY_NAME: ta.Mapping[str, ta.Type[InterpProvider]] = {
|
|
@@ -4284,17 +4404,47 @@ class InterpResolver:
|
|
|
4284
4404
|
super().__init__()
|
|
4285
4405
|
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
|
|
4286
4406
|
|
|
4287
|
-
def
|
|
4407
|
+
def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
|
4288
4408
|
lst = [
|
|
4289
4409
|
(i, si)
|
|
4290
4410
|
for i, p in enumerate(self._providers.values())
|
|
4291
4411
|
for si in p.get_installed_versions(spec)
|
|
4292
4412
|
if spec.contains(si)
|
|
4293
4413
|
]
|
|
4294
|
-
|
|
4295
|
-
|
|
4414
|
+
|
|
4415
|
+
slst = sorted(lst, key=lambda t: (-t[0], t[1]))
|
|
4416
|
+
if not slst:
|
|
4417
|
+
return None
|
|
4418
|
+
|
|
4419
|
+
bi, bv = slst[-1]
|
|
4296
4420
|
bp = list(self._providers.values())[bi]
|
|
4297
|
-
return bp
|
|
4421
|
+
return (bp, bv)
|
|
4422
|
+
|
|
4423
|
+
def resolve(
|
|
4424
|
+
self,
|
|
4425
|
+
spec: InterpSpecifier,
|
|
4426
|
+
*,
|
|
4427
|
+
install: bool = False,
|
|
4428
|
+
) -> ta.Optional[Interp]:
|
|
4429
|
+
tup = self._resolve_installed(spec)
|
|
4430
|
+
if tup is not None:
|
|
4431
|
+
bp, bv = tup
|
|
4432
|
+
return bp.get_installed_version(bv)
|
|
4433
|
+
|
|
4434
|
+
if not install:
|
|
4435
|
+
return None
|
|
4436
|
+
|
|
4437
|
+
tp = list(self._providers.values())[0] # noqa
|
|
4438
|
+
|
|
4439
|
+
sv = sorted(
|
|
4440
|
+
[s for s in tp.get_installable_versions(spec) if s in spec],
|
|
4441
|
+
key=lambda s: s.version,
|
|
4442
|
+
)
|
|
4443
|
+
if not sv:
|
|
4444
|
+
return None
|
|
4445
|
+
|
|
4446
|
+
bv = sv[-1]
|
|
4447
|
+
return tp.install_version(bv)
|
|
4298
4448
|
|
|
4299
4449
|
def list(self, spec: InterpSpecifier) -> None:
|
|
4300
4450
|
print('installed:')
|
|
@@ -4409,7 +4559,7 @@ class Venv:
|
|
|
4409
4559
|
@cached_nullary
|
|
4410
4560
|
def interp_exe(self) -> str:
|
|
4411
4561
|
i = InterpSpecifier.parse(check_not_none(self._cfg.interp))
|
|
4412
|
-
return DEFAULT_INTERP_RESOLVER.resolve(i).exe
|
|
4562
|
+
return check_not_none(DEFAULT_INTERP_RESOLVER.resolve(i, install=True)).exe
|
|
4413
4563
|
|
|
4414
4564
|
@cached_nullary
|
|
4415
4565
|
def exe(self) -> str:
|
|
@@ -4429,6 +4579,7 @@ class Venv:
|
|
|
4429
4579
|
subprocess_check_call(ie, '-m', 'venv', dn)
|
|
4430
4580
|
|
|
4431
4581
|
ve = self.exe()
|
|
4582
|
+
uv = self._cfg.use_uv
|
|
4432
4583
|
|
|
4433
4584
|
subprocess_check_call(
|
|
4434
4585
|
ve,
|
|
@@ -4437,14 +4588,20 @@ class Venv:
|
|
|
4437
4588
|
'pip',
|
|
4438
4589
|
'setuptools',
|
|
4439
4590
|
'wheel',
|
|
4591
|
+
*(['uv'] if uv else []),
|
|
4440
4592
|
)
|
|
4441
4593
|
|
|
4442
4594
|
if (sr := self._cfg.requires):
|
|
4595
|
+
rr = RequirementsRewriter(self._name)
|
|
4596
|
+
reqs = [rr.rewrite(req) for req in sr]
|
|
4443
4597
|
subprocess_check_call(
|
|
4444
4598
|
ve,
|
|
4445
|
-
'-m',
|
|
4446
|
-
'
|
|
4447
|
-
|
|
4599
|
+
'-m',
|
|
4600
|
+
*(['uv'] if uv else []),
|
|
4601
|
+
'pip',
|
|
4602
|
+
'install',
|
|
4603
|
+
*([] if uv else ['-v']),
|
|
4604
|
+
*reqs,
|
|
4448
4605
|
)
|
|
4449
4606
|
|
|
4450
4607
|
return True
|
omdev/tools/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Tools with no reason to be imported by any other module. May have deps."""
|
omdev/tools/rst.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import contextlib
|
|
3
|
+
import io
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import docutils.core
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def rst2html(rst, report_level=None):
|
|
10
|
+
kwargs = {
|
|
11
|
+
'writer_name': 'html',
|
|
12
|
+
'settings_overrides': {
|
|
13
|
+
'_disable_config': True,
|
|
14
|
+
'report_level': int(report_level) if report_level else 0,
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
target = io.StringIO()
|
|
19
|
+
with contextlib.redirect_stderr(target):
|
|
20
|
+
parts = docutils.core.publish_parts(rst, **kwargs) # type: ignore
|
|
21
|
+
html = parts['html_body']
|
|
22
|
+
warning = target.getvalue().strip()
|
|
23
|
+
return html, warning
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _main() -> None:
|
|
27
|
+
parser = argparse.ArgumentParser()
|
|
28
|
+
parser.add_argument('input', nargs='?')
|
|
29
|
+
args = parser.parse_args()
|
|
30
|
+
|
|
31
|
+
if args.input:
|
|
32
|
+
with open(args.input) as f:
|
|
33
|
+
src = f.read()
|
|
34
|
+
else:
|
|
35
|
+
src = sys.stdin.read()
|
|
36
|
+
|
|
37
|
+
html, warning = rst2html(src)
|
|
38
|
+
if warning:
|
|
39
|
+
sys.stderr.write(warning)
|
|
40
|
+
print(html)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == '__main__':
|
|
44
|
+
_main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: omdev
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev21
|
|
4
4
|
Summary: omdev
|
|
5
5
|
Author: wrmsr
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -12,11 +12,12 @@ Classifier: Operating System :: OS Independent
|
|
|
12
12
|
Classifier: Operating System :: POSIX
|
|
13
13
|
Requires-Python: ~=3.12
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: omlish ==0.0.0.
|
|
15
|
+
Requires-Dist: omlish ==0.0.0.dev21
|
|
16
16
|
Provides-Extra: all
|
|
17
17
|
Requires-Dist: pycparser ~=2.22 ; extra == 'all'
|
|
18
18
|
Requires-Dist: cffi ~=1.17 ; extra == 'all'
|
|
19
19
|
Requires-Dist: pcpp ~=1.30 ; extra == 'all'
|
|
20
|
+
Requires-Dist: docutils ~=0.21 ; extra == 'all'
|
|
20
21
|
Requires-Dist: mypy ~=1.11 ; extra == 'all'
|
|
21
22
|
Requires-Dist: tokenize-rt ~=6.0 ; extra == 'all'
|
|
22
23
|
Requires-Dist: wheel ~=0.44 ; extra == 'all'
|
|
@@ -24,6 +25,8 @@ Provides-Extra: c
|
|
|
24
25
|
Requires-Dist: pycparser ~=2.22 ; extra == 'c'
|
|
25
26
|
Requires-Dist: cffi ~=1.17 ; extra == 'c'
|
|
26
27
|
Requires-Dist: pcpp ~=1.30 ; extra == 'c'
|
|
28
|
+
Provides-Extra: docutils
|
|
29
|
+
Requires-Dist: docutils ~=0.21 ; extra == 'docutils'
|
|
27
30
|
Provides-Extra: mypy
|
|
28
31
|
Requires-Dist: mypy ~=1.11 ; extra == 'mypy'
|
|
29
32
|
Provides-Extra: tokens
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
omdev/__about__.py,sha256=
|
|
1
|
+
omdev/__about__.py,sha256=788lo_UuOSYF74y1RBiNlWkDdPnRFcmBAV5qYkaFJzE,868
|
|
2
2
|
omdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
omdev/bracepy.py,sha256=HwBK5XmlOsF_juTel25fRLJK9vHSJCWXuCc-OZlevRQ,2619
|
|
4
4
|
omdev/classdot.py,sha256=urN5Pzd2ooAwnfkH0z-muQxdO90IMo-sX2WB-A37lVU,1533
|
|
5
5
|
omdev/cmake.py,sha256=Diy2ry65806dQP125DAstD3w46z_wszMH7PwC2-6iik,4578
|
|
6
6
|
omdev/findimports.py,sha256=P8v4I1tm6g-PEWJiNwAKxErvWwL-Nop83vAuwq1kR5A,2246
|
|
7
7
|
omdev/findmagic.py,sha256=t8q1OoWVTFXTSDS36dr79ScTYLYk786Z9wFj8UObneQ,2170
|
|
8
|
+
omdev/revisions.py,sha256=kYrYoxmUkpwgbmLEijHu5bwjyOxggCt8N6bnWFwA-60,5392
|
|
8
9
|
omdev/tokens.py,sha256=GusxQ1Cd_eiScuR8XTTtc9QFhOgYviYGBZmFnn3Hj7s,756
|
|
9
10
|
omdev/wheelfile.py,sha256=yfupGcGkbFlmzGzKU64k_vmOKpaKnUlDWxeGn2KdekU,10005
|
|
10
11
|
omdev/amalg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -33,14 +34,14 @@ omdev/cexts/_distutils/compilers/options.py,sha256=H7r5IcLvga5Fs3jjXWIT-6ap3JBdu
|
|
|
33
34
|
omdev/cexts/_distutils/compilers/unixccompiler.py,sha256=o1h8QuyupLntv4F21_XjzAZmCiwwxJuTmOirvBSL-Qw,15419
|
|
34
35
|
omdev/interp/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
|
35
36
|
omdev/interp/__main__.py,sha256=gFhR9DikwDZk0LqgdR3qq_aXQHThUOPllDmHDOfnFAU,67
|
|
36
|
-
omdev/interp/cli.py,sha256=
|
|
37
|
+
omdev/interp/cli.py,sha256=8T3qLXTC2mni5FXDHkHN3mZG9_BnjkDMXYy6EYbAYR8,1679
|
|
37
38
|
omdev/interp/inspect.py,sha256=SI4jQmWfXCnlceFTxlVRfTlEYYCjO_X12wuG5e74yto,2849
|
|
38
|
-
omdev/interp/providers.py,sha256=
|
|
39
|
-
omdev/interp/pyenv.py,sha256=
|
|
40
|
-
omdev/interp/resolvers.py,sha256=
|
|
39
|
+
omdev/interp/providers.py,sha256=PFEjozW0c33eqg8sno-GHMKbhVUzQF9jrAx-M0uQimk,1787
|
|
40
|
+
omdev/interp/pyenv.py,sha256=oxwvX7fpM4VMVeqq09JHHweifPI5l4uFAa3V_V9z5Yg,11774
|
|
41
|
+
omdev/interp/resolvers.py,sha256=e8H8WcVC0Du3nCWrghsbVLJuP3ABaiH_DexZhjZITpQ,3007
|
|
41
42
|
omdev/interp/standalone.py,sha256=XcltiL7ypcfV89C82_3knQ3Kx7aW4wnnxf2056ZXC3A,7731
|
|
42
43
|
omdev/interp/system.py,sha256=UFHfMR0CHCEnNx5fhrze8esAwigpRrJUA33ftq6nA0I,3514
|
|
43
|
-
omdev/interp/types.py,sha256=
|
|
44
|
+
omdev/interp/types.py,sha256=2nM3MJaOU8O1XA8DrvwyOjBWSboBn16kgFIy5JVkDck,2440
|
|
44
45
|
omdev/mypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
46
|
omdev/mypy/debug.py,sha256=WcZw-3Z1njg_KFGqi3DB6RuqbBa3dLArJnjVCuY1Mn0,3003
|
|
46
47
|
omdev/precheck/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -49,27 +50,29 @@ omdev/precheck/precheck.py,sha256=2yTjNGvjPYf3QxUBbCbehBYYuB8gDR_dYSTrlNCs9qU,83
|
|
|
49
50
|
omdev/pyproject/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
|
50
51
|
omdev/pyproject/__main__.py,sha256=gFhR9DikwDZk0LqgdR3qq_aXQHThUOPllDmHDOfnFAU,67
|
|
51
52
|
omdev/pyproject/cexts.py,sha256=x13piOOnNrYbA17qZLDVuR0p1sqhgEwpk4FtImX-klM,4281
|
|
52
|
-
omdev/pyproject/cli.py,sha256=
|
|
53
|
-
omdev/pyproject/configs.py,sha256=
|
|
54
|
-
omdev/pyproject/pkg.py,sha256=
|
|
55
|
-
omdev/
|
|
53
|
+
omdev/pyproject/cli.py,sha256=bj7BMsYjUagp266ms-maU11woWC2hP9eQoOsisCzrCY,10358
|
|
54
|
+
omdev/pyproject/configs.py,sha256=K9H5cGwVLgHi8wKwtYvlXHZ9ThtmnI4jo8JAb-t1-70,2859
|
|
55
|
+
omdev/pyproject/pkg.py,sha256=1HcVUoTE_vdc5bAW3AUFcM-3BWI1ICoXEJlkTFIAmh4,9856
|
|
56
|
+
omdev/pyproject/reqs.py,sha256=coq21cdWQIPs06-iuRnwc6F2Sf-IxpqoT6DEMhol2kA,2298
|
|
57
|
+
omdev/scripts/__init__.py,sha256=MKCvUAEQwsIvwLixwtPlpBqmkMXLCnjjXyAXvVpDwVk,91
|
|
58
|
+
omdev/scripts/bumpversion.py,sha256=Kn7fo73Hs8uJh3Hi3EIyLOlzLPWAC6dwuD_lZ3cIzuY,1064
|
|
56
59
|
omdev/scripts/execrss.py,sha256=HzDNmwXOO8fMwIRXw9q8CUnVfLFCQASyU2tfY_y2Vf8,324
|
|
57
|
-
omdev/scripts/interp.py,sha256=
|
|
58
|
-
omdev/scripts/pyproject.py,sha256=
|
|
60
|
+
omdev/scripts/interp.py,sha256=i0Mq1ryZOTPOchV4liGjUiWNv0xLkoRWWIRb5BUH36s,65122
|
|
61
|
+
omdev/scripts/pyproject.py,sha256=MoILXhFFu5ItB1a9680TzuiwS-hosd2AwXy8rxEa_hk,144373
|
|
59
62
|
omdev/toml/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
|
60
63
|
omdev/toml/parser.py,sha256=84bn09uhYHwQGyfww6Rw6y1RxPAE_HDltODOSakcqDM,29186
|
|
61
64
|
omdev/toml/writer.py,sha256=dwz_Qw8z5Z_nmWpXqch63W6S_j6n256erb7AGFTVzB4,2872
|
|
62
|
-
omdev/tools/__init__.py,sha256=
|
|
65
|
+
omdev/tools/__init__.py,sha256=iVJAOQ0viGTQOm0DLX4uZLro-9jOioYJGLg9s0kDx1A,78
|
|
63
66
|
omdev/tools/dockertools.py,sha256=3844AhUst6kYo2xKNn-2Npi-f6r4rocxEOx0tHjE0dk,2063
|
|
64
67
|
omdev/tools/gittools.py,sha256=zPy2D5WDs-CbwT86_T_hbaq5yCuss5e-ouUccXC6xlg,578
|
|
65
|
-
omdev/tools/
|
|
68
|
+
omdev/tools/rst.py,sha256=6dWk8QZHoGiLSuBw3TKsXZjjFK6wWBEtPi9krdCLKKg,977
|
|
66
69
|
omdev/tools/sqlrepl.py,sha256=v9uVQ4nvquSXcQVYIFq34ikumSILvKqzD6lUKLcncCE,5646
|
|
67
70
|
omdev/tools/traceimport.py,sha256=oDry9CwIv5h96wSaTVKJ0qQ5vMGxYE5oBtfF-GYNLJs,13430
|
|
68
71
|
omdev/versioning/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
|
69
72
|
omdev/versioning/specifiers.py,sha256=6Odf9e6farwlPRsD_YqwTfYKG-BXn_dIcKtqfkhfodI,17432
|
|
70
73
|
omdev/versioning/versions.py,sha256=ei2eopEsJq3zSMJmezK1nzZgikgCdxFtnF3f69nCRZQ,12246
|
|
71
|
-
omdev-0.0.0.
|
|
72
|
-
omdev-0.0.0.
|
|
73
|
-
omdev-0.0.0.
|
|
74
|
-
omdev-0.0.0.
|
|
75
|
-
omdev-0.0.0.
|
|
74
|
+
omdev-0.0.0.dev21.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
|
75
|
+
omdev-0.0.0.dev21.dist-info/METADATA,sha256=h3RxJqAk0fzGr9-390t3pwny9JK_LS-lOrUqfiuYC0Y,1252
|
|
76
|
+
omdev-0.0.0.dev21.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
|
|
77
|
+
omdev-0.0.0.dev21.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
|
|
78
|
+
omdev-0.0.0.dev21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|