omdev 0.0.0.dev17__py3-none-any.whl → 0.0.0.dev19__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
@@ -33,6 +33,8 @@ class Project(ProjectBase):
33
33
 
34
34
 
35
35
  class Setuptools(SetuptoolsBase):
36
+ cexts = True
37
+
36
38
  find_packages = {
37
39
  'include': [Project.name, f'{Project.name}.*'],
38
40
  'exclude': [*SetuptoolsBase.find_packages['exclude']],
omdev/cexts/cmake.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """
2
2
  FIXME:
3
3
  - debug tables don't handle symlinks
4
+ - use relapths in cml.txt
4
5
 
5
6
  TODO:
6
7
  - symlink headers, included src files (hamt_impl, ...)
@@ -37,6 +38,7 @@ from omlish import logs
37
38
 
38
39
  from .. import cmake
39
40
  from .. import findmagic
41
+ from .magic import CextMagic
40
42
 
41
43
 
42
44
  log = logging.getLogger(__name__)
@@ -45,12 +47,6 @@ log = logging.getLogger(__name__)
45
47
  ##
46
48
 
47
49
 
48
- MAGIC = '@omdev-cext'
49
- MAGIC_COMMENT = f'// {MAGIC}'
50
-
51
- FILE_EXTENSIONS = ('c', 'cc', 'cpp')
52
-
53
-
54
50
  def _sep_str_grps(*ls: ta.Sequence[str]) -> list[str]:
55
51
  o = []
56
52
  for i, l in enumerate(ls):
@@ -87,7 +83,7 @@ class CmakeProjectGen:
87
83
 
88
84
  @lang.cached_function
89
85
  def cmake_dir(self) -> str:
90
- cmake_dir = os.path.join(self.prj_root, 'cmake')
86
+ cmake_dir = os.path.join(self.prj_root, 'cmake', self.prj_name())
91
87
  if os.path.exists(cmake_dir):
92
88
  for e in os.listdir(cmake_dir):
93
89
  if e == '.idea':
@@ -98,7 +94,7 @@ class CmakeProjectGen:
98
94
  else:
99
95
  shutil.rmtree(ep)
100
96
  else:
101
- os.mkdir(cmake_dir)
97
+ os.makedirs(cmake_dir)
102
98
  return cmake_dir
103
99
 
104
100
  #
@@ -109,17 +105,6 @@ class CmakeProjectGen:
109
105
 
110
106
  #
111
107
 
112
- def write_idea_name(self) -> None:
113
- idea_dir = os.path.join(self.cmake_dir(), '.idea')
114
- if not os.path.isdir(idea_dir):
115
- os.mkdir(idea_dir)
116
- idea_name_file = os.path.join(idea_dir, '.name')
117
- if not os.path.isfile(idea_name_file):
118
- with open(idea_name_file, 'w') as f:
119
- f.write(self.prj_name())
120
-
121
- #
122
-
123
108
  @dc.dataclass(frozen=True, kw_only=True)
124
109
  class PyInfo:
125
110
  venv_exe: str
@@ -153,8 +138,8 @@ class CmakeProjectGen:
153
138
  out.extend(
154
139
  findmagic.find_magic(
155
140
  [e],
156
- [MAGIC_COMMENT],
157
- FILE_EXTENSIONS,
141
+ [CextMagic.MAGIC_COMMENT],
142
+ CextMagic.FILE_EXTENSIONS,
158
143
  ),
159
144
  )
160
145
  else:
@@ -224,7 +209,7 @@ class CmakeProjectGen:
224
209
  [
225
210
  ' '.join([
226
211
  'COMMAND ${CMAKE_COMMAND} -E ',
227
- f'copy $<TARGET_FILE_NAME:{ext_name}> ../../{os.path.dirname(ext_src)}/{so_name}',
212
+ f'copy $<TARGET_FILE_NAME:{ext_name}> ../../../{os.path.dirname(ext_src)}/{so_name}',
228
213
  ]),
229
214
  'COMMAND_EXPAND_LISTS',
230
215
  ],
@@ -311,7 +296,6 @@ class CmakeProjectGen:
311
296
 
312
297
  self.cmake_dir()
313
298
  self.write_git_ignore()
314
- self.write_idea_name()
315
299
 
316
300
  out = io.StringIO()
317
301
  clg = self._CmakeListsGen(self, out)
omdev/cexts/magic.py ADDED
@@ -0,0 +1,7 @@
1
+ # @omlish-lite
2
+
3
+ class CextMagic:
4
+ MAGIC = '@omdev-cext'
5
+ MAGIC_COMMENT = f'// {MAGIC}'
6
+
7
+ FILE_EXTENSIONS = ('c', 'cc', 'cpp')
omdev/cexts/scan.py CHANGED
@@ -5,18 +5,17 @@ import typing as ta
5
5
 
6
6
  from omlish import logs
7
7
 
8
-
9
- log = logging.getLogger(__name__)
8
+ from .magic import CextMagic
10
9
 
11
10
 
12
- SCAN_COMMENT = '// @omdev-cext'
11
+ log = logging.getLogger(__name__)
13
12
 
14
13
 
15
14
  def scan_one(
16
15
  input_path: str,
17
16
  **kwargs: ta.Any,
18
17
  ) -> None:
19
- if not any(input_path.endswith(fx) for fx in ('.c', '.cc', '.cpp')):
18
+ if not any(input_path.endswith('.' + fx) for fx in CextMagic.FILE_EXTENSIONS):
20
19
  return
21
20
 
22
21
  with open(input_path, 'rb') as f:
@@ -27,9 +26,9 @@ def scan_one(
27
26
  except UnicodeDecodeError:
28
27
  return
29
28
 
30
- sls = [l for l in src.splitlines() if l.startswith(SCAN_COMMENT)]
29
+ sls = [l for l in src.splitlines() if l.startswith(CextMagic.MAGIC_COMMENT)]
31
30
  for sl in sls:
32
- sas = sl[len(SCAN_COMMENT):].split() # noqa
31
+ sas = sl[len(CextMagic.MAGIC_COMMENT):].split() # noqa
33
32
 
34
33
  log.info('Found ext: %s', input_path)
35
34
 
omdev/pyproject/cli.py CHANGED
@@ -301,10 +301,10 @@ def _pkg_cmd(args) -> None:
301
301
  raise Exception('must specify command')
302
302
 
303
303
  elif cmd == 'gen':
304
- build_root = os.path.join('.pkg')
304
+ pkgs_root = os.path.join('.pkg')
305
305
 
306
- if os.path.exists(build_root):
307
- shutil.rmtree(build_root)
306
+ if os.path.exists(pkgs_root):
307
+ shutil.rmtree(pkgs_root)
308
308
 
309
309
  build_output_dir = 'dist'
310
310
  run_build = bool(args.build)
@@ -319,11 +319,13 @@ def _pkg_cmd(args) -> None:
319
319
  ex.submit(functools.partial(
320
320
  PyprojectPackageGenerator(
321
321
  dir_name,
322
- build_root,
322
+ pkgs_root,
323
323
  ).gen,
324
- run_build=run_build,
325
- build_output_dir=build_output_dir,
326
- add_revision=add_revision,
324
+ PyprojectPackageGenerator.GenOpts(
325
+ run_build=run_build,
326
+ build_output_dir=build_output_dir,
327
+ add_revision=add_revision,
328
+ ),
327
329
  ))
328
330
  for dir_name in run.cfg().pkgs
329
331
  ]
omdev/pyproject/pkg.py CHANGED
@@ -4,6 +4,14 @@ TODO:
4
4
  - __revision__
5
5
  - entry_points
6
6
 
7
+ ** NOTE **
8
+ setuptools now (2024/09/02) has experimental support for extensions in pure pyproject.toml - but we still want a
9
+ separate '-cext' package
10
+ https://setuptools.pypa.io/en/latest/userguide/ext_modules.html
11
+ https://github.com/pypa/setuptools/commit/1a9d87308dc0d8aabeaae0dce989b35dfb7699f0#diff-61d113525e9cc93565799a4bb8b34a68e2945b8a3f7d90c81380614a4ea39542R7-R8
12
+
13
+ --
14
+
7
15
  https://setuptools.pypa.io/en/latest/references/keywords.html
8
16
  https://packaging.python.org/en/latest/specifications/pyproject-toml
9
17
 
@@ -15,8 +23,9 @@ https://github.com/pypa/sampleproject/blob/db5806e0a3204034c51b1c00dde7d5eb3fa25
15
23
  https://pip.pypa.io/en/stable/cli/pip_install/#vcs-support
16
24
  vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir
17
25
  'git+https://github.com/wrmsr/omlish@master#subdirectory=.pip/omlish'
18
- """
26
+ """ # noqa
19
27
  # ruff: noqa: UP006 UP007
28
+ import abc
20
29
  import dataclasses as dc
21
30
  import importlib
22
31
  import os.path
@@ -29,19 +38,27 @@ import typing as ta
29
38
  from omlish.lite.cached import cached_nullary
30
39
  from omlish.lite.logs import log
31
40
 
41
+ from ..cexts.magic import CextMagic
42
+ from ..findmagic import find_magic
32
43
  from ..toml.writer import TomlWriter
33
44
  from ..tools.revisions import GitRevisionAdder
34
45
 
35
46
 
36
- class PyprojectPackageGenerator:
47
+ #
48
+
49
+
50
+ class BasePyprojectPackageGenerator(abc.ABC):
37
51
  def __init__(
38
52
  self,
39
53
  dir_name: str,
40
- build_root: str,
54
+ pkgs_root: str,
55
+ *,
56
+ pkg_suffix: str = '',
41
57
  ) -> None:
42
58
  super().__init__()
43
59
  self._dir_name = dir_name
44
- self._build_root = build_root
60
+ self._pkgs_root = pkgs_root
61
+ self._pkg_suffix = pkg_suffix
45
62
 
46
63
  #
47
64
 
@@ -49,48 +66,44 @@ class PyprojectPackageGenerator:
49
66
  def about(self) -> types.ModuleType:
50
67
  return importlib.import_module(f'{self._dir_name}.__about__')
51
68
 
52
- @cached_nullary
53
- def project_cls(self) -> type:
54
- return self.about().Project
55
-
56
- @cached_nullary
57
- def setuptools_cls(self) -> type:
58
- return self.about().Setuptools
59
-
60
69
  #
61
70
 
62
71
  @cached_nullary
63
- def _build_dir(self) -> str:
64
- build_dir: str = os.path.join(self._build_root, self._dir_name)
65
- if os.path.isdir(build_dir):
66
- shutil.rmtree(build_dir)
67
- os.makedirs(build_dir)
68
- return build_dir
72
+ def _pkg_dir(self) -> str:
73
+ pkg_dir: str = os.path.join(self._pkgs_root, self._dir_name + self._pkg_suffix)
74
+ if os.path.isdir(pkg_dir):
75
+ shutil.rmtree(pkg_dir)
76
+ os.makedirs(pkg_dir)
77
+ return pkg_dir
69
78
 
70
79
  #
71
80
 
81
+ _GIT_IGNORE: ta.Sequence[str] = [
82
+ '/*.egg-info/',
83
+ '/dist',
84
+ ]
85
+
72
86
  def _write_git_ignore(self) -> None:
73
- git_ignore = [
74
- '/*.egg-info/',
75
- '/dist',
76
- ]
77
- with open(os.path.join(self._build_dir(), '.gitignore'), 'w') as f:
78
- f.write('\n'.join(git_ignore))
87
+ with open(os.path.join(self._pkg_dir(), '.gitignore'), 'w') as f:
88
+ f.write('\n'.join(self._GIT_IGNORE))
79
89
 
80
90
  #
81
91
 
82
92
  def _symlink_source_dir(self) -> None:
83
93
  os.symlink(
84
- os.path.relpath(self._dir_name, self._build_dir()),
85
- os.path.join(self._build_dir(), self._dir_name),
94
+ os.path.relpath(self._dir_name, self._pkg_dir()),
95
+ os.path.join(self._pkg_dir(), self._dir_name),
86
96
  )
87
97
 
88
98
  #
89
99
 
90
- @dc.dataclass(frozen=True)
91
- class FileContents:
92
- pyproject_dct: ta.Mapping[str, ta.Any]
93
- manifest_in: ta.Optional[ta.Sequence[str]]
100
+ @cached_nullary
101
+ def project_cls(self) -> type:
102
+ return self.about().Project
103
+
104
+ @cached_nullary
105
+ def setuptools_cls(self) -> type:
106
+ return self.about().Setuptools
94
107
 
95
108
  @staticmethod
96
109
  def _build_cls_dct(cls: type) -> ta.Dict[str, ta.Any]: # noqa
@@ -112,18 +125,115 @@ class PyprojectPackageGenerator:
112
125
  if sk in sd:
113
126
  dd[dk] = sd.pop(sk)
114
127
 
128
+ @dc.dataclass(frozen=True)
129
+ class Specs:
130
+ pyproject: ta.Dict[str, ta.Any]
131
+ setuptools: ta.Dict[str, ta.Any]
132
+
133
+ def build_specs(self) -> Specs:
134
+ return self.Specs(
135
+ self._build_cls_dct(self.project_cls()),
136
+ self._build_cls_dct(self.setuptools_cls()),
137
+ )
138
+
139
+ #
140
+
141
+ @abc.abstractmethod
142
+ def _write_file_contents(self) -> None:
143
+ raise NotImplementedError
144
+
145
+ #
146
+
147
+ _STANDARD_FILES: ta.Sequence[str] = [
148
+ 'LICENSE',
149
+ 'README.rst',
150
+ ]
151
+
152
+ def _symlink_standard_files(self) -> None:
153
+ for fn in self._STANDARD_FILES:
154
+ if os.path.exists(fn):
155
+ os.symlink(os.path.relpath(fn, self._pkg_dir()), os.path.join(self._pkg_dir(), fn))
156
+
157
+ #
158
+
159
+ def _run_build(
160
+ self,
161
+ build_output_dir: ta.Optional[str] = None,
162
+ *,
163
+ add_revision: bool = False,
164
+ ) -> None:
165
+ subprocess.check_call(
166
+ [
167
+ sys.executable,
168
+ '-m',
169
+ 'build',
170
+ ],
171
+ cwd=self._pkg_dir(),
172
+ )
173
+
174
+ dist_dir = os.path.join(self._pkg_dir(), 'dist')
175
+
176
+ if add_revision:
177
+ GitRevisionAdder().add_to(dist_dir)
178
+
179
+ if build_output_dir is not None:
180
+ for fn in os.listdir(dist_dir):
181
+ shutil.copyfile(os.path.join(dist_dir, fn), os.path.join(build_output_dir, fn))
182
+
183
+ #
184
+
185
+ @dc.dataclass(frozen=True)
186
+ class GenOpts:
187
+ run_build: bool = False
188
+ build_output_dir: ta.Optional[str] = None
189
+ add_revision: bool = False
190
+
191
+ def gen(self, opts: GenOpts = GenOpts()) -> str:
192
+ log.info('Generating pyproject package: %s -> %s (%s)', self._dir_name, self._pkgs_root, self._pkg_suffix)
193
+
194
+ self._pkg_dir()
195
+ self._write_git_ignore()
196
+ self._symlink_source_dir()
197
+ self._write_file_contents()
198
+ self._symlink_standard_files()
199
+
200
+ if opts.run_build:
201
+ self._run_build(
202
+ opts.build_output_dir,
203
+ add_revision=opts.add_revision,
204
+ )
205
+
206
+ return self._pkg_dir()
207
+
208
+
209
+ #
210
+
211
+
212
+ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
213
+
214
+ #
215
+
216
+ @dc.dataclass(frozen=True)
217
+ class FileContents:
218
+ pyproject_dct: ta.Mapping[str, ta.Any]
219
+ manifest_in: ta.Optional[ta.Sequence[str]]
220
+
115
221
  @cached_nullary
116
222
  def file_contents(self) -> FileContents:
117
- pyp_dct = {}
223
+ specs = self.build_specs()
118
224
 
119
225
  #
120
226
 
227
+ pyp_dct = {}
228
+
121
229
  pyp_dct['build-system'] = {
122
230
  'requires': ['setuptools'],
123
231
  'build-backend': 'setuptools.build_meta',
124
232
  }
125
233
 
126
- prj = self._build_cls_dct(self.project_cls())
234
+ prj = specs.pyproject
235
+ prj['name'] += self._pkg_suffix
236
+
127
237
  pyp_dct['project'] = prj
128
238
 
129
239
  self._move_dict_key(prj, 'optional_dependencies', pyp_dct, extrask := 'project.optional-dependencies')
@@ -139,9 +249,11 @@ class PyprojectPackageGenerator:
139
249
 
140
250
  #
141
251
 
142
- st = self._build_cls_dct(self.setuptools_cls())
252
+ st = specs.setuptools
143
253
  pyp_dct['tool.setuptools'] = st
144
254
 
255
+ st.pop('cexts', None)
256
+
145
257
  self._move_dict_key(st, 'find_packages', pyp_dct, 'tool.setuptools.packages.find')
146
258
 
147
259
  mani_in = st.pop('manifest_in', None)
@@ -156,72 +268,121 @@ class PyprojectPackageGenerator:
156
268
  def _write_file_contents(self) -> None:
157
269
  fc = self.file_contents()
158
270
 
159
- with open(os.path.join(self._build_dir(), 'pyproject.toml'), 'w') as f:
271
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
160
272
  TomlWriter(f).write_root(fc.pyproject_dct)
161
273
 
162
274
  if fc.manifest_in:
163
- with open(os.path.join(self._build_dir(), 'MANIFEST.in'), 'w') as f:
275
+ with open(os.path.join(self._pkg_dir(), 'MANIFEST.in'), 'w') as f:
164
276
  f.write('\n'.join(fc.manifest_in)) # noqa
165
277
 
166
278
  #
167
279
 
168
- _STANDARD_FILES: ta.Sequence[str] = [
169
- 'LICENSE',
170
- 'README.rst',
171
- ]
280
+ def gen(self, opts: BasePyprojectPackageGenerator.GenOpts = BasePyprojectPackageGenerator.GenOpts()) -> str:
281
+ ret = super().gen(opts)
172
282
 
173
- def _symlink_standard_files(self) -> None:
174
- for fn in self._STANDARD_FILES:
175
- if os.path.exists(fn):
176
- os.symlink(os.path.relpath(fn, self._build_dir()), os.path.join(self._build_dir(), fn))
283
+ if self.build_specs().setuptools.get('cexts'):
284
+ _PyprojectCextPackageGenerator(
285
+ self._dir_name,
286
+ self._pkgs_root,
287
+ pkg_suffix='-cext',
288
+ ).gen(opts)
177
289
 
178
- #
290
+ return ret
179
291
 
180
- def _run_build(
181
- self,
182
- build_output_dir: ta.Optional[str] = None,
183
- *,
184
- add_revision: bool = False,
185
- ) -> None:
186
- subprocess.check_call(
187
- [
188
- sys.executable,
189
- '-m',
190
- 'build',
191
- ],
192
- cwd=self._build_dir(),
193
- )
194
292
 
195
- dist_dir = os.path.join(self._build_dir(), 'dist')
293
+ #
196
294
 
197
- if add_revision:
198
- GitRevisionAdder().add_to(dist_dir)
199
295
 
200
- if build_output_dir is not None:
201
- for fn in os.listdir(dist_dir):
202
- shutil.copyfile(os.path.join(dist_dir, fn), os.path.join(build_output_dir, fn))
296
+ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
203
297
 
204
298
  #
205
299
 
206
- def gen(
207
- self,
208
- *,
209
- run_build: bool = False,
210
- build_output_dir: ta.Optional[str] = None,
211
- add_revision: bool = False,
212
- ) -> str:
213
- log.info('Generating pyproject package: %s -> %s', self._dir_name, self._build_root)
300
+ @cached_nullary
301
+ def find_cext_srcs(self) -> ta.Sequence[str]:
302
+ return sorted(find_magic(
303
+ [self._dir_name],
304
+ [CextMagic.MAGIC_COMMENT],
305
+ CextMagic.FILE_EXTENSIONS,
306
+ ))
214
307
 
215
- self._build_dir()
216
- self._write_git_ignore()
217
- self._symlink_source_dir()
218
- self._write_file_contents()
219
- self._symlink_standard_files()
308
+ #
220
309
 
221
- if run_build:
222
- self._run_build(
223
- build_output_dir,
224
- add_revision=add_revision,
225
- )
310
+ @dc.dataclass(frozen=True)
311
+ class FileContents:
312
+ pyproject_dct: ta.Mapping[str, ta.Any]
313
+ setup_py: str
314
+
315
+ @cached_nullary
316
+ def file_contents(self) -> FileContents:
317
+ specs = self.build_specs()
318
+
319
+ #
320
+
321
+ pyp_dct = {}
322
+
323
+ pyp_dct['build-system'] = {
324
+ 'requires': ['setuptools'],
325
+ 'build-backend': 'setuptools.build_meta',
326
+ }
327
+
328
+ prj = specs.pyproject
329
+ prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
330
+ prj['name'] += self._pkg_suffix
331
+ prj.pop('optional_dependencies', None)
332
+
333
+ pyp_dct['project'] = prj
334
+
335
+ #
336
+
337
+ st = specs.setuptools
338
+ pyp_dct['tool.setuptools'] = st
339
+
340
+ st.pop('cexts', None)
341
+ st.pop('find_packages', None)
342
+ st.pop('manifest_in', None)
343
+
344
+ pyp_dct['tool.setuptools.packages.find'] = {
345
+ 'include': [],
346
+ }
347
+
348
+ #
349
+
350
+ ext_lines = []
351
+
352
+ for ext_src in self.find_cext_srcs():
353
+ ext_name = ext_src.rpartition('.')[0].replace(os.sep, '.')
354
+ ext_lines.extend([
355
+ 'st.Extension(',
356
+ f" name='{ext_name}',",
357
+ f" sources=['{ext_src}'],",
358
+ " extra_compile_args=['-std=c++20'],",
359
+ '),',
360
+ ])
361
+
362
+ src = '\n'.join([
363
+ 'import setuptools as st',
364
+ '',
365
+ '',
366
+ 'st.setup(',
367
+ ' ext_modules=[',
368
+ *[' ' + l for l in ext_lines],
369
+ ' ]',
370
+ ')',
371
+ '',
372
+ ])
373
+
374
+ #
375
+
376
+ return self.FileContents(
377
+ pyp_dct,
378
+ src,
379
+ )
380
+
381
+ def _write_file_contents(self) -> None:
382
+ fc = self.file_contents()
383
+
384
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
385
+ TomlWriter(f).write_root(fc.pyproject_dct)
226
386
 
227
- return self._build_dir()
387
+ with open(os.path.join(self._pkg_dir(), 'setup.py'), 'w') as f:
388
+ f.write(fc.setup_py)
omdev/scripts/interp.py CHANGED
@@ -1206,7 +1206,7 @@ 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)-16s'),
1209
+ ('thread', 'tid=%(thread)-10x'),
1210
1210
  ('levelname', '%(levelname)-8s'),
1211
1211
  ('name', '%(name)s'),
1212
1212
  ('separator', '::'),
@@ -86,6 +86,71 @@ UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
86
86
  CallableVersionOperator = ta.Callable[['Version', str], bool]
87
87
 
88
88
 
89
+ ########################################
90
+ # ../../cexts/magic.py
91
+
92
+
93
+ class CextMagic:
94
+ MAGIC = '@omdev-cext'
95
+ MAGIC_COMMENT = f'// {MAGIC}'
96
+
97
+ FILE_EXTENSIONS = ('c', 'cc', 'cpp')
98
+
99
+
100
+ ########################################
101
+ # ../../findmagic.py
102
+ # @omlish-script
103
+
104
+
105
+ def compile_magic_pat(m: str) -> re.Pattern:
106
+ return re.compile('^' + re.escape(m) + r'($|(\s.*))')
107
+
108
+
109
+ def find_magic(
110
+ roots: ta.Sequence[str],
111
+ magics: ta.Sequence[str],
112
+ exts: ta.Sequence[str],
113
+ *,
114
+ py: bool = False,
115
+ ) -> ta.Iterator[str]:
116
+ if not magics:
117
+ raise Exception('Must specify magics')
118
+ if not exts:
119
+ raise Exception('Must specify extensions')
120
+
121
+ pats = [compile_magic_pat(m) for m in magics]
122
+
123
+ for root in roots:
124
+ for dp, dns, fns in os.walk(root): # noqa
125
+ for fn in fns:
126
+ if not any(fn.endswith(f'.{x}') for x in exts):
127
+ continue
128
+
129
+ fp = os.path.join(dp, fn)
130
+ try:
131
+ with open(fp) as f:
132
+ src = f.read()
133
+ except UnicodeDecodeError:
134
+ continue
135
+
136
+ if not any(
137
+ any(pat.fullmatch(l) for pat in pats)
138
+ for l in src.splitlines()
139
+ ):
140
+ continue
141
+
142
+ if py:
143
+ if fn == '__init__.py':
144
+ out = dp.replace(os.sep, '.')
145
+ elif fn.endswith('.py'):
146
+ out = fp[:-3].replace(os.sep, '.')
147
+ else:
148
+ out = fp
149
+ else:
150
+ out = fp
151
+ yield out
152
+
153
+
89
154
  ########################################
90
155
  # ../../toml/parser.py
91
156
  # SPDX-License-Identifier: MIT
@@ -1003,7 +1068,10 @@ class TomlWriter:
1003
1068
  elif isinstance(obj, ta.Mapping):
1004
1069
  self.write_inline_table(obj)
1005
1070
  elif isinstance(obj, ta.Sequence):
1006
- self.write_array(obj)
1071
+ if not obj:
1072
+ self.write_inline_array(obj)
1073
+ else:
1074
+ self.write_array(obj)
1007
1075
  else:
1008
1076
  raise TypeError(obj)
1009
1077
 
@@ -2405,7 +2473,7 @@ class JsonLogFormatter(logging.Formatter):
2405
2473
  STANDARD_LOG_FORMAT_PARTS = [
2406
2474
  ('asctime', '%(asctime)-15s'),
2407
2475
  ('process', 'pid=%(process)-6s'),
2408
- ('thread', 'tid=%(thread)-16s'),
2476
+ ('thread', 'tid=%(thread)-10x'),
2409
2477
  ('levelname', '%(levelname)-8s'),
2410
2478
  ('name', '%(name)s'),
2411
2479
  ('separator', '::'),
@@ -3320,6 +3388,14 @@ TODO:
3320
3388
  - __revision__
3321
3389
  - entry_points
3322
3390
 
3391
+ ** NOTE **
3392
+ setuptools now (2024/09/02) has experimental support for extensions in pure pyproject.toml - but we still want a
3393
+ separate '-cext' package
3394
+ https://setuptools.pypa.io/en/latest/userguide/ext_modules.html
3395
+ https://github.com/pypa/setuptools/commit/1a9d87308dc0d8aabeaae0dce989b35dfb7699f0#diff-61d113525e9cc93565799a4bb8b34a68e2945b8a3f7d90c81380614a4ea39542R7-R8
3396
+
3397
+ --
3398
+
3323
3399
  https://setuptools.pypa.io/en/latest/references/keywords.html
3324
3400
  https://packaging.python.org/en/latest/specifications/pyproject-toml
3325
3401
 
@@ -3331,19 +3407,25 @@ https://github.com/pypa/sampleproject/blob/db5806e0a3204034c51b1c00dde7d5eb3fa25
3331
3407
  https://pip.pypa.io/en/stable/cli/pip_install/#vcs-support
3332
3408
  vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir
3333
3409
  'git+https://github.com/wrmsr/omlish@master#subdirectory=.pip/omlish'
3334
- """
3410
+ """ # noqa
3335
3411
  # ruff: noqa: UP006 UP007
3336
3412
 
3337
3413
 
3338
- class PyprojectPackageGenerator:
3414
+ #
3415
+
3416
+
3417
+ class BasePyprojectPackageGenerator(abc.ABC):
3339
3418
  def __init__(
3340
3419
  self,
3341
3420
  dir_name: str,
3342
- build_root: str,
3421
+ pkgs_root: str,
3422
+ *,
3423
+ pkg_suffix: str = '',
3343
3424
  ) -> None:
3344
3425
  super().__init__()
3345
3426
  self._dir_name = dir_name
3346
- self._build_root = build_root
3427
+ self._pkgs_root = pkgs_root
3428
+ self._pkg_suffix = pkg_suffix
3347
3429
 
3348
3430
  #
3349
3431
 
@@ -3351,48 +3433,44 @@ class PyprojectPackageGenerator:
3351
3433
  def about(self) -> types.ModuleType:
3352
3434
  return importlib.import_module(f'{self._dir_name}.__about__')
3353
3435
 
3354
- @cached_nullary
3355
- def project_cls(self) -> type:
3356
- return self.about().Project
3357
-
3358
- @cached_nullary
3359
- def setuptools_cls(self) -> type:
3360
- return self.about().Setuptools
3361
-
3362
3436
  #
3363
3437
 
3364
3438
  @cached_nullary
3365
- def _build_dir(self) -> str:
3366
- build_dir: str = os.path.join(self._build_root, self._dir_name)
3367
- if os.path.isdir(build_dir):
3368
- shutil.rmtree(build_dir)
3369
- os.makedirs(build_dir)
3370
- return build_dir
3439
+ def _pkg_dir(self) -> str:
3440
+ pkg_dir: str = os.path.join(self._pkgs_root, self._dir_name + self._pkg_suffix)
3441
+ if os.path.isdir(pkg_dir):
3442
+ shutil.rmtree(pkg_dir)
3443
+ os.makedirs(pkg_dir)
3444
+ return pkg_dir
3371
3445
 
3372
3446
  #
3373
3447
 
3448
+ _GIT_IGNORE: ta.Sequence[str] = [
3449
+ '/*.egg-info/',
3450
+ '/dist',
3451
+ ]
3452
+
3374
3453
  def _write_git_ignore(self) -> None:
3375
- git_ignore = [
3376
- '/*.egg-info/',
3377
- '/dist',
3378
- ]
3379
- with open(os.path.join(self._build_dir(), '.gitignore'), 'w') as f:
3380
- f.write('\n'.join(git_ignore))
3454
+ with open(os.path.join(self._pkg_dir(), '.gitignore'), 'w') as f:
3455
+ f.write('\n'.join(self._GIT_IGNORE))
3381
3456
 
3382
3457
  #
3383
3458
 
3384
3459
  def _symlink_source_dir(self) -> None:
3385
3460
  os.symlink(
3386
- os.path.relpath(self._dir_name, self._build_dir()),
3387
- os.path.join(self._build_dir(), self._dir_name),
3461
+ os.path.relpath(self._dir_name, self._pkg_dir()),
3462
+ os.path.join(self._pkg_dir(), self._dir_name),
3388
3463
  )
3389
3464
 
3390
3465
  #
3391
3466
 
3392
- @dc.dataclass(frozen=True)
3393
- class FileContents:
3394
- pyproject_dct: ta.Mapping[str, ta.Any]
3395
- manifest_in: ta.Optional[ta.Sequence[str]]
3467
+ @cached_nullary
3468
+ def project_cls(self) -> type:
3469
+ return self.about().Project
3470
+
3471
+ @cached_nullary
3472
+ def setuptools_cls(self) -> type:
3473
+ return self.about().Setuptools
3396
3474
 
3397
3475
  @staticmethod
3398
3476
  def _build_cls_dct(cls: type) -> ta.Dict[str, ta.Any]: # noqa
@@ -3414,18 +3492,115 @@ class PyprojectPackageGenerator:
3414
3492
  if sk in sd:
3415
3493
  dd[dk] = sd.pop(sk)
3416
3494
 
3495
+ @dc.dataclass(frozen=True)
3496
+ class Specs:
3497
+ pyproject: ta.Dict[str, ta.Any]
3498
+ setuptools: ta.Dict[str, ta.Any]
3499
+
3500
+ def build_specs(self) -> Specs:
3501
+ return self.Specs(
3502
+ self._build_cls_dct(self.project_cls()),
3503
+ self._build_cls_dct(self.setuptools_cls()),
3504
+ )
3505
+
3506
+ #
3507
+
3508
+ @abc.abstractmethod
3509
+ def _write_file_contents(self) -> None:
3510
+ raise NotImplementedError
3511
+
3512
+ #
3513
+
3514
+ _STANDARD_FILES: ta.Sequence[str] = [
3515
+ 'LICENSE',
3516
+ 'README.rst',
3517
+ ]
3518
+
3519
+ def _symlink_standard_files(self) -> None:
3520
+ for fn in self._STANDARD_FILES:
3521
+ if os.path.exists(fn):
3522
+ os.symlink(os.path.relpath(fn, self._pkg_dir()), os.path.join(self._pkg_dir(), fn))
3523
+
3524
+ #
3525
+
3526
+ def _run_build(
3527
+ self,
3528
+ build_output_dir: ta.Optional[str] = None,
3529
+ *,
3530
+ add_revision: bool = False,
3531
+ ) -> None:
3532
+ subprocess.check_call(
3533
+ [
3534
+ sys.executable,
3535
+ '-m',
3536
+ 'build',
3537
+ ],
3538
+ cwd=self._pkg_dir(),
3539
+ )
3540
+
3541
+ dist_dir = os.path.join(self._pkg_dir(), 'dist')
3542
+
3543
+ if add_revision:
3544
+ GitRevisionAdder().add_to(dist_dir)
3545
+
3546
+ if build_output_dir is not None:
3547
+ for fn in os.listdir(dist_dir):
3548
+ shutil.copyfile(os.path.join(dist_dir, fn), os.path.join(build_output_dir, fn))
3549
+
3550
+ #
3551
+
3552
+ @dc.dataclass(frozen=True)
3553
+ class GenOpts:
3554
+ run_build: bool = False
3555
+ build_output_dir: ta.Optional[str] = None
3556
+ add_revision: bool = False
3557
+
3558
+ def gen(self, opts: GenOpts = GenOpts()) -> str:
3559
+ log.info('Generating pyproject package: %s -> %s (%s)', self._dir_name, self._pkgs_root, self._pkg_suffix)
3560
+
3561
+ self._pkg_dir()
3562
+ self._write_git_ignore()
3563
+ self._symlink_source_dir()
3564
+ self._write_file_contents()
3565
+ self._symlink_standard_files()
3566
+
3567
+ if opts.run_build:
3568
+ self._run_build(
3569
+ opts.build_output_dir,
3570
+ add_revision=opts.add_revision,
3571
+ )
3572
+
3573
+ return self._pkg_dir()
3574
+
3575
+
3576
+ #
3577
+
3578
+
3579
+ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
3580
+
3581
+ #
3582
+
3583
+ @dc.dataclass(frozen=True)
3584
+ class FileContents:
3585
+ pyproject_dct: ta.Mapping[str, ta.Any]
3586
+ manifest_in: ta.Optional[ta.Sequence[str]]
3587
+
3417
3588
  @cached_nullary
3418
3589
  def file_contents(self) -> FileContents:
3419
- pyp_dct = {}
3590
+ specs = self.build_specs()
3420
3591
 
3421
3592
  #
3422
3593
 
3594
+ pyp_dct = {}
3595
+
3423
3596
  pyp_dct['build-system'] = {
3424
3597
  'requires': ['setuptools'],
3425
3598
  'build-backend': 'setuptools.build_meta',
3426
3599
  }
3427
3600
 
3428
- prj = self._build_cls_dct(self.project_cls())
3601
+ prj = specs.pyproject
3602
+ prj['name'] += self._pkg_suffix
3603
+
3429
3604
  pyp_dct['project'] = prj
3430
3605
 
3431
3606
  self._move_dict_key(prj, 'optional_dependencies', pyp_dct, extrask := 'project.optional-dependencies')
@@ -3441,9 +3616,11 @@ class PyprojectPackageGenerator:
3441
3616
 
3442
3617
  #
3443
3618
 
3444
- st = self._build_cls_dct(self.setuptools_cls())
3619
+ st = specs.setuptools
3445
3620
  pyp_dct['tool.setuptools'] = st
3446
3621
 
3622
+ st.pop('cexts', None)
3623
+
3447
3624
  self._move_dict_key(st, 'find_packages', pyp_dct, 'tool.setuptools.packages.find')
3448
3625
 
3449
3626
  mani_in = st.pop('manifest_in', None)
@@ -3458,75 +3635,124 @@ class PyprojectPackageGenerator:
3458
3635
  def _write_file_contents(self) -> None:
3459
3636
  fc = self.file_contents()
3460
3637
 
3461
- with open(os.path.join(self._build_dir(), 'pyproject.toml'), 'w') as f:
3638
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
3462
3639
  TomlWriter(f).write_root(fc.pyproject_dct)
3463
3640
 
3464
3641
  if fc.manifest_in:
3465
- with open(os.path.join(self._build_dir(), 'MANIFEST.in'), 'w') as f:
3642
+ with open(os.path.join(self._pkg_dir(), 'MANIFEST.in'), 'w') as f:
3466
3643
  f.write('\n'.join(fc.manifest_in)) # noqa
3467
3644
 
3468
3645
  #
3469
3646
 
3470
- _STANDARD_FILES: ta.Sequence[str] = [
3471
- 'LICENSE',
3472
- 'README.rst',
3473
- ]
3647
+ def gen(self, opts: BasePyprojectPackageGenerator.GenOpts = BasePyprojectPackageGenerator.GenOpts()) -> str:
3648
+ ret = super().gen(opts)
3474
3649
 
3475
- def _symlink_standard_files(self) -> None:
3476
- for fn in self._STANDARD_FILES:
3477
- if os.path.exists(fn):
3478
- os.symlink(os.path.relpath(fn, self._build_dir()), os.path.join(self._build_dir(), fn))
3650
+ if self.build_specs().setuptools.get('cexts'):
3651
+ _PyprojectCextPackageGenerator(
3652
+ self._dir_name,
3653
+ self._pkgs_root,
3654
+ pkg_suffix='-cext',
3655
+ ).gen(opts)
3479
3656
 
3480
- #
3657
+ return ret
3481
3658
 
3482
- def _run_build(
3483
- self,
3484
- build_output_dir: ta.Optional[str] = None,
3485
- *,
3486
- add_revision: bool = False,
3487
- ) -> None:
3488
- subprocess.check_call(
3489
- [
3490
- sys.executable,
3491
- '-m',
3492
- 'build',
3493
- ],
3494
- cwd=self._build_dir(),
3495
- )
3496
3659
 
3497
- dist_dir = os.path.join(self._build_dir(), 'dist')
3660
+ #
3498
3661
 
3499
- if add_revision:
3500
- GitRevisionAdder().add_to(dist_dir)
3501
3662
 
3502
- if build_output_dir is not None:
3503
- for fn in os.listdir(dist_dir):
3504
- shutil.copyfile(os.path.join(dist_dir, fn), os.path.join(build_output_dir, fn))
3663
+ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
3505
3664
 
3506
3665
  #
3507
3666
 
3508
- def gen(
3509
- self,
3510
- *,
3511
- run_build: bool = False,
3512
- build_output_dir: ta.Optional[str] = None,
3513
- add_revision: bool = False,
3514
- ) -> str:
3515
- log.info('Generating pyproject package: %s -> %s', self._dir_name, self._build_root)
3667
+ @cached_nullary
3668
+ def find_cext_srcs(self) -> ta.Sequence[str]:
3669
+ return sorted(find_magic(
3670
+ [self._dir_name],
3671
+ [CextMagic.MAGIC_COMMENT],
3672
+ CextMagic.FILE_EXTENSIONS,
3673
+ ))
3516
3674
 
3517
- self._build_dir()
3518
- self._write_git_ignore()
3519
- self._symlink_source_dir()
3520
- self._write_file_contents()
3521
- self._symlink_standard_files()
3675
+ #
3522
3676
 
3523
- if run_build:
3524
- self._run_build(
3525
- build_output_dir,
3526
- add_revision=add_revision,
3527
- )
3677
+ @dc.dataclass(frozen=True)
3678
+ class FileContents:
3679
+ pyproject_dct: ta.Mapping[str, ta.Any]
3680
+ setup_py: str
3681
+
3682
+ @cached_nullary
3683
+ def file_contents(self) -> FileContents:
3684
+ specs = self.build_specs()
3685
+
3686
+ #
3687
+
3688
+ pyp_dct = {}
3689
+
3690
+ pyp_dct['build-system'] = {
3691
+ 'requires': ['setuptools'],
3692
+ 'build-backend': 'setuptools.build_meta',
3693
+ }
3694
+
3695
+ prj = specs.pyproject
3696
+ prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
3697
+ prj['name'] += self._pkg_suffix
3698
+ prj.pop('optional_dependencies', None)
3699
+
3700
+ pyp_dct['project'] = prj
3701
+
3702
+ #
3703
+
3704
+ st = specs.setuptools
3705
+ pyp_dct['tool.setuptools'] = st
3706
+
3707
+ st.pop('cexts', None)
3708
+ st.pop('find_packages', None)
3709
+ st.pop('manifest_in', None)
3710
+
3711
+ pyp_dct['tool.setuptools.packages.find'] = {
3712
+ 'include': [],
3713
+ }
3714
+
3715
+ #
3716
+
3717
+ ext_lines = []
3718
+
3719
+ for ext_src in self.find_cext_srcs():
3720
+ ext_name = ext_src.rpartition('.')[0].replace(os.sep, '.')
3721
+ ext_lines.extend([
3722
+ 'st.Extension(',
3723
+ f" name='{ext_name}',",
3724
+ f" sources=['{ext_src}'],",
3725
+ " extra_compile_args=['-std=c++20'],",
3726
+ '),',
3727
+ ])
3728
+
3729
+ src = '\n'.join([
3730
+ 'import setuptools as st',
3731
+ '',
3732
+ '',
3733
+ 'st.setup(',
3734
+ ' ext_modules=[',
3735
+ *[' ' + l for l in ext_lines],
3736
+ ' ]',
3737
+ ')',
3738
+ '',
3739
+ ])
3740
+
3741
+ #
3742
+
3743
+ return self.FileContents(
3744
+ pyp_dct,
3745
+ src,
3746
+ )
3747
+
3748
+ def _write_file_contents(self) -> None:
3749
+ fc = self.file_contents()
3750
+
3751
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
3752
+ TomlWriter(f).write_root(fc.pyproject_dct)
3528
3753
 
3529
- return self._build_dir()
3754
+ with open(os.path.join(self._pkg_dir(), 'setup.py'), 'w') as f:
3755
+ f.write(fc.setup_py)
3530
3756
 
3531
3757
 
3532
3758
  ########################################
@@ -4363,10 +4589,10 @@ def _pkg_cmd(args) -> None:
4363
4589
  raise Exception('must specify command')
4364
4590
 
4365
4591
  elif cmd == 'gen':
4366
- build_root = os.path.join('.pkg')
4592
+ pkgs_root = os.path.join('.pkg')
4367
4593
 
4368
- if os.path.exists(build_root):
4369
- shutil.rmtree(build_root)
4594
+ if os.path.exists(pkgs_root):
4595
+ shutil.rmtree(pkgs_root)
4370
4596
 
4371
4597
  build_output_dir = 'dist'
4372
4598
  run_build = bool(args.build)
@@ -4381,11 +4607,13 @@ def _pkg_cmd(args) -> None:
4381
4607
  ex.submit(functools.partial(
4382
4608
  PyprojectPackageGenerator(
4383
4609
  dir_name,
4384
- build_root,
4610
+ pkgs_root,
4385
4611
  ).gen,
4386
- run_build=run_build,
4387
- build_output_dir=build_output_dir,
4388
- add_revision=add_revision,
4612
+ PyprojectPackageGenerator.GenOpts(
4613
+ run_build=run_build,
4614
+ build_output_dir=build_output_dir,
4615
+ add_revision=add_revision,
4616
+ ),
4389
4617
  ))
4390
4618
  for dir_name in run.cfg().pkgs
4391
4619
  ]
omdev/toml/writer.py CHANGED
@@ -99,6 +99,9 @@ class TomlWriter:
99
99
  elif isinstance(obj, ta.Mapping):
100
100
  self.write_inline_table(obj)
101
101
  elif isinstance(obj, ta.Sequence):
102
- self.write_array(obj)
102
+ if not obj:
103
+ self.write_inline_array(obj)
104
+ else:
105
+ self.write_array(obj)
103
106
  else:
104
107
  raise TypeError(obj)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev17
3
+ Version: 0.0.0.dev19
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ 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.dev17
15
+ Requires-Dist: omlish ==0.0.0.dev19
16
16
  Provides-Extra: all
17
17
  Requires-Dist: pycparser ~=2.22 ; extra == 'all'
18
18
  Requires-Dist: cffi ~=1.17 ; extra == 'all'
@@ -1,4 +1,4 @@
1
- omdev/__about__.py,sha256=VuY8DTDYJifMW_xeF21JIhFM-MwVp1F0vWUhzIqomJA,784
1
+ omdev/__about__.py,sha256=x1427IilNX73BS7VDiNwnCFDuzGfPVPoRvJze6stnsE,802
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
@@ -12,9 +12,10 @@ omdev/amalg/__main__.py,sha256=OE1udULO1g4McUbeg1CoHbSm4hbQ2kcE3ffEGxlnPh4,69
12
12
  omdev/amalg/amalg.py,sha256=YEyH097MZop-f1qobZJW__srtyLFS3rI7M2MaRtshKg,13057
13
13
  omdev/cexts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  omdev/cexts/build.py,sha256=zViF1wYx6z5ACyifgNjlCAVoPAMCKpTr_VoAvwtmvtY,1013
15
- omdev/cexts/cmake.py,sha256=7-teRL_PAAhg11upu2S93abd3zAEXz3Tjk9PlCB8oAM,10121
15
+ omdev/cexts/cmake.py,sha256=WrH5l3WnamyVEcMMjxkX87bNT7O7ZWX-docajc7XwAg,9726
16
16
  omdev/cexts/importhook.py,sha256=nljqEuPopuh10DPeSrIYKmkV4z-Wk5Q7WpUid1JEmkg,3530
17
- omdev/cexts/scan.py,sha256=lYb-0622Bd18aQGMxN_EmqrT5lUPzCe0GuXFbYSuL38,1641
17
+ omdev/cexts/magic.py,sha256=LhC31I2GiCq3NRU5dpy_9do6IVjhdGu58uPPFffQx5Q,135
18
+ omdev/cexts/scan.py,sha256=_U5DX9ksHP1845PdGxWh4Rf1a6x_sG1MH3uL_hwBnKY,1669
18
19
  omdev/cexts/_distutils/__init__.py,sha256=c1zImtnPh3uY8BUTV4RLKtGKqTPx3c_pBbhA6tPtNsE,297
19
20
  omdev/cexts/_distutils/build_ext.py,sha256=STHl9Rq2KeWJ3dQ8j8LwIQ-vFc4-3XsYWQ8Qc5_VByU,13833
20
21
  omdev/cexts/_distutils/dir_util.py,sha256=xxfAIPHbjlh-aW9OX6UGDrXiXfB5biG4xEC5RA6oszM,2882
@@ -47,17 +48,17 @@ omdev/precheck/__main__.py,sha256=wKF_2KP2Yn1hKDEOCGR_fm5zu9UHMWCZtuEmWjpprrU,72
47
48
  omdev/precheck/precheck.py,sha256=2yTjNGvjPYf3QxUBbCbehBYYuB8gDR_dYSTrlNCs9qU,8322
48
49
  omdev/pyproject/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
49
50
  omdev/pyproject/__main__.py,sha256=gFhR9DikwDZk0LqgdR3qq_aXQHThUOPllDmHDOfnFAU,67
50
- omdev/pyproject/cli.py,sha256=ywK2RyovwgwameZfXrvZylzZ87KQ0RDhzEAljKi7qv8,9918
51
+ omdev/pyproject/cexts.py,sha256=x13piOOnNrYbA17qZLDVuR0p1sqhgEwpk4FtImX-klM,4281
52
+ omdev/pyproject/cli.py,sha256=RnRj8zfGGUcLJ-oiQS90gR2O0XAH4iwNSX5JIDWzM4U,10004
51
53
  omdev/pyproject/configs.py,sha256=MFHnmpMjlwxw74-SyX1Q1qNQ4ptwTXEzDGkeUcGY0mA,2822
52
- omdev/pyproject/ext.py,sha256=x13piOOnNrYbA17qZLDVuR0p1sqhgEwpk4FtImX-klM,4281
53
- omdev/pyproject/pkg.py,sha256=YrnqZK-b2qJh6kSkvYjZ19F39NU0kpbth1FYItpFZ80,5977
54
+ omdev/pyproject/pkg.py,sha256=_uPJNU9i3zbtZ8yw6h0ZTEGtEVJp07EacdHFs3jMMHM,9862
54
55
  omdev/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
56
  omdev/scripts/execrss.py,sha256=HzDNmwXOO8fMwIRXw9q8CUnVfLFCQASyU2tfY_y2Vf8,324
56
- omdev/scripts/interp.py,sha256=Xuj509nGwClnR4MvnB8CJJQ7KhfjdGmzN9ul17-SXjI,63069
57
- omdev/scripts/pyproject.py,sha256=JwEjizuEdKH0TOzfqlfQ0NYkQ3KqzUg-8FtS6lR_-F8,134057
57
+ omdev/scripts/interp.py,sha256=fLO1WXW6_3zr6VlyM9om7RNRtG1yj2TPZpNHOYKfk98,63069
58
+ omdev/scripts/pyproject.py,sha256=3-skV2FFYDPI2TeXQ9DzfS_BFBjmghFFhVcPVLHVlac,139733
58
59
  omdev/toml/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
59
60
  omdev/toml/parser.py,sha256=84bn09uhYHwQGyfww6Rw6y1RxPAE_HDltODOSakcqDM,29186
60
- omdev/toml/writer.py,sha256=StGYPvqgN__A2IxTI4rYeHMx8dLAFt8uogHG8dJdShs,2781
61
+ omdev/toml/writer.py,sha256=dwz_Qw8z5Z_nmWpXqch63W6S_j6n256erb7AGFTVzB4,2872
61
62
  omdev/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
63
  omdev/tools/dockertools.py,sha256=3844AhUst6kYo2xKNn-2Npi-f6r4rocxEOx0tHjE0dk,2063
63
64
  omdev/tools/gittools.py,sha256=zPy2D5WDs-CbwT86_T_hbaq5yCuss5e-ouUccXC6xlg,578
@@ -67,8 +68,8 @@ omdev/tools/traceimport.py,sha256=oDry9CwIv5h96wSaTVKJ0qQ5vMGxYE5oBtfF-GYNLJs,13
67
68
  omdev/versioning/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
68
69
  omdev/versioning/specifiers.py,sha256=6Odf9e6farwlPRsD_YqwTfYKG-BXn_dIcKtqfkhfodI,17432
69
70
  omdev/versioning/versions.py,sha256=ei2eopEsJq3zSMJmezK1nzZgikgCdxFtnF3f69nCRZQ,12246
70
- omdev-0.0.0.dev17.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
71
- omdev-0.0.0.dev17.dist-info/METADATA,sha256=F2d1GkBDHzyYWkvB6pP2vKL0cIljcGVEAEeiFgZm1pc,1126
72
- omdev-0.0.0.dev17.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
73
- omdev-0.0.0.dev17.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
74
- omdev-0.0.0.dev17.dist-info/RECORD,,
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,,
File without changes