omdev 0.0.0.dev17__tar.gz → 0.0.0.dev19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of omdev might be problematic. Click here for more details.

Files changed (82) hide show
  1. {omdev-0.0.0.dev17/omdev.egg-info → omdev-0.0.0.dev19}/PKG-INFO +2 -2
  2. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/__about__.py +2 -0
  3. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/cmake.py +7 -23
  4. omdev-0.0.0.dev19/omdev/cexts/magic.py +7 -0
  5. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/scan.py +5 -6
  6. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/pyproject/cli.py +9 -7
  7. omdev-0.0.0.dev19/omdev/pyproject/pkg.py +388 -0
  8. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/scripts/interp.py +1 -1
  9. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/scripts/pyproject.py +320 -92
  10. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/toml/writer.py +4 -1
  11. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19/omdev.egg-info}/PKG-INFO +2 -2
  12. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev.egg-info/SOURCES.txt +2 -1
  13. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev.egg-info/requires.txt +1 -1
  14. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/pyproject.toml +2 -2
  15. omdev-0.0.0.dev17/omdev/pyproject/pkg.py +0 -227
  16. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/LICENSE +0 -0
  17. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/MANIFEST.in +0 -0
  18. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/README.rst +0 -0
  19. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/__init__.py +0 -0
  20. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/amalg/__init__.py +0 -0
  21. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/amalg/__main__.py +0 -0
  22. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/amalg/amalg.py +0 -0
  23. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/bracepy.py +0 -0
  24. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/__init__.py +0 -0
  25. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/__init__.py +0 -0
  26. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/build_ext.py +0 -0
  27. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
  28. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
  29. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/compilers/options.py +0 -0
  30. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
  31. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/dir_util.py +0 -0
  32. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/errors.py +0 -0
  33. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/extension.py +0 -0
  34. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/file_util.py +0 -0
  35. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/modified.py +0 -0
  36. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/spawn.py +0 -0
  37. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/sysconfig.py +0 -0
  38. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/util.py +0 -0
  39. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/_distutils/version.py +0 -0
  40. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/build.py +0 -0
  41. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cexts/importhook.py +0 -0
  42. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/classdot.py +0 -0
  43. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/cmake.py +0 -0
  44. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/findimports.py +0 -0
  45. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/findmagic.py +0 -0
  46. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/__init__.py +0 -0
  47. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/__main__.py +0 -0
  48. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/cli.py +0 -0
  49. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/inspect.py +0 -0
  50. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/providers.py +0 -0
  51. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/pyenv.py +0 -0
  52. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/resolvers.py +0 -0
  53. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/standalone.py +0 -0
  54. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/system.py +0 -0
  55. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/interp/types.py +0 -0
  56. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/mypy/__init__.py +0 -0
  57. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/mypy/debug.py +0 -0
  58. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/precheck/__init__.py +0 -0
  59. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/precheck/__main__.py +0 -0
  60. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/precheck/precheck.py +0 -0
  61. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/pyproject/__init__.py +0 -0
  62. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/pyproject/__main__.py +0 -0
  63. /omdev-0.0.0.dev17/omdev/pyproject/ext.py → /omdev-0.0.0.dev19/omdev/pyproject/cexts.py +0 -0
  64. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/pyproject/configs.py +0 -0
  65. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/scripts/__init__.py +0 -0
  66. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/scripts/execrss.py +0 -0
  67. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/tokens.py +0 -0
  68. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/toml/__init__.py +0 -0
  69. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/toml/parser.py +0 -0
  70. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/tools/__init__.py +0 -0
  71. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/tools/dockertools.py +0 -0
  72. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/tools/gittools.py +0 -0
  73. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/tools/revisions.py +0 -0
  74. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/tools/sqlrepl.py +0 -0
  75. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/tools/traceimport.py +0 -0
  76. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/versioning/__init__.py +0 -0
  77. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/versioning/specifiers.py +0 -0
  78. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/versioning/versions.py +0 -0
  79. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev/wheelfile.py +0 -0
  80. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev.egg-info/dependency_links.txt +0 -0
  81. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/omdev.egg-info/top_level.txt +0 -0
  82. {omdev-0.0.0.dev17 → omdev-0.0.0.dev19}/setup.cfg +0 -0
@@ -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"
@@ -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']],
@@ -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)
@@ -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')
@@ -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
 
@@ -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
  ]
@@ -0,0 +1,388 @@
1
+ """
2
+ TODO:
3
+ - ext scanning
4
+ - __revision__
5
+ - entry_points
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
+
15
+ https://setuptools.pypa.io/en/latest/references/keywords.html
16
+ https://packaging.python.org/en/latest/specifications/pyproject-toml
17
+
18
+ How to build a C extension in keeping with PEP 517, i.e. with pyproject.toml instead of setup.py?
19
+ https://stackoverflow.com/a/66479252
20
+
21
+ https://github.com/pypa/sampleproject/blob/db5806e0a3204034c51b1c00dde7d5eb3fa2532e/setup.py
22
+
23
+ https://pip.pypa.io/en/stable/cli/pip_install/#vcs-support
24
+ vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir
25
+ 'git+https://github.com/wrmsr/omlish@master#subdirectory=.pip/omlish'
26
+ """ # noqa
27
+ # ruff: noqa: UP006 UP007
28
+ import abc
29
+ import dataclasses as dc
30
+ import importlib
31
+ import os.path
32
+ import shutil
33
+ import subprocess
34
+ import sys
35
+ import types
36
+ import typing as ta
37
+
38
+ from omlish.lite.cached import cached_nullary
39
+ from omlish.lite.logs import log
40
+
41
+ from ..cexts.magic import CextMagic
42
+ from ..findmagic import find_magic
43
+ from ..toml.writer import TomlWriter
44
+ from ..tools.revisions import GitRevisionAdder
45
+
46
+
47
+ #
48
+
49
+
50
+ class BasePyprojectPackageGenerator(abc.ABC):
51
+ def __init__(
52
+ self,
53
+ dir_name: str,
54
+ pkgs_root: str,
55
+ *,
56
+ pkg_suffix: str = '',
57
+ ) -> None:
58
+ super().__init__()
59
+ self._dir_name = dir_name
60
+ self._pkgs_root = pkgs_root
61
+ self._pkg_suffix = pkg_suffix
62
+
63
+ #
64
+
65
+ @cached_nullary
66
+ def about(self) -> types.ModuleType:
67
+ return importlib.import_module(f'{self._dir_name}.__about__')
68
+
69
+ #
70
+
71
+ @cached_nullary
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
78
+
79
+ #
80
+
81
+ _GIT_IGNORE: ta.Sequence[str] = [
82
+ '/*.egg-info/',
83
+ '/dist',
84
+ ]
85
+
86
+ def _write_git_ignore(self) -> None:
87
+ with open(os.path.join(self._pkg_dir(), '.gitignore'), 'w') as f:
88
+ f.write('\n'.join(self._GIT_IGNORE))
89
+
90
+ #
91
+
92
+ def _symlink_source_dir(self) -> None:
93
+ os.symlink(
94
+ os.path.relpath(self._dir_name, self._pkg_dir()),
95
+ os.path.join(self._pkg_dir(), self._dir_name),
96
+ )
97
+
98
+ #
99
+
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
107
+
108
+ @staticmethod
109
+ def _build_cls_dct(cls: type) -> ta.Dict[str, ta.Any]: # noqa
110
+ dct = {}
111
+ for b in reversed(cls.__mro__):
112
+ for k, v in b.__dict__.items():
113
+ if k.startswith('_'):
114
+ continue
115
+ dct[k] = v
116
+ return dct
117
+
118
+ @staticmethod
119
+ def _move_dict_key(
120
+ sd: ta.Dict[str, ta.Any],
121
+ sk: str,
122
+ dd: ta.Dict[str, ta.Any],
123
+ dk: str,
124
+ ) -> None:
125
+ if sk in sd:
126
+ dd[dk] = sd.pop(sk)
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
+
221
+ @cached_nullary
222
+ def file_contents(self) -> FileContents:
223
+ specs = self.build_specs()
224
+
225
+ #
226
+
227
+ pyp_dct = {}
228
+
229
+ pyp_dct['build-system'] = {
230
+ 'requires': ['setuptools'],
231
+ 'build-backend': 'setuptools.build_meta',
232
+ }
233
+
234
+ prj = specs.pyproject
235
+ prj['name'] += self._pkg_suffix
236
+
237
+ pyp_dct['project'] = prj
238
+
239
+ self._move_dict_key(prj, 'optional_dependencies', pyp_dct, extrask := 'project.optional-dependencies')
240
+ if (extras := pyp_dct.get(extrask)):
241
+ pyp_dct[extrask] = {
242
+ 'all': [
243
+ e
244
+ for lst in extras.values()
245
+ for e in lst
246
+ ],
247
+ **extras,
248
+ }
249
+
250
+ #
251
+
252
+ st = specs.setuptools
253
+ pyp_dct['tool.setuptools'] = st
254
+
255
+ st.pop('cexts', None)
256
+
257
+ self._move_dict_key(st, 'find_packages', pyp_dct, 'tool.setuptools.packages.find')
258
+
259
+ mani_in = st.pop('manifest_in', None)
260
+
261
+ #
262
+
263
+ return self.FileContents(
264
+ pyp_dct,
265
+ mani_in,
266
+ )
267
+
268
+ def _write_file_contents(self) -> None:
269
+ fc = self.file_contents()
270
+
271
+ with open(os.path.join(self._pkg_dir(), 'pyproject.toml'), 'w') as f:
272
+ TomlWriter(f).write_root(fc.pyproject_dct)
273
+
274
+ if fc.manifest_in:
275
+ with open(os.path.join(self._pkg_dir(), 'MANIFEST.in'), 'w') as f:
276
+ f.write('\n'.join(fc.manifest_in)) # noqa
277
+
278
+ #
279
+
280
+ def gen(self, opts: BasePyprojectPackageGenerator.GenOpts = BasePyprojectPackageGenerator.GenOpts()) -> str:
281
+ ret = super().gen(opts)
282
+
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)
289
+
290
+ return ret
291
+
292
+
293
+ #
294
+
295
+
296
+ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
297
+
298
+ #
299
+
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
+ ))
307
+
308
+ #
309
+
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)
386
+
387
+ with open(os.path.join(self._pkg_dir(), 'setup.py'), 'w') as f:
388
+ f.write(fc.setup_py)
@@ -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', '::'),