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 CHANGED
@@ -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
  ],
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
@@ -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
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
- 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)
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 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:')
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', '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)
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
  #
@@ -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
  ##
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)-10x'),
1210
- ('levelname', '%(levelname)-8s'),
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
- pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
1791
- if 'PKG_CONFIG_PATH' in os.environ:
1792
- pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
1793
- return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
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
- debug: bool = False,
1830
+ no_default_opts: bool = False,
1821
1831
  pyenv: Pyenv = Pyenv(),
1822
1832
  ) -> None:
1823
1833
  super().__init__()
1824
1834
 
1825
- if opts is None:
1826
- lst = [DEFAULT_PYENV_INSTALL_OPTS]
1827
- if debug:
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._debug = debug
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._debug else '')
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 = dict(self._opts.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(self._pyenv.exe(), 'install', *self._opts.opts, self._version, env=env)
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 resolve(self, spec: InterpSpecifier) -> Interp:
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
- best = sorted(lst, key=lambda t: (-t[0], t[1]))[-1]
2109
- bi, bv = best
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.get_installed_version(bv)
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:
@@ -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)-10x'),
2477
- ('levelname', '%(levelname)-8s'),
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
- **{t: frozenset for t in (collections.abc.Set, collections.abc.MutableSet)},
2744
- **{t: tuple for t in (collections.abc.Sequence, collections.abc.MutableSequence)},
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
- # ../../tools/revisions.py
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
- pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
3977
- if 'PKG_CONFIG_PATH' in os.environ:
3978
- pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
3979
- return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
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
- debug: bool = False,
4098
+ no_default_opts: bool = False,
4007
4099
  pyenv: Pyenv = Pyenv(),
4008
4100
  ) -> None:
4009
4101
  super().__init__()
4010
4102
 
4011
- if opts is None:
4012
- lst = [DEFAULT_PYENV_INSTALL_OPTS]
4013
- if debug:
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._debug = debug
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._debug else '')
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 = dict(self._opts.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(self._pyenv.exe(), 'install', *self._opts.opts, self._version, env=env)
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 resolve(self, spec: InterpSpecifier) -> Interp:
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
- best = sorted(lst, key=lambda t: (-t[0], t[1]))[-1]
4295
- bi, bv = best
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.get_installed_version(bv)
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', 'pip',
4446
- 'install', '-v',
4447
- *sr,
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.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
@@ -1,10 +1,11 @@
1
- omdev/__about__.py,sha256=x1427IilNX73BS7VDiNwnCFDuzGfPVPoRvJze6stnsE,802
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=pobok11AGS7UrlCcORyARiS03878rpSVTaFxfv5aaUE,1618
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=9eooFFf1qYK3k_84TTvMxCRmajyQKH1DpLdL8L523ww,1780
39
- omdev/interp/pyenv.py,sha256=7o0_9yH-7ynMzRBVBTq-vSz4haI7h6sA0bAWSC4_DUk,10563
40
- omdev/interp/resolvers.py,sha256=RgNgoe7Q34ivi3d9uXhfmtTfnRwaNDnJieJLJB8H3js,2239
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=lY0pDECxy4qtx2KI7Ve8r2quriiBi9px0Bull2zsYPw,2351
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=RnRj8zfGGUcLJ-oiQS90gR2O0XAH4iwNSX5JIDWzM4U,10004
53
- omdev/pyproject/configs.py,sha256=MFHnmpMjlwxw74-SyX1Q1qNQ4ptwTXEzDGkeUcGY0mA,2822
54
- omdev/pyproject/pkg.py,sha256=_uPJNU9i3zbtZ8yw6h0ZTEGtEVJp07EacdHFs3jMMHM,9862
55
- omdev/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
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=fLO1WXW6_3zr6VlyM9om7RNRtG1yj2TPZpNHOYKfk98,63069
58
- omdev/scripts/pyproject.py,sha256=3-skV2FFYDPI2TeXQ9DzfS_BFBjmghFFhVcPVLHVlac,139733
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=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
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/revisions.py,sha256=pJBHRdgImLnFSo9h6pPsdX-Xbam3UnFOapWrY4U49-A,5393
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.dev19.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
72
- omdev-0.0.0.dev19.dist-info/METADATA,sha256=k0Elh8TPD7dB1z2dwbDPyQ_-GUOLna4LW_oPSYlmNB0,1126
73
- omdev-0.0.0.dev19.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
74
- omdev-0.0.0.dev19.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
75
- omdev-0.0.0.dev19.dist-info/RECORD,,
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,,