omdev 0.0.0.dev19__tar.gz → 0.0.0.dev21__tar.gz

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.

Files changed (87) hide show
  1. {omdev-0.0.0.dev19/omdev.egg-info → omdev-0.0.0.dev21}/PKG-INFO +5 -2
  2. omdev-0.0.0.dev21/README.rst +10 -0
  3. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/__about__.py +4 -0
  4. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/cli.py +2 -1
  5. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/providers.py +1 -0
  6. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/pyenv.py +49 -15
  7. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/resolvers.py +36 -5
  8. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/types.py +3 -0
  9. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/pyproject/cli.py +13 -4
  10. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/pyproject/configs.py +1 -0
  11. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/pyproject/pkg.py +1 -1
  12. omdev-0.0.0.dev21/omdev/pyproject/reqs.py +78 -0
  13. {omdev-0.0.0.dev19/omdev/tools → omdev-0.0.0.dev21/omdev}/revisions.py +1 -1
  14. omdev-0.0.0.dev21/omdev/scripts/__init__.py +1 -0
  15. omdev-0.0.0.dev21/omdev/scripts/bumpversion.py +43 -0
  16. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/scripts/interp.py +91 -23
  17. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/scripts/pyproject.py +186 -29
  18. omdev-0.0.0.dev21/omdev/tools/__init__.py +1 -0
  19. omdev-0.0.0.dev21/omdev/tools/rst.py +44 -0
  20. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21/omdev.egg-info}/PKG-INFO +5 -2
  21. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev.egg-info/SOURCES.txt +4 -1
  22. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev.egg-info/requires.txt +5 -1
  23. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/pyproject.toml +6 -2
  24. omdev-0.0.0.dev19/README.rst +0 -5
  25. omdev-0.0.0.dev19/omdev/scripts/__init__.py +0 -0
  26. omdev-0.0.0.dev19/omdev/tools/__init__.py +0 -0
  27. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/LICENSE +0 -0
  28. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/MANIFEST.in +0 -0
  29. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/__init__.py +0 -0
  30. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/amalg/__init__.py +0 -0
  31. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/amalg/__main__.py +0 -0
  32. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/amalg/amalg.py +0 -0
  33. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/bracepy.py +0 -0
  34. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/__init__.py +0 -0
  35. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/__init__.py +0 -0
  36. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/build_ext.py +0 -0
  37. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
  38. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
  39. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/compilers/options.py +0 -0
  40. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
  41. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/dir_util.py +0 -0
  42. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/errors.py +0 -0
  43. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/extension.py +0 -0
  44. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/file_util.py +0 -0
  45. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/modified.py +0 -0
  46. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/spawn.py +0 -0
  47. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/sysconfig.py +0 -0
  48. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/util.py +0 -0
  49. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/_distutils/version.py +0 -0
  50. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/build.py +0 -0
  51. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/cmake.py +0 -0
  52. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/importhook.py +0 -0
  53. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/magic.py +0 -0
  54. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cexts/scan.py +0 -0
  55. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/classdot.py +0 -0
  56. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/cmake.py +0 -0
  57. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/findimports.py +0 -0
  58. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/findmagic.py +0 -0
  59. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/__init__.py +0 -0
  60. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/__main__.py +0 -0
  61. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/inspect.py +0 -0
  62. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/standalone.py +0 -0
  63. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/interp/system.py +0 -0
  64. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/mypy/__init__.py +0 -0
  65. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/mypy/debug.py +0 -0
  66. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/precheck/__init__.py +0 -0
  67. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/precheck/__main__.py +0 -0
  68. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/precheck/precheck.py +0 -0
  69. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/pyproject/__init__.py +0 -0
  70. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/pyproject/__main__.py +0 -0
  71. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/pyproject/cexts.py +0 -0
  72. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/scripts/execrss.py +0 -0
  73. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/tokens.py +0 -0
  74. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/toml/__init__.py +0 -0
  75. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/toml/parser.py +0 -0
  76. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/toml/writer.py +0 -0
  77. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/tools/dockertools.py +0 -0
  78. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/tools/gittools.py +0 -0
  79. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/tools/sqlrepl.py +0 -0
  80. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/tools/traceimport.py +0 -0
  81. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/versioning/__init__.py +0 -0
  82. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/versioning/specifiers.py +0 -0
  83. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/versioning/versions.py +0 -0
  84. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev/wheelfile.py +0 -0
  85. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev.egg-info/dependency_links.txt +0 -0
  86. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/omdev.egg-info/top_level.txt +0 -0
  87. {omdev-0.0.0.dev19 → omdev-0.0.0.dev21}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev19
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.dev19
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
@@ -0,0 +1,10 @@
1
+ It's like my previous python monorepo-ey thing `omnibus
2
+ <https://github.com/wrmsr/omnibus/tree/wrmsr_exp_split>`_... ish.
3
+
4
+ Core packages begin with ``om``, scratch app is in ``app``, temp / dump code is in ``x``.
5
+
6
+ Core packages installable from git via:
7
+
8
+ .. code-block::
9
+
10
+ pip install 'git+https://github.com/wrmsr/omlish@master#subdirectory=.pkg/<pkg>'
@@ -18,6 +18,10 @@ class Project(ProjectBase):
18
18
  'pcpp ~= 1.30',
19
19
  ],
20
20
 
21
+ 'docutils': [
22
+ 'docutils ~= 0.21',
23
+ ],
24
+
21
25
  'mypy': [
22
26
  'mypy ~= 1.11',
23
27
  ],
@@ -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:
@@ -3,6 +3,7 @@ TODO:
3
3
  - backends
4
4
  - local builds
5
5
  - deadsnakes?
6
+ - uv
6
7
  - loose versions
7
8
  """
8
9
  import abc
@@ -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
- pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
182
- if 'PKG_CONFIG_PATH' in os.environ:
183
- pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
184
- return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
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
- debug: bool = False,
217
+ no_default_opts: bool = False,
212
218
  pyenv: Pyenv = Pyenv(),
213
219
  ) -> None:
214
220
  super().__init__()
215
221
 
216
- if opts is None:
217
- lst = [DEFAULT_PYENV_INSTALL_OPTS]
218
- if debug:
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._debug = debug
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._debug else '')
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 = dict(self._opts.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(self._pyenv.exe(), 'install', *self._opts.opts, self._version, env=env)
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)
@@ -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 resolve(self, spec: InterpSpecifier) -> Interp:
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
- best = sorted(lst, key=lambda t: (-t[0], t[1]))[-1]
37
- bi, bv = best
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.get_installed_version(bv)
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:')
@@ -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:
@@ -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', 'pip',
158
- 'install', '-v',
159
- *sr,
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
@@ -12,6 +12,7 @@ class VenvConfig:
12
12
  requires: ta.Optional[ta.List[str]] = None
13
13
  docker: ta.Optional[str] = None
14
14
  srcs: ta.Optional[ta.List[str]] = None
15
+ use_uv: ta.Optional[bool] = None
15
16
 
16
17
 
17
18
  @dc.dataclass(frozen=True)
@@ -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
  #
@@ -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
@@ -18,7 +18,7 @@ from omlish.lite.cached import cached_nullary
18
18
  from omlish.lite.logs import configure_standard_logging
19
19
  from omlish.lite.logs import log
20
20
 
21
- from ..wheelfile import WheelFile
21
+ from .wheelfile import WheelFile
22
22
 
23
23
 
24
24
  ##
@@ -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()