omdev 0.0.0.dev17__py3-none-any.whl → 0.0.0.dev18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
omdev/__about__.py 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
@@ -17,6 +17,7 @@ vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir
17
17
  'git+https://github.com/wrmsr/omlish@master#subdirectory=.pip/omlish'
18
18
  """
19
19
  # ruff: noqa: UP006 UP007
20
+ import abc
20
21
  import dataclasses as dc
21
22
  import importlib
22
23
  import os.path
@@ -29,19 +30,27 @@ import typing as ta
29
30
  from omlish.lite.cached import cached_nullary
30
31
  from omlish.lite.logs import log
31
32
 
33
+ from ..cexts.magic import CextMagic
34
+ from ..findmagic import find_magic
32
35
  from ..toml.writer import TomlWriter
33
36
  from ..tools.revisions import GitRevisionAdder
34
37
 
35
38
 
36
- class PyprojectPackageGenerator:
39
+ #
40
+
41
+
42
+ class BasePyprojectPackageGenerator(abc.ABC):
37
43
  def __init__(
38
44
  self,
39
45
  dir_name: str,
40
- build_root: str,
46
+ pkgs_root: str,
47
+ *,
48
+ pkg_suffix: str = '',
41
49
  ) -> None:
42
50
  super().__init__()
43
51
  self._dir_name = dir_name
44
- self._build_root = build_root
52
+ self._pkgs_root = pkgs_root
53
+ self._pkg_suffix = pkg_suffix
45
54
 
46
55
  #
47
56
 
@@ -49,48 +58,44 @@ class PyprojectPackageGenerator:
49
58
  def about(self) -> types.ModuleType:
50
59
  return importlib.import_module(f'{self._dir_name}.__about__')
51
60
 
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
61
  #
61
62
 
62
63
  @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
64
+ def _pkg_dir(self) -> str:
65
+ pkg_dir: str = os.path.join(self._pkgs_root, self._dir_name + self._pkg_suffix)
66
+ if os.path.isdir(pkg_dir):
67
+ shutil.rmtree(pkg_dir)
68
+ os.makedirs(pkg_dir)
69
+ return pkg_dir
69
70
 
70
71
  #
71
72
 
73
+ _GIT_IGNORE: ta.Sequence[str] = [
74
+ '/*.egg-info/',
75
+ '/dist',
76
+ ]
77
+
72
78
  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))
79
+ with open(os.path.join(self._pkg_dir(), '.gitignore'), 'w') as f:
80
+ f.write('\n'.join(self._GIT_IGNORE))
79
81
 
80
82
  #
81
83
 
82
84
  def _symlink_source_dir(self) -> None:
83
85
  os.symlink(
84
- os.path.relpath(self._dir_name, self._build_dir()),
85
- os.path.join(self._build_dir(), self._dir_name),
86
+ os.path.relpath(self._dir_name, self._pkg_dir()),
87
+ os.path.join(self._pkg_dir(), self._dir_name),
86
88
  )
87
89
 
88
90
  #
89
91
 
90
- @dc.dataclass(frozen=True)
91
- class FileContents:
92
- pyproject_dct: ta.Mapping[str, ta.Any]
93
- manifest_in: ta.Optional[ta.Sequence[str]]
92
+ @cached_nullary
93
+ def project_cls(self) -> type:
94
+ return self.about().Project
95
+
96
+ @cached_nullary
97
+ def setuptools_cls(self) -> type:
98
+ return self.about().Setuptools
94
99
 
95
100
  @staticmethod
96
101
  def _build_cls_dct(cls: type) -> ta.Dict[str, ta.Any]: # noqa
@@ -112,18 +117,115 @@ class PyprojectPackageGenerator:
112
117
  if sk in sd:
113
118
  dd[dk] = sd.pop(sk)
114
119
 
120
+ @dc.dataclass(frozen=True)
121
+ class Specs:
122
+ pyproject: ta.Dict[str, ta.Any]
123
+ setuptools: ta.Dict[str, ta.Any]
124
+
125
+ def build_specs(self) -> Specs:
126
+ return self.Specs(
127
+ self._build_cls_dct(self.project_cls()),
128
+ self._build_cls_dct(self.setuptools_cls()),
129
+ )
130
+
131
+ #
132
+
133
+ @abc.abstractmethod
134
+ def _write_file_contents(self) -> None:
135
+ raise NotImplementedError
136
+
137
+ #
138
+
139
+ _STANDARD_FILES: ta.Sequence[str] = [
140
+ 'LICENSE',
141
+ 'README.rst',
142
+ ]
143
+
144
+ def _symlink_standard_files(self) -> None:
145
+ for fn in self._STANDARD_FILES:
146
+ if os.path.exists(fn):
147
+ os.symlink(os.path.relpath(fn, self._pkg_dir()), os.path.join(self._pkg_dir(), fn))
148
+
149
+ #
150
+
151
+ def _run_build(
152
+ self,
153
+ build_output_dir: ta.Optional[str] = None,
154
+ *,
155
+ add_revision: bool = False,
156
+ ) -> None:
157
+ subprocess.check_call(
158
+ [
159
+ sys.executable,
160
+ '-m',
161
+ 'build',
162
+ ],
163
+ cwd=self._pkg_dir(),
164
+ )
165
+
166
+ dist_dir = os.path.join(self._pkg_dir(), 'dist')
167
+
168
+ if add_revision:
169
+ GitRevisionAdder().add_to(dist_dir)
170
+
171
+ if build_output_dir is not None:
172
+ for fn in os.listdir(dist_dir):
173
+ shutil.copyfile(os.path.join(dist_dir, fn), os.path.join(build_output_dir, fn))
174
+
175
+ #
176
+
177
+ @dc.dataclass(frozen=True)
178
+ class GenOpts:
179
+ run_build: bool = False
180
+ build_output_dir: ta.Optional[str] = None
181
+ add_revision: bool = False
182
+
183
+ def gen(self, opts: GenOpts = GenOpts()) -> str:
184
+ log.info('Generating pyproject package: %s -> %s (%s)', self._dir_name, self._pkgs_root, self._pkg_suffix)
185
+
186
+ self._pkg_dir()
187
+ self._write_git_ignore()
188
+ self._symlink_source_dir()
189
+ self._write_file_contents()
190
+ self._symlink_standard_files()
191
+
192
+ if opts.run_build:
193
+ self._run_build(
194
+ opts.build_output_dir,
195
+ add_revision=opts.add_revision,
196
+ )
197
+
198
+ return self._pkg_dir()
199
+
200
+
201
+ #
202
+
203
+
204
+ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
205
+
206
+ #
207
+
208
+ @dc.dataclass(frozen=True)
209
+ class FileContents:
210
+ pyproject_dct: ta.Mapping[str, ta.Any]
211
+ manifest_in: ta.Optional[ta.Sequence[str]]
212
+
115
213
  @cached_nullary
116
214
  def file_contents(self) -> FileContents:
117
- pyp_dct = {}
215
+ specs = self.build_specs()
118
216
 
119
217
  #
120
218
 
219
+ pyp_dct = {}
220
+
121
221
  pyp_dct['build-system'] = {
122
222
  'requires': ['setuptools'],
123
223
  'build-backend': 'setuptools.build_meta',
124
224
  }
125
225
 
126
- prj = self._build_cls_dct(self.project_cls())
226
+ prj = specs.pyproject
227
+ prj['name'] += self._pkg_suffix
228
+
127
229
  pyp_dct['project'] = prj
128
230
 
129
231
  self._move_dict_key(prj, 'optional_dependencies', pyp_dct, extrask := 'project.optional-dependencies')
@@ -139,9 +241,11 @@ class PyprojectPackageGenerator:
139
241
 
140
242
  #
141
243
 
142
- st = self._build_cls_dct(self.setuptools_cls())
244
+ st = specs.setuptools
143
245
  pyp_dct['tool.setuptools'] = st
144
246
 
247
+ st.pop('cexts', None)
248
+
145
249
  self._move_dict_key(st, 'find_packages', pyp_dct, 'tool.setuptools.packages.find')
146
250
 
147
251
  mani_in = st.pop('manifest_in', None)
@@ -156,72 +260,121 @@ class PyprojectPackageGenerator:
156
260
  def _write_file_contents(self) -> None:
157
261
  fc = self.file_contents()
158
262
 
159
- with open(os.path.join(self._build_dir(), 'pyproject.toml'), 'w') as f:
263
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
160
264
  TomlWriter(f).write_root(fc.pyproject_dct)
161
265
 
162
266
  if fc.manifest_in:
163
- with open(os.path.join(self._build_dir(), 'MANIFEST.in'), 'w') as f:
267
+ with open(os.path.join(self._pkg_dir(), 'MANIFEST.in'), 'w') as f:
164
268
  f.write('\n'.join(fc.manifest_in)) # noqa
165
269
 
166
270
  #
167
271
 
168
- _STANDARD_FILES: ta.Sequence[str] = [
169
- 'LICENSE',
170
- 'README.rst',
171
- ]
272
+ def gen(self, opts: BasePyprojectPackageGenerator.GenOpts = BasePyprojectPackageGenerator.GenOpts()) -> str:
273
+ ret = super().gen(opts)
172
274
 
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))
275
+ if self.build_specs().setuptools.get('cexts'):
276
+ _PyprojectCextPackageGenerator(
277
+ self._dir_name,
278
+ self._pkgs_root,
279
+ pkg_suffix='-cext',
280
+ ).gen(opts)
177
281
 
178
- #
282
+ return ret
179
283
 
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
284
 
195
- dist_dir = os.path.join(self._build_dir(), 'dist')
285
+ #
196
286
 
197
- if add_revision:
198
- GitRevisionAdder().add_to(dist_dir)
199
287
 
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))
288
+ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
203
289
 
204
290
  #
205
291
 
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)
292
+ @cached_nullary
293
+ def find_cext_srcs(self) -> ta.Sequence[str]:
294
+ return sorted(find_magic(
295
+ [self._dir_name],
296
+ [CextMagic.MAGIC_COMMENT],
297
+ CextMagic.FILE_EXTENSIONS,
298
+ ))
214
299
 
215
- self._build_dir()
216
- self._write_git_ignore()
217
- self._symlink_source_dir()
218
- self._write_file_contents()
219
- self._symlink_standard_files()
300
+ #
220
301
 
221
- if run_build:
222
- self._run_build(
223
- build_output_dir,
224
- add_revision=add_revision,
225
- )
302
+ @dc.dataclass(frozen=True)
303
+ class FileContents:
304
+ pyproject_dct: ta.Mapping[str, ta.Any]
305
+ setup_py: str
306
+
307
+ @cached_nullary
308
+ def file_contents(self) -> FileContents:
309
+ specs = self.build_specs()
310
+
311
+ #
312
+
313
+ pyp_dct = {}
314
+
315
+ pyp_dct['build-system'] = {
316
+ 'requires': ['setuptools'],
317
+ 'build-backend': 'setuptools.build_meta',
318
+ }
319
+
320
+ prj = specs.pyproject
321
+ prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
322
+ prj['name'] += self._pkg_suffix
323
+ prj.pop('optional_dependencies', None)
324
+
325
+ pyp_dct['project'] = prj
326
+
327
+ #
328
+
329
+ st = specs.setuptools
330
+ pyp_dct['tool.setuptools'] = st
331
+
332
+ st.pop('cexts', None)
333
+ st.pop('find_packages', None)
334
+ st.pop('manifest_in', None)
335
+
336
+ pyp_dct['tool.setuptools.packages.find'] = {
337
+ 'include': [],
338
+ }
339
+
340
+ #
341
+
342
+ ext_lines = []
343
+
344
+ for ext_src in self.find_cext_srcs():
345
+ ext_name = ext_src.rpartition('.')[0].replace(os.sep, '.')
346
+ ext_lines.extend([
347
+ 'st.Extension(',
348
+ f" name='{ext_name}',",
349
+ f" sources=['{ext_src}'],",
350
+ " extra_compile_args=['-std=c++20'],",
351
+ '),',
352
+ ])
353
+
354
+ src = '\n'.join([
355
+ 'import setuptools as st',
356
+ '',
357
+ '',
358
+ 'st.setup(',
359
+ ' ext_modules=[',
360
+ *[' ' + l for l in ext_lines],
361
+ ' ]',
362
+ ')',
363
+ '',
364
+ ])
365
+
366
+ #
367
+
368
+ return self.FileContents(
369
+ pyp_dct,
370
+ src,
371
+ )
372
+
373
+ def _write_file_contents(self) -> None:
374
+ fc = self.file_contents()
375
+
376
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
377
+ TomlWriter(f).write_root(fc.pyproject_dct)
226
378
 
227
- return self._build_dir()
379
+ with open(os.path.join(self._pkg_dir(), 'setup.py'), 'w') as f:
380
+ f.write(fc.setup_py)
@@ -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
 
@@ -3335,15 +3403,21 @@ vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir
3335
3403
  # ruff: noqa: UP006 UP007
3336
3404
 
3337
3405
 
3338
- class PyprojectPackageGenerator:
3406
+ #
3407
+
3408
+
3409
+ class BasePyprojectPackageGenerator(abc.ABC):
3339
3410
  def __init__(
3340
3411
  self,
3341
3412
  dir_name: str,
3342
- build_root: str,
3413
+ pkgs_root: str,
3414
+ *,
3415
+ pkg_suffix: str = '',
3343
3416
  ) -> None:
3344
3417
  super().__init__()
3345
3418
  self._dir_name = dir_name
3346
- self._build_root = build_root
3419
+ self._pkgs_root = pkgs_root
3420
+ self._pkg_suffix = pkg_suffix
3347
3421
 
3348
3422
  #
3349
3423
 
@@ -3351,48 +3425,44 @@ class PyprojectPackageGenerator:
3351
3425
  def about(self) -> types.ModuleType:
3352
3426
  return importlib.import_module(f'{self._dir_name}.__about__')
3353
3427
 
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
3428
  #
3363
3429
 
3364
3430
  @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
3431
+ def _pkg_dir(self) -> str:
3432
+ pkg_dir: str = os.path.join(self._pkgs_root, self._dir_name + self._pkg_suffix)
3433
+ if os.path.isdir(pkg_dir):
3434
+ shutil.rmtree(pkg_dir)
3435
+ os.makedirs(pkg_dir)
3436
+ return pkg_dir
3371
3437
 
3372
3438
  #
3373
3439
 
3440
+ _GIT_IGNORE: ta.Sequence[str] = [
3441
+ '/*.egg-info/',
3442
+ '/dist',
3443
+ ]
3444
+
3374
3445
  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))
3446
+ with open(os.path.join(self._pkg_dir(), '.gitignore'), 'w') as f:
3447
+ f.write('\n'.join(self._GIT_IGNORE))
3381
3448
 
3382
3449
  #
3383
3450
 
3384
3451
  def _symlink_source_dir(self) -> None:
3385
3452
  os.symlink(
3386
- os.path.relpath(self._dir_name, self._build_dir()),
3387
- os.path.join(self._build_dir(), self._dir_name),
3453
+ os.path.relpath(self._dir_name, self._pkg_dir()),
3454
+ os.path.join(self._pkg_dir(), self._dir_name),
3388
3455
  )
3389
3456
 
3390
3457
  #
3391
3458
 
3392
- @dc.dataclass(frozen=True)
3393
- class FileContents:
3394
- pyproject_dct: ta.Mapping[str, ta.Any]
3395
- manifest_in: ta.Optional[ta.Sequence[str]]
3459
+ @cached_nullary
3460
+ def project_cls(self) -> type:
3461
+ return self.about().Project
3462
+
3463
+ @cached_nullary
3464
+ def setuptools_cls(self) -> type:
3465
+ return self.about().Setuptools
3396
3466
 
3397
3467
  @staticmethod
3398
3468
  def _build_cls_dct(cls: type) -> ta.Dict[str, ta.Any]: # noqa
@@ -3414,18 +3484,115 @@ class PyprojectPackageGenerator:
3414
3484
  if sk in sd:
3415
3485
  dd[dk] = sd.pop(sk)
3416
3486
 
3487
+ @dc.dataclass(frozen=True)
3488
+ class Specs:
3489
+ pyproject: ta.Dict[str, ta.Any]
3490
+ setuptools: ta.Dict[str, ta.Any]
3491
+
3492
+ def build_specs(self) -> Specs:
3493
+ return self.Specs(
3494
+ self._build_cls_dct(self.project_cls()),
3495
+ self._build_cls_dct(self.setuptools_cls()),
3496
+ )
3497
+
3498
+ #
3499
+
3500
+ @abc.abstractmethod
3501
+ def _write_file_contents(self) -> None:
3502
+ raise NotImplementedError
3503
+
3504
+ #
3505
+
3506
+ _STANDARD_FILES: ta.Sequence[str] = [
3507
+ 'LICENSE',
3508
+ 'README.rst',
3509
+ ]
3510
+
3511
+ def _symlink_standard_files(self) -> None:
3512
+ for fn in self._STANDARD_FILES:
3513
+ if os.path.exists(fn):
3514
+ os.symlink(os.path.relpath(fn, self._pkg_dir()), os.path.join(self._pkg_dir(), fn))
3515
+
3516
+ #
3517
+
3518
+ def _run_build(
3519
+ self,
3520
+ build_output_dir: ta.Optional[str] = None,
3521
+ *,
3522
+ add_revision: bool = False,
3523
+ ) -> None:
3524
+ subprocess.check_call(
3525
+ [
3526
+ sys.executable,
3527
+ '-m',
3528
+ 'build',
3529
+ ],
3530
+ cwd=self._pkg_dir(),
3531
+ )
3532
+
3533
+ dist_dir = os.path.join(self._pkg_dir(), 'dist')
3534
+
3535
+ if add_revision:
3536
+ GitRevisionAdder().add_to(dist_dir)
3537
+
3538
+ if build_output_dir is not None:
3539
+ for fn in os.listdir(dist_dir):
3540
+ shutil.copyfile(os.path.join(dist_dir, fn), os.path.join(build_output_dir, fn))
3541
+
3542
+ #
3543
+
3544
+ @dc.dataclass(frozen=True)
3545
+ class GenOpts:
3546
+ run_build: bool = False
3547
+ build_output_dir: ta.Optional[str] = None
3548
+ add_revision: bool = False
3549
+
3550
+ def gen(self, opts: GenOpts = GenOpts()) -> str:
3551
+ log.info('Generating pyproject package: %s -> %s (%s)', self._dir_name, self._pkgs_root, self._pkg_suffix)
3552
+
3553
+ self._pkg_dir()
3554
+ self._write_git_ignore()
3555
+ self._symlink_source_dir()
3556
+ self._write_file_contents()
3557
+ self._symlink_standard_files()
3558
+
3559
+ if opts.run_build:
3560
+ self._run_build(
3561
+ opts.build_output_dir,
3562
+ add_revision=opts.add_revision,
3563
+ )
3564
+
3565
+ return self._pkg_dir()
3566
+
3567
+
3568
+ #
3569
+
3570
+
3571
+ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
3572
+
3573
+ #
3574
+
3575
+ @dc.dataclass(frozen=True)
3576
+ class FileContents:
3577
+ pyproject_dct: ta.Mapping[str, ta.Any]
3578
+ manifest_in: ta.Optional[ta.Sequence[str]]
3579
+
3417
3580
  @cached_nullary
3418
3581
  def file_contents(self) -> FileContents:
3419
- pyp_dct = {}
3582
+ specs = self.build_specs()
3420
3583
 
3421
3584
  #
3422
3585
 
3586
+ pyp_dct = {}
3587
+
3423
3588
  pyp_dct['build-system'] = {
3424
3589
  'requires': ['setuptools'],
3425
3590
  'build-backend': 'setuptools.build_meta',
3426
3591
  }
3427
3592
 
3428
- prj = self._build_cls_dct(self.project_cls())
3593
+ prj = specs.pyproject
3594
+ prj['name'] += self._pkg_suffix
3595
+
3429
3596
  pyp_dct['project'] = prj
3430
3597
 
3431
3598
  self._move_dict_key(prj, 'optional_dependencies', pyp_dct, extrask := 'project.optional-dependencies')
@@ -3441,9 +3608,11 @@ class PyprojectPackageGenerator:
3441
3608
 
3442
3609
  #
3443
3610
 
3444
- st = self._build_cls_dct(self.setuptools_cls())
3611
+ st = specs.setuptools
3445
3612
  pyp_dct['tool.setuptools'] = st
3446
3613
 
3614
+ st.pop('cexts', None)
3615
+
3447
3616
  self._move_dict_key(st, 'find_packages', pyp_dct, 'tool.setuptools.packages.find')
3448
3617
 
3449
3618
  mani_in = st.pop('manifest_in', None)
@@ -3458,75 +3627,124 @@ class PyprojectPackageGenerator:
3458
3627
  def _write_file_contents(self) -> None:
3459
3628
  fc = self.file_contents()
3460
3629
 
3461
- with open(os.path.join(self._build_dir(), 'pyproject.toml'), 'w') as f:
3630
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
3462
3631
  TomlWriter(f).write_root(fc.pyproject_dct)
3463
3632
 
3464
3633
  if fc.manifest_in:
3465
- with open(os.path.join(self._build_dir(), 'MANIFEST.in'), 'w') as f:
3634
+ with open(os.path.join(self._pkg_dir(), 'MANIFEST.in'), 'w') as f:
3466
3635
  f.write('\n'.join(fc.manifest_in)) # noqa
3467
3636
 
3468
3637
  #
3469
3638
 
3470
- _STANDARD_FILES: ta.Sequence[str] = [
3471
- 'LICENSE',
3472
- 'README.rst',
3473
- ]
3639
+ def gen(self, opts: BasePyprojectPackageGenerator.GenOpts = BasePyprojectPackageGenerator.GenOpts()) -> str:
3640
+ ret = super().gen(opts)
3474
3641
 
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))
3642
+ if self.build_specs().setuptools.get('cexts'):
3643
+ _PyprojectCextPackageGenerator(
3644
+ self._dir_name,
3645
+ self._pkgs_root,
3646
+ pkg_suffix='-cext',
3647
+ ).gen(opts)
3479
3648
 
3480
- #
3649
+ return ret
3481
3650
 
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
3651
 
3497
- dist_dir = os.path.join(self._build_dir(), 'dist')
3652
+ #
3498
3653
 
3499
- if add_revision:
3500
- GitRevisionAdder().add_to(dist_dir)
3501
3654
 
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))
3655
+ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
3505
3656
 
3506
3657
  #
3507
3658
 
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)
3659
+ @cached_nullary
3660
+ def find_cext_srcs(self) -> ta.Sequence[str]:
3661
+ return sorted(find_magic(
3662
+ [self._dir_name],
3663
+ [CextMagic.MAGIC_COMMENT],
3664
+ CextMagic.FILE_EXTENSIONS,
3665
+ ))
3516
3666
 
3517
- self._build_dir()
3518
- self._write_git_ignore()
3519
- self._symlink_source_dir()
3520
- self._write_file_contents()
3521
- self._symlink_standard_files()
3667
+ #
3522
3668
 
3523
- if run_build:
3524
- self._run_build(
3525
- build_output_dir,
3526
- add_revision=add_revision,
3527
- )
3669
+ @dc.dataclass(frozen=True)
3670
+ class FileContents:
3671
+ pyproject_dct: ta.Mapping[str, ta.Any]
3672
+ setup_py: str
3673
+
3674
+ @cached_nullary
3675
+ def file_contents(self) -> FileContents:
3676
+ specs = self.build_specs()
3677
+
3678
+ #
3679
+
3680
+ pyp_dct = {}
3681
+
3682
+ pyp_dct['build-system'] = {
3683
+ 'requires': ['setuptools'],
3684
+ 'build-backend': 'setuptools.build_meta',
3685
+ }
3686
+
3687
+ prj = specs.pyproject
3688
+ prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
3689
+ prj['name'] += self._pkg_suffix
3690
+ prj.pop('optional_dependencies', None)
3691
+
3692
+ pyp_dct['project'] = prj
3693
+
3694
+ #
3695
+
3696
+ st = specs.setuptools
3697
+ pyp_dct['tool.setuptools'] = st
3698
+
3699
+ st.pop('cexts', None)
3700
+ st.pop('find_packages', None)
3701
+ st.pop('manifest_in', None)
3702
+
3703
+ pyp_dct['tool.setuptools.packages.find'] = {
3704
+ 'include': [],
3705
+ }
3706
+
3707
+ #
3708
+
3709
+ ext_lines = []
3710
+
3711
+ for ext_src in self.find_cext_srcs():
3712
+ ext_name = ext_src.rpartition('.')[0].replace(os.sep, '.')
3713
+ ext_lines.extend([
3714
+ 'st.Extension(',
3715
+ f" name='{ext_name}',",
3716
+ f" sources=['{ext_src}'],",
3717
+ " extra_compile_args=['-std=c++20'],",
3718
+ '),',
3719
+ ])
3720
+
3721
+ src = '\n'.join([
3722
+ 'import setuptools as st',
3723
+ '',
3724
+ '',
3725
+ 'st.setup(',
3726
+ ' ext_modules=[',
3727
+ *[' ' + l for l in ext_lines],
3728
+ ' ]',
3729
+ ')',
3730
+ '',
3731
+ ])
3732
+
3733
+ #
3734
+
3735
+ return self.FileContents(
3736
+ pyp_dct,
3737
+ src,
3738
+ )
3739
+
3740
+ def _write_file_contents(self) -> None:
3741
+ fc = self.file_contents()
3742
+
3743
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
3744
+ TomlWriter(f).write_root(fc.pyproject_dct)
3528
3745
 
3529
- return self._build_dir()
3746
+ with open(os.path.join(self._pkg_dir(), 'setup.py'), 'w') as f:
3747
+ f.write(fc.setup_py)
3530
3748
 
3531
3749
 
3532
3750
  ########################################
@@ -4363,10 +4581,10 @@ def _pkg_cmd(args) -> None:
4363
4581
  raise Exception('must specify command')
4364
4582
 
4365
4583
  elif cmd == 'gen':
4366
- build_root = os.path.join('.pkg')
4584
+ pkgs_root = os.path.join('.pkg')
4367
4585
 
4368
- if os.path.exists(build_root):
4369
- shutil.rmtree(build_root)
4586
+ if os.path.exists(pkgs_root):
4587
+ shutil.rmtree(pkgs_root)
4370
4588
 
4371
4589
  build_output_dir = 'dist'
4372
4590
  run_build = bool(args.build)
@@ -4381,11 +4599,13 @@ def _pkg_cmd(args) -> None:
4381
4599
  ex.submit(functools.partial(
4382
4600
  PyprojectPackageGenerator(
4383
4601
  dir_name,
4384
- build_root,
4602
+ pkgs_root,
4385
4603
  ).gen,
4386
- run_build=run_build,
4387
- build_output_dir=build_output_dir,
4388
- add_revision=add_revision,
4604
+ PyprojectPackageGenerator.GenOpts(
4605
+ run_build=run_build,
4606
+ build_output_dir=build_output_dir,
4607
+ add_revision=add_revision,
4608
+ ),
4389
4609
  ))
4390
4610
  for dir_name in run.cfg().pkgs
4391
4611
  ]
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.dev18
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.dev18
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=dJ8KFx7aK9bMxWtSjVoAYqWwNCabz2MmtKFYB7BpFyw,9474
54
55
  omdev/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
56
  omdev/scripts/execrss.py,sha256=HzDNmwXOO8fMwIRXw9q8CUnVfLFCQASyU2tfY_y2Vf8,324
56
57
  omdev/scripts/interp.py,sha256=Xuj509nGwClnR4MvnB8CJJQ7KhfjdGmzN9ul17-SXjI,63069
57
- omdev/scripts/pyproject.py,sha256=JwEjizuEdKH0TOzfqlfQ0NYkQ3KqzUg-8FtS6lR_-F8,134057
58
+ omdev/scripts/pyproject.py,sha256=yHgVqaESt3TdHClqeqOxKXe6jTwe64LGAskSsYSx4Ls,139345
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.dev18.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
72
+ omdev-0.0.0.dev18.dist-info/METADATA,sha256=2ww7yF1h3owq29eE0vXnR8thV1ZedVaHJaTv9i3jXNk,1126
73
+ omdev-0.0.0.dev18.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
74
+ omdev-0.0.0.dev18.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
75
+ omdev-0.0.0.dev18.dist-info/RECORD,,
File without changes