omdev 0.0.0.dev23__tar.gz → 0.0.0.dev25__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.
- {omdev-0.0.0.dev23/omdev.egg-info → omdev-0.0.0.dev25}/PKG-INFO +2 -2
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/README.rst +3 -0
- omdev-0.0.0.dev25/omdev/_manifests.json +1 -0
- omdev-0.0.0.dev25/omdev/cexts/_boilerplate.cc +82 -0
- omdev-0.0.0.dev25/omdev/cexts/_distutils/LICENSE +12 -0
- omdev-0.0.0.dev25/omdev/cexts/build.py +87 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/cmake.py +1 -1
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/importhook.py +1 -1
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/findmagic.py +7 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/pyenv.py +26 -1
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/resolvers.py +1 -1
- omdev-0.0.0.dev25/omdev/manifests.py +225 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/pyproject/cli.py +14 -2
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/pyproject/pkg.py +9 -3
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/scripts/interp.py +160 -6
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/scripts/pyproject.py +190 -11
- omdev-0.0.0.dev25/omdev/tools/importscan.py +187 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25/omdev.egg-info}/PKG-INFO +2 -2
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev.egg-info/SOURCES.txt +6 -1
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev.egg-info/requires.txt +1 -1
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/pyproject.toml +12 -3
- omdev-0.0.0.dev23/omdev/cexts/build.py +0 -43
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/LICENSE +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/MANIFEST.in +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/__about__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/amalg/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/amalg/__main__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/amalg/amalg.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/bracepy.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/build_ext.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/compilers/options.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/dir_util.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/errors.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/extension.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/file_util.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/modified.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/spawn.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/sysconfig.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/util.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/_distutils/version.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/magic.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cexts/scan.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/classdot.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/cmake.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/findimports.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/__main__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/cli.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/inspect.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/providers.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/standalone.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/system.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/interp/types.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/mypy/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/mypy/debug.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/precheck/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/precheck/__main__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/precheck/precheck.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/pyproject/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/pyproject/__main__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/pyproject/cexts.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/pyproject/configs.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/pyproject/reqs.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/revisions.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/scripts/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/scripts/bumpversion.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/scripts/execrss.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/tokens.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/toml/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/toml/parser.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/toml/writer.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/tools/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/tools/dockertools.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/tools/gittools.py +0 -0
- /omdev-0.0.0.dev23/omdev/tools/traceimport.py → /omdev-0.0.0.dev25/omdev/tools/importtrace.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/tools/rst.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/tools/sqlrepl.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/versioning/__init__.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/versioning/specifiers.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/versioning/versions.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev/wheelfile.py +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev.egg-info/dependency_links.txt +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/omdev.egg-info/top_level.txt +0 -0
- {omdev-0.0.0.dev23 → omdev-0.0.0.dev25}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: omdev
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev25
|
|
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.
|
|
15
|
+
Requires-Dist: omlish==0.0.0.dev25
|
|
16
16
|
Provides-Extra: all
|
|
17
17
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
|
18
18
|
Requires-Dist: cffi~=1.17; extra == "all"
|
|
@@ -8,3 +8,6 @@ Core packages installable from git via:
|
|
|
8
8
|
.. code-block::
|
|
9
9
|
|
|
10
10
|
pip install 'git+https://github.com/wrmsr/omlish@master#subdirectory=.pkg/<pkg>'
|
|
11
|
+
|
|
12
|
+
Core packages have no required dependencies, but numerous optional ones - see their respective ``pyproject.toml`` files
|
|
13
|
+
for details.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// @omdev-cext
|
|
2
|
+
#define PY_SSIZE_T_CLEAN
|
|
3
|
+
#include "Python.h"
|
|
4
|
+
#include "structmember.h"
|
|
5
|
+
|
|
6
|
+
#include <unistd.h>
|
|
7
|
+
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
#define _MODULE_NAME "_boilerplate"
|
|
11
|
+
#define _PACKAGE_NAME "omdev.cexts"
|
|
12
|
+
#define _MODULE_FULL_NAME _PACKAGE_NAME "." _MODULE_NAME
|
|
13
|
+
|
|
14
|
+
typedef struct boilerplate_state {
|
|
15
|
+
} boilerplate_state;
|
|
16
|
+
|
|
17
|
+
static inline boilerplate_state * get_boilerplate_state(PyObject *module)
|
|
18
|
+
{
|
|
19
|
+
void *state = PyModule_GetState(module);
|
|
20
|
+
assert(state != NULL);
|
|
21
|
+
return (boilerplate_state *)state;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//
|
|
25
|
+
|
|
26
|
+
PyDoc_STRVAR(boilerplate_doc, "boilerplate");
|
|
27
|
+
|
|
28
|
+
static int boilerplate_exec(PyObject *module)
|
|
29
|
+
{
|
|
30
|
+
get_boilerplate_state(module);
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static int boilerplate_traverse(PyObject *module, visitproc visit, void *arg)
|
|
35
|
+
{
|
|
36
|
+
get_boilerplate_state(module);
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static int boilerplate_clear(PyObject *module)
|
|
41
|
+
{
|
|
42
|
+
get_boilerplate_state(module);
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static void boilerplate_free(void *module)
|
|
47
|
+
{
|
|
48
|
+
boilerplate_clear((PyObject *)module);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static PyMethodDef boilerplate_methods[] = {
|
|
52
|
+
{NULL, NULL, 0, NULL}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
static struct PyModuleDef_Slot boilerplate_slots[] = {
|
|
56
|
+
{Py_mod_exec, (void *) boilerplate_exec},
|
|
57
|
+
// #if PY_VERSION_HEX >= 0x030D0000
|
|
58
|
+
// {Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
|
59
|
+
// #endif
|
|
60
|
+
{0, NULL}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
static struct PyModuleDef boilerplate_module = {
|
|
64
|
+
.m_base = PyModuleDef_HEAD_INIT,
|
|
65
|
+
.m_name = _MODULE_NAME,
|
|
66
|
+
.m_doc = boilerplate_doc,
|
|
67
|
+
.m_size = sizeof(boilerplate_state),
|
|
68
|
+
.m_methods = boilerplate_methods,
|
|
69
|
+
.m_slots = boilerplate_slots,
|
|
70
|
+
.m_traverse = boilerplate_traverse,
|
|
71
|
+
.m_clear = boilerplate_clear,
|
|
72
|
+
.m_free = boilerplate_free,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
extern "C" {
|
|
76
|
+
|
|
77
|
+
PyMODINIT_FUNC PyInit__boilerplate(void)
|
|
78
|
+
{
|
|
79
|
+
return PyModuleDef_Init(&boilerplate_module);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
2
|
+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
|
3
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
4
|
+
persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
5
|
+
|
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
7
|
+
Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
10
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
11
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
12
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import dataclasses as dc
|
|
2
|
+
import os.path
|
|
3
|
+
import sys
|
|
4
|
+
import sysconfig
|
|
5
|
+
import typing as ta
|
|
6
|
+
|
|
7
|
+
from omlish import check
|
|
8
|
+
from omlish import lang
|
|
9
|
+
|
|
10
|
+
from . import _distutils as du
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
CPP_STD = 'c++20'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dc.dataclass(frozen=True)
|
|
17
|
+
class BuildExt:
|
|
18
|
+
full_name: str
|
|
19
|
+
src_file: str
|
|
20
|
+
|
|
21
|
+
inplace: bool = dc.field(default=True, kw_only=True)
|
|
22
|
+
debug: bool = dc.field(default=True, kw_only=True)
|
|
23
|
+
force: bool = dc.field(default=False, kw_only=True)
|
|
24
|
+
|
|
25
|
+
dry_run: bool = dc.field(default=False, kw_only=True)
|
|
26
|
+
verbose: bool = dc.field(default=False, kw_only=True)
|
|
27
|
+
|
|
28
|
+
extra_src_files: lang.SequenceNotStr[str] | None = dc.field(default=None, kw_only=True)
|
|
29
|
+
include_dirs: lang.SequenceNotStr[str] | None = dc.field(default=None, kw_only=True)
|
|
30
|
+
compile_args: lang.SequenceNotStr[str] | None = dc.field(default=None, kw_only=True)
|
|
31
|
+
link_args: lang.SequenceNotStr[str] | None = dc.field(default=None, kw_only=True)
|
|
32
|
+
define_macros: ta.Sequence[tuple[str, str]] | None = dc.field(default=None, kw_only=True)
|
|
33
|
+
undef_macros: lang.SequenceNotStr[str] | None = dc.field(default=None, kw_only=True)
|
|
34
|
+
|
|
35
|
+
def __post_init__(self) -> None:
|
|
36
|
+
check.not_isinstance(self.compile_args, str)
|
|
37
|
+
check.not_isinstance(self.link_args, str)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def build_ext(ext: BuildExt) -> str:
|
|
41
|
+
extra_link_args: list[str] = []
|
|
42
|
+
if sys.platform == 'darwin':
|
|
43
|
+
extra_link_args.append('-Wl,-no_fixup_chains')
|
|
44
|
+
|
|
45
|
+
du_ext = du.Extension(
|
|
46
|
+
ext.full_name,
|
|
47
|
+
sources=[
|
|
48
|
+
ext.src_file,
|
|
49
|
+
*(ext.extra_src_files or []),
|
|
50
|
+
],
|
|
51
|
+
include_dirs=[
|
|
52
|
+
os.path.dirname(ext.src_file),
|
|
53
|
+
*(ext.include_dirs or []),
|
|
54
|
+
],
|
|
55
|
+
extra_compile_args=[
|
|
56
|
+
*([f'-std={CPP_STD}'] if any(ext.src_file.endswith(sf) for sf in ('cc', 'cpp')) else []),
|
|
57
|
+
*(ext.compile_args or []),
|
|
58
|
+
],
|
|
59
|
+
extra_link_args=[
|
|
60
|
+
*extra_link_args,
|
|
61
|
+
*(ext.link_args or []),
|
|
62
|
+
],
|
|
63
|
+
define_macros=(list(ext.define_macros) if ext.define_macros is not None else None),
|
|
64
|
+
undef_macros=(list(ext.undef_macros) if ext.undef_macros is not None else None),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
cmd_obj = du.BuildExt(du.BuildExt.Options(
|
|
68
|
+
inplace=ext.inplace,
|
|
69
|
+
debug=ext.debug,
|
|
70
|
+
force=ext.force,
|
|
71
|
+
|
|
72
|
+
dry_run=ext.dry_run,
|
|
73
|
+
verbose=ext.verbose,
|
|
74
|
+
))
|
|
75
|
+
cmd_obj.build_extension(du_ext)
|
|
76
|
+
|
|
77
|
+
so_file = os.path.join(
|
|
78
|
+
os.path.dirname(ext.src_file),
|
|
79
|
+
''.join([
|
|
80
|
+
ext.full_name.rpartition('.')[2],
|
|
81
|
+
'.',
|
|
82
|
+
sysconfig.get_config_var('SOABI'),
|
|
83
|
+
sysconfig.get_config_var('SHLIB_SUFFIX'),
|
|
84
|
+
]),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return so_file
|
|
@@ -42,7 +42,7 @@ class CextImportLoader(importlib.machinery.ExtensionFileLoader):
|
|
|
42
42
|
super().__init__(module_name, filename)
|
|
43
43
|
|
|
44
44
|
def create_module(self, spec: importlib.machinery.ModuleSpec) -> types.ModuleType:
|
|
45
|
-
so_path = build.build_ext(spec.name, check.non_empty_str(spec.origin))
|
|
45
|
+
so_path = build.build_ext(build.BuildExt(spec.name, check.non_empty_str(spec.origin)))
|
|
46
46
|
self.path = so_path # noqa
|
|
47
47
|
spec.origin = so_path
|
|
48
48
|
return super().create_module(spec)
|
|
@@ -17,6 +17,13 @@ def find_magic(
|
|
|
17
17
|
*,
|
|
18
18
|
py: bool = False,
|
|
19
19
|
) -> ta.Iterator[str]:
|
|
20
|
+
if isinstance(roots, str):
|
|
21
|
+
raise TypeError(roots)
|
|
22
|
+
if isinstance(magics, str):
|
|
23
|
+
raise TypeError(magics)
|
|
24
|
+
if isinstance(exts, str):
|
|
25
|
+
raise TypeError(exts)
|
|
26
|
+
|
|
20
27
|
if not magics:
|
|
21
28
|
raise Exception('Must specify magics')
|
|
22
29
|
if not exts:
|
|
@@ -92,6 +92,14 @@ class Pyenv:
|
|
|
92
92
|
ret.append(l)
|
|
93
93
|
return ret
|
|
94
94
|
|
|
95
|
+
def update(self) -> bool:
|
|
96
|
+
if (root := self.root()) is None:
|
|
97
|
+
return False
|
|
98
|
+
if not os.path.isdir(os.path.join(root, '.git')):
|
|
99
|
+
return False
|
|
100
|
+
subprocess_check_call('git', 'pull', cwd=root)
|
|
101
|
+
return True
|
|
102
|
+
|
|
95
103
|
|
|
96
104
|
##
|
|
97
105
|
|
|
@@ -292,6 +300,10 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
292
300
|
|
|
293
301
|
inspect: bool = False,
|
|
294
302
|
inspector: InterpInspector = INTERP_INSPECTOR,
|
|
303
|
+
|
|
304
|
+
*,
|
|
305
|
+
|
|
306
|
+
try_update: bool = False,
|
|
295
307
|
) -> None:
|
|
296
308
|
super().__init__()
|
|
297
309
|
|
|
@@ -300,6 +312,8 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
300
312
|
self._inspect = inspect
|
|
301
313
|
self._inspector = inspector
|
|
302
314
|
|
|
315
|
+
self._try_update = try_update
|
|
316
|
+
|
|
303
317
|
#
|
|
304
318
|
|
|
305
319
|
@staticmethod
|
|
@@ -364,8 +378,9 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
364
378
|
|
|
365
379
|
#
|
|
366
380
|
|
|
367
|
-
def
|
|
381
|
+
def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
368
382
|
lst = []
|
|
383
|
+
|
|
369
384
|
for vs in self._pyenv.installable_versions():
|
|
370
385
|
if (iv := self.guess_version(vs)) is None:
|
|
371
386
|
continue
|
|
@@ -373,6 +388,16 @@ class PyenvInterpProvider(InterpProvider):
|
|
|
373
388
|
raise Exception('Pyenv installable versions not expected to have debug suffix')
|
|
374
389
|
for d in [False, True]:
|
|
375
390
|
lst.append(dc.replace(iv, opts=dc.replace(iv.opts, debug=d)))
|
|
391
|
+
|
|
392
|
+
return lst
|
|
393
|
+
|
|
394
|
+
def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
|
395
|
+
lst = self._get_installable_versions(spec)
|
|
396
|
+
|
|
397
|
+
if self._try_update and not any(v in spec for v in lst):
|
|
398
|
+
if self._pyenv.update():
|
|
399
|
+
lst = self._get_installable_versions(spec)
|
|
400
|
+
|
|
376
401
|
return lst
|
|
377
402
|
|
|
378
403
|
def install_version(self, version: InterpVersion) -> Interp:
|
|
@@ -99,7 +99,7 @@ class InterpResolver:
|
|
|
99
99
|
|
|
100
100
|
DEFAULT_INTERP_RESOLVER = InterpResolver([(p.name, p) for p in [
|
|
101
101
|
# pyenv is preferred to system interpreters as it tends to have more support for things like tkinter
|
|
102
|
-
PyenvInterpProvider(),
|
|
102
|
+
PyenvInterpProvider(try_update=True),
|
|
103
103
|
|
|
104
104
|
RunningInterpProvider(),
|
|
105
105
|
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""
|
|
2
|
+
!!! manifests! get-manifest, _manifest.py
|
|
3
|
+
- dumb dicts, root keys are 'types'
|
|
4
|
+
- get put in _manifest.py, root level dict or smth
|
|
5
|
+
- IMPORT files w comment
|
|
6
|
+
- comment must immediately precede a global val setter
|
|
7
|
+
- val is grabbed from imported module dict by name
|
|
8
|
+
- value is repr'd somehow (roundtrip checked) (naw, json lol)
|
|
9
|
+
- dumped in _manifest.py
|
|
10
|
+
- # @omlish-manifest \n _CACHE_MANIFEST = {'cache': {'name': 'llm', …
|
|
11
|
+
- also can do prechecks!
|
|
12
|
+
"""
|
|
13
|
+
# ruff: noqa: UP006
|
|
14
|
+
# @omlish-lite
|
|
15
|
+
import argparse
|
|
16
|
+
import collections
|
|
17
|
+
import dataclasses as dc
|
|
18
|
+
import inspect
|
|
19
|
+
import json
|
|
20
|
+
import os.path
|
|
21
|
+
import re
|
|
22
|
+
import shlex
|
|
23
|
+
import subprocess
|
|
24
|
+
import sys
|
|
25
|
+
import typing as ta
|
|
26
|
+
|
|
27
|
+
from omlish.lite.cached import cached_nullary
|
|
28
|
+
from omlish.lite.json import json_dumps_pretty
|
|
29
|
+
|
|
30
|
+
from . import findmagic
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dc.dataclass(frozen=True)
|
|
37
|
+
class ManifestOrigin:
|
|
38
|
+
module: str
|
|
39
|
+
attr: str
|
|
40
|
+
|
|
41
|
+
file: str
|
|
42
|
+
line: int
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dc.dataclass(frozen=True)
|
|
46
|
+
class Manifest(ManifestOrigin):
|
|
47
|
+
value: ta.Any
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
MANIFEST_MAGIC = '# @omlish-manifest'
|
|
51
|
+
|
|
52
|
+
_MANIFEST_GLOBAL_PAT = re.compile(r'^(?P<name>[A-Za-z_][A-Za-z0-9_]*)\s*=.*')
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _dump_module_manifests(spec: str, *attrs: str) -> None:
|
|
56
|
+
import importlib
|
|
57
|
+
import json
|
|
58
|
+
|
|
59
|
+
mod = importlib.import_module(spec)
|
|
60
|
+
|
|
61
|
+
out = {}
|
|
62
|
+
for attr in attrs:
|
|
63
|
+
manifest = getattr(mod, attr)
|
|
64
|
+
|
|
65
|
+
manifest_json = json.dumps(manifest)
|
|
66
|
+
rt_manifest = json.loads(manifest_json)
|
|
67
|
+
|
|
68
|
+
if rt_manifest != manifest:
|
|
69
|
+
raise Exception(f'Manifest failed to roundtrip: {manifest} != {rt_manifest}')
|
|
70
|
+
|
|
71
|
+
out[attr] = rt_manifest
|
|
72
|
+
|
|
73
|
+
out_json = json.dumps(out, indent=None, separators=(',', ':'))
|
|
74
|
+
print(out_json)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@cached_nullary
|
|
78
|
+
def _payload_src() -> str:
|
|
79
|
+
return inspect.getsource(_dump_module_manifests)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def build_module_manifests(
|
|
83
|
+
file: str,
|
|
84
|
+
base: str,
|
|
85
|
+
*,
|
|
86
|
+
shell_wrap: bool = True,
|
|
87
|
+
) -> ta.Sequence[Manifest]:
|
|
88
|
+
print((file, base))
|
|
89
|
+
|
|
90
|
+
if not file.endswith('.py'):
|
|
91
|
+
raise Exception(file)
|
|
92
|
+
|
|
93
|
+
mod_name = file.rpartition('.')[0].replace(os.sep, '.')
|
|
94
|
+
|
|
95
|
+
with open(os.path.join(base, file)) as f:
|
|
96
|
+
src = f.read()
|
|
97
|
+
|
|
98
|
+
origins: ta.List[ManifestOrigin] = []
|
|
99
|
+
lines = src.splitlines(keepends=True)
|
|
100
|
+
for i, l in enumerate(lines):
|
|
101
|
+
if l.startswith(MANIFEST_MAGIC):
|
|
102
|
+
if (m := _MANIFEST_GLOBAL_PAT.match(nl := lines[i + 1])) is None:
|
|
103
|
+
raise Exception(nl)
|
|
104
|
+
|
|
105
|
+
origins.append(ManifestOrigin(
|
|
106
|
+
module=mod_name,
|
|
107
|
+
attr=m.groupdict()['name'],
|
|
108
|
+
|
|
109
|
+
file=file,
|
|
110
|
+
line=i + 1,
|
|
111
|
+
))
|
|
112
|
+
|
|
113
|
+
if not origins:
|
|
114
|
+
raise Exception('no manifests found')
|
|
115
|
+
|
|
116
|
+
if (dups := [k for k, v in collections.Counter(o.attr for o in origins).items() if v > 1]):
|
|
117
|
+
raise Exception(f'Duplicate attrs: {dups}')
|
|
118
|
+
|
|
119
|
+
attrs = [o.attr for o in origins]
|
|
120
|
+
|
|
121
|
+
subproc_src = '\n\n'.join([
|
|
122
|
+
_payload_src(),
|
|
123
|
+
f'_dump_module_manifests({mod_name!r}, {", ".join(repr(a) for a in attrs)})\n',
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
args = [
|
|
127
|
+
sys.executable,
|
|
128
|
+
'-c',
|
|
129
|
+
subproc_src,
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
if shell_wrap:
|
|
133
|
+
args = ['sh', '-c', ' '.join(map(shlex.quote, args))]
|
|
134
|
+
|
|
135
|
+
subproc_out = subprocess.check_output(args)
|
|
136
|
+
|
|
137
|
+
sp_lines = subproc_out.decode().strip().splitlines()
|
|
138
|
+
if len(sp_lines) != 1:
|
|
139
|
+
raise Exception('Unexpected subprocess output')
|
|
140
|
+
|
|
141
|
+
dct = json.loads(sp_lines[0])
|
|
142
|
+
if set(dct) != set(attrs):
|
|
143
|
+
raise Exception('Unexpected subprocess output keys')
|
|
144
|
+
|
|
145
|
+
out: ta.List[Manifest] = []
|
|
146
|
+
|
|
147
|
+
for o in origins:
|
|
148
|
+
manifest = dct[o.attr]
|
|
149
|
+
|
|
150
|
+
out.append(Manifest(
|
|
151
|
+
**dc.asdict(o),
|
|
152
|
+
value=manifest,
|
|
153
|
+
))
|
|
154
|
+
|
|
155
|
+
return out
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def build_package_manifests(
|
|
159
|
+
name: str,
|
|
160
|
+
base: str,
|
|
161
|
+
*,
|
|
162
|
+
write: bool = False,
|
|
163
|
+
) -> ta.List[Manifest]:
|
|
164
|
+
pkg_dir = os.path.join(base, name)
|
|
165
|
+
if not os.path.isdir(pkg_dir) or not os.path.isfile(os.path.join(pkg_dir, '__init__.py')):
|
|
166
|
+
raise Exception(pkg_dir)
|
|
167
|
+
|
|
168
|
+
manifests: ta.List[Manifest] = []
|
|
169
|
+
|
|
170
|
+
for file in findmagic.find_magic(
|
|
171
|
+
[pkg_dir],
|
|
172
|
+
[MANIFEST_MAGIC],
|
|
173
|
+
['py'],
|
|
174
|
+
):
|
|
175
|
+
manifests.extend(build_module_manifests(os.path.relpath(file, base), base))
|
|
176
|
+
|
|
177
|
+
if write:
|
|
178
|
+
with open(os.path.join(pkg_dir, '_manifests.json'), 'w') as f:
|
|
179
|
+
f.write(json_dumps_pretty([dc.asdict(m) for m in manifests]))
|
|
180
|
+
f.write('\n')
|
|
181
|
+
|
|
182
|
+
return manifests
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
##
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
if __name__ == '__main__':
|
|
189
|
+
def _gen_cmd(args) -> None:
|
|
190
|
+
if args.base is not None:
|
|
191
|
+
base = args.base
|
|
192
|
+
else:
|
|
193
|
+
base = os.getcwd()
|
|
194
|
+
base = os.path.abspath(base)
|
|
195
|
+
if not os.path.isdir(base):
|
|
196
|
+
raise RuntimeError(base)
|
|
197
|
+
|
|
198
|
+
for pkg in args.package:
|
|
199
|
+
ms = build_package_manifests(
|
|
200
|
+
pkg,
|
|
201
|
+
base,
|
|
202
|
+
write=args.write or False,
|
|
203
|
+
)
|
|
204
|
+
if not args.quiet:
|
|
205
|
+
print(json_dumps_pretty(ms))
|
|
206
|
+
|
|
207
|
+
def _main(argv=None) -> None:
|
|
208
|
+
parser = argparse.ArgumentParser()
|
|
209
|
+
subparsers = parser.add_subparsers()
|
|
210
|
+
|
|
211
|
+
parser_gen = subparsers.add_parser('gen')
|
|
212
|
+
parser_gen.add_argument('-b', '--base')
|
|
213
|
+
parser_gen.add_argument('-w', '--write', action='store_true')
|
|
214
|
+
parser_gen.add_argument('-q', '--quiet', action='store_true')
|
|
215
|
+
parser_gen.add_argument('package', nargs='*')
|
|
216
|
+
|
|
217
|
+
parser_gen.set_defaults(func=_gen_cmd)
|
|
218
|
+
|
|
219
|
+
args = parser.parse_args(argv)
|
|
220
|
+
if not getattr(args, 'func', None):
|
|
221
|
+
parser.print_help()
|
|
222
|
+
else:
|
|
223
|
+
args.func(args)
|
|
224
|
+
|
|
225
|
+
_main()
|
|
@@ -243,18 +243,30 @@ def _venv_cmd(args) -> None:
|
|
|
243
243
|
f'--_docker_container={shlex.quote(sd)}',
|
|
244
244
|
*map(shlex.quote, sys.argv[1:]),
|
|
245
245
|
])
|
|
246
|
+
|
|
247
|
+
docker_env = {
|
|
248
|
+
'DOCKER_HOST_PLATFORM': os.environ.get('DOCKER_HOST_PLATFORM', sys.platform),
|
|
249
|
+
}
|
|
250
|
+
for e in args.docker_env or []:
|
|
251
|
+
if '=' in e:
|
|
252
|
+
k, _, v = e.split('=')
|
|
253
|
+
docker_env[k] = v
|
|
254
|
+
else:
|
|
255
|
+
docker_env[e] = os.environ.get(e, '')
|
|
256
|
+
|
|
246
257
|
subprocess_check_call(
|
|
247
258
|
'docker',
|
|
248
259
|
'compose',
|
|
249
260
|
'-f', 'docker/compose.yml',
|
|
250
261
|
'exec',
|
|
251
262
|
*itertools.chain.from_iterable(
|
|
252
|
-
('-e', f'{
|
|
253
|
-
for
|
|
263
|
+
('-e', f'{k}={v}')
|
|
264
|
+
for k, v in docker_env.items()
|
|
254
265
|
),
|
|
255
266
|
'-it', sd,
|
|
256
267
|
'bash', '--login', '-c', script,
|
|
257
268
|
)
|
|
269
|
+
|
|
258
270
|
return
|
|
259
271
|
|
|
260
272
|
cmd = args.cmd
|
|
@@ -255,6 +255,7 @@ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
255
255
|
st.pop('cexts', None)
|
|
256
256
|
|
|
257
257
|
self._move_dict_key(st, 'find_packages', pyp_dct, 'tool.setuptools.packages.find')
|
|
258
|
+
self._move_dict_key(st, 'package_data', pyp_dct, 'tool.setuptools.package-data')
|
|
258
259
|
|
|
259
260
|
mani_in = st.pop('manifest_in', None)
|
|
260
261
|
|
|
@@ -337,9 +338,14 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
|
|
|
337
338
|
st = specs.setuptools
|
|
338
339
|
pyp_dct['tool.setuptools'] = st
|
|
339
340
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
341
|
+
for k in [
|
|
342
|
+
'cexts',
|
|
343
|
+
|
|
344
|
+
'find_packages',
|
|
345
|
+
'package_data',
|
|
346
|
+
'manifest_in',
|
|
347
|
+
]:
|
|
348
|
+
st.pop(k, None)
|
|
343
349
|
|
|
344
350
|
pyp_dct['tool.setuptools.packages.find'] = {
|
|
345
351
|
'include': [],
|