omdev 0.0.0.dev237__py3-none-any.whl → 0.0.0.dev239__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/.manifests.json +2 -2
- omdev/home/paths.py +31 -3
- omdev/home/secrets.py +10 -2
- omdev/home/{configs.py → shadow.py} +5 -4
- omdev/magic/find.py +7 -1
- omdev/manifests/build.py +103 -63
- omdev/manifests/dumping.py +94 -0
- omdev/pip.py +6 -13
- omdev/scripts/pyproject.py +7 -1
- omdev/tools/git/cli.py +3 -3
- omdev/tools/git/messages.py +13 -7
- omdev/tools/shadow.py +2 -1
- {omdev-0.0.0.dev237.dist-info → omdev-0.0.0.dev239.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev237.dist-info → omdev-0.0.0.dev239.dist-info}/RECORD +18 -17
- {omdev-0.0.0.dev237.dist-info → omdev-0.0.0.dev239.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev237.dist-info → omdev-0.0.0.dev239.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev237.dist-info → omdev-0.0.0.dev239.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev237.dist-info → omdev-0.0.0.dev239.dist-info}/top_level.txt +0 -0
omdev/.manifests.json
CHANGED
@@ -291,7 +291,7 @@
|
|
291
291
|
"module": ".tools.git.messages",
|
292
292
|
"attr": "_TIMESTAMP_GIT_MESSAGE_GENERATOR_MANIFEST",
|
293
293
|
"file": "omdev/tools/git/messages.py",
|
294
|
-
"line":
|
294
|
+
"line": 85,
|
295
295
|
"value": {
|
296
296
|
"$.tools.git.messages.GitMessageGeneratorManifest": {
|
297
297
|
"mod_name": "omdev.tools.git.messages",
|
@@ -435,7 +435,7 @@
|
|
435
435
|
"module": ".tools.shadow",
|
436
436
|
"attr": "_CLI_MODULE",
|
437
437
|
"file": "omdev/tools/shadow.py",
|
438
|
-
"line":
|
438
|
+
"line": 64,
|
439
439
|
"value": {
|
440
440
|
"$.cli.types.CliModule": {
|
441
441
|
"cmd_name": "shadow",
|
omdev/home/paths.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
1
3
|
"""
|
2
4
|
TODO:
|
3
5
|
- XDG cache root
|
@@ -5,16 +7,42 @@ TODO:
|
|
5
7
|
import os.path
|
6
8
|
|
7
9
|
|
10
|
+
##
|
11
|
+
|
12
|
+
|
8
13
|
HOME_DIR_ENV_VAR = 'OMLISH_HOME'
|
9
14
|
DEFAULT_HOME_DIR = '~/.omlish'
|
10
15
|
|
11
|
-
CACHE_DIR_ENV_VAR = 'OMLISH_CACHE'
|
12
|
-
DEFAULT_CACHE_DIR = '~/.cache/omlish'
|
13
|
-
|
14
16
|
|
15
17
|
def get_home_dir() -> str:
|
16
18
|
return os.path.expanduser(os.getenv(HOME_DIR_ENV_VAR, DEFAULT_HOME_DIR))
|
17
19
|
|
18
20
|
|
21
|
+
#
|
22
|
+
|
23
|
+
|
24
|
+
def get_config_dir() -> str:
|
25
|
+
return os.path.join(get_home_dir(), 'config')
|
26
|
+
|
27
|
+
|
28
|
+
def get_run_dir() -> str:
|
29
|
+
return os.path.join(get_home_dir(), 'run')
|
30
|
+
|
31
|
+
|
32
|
+
def get_shadow_dir() -> str:
|
33
|
+
return os.path.join(get_home_dir(), 'shadow')
|
34
|
+
|
35
|
+
|
36
|
+
def get_state_dir() -> str:
|
37
|
+
return os.path.join(get_home_dir(), 'state')
|
38
|
+
|
39
|
+
|
40
|
+
##
|
41
|
+
|
42
|
+
|
43
|
+
CACHE_DIR_ENV_VAR = 'OMLISH_CACHE'
|
44
|
+
DEFAULT_CACHE_DIR = '~/.cache/omlish'
|
45
|
+
|
46
|
+
|
19
47
|
def get_cache_dir() -> str:
|
20
48
|
return os.path.expanduser(os.getenv(DEFAULT_CACHE_DIR, DEFAULT_CACHE_DIR))
|
omdev/home/secrets.py
CHANGED
@@ -4,7 +4,7 @@ import typing as ta
|
|
4
4
|
from omlish import lang
|
5
5
|
from omlish.secrets import all as sec
|
6
6
|
|
7
|
-
from .paths import
|
7
|
+
from .paths import get_config_dir
|
8
8
|
|
9
9
|
|
10
10
|
if ta.TYPE_CHECKING:
|
@@ -13,12 +13,20 @@ else:
|
|
13
13
|
yaml = lang.proxy_import('yaml')
|
14
14
|
|
15
15
|
|
16
|
+
##
|
17
|
+
|
18
|
+
|
16
19
|
SECRETS_FILE_ENV_VAR = 'OMLISH_SECRETS'
|
17
20
|
DEFAULT_SECRETS_FILE_NAME = 'secrets.yml'
|
18
21
|
|
19
22
|
|
20
23
|
def get_secrets_file() -> str:
|
21
|
-
return os.path.expanduser(
|
24
|
+
return os.path.expanduser(
|
25
|
+
os.getenv(
|
26
|
+
SECRETS_FILE_ENV_VAR,
|
27
|
+
os.path.join(get_config_dir(), DEFAULT_SECRETS_FILE_NAME),
|
28
|
+
),
|
29
|
+
)
|
22
30
|
|
23
31
|
|
24
32
|
def load_secrets() -> sec.Secrets:
|
@@ -1,13 +1,14 @@
|
|
1
|
-
import os.path
|
2
|
-
|
3
1
|
from omlish.configs.shadow import MangledFilesShadowConfigs
|
4
2
|
from omlish.configs.shadow import ShadowConfigs
|
5
3
|
|
6
|
-
from .paths import
|
4
|
+
from .paths import get_shadow_dir
|
5
|
+
|
6
|
+
|
7
|
+
##
|
7
8
|
|
8
9
|
|
9
10
|
def get_shadow_configs() -> ShadowConfigs:
|
10
11
|
return MangledFilesShadowConfigs(
|
11
|
-
|
12
|
+
get_shadow_dir(),
|
12
13
|
create=True,
|
13
14
|
)
|
omdev/magic/find.py
CHANGED
@@ -99,7 +99,11 @@ def find_magic(
|
|
99
99
|
*,
|
100
100
|
file: ta.Optional[str] = None,
|
101
101
|
preparer: ta.Callable[[str], ta.Any] = py_compile_magic_preparer,
|
102
|
+
keys: ta.Optional[ta.Container[str]] = None,
|
102
103
|
) -> ta.List[Magic]:
|
104
|
+
if keys is not None and isinstance(keys, str):
|
105
|
+
raise TypeError(keys)
|
106
|
+
|
103
107
|
out: ta.List[Magic] = []
|
104
108
|
|
105
109
|
start = 0
|
@@ -163,7 +167,9 @@ def find_magic(
|
|
163
167
|
if magic is None:
|
164
168
|
raise Exception(f'Failed to find magic block terminator : {file=} {start=} {end=}')
|
165
169
|
|
166
|
-
|
170
|
+
if keys is None or key in keys:
|
171
|
+
out.append(magic)
|
172
|
+
|
167
173
|
start = end + 1
|
168
174
|
|
169
175
|
return out
|
omdev/manifests/build.py
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
TODO:
|
4
4
|
- verify classes instantiate
|
5
5
|
- embed in pyproject
|
6
|
+
- roundtrip flexibility regarding json-ness - tuples vs lists vs sets vs frozensets etc
|
6
7
|
|
7
8
|
See (entry_points):
|
8
9
|
- https://github.com/pytest-dev/pluggy/blob/main/src/pluggy/_manager.py#L405
|
@@ -26,13 +27,17 @@ import time
|
|
26
27
|
import typing as ta
|
27
28
|
|
28
29
|
from omlish.lite.cached import cached_nullary
|
30
|
+
from omlish.lite.check import check
|
31
|
+
from omlish.lite.imports import import_attr
|
29
32
|
from omlish.lite.json import json_dumps_pretty
|
30
33
|
from omlish.lite.logs import log
|
34
|
+
from omlish.manifests.base import ModAttrManifest
|
31
35
|
from omlish.manifests.load import MANIFEST_LOADER
|
32
36
|
from omlish.manifests.types import Manifest
|
33
37
|
from omlish.manifests.types import ManifestOrigin
|
34
38
|
|
35
39
|
from .. import magic
|
40
|
+
from .dumping import _ModuleManifestDumper
|
36
41
|
|
37
42
|
|
38
43
|
T = ta.TypeVar('T')
|
@@ -43,58 +48,32 @@ T = ta.TypeVar('T')
|
|
43
48
|
|
44
49
|
MANIFEST_MAGIC_KEY = '@omlish-manifest'
|
45
50
|
|
46
|
-
_MANIFEST_GLOBAL_PAT = re.compile(r'^(?P<name>[A-Za-z_][A-Za-z0-9_]*)\s*=.*')
|
47
51
|
|
52
|
+
_MANIFEST_GLOBAL_PATS = tuple(re.compile(p) for p in [
|
53
|
+
# _FOO_MANIFEST = FooManifest(...
|
54
|
+
r'^(?P<name>[A-Za-z_][A-Za-z0-9_]*)\s*=.*',
|
48
55
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
import importlib
|
53
|
-
import json
|
56
|
+
# class _FOO_MANIFEST(StaticFooManifest): ...
|
57
|
+
r'^class (?P<name>[A-Za-z_][A-Za-z0-9_]*)\s*(\(|$)',
|
58
|
+
])
|
54
59
|
|
55
|
-
mod = importlib.import_module(spec)
|
56
60
|
|
57
|
-
|
58
|
-
for
|
59
|
-
|
61
|
+
def extract_manifest_target_name(line: str) -> str:
|
62
|
+
for pat in _MANIFEST_GLOBAL_PATS:
|
63
|
+
if (m := pat.match(line)) is not None:
|
64
|
+
return m.groupdict()['name']
|
65
|
+
raise Exception(line)
|
60
66
|
|
61
|
-
if dc.is_dataclass(manifest):
|
62
|
-
cls = type(manifest)
|
63
|
-
manifest_json = json.dumps(dc.asdict(manifest)) # type: ignore
|
64
|
-
manifest_dct = json.loads(manifest_json)
|
65
67
|
|
66
|
-
|
67
|
-
if rt_manifest != manifest:
|
68
|
-
raise Exception(f'Manifest failed to roundtrip: {manifest} -> {manifest_dct} != {rt_manifest}')
|
68
|
+
_INLINE_MANIFEST_CLS_NAME_PAT = re.compile(r'^(?P<cls_name>[_a-zA-Z][_a-zA-Z0-9.]*)\s*(?P<cls_args>\()?')
|
69
69
|
|
70
|
-
key = f'${cls.__module__}.{cls.__qualname__}'
|
71
|
-
out[attr] = {key: manifest_dct}
|
72
70
|
|
73
|
-
|
74
|
-
[(key, manifest_dct)] = manifest.items()
|
75
|
-
if not key.startswith('$'): # noqa
|
76
|
-
raise Exception(f'Bad key: {key}')
|
77
|
-
|
78
|
-
if not isinstance(manifest_dct, collections.abc.Mapping):
|
79
|
-
raise Exception(f'Bad value: {manifest_dct}')
|
80
|
-
|
81
|
-
manifest_json = json.dumps(manifest_dct)
|
82
|
-
rt_manifest_dct = json.loads(manifest_json)
|
83
|
-
if manifest_dct != rt_manifest_dct:
|
84
|
-
raise Exception(f'Manifest failed to roundtrip: {manifest_dct} != {rt_manifest_dct}')
|
85
|
-
|
86
|
-
out[attr] = {key: manifest_dct}
|
87
|
-
|
88
|
-
else:
|
89
|
-
raise TypeError(f'Manifest must be dataclass or mapping: {manifest!r}')
|
90
|
-
|
91
|
-
out_json = json.dumps(out, indent=None, separators=(',', ':'))
|
92
|
-
print(out_json)
|
71
|
+
##
|
93
72
|
|
94
73
|
|
95
74
|
@cached_nullary
|
96
75
|
def _payload_src() -> str:
|
97
|
-
return inspect.getsource(
|
76
|
+
return inspect.getsource(_ModuleManifestDumper)
|
98
77
|
|
99
78
|
|
100
79
|
class ManifestBuilder:
|
@@ -142,20 +121,83 @@ class ManifestBuilder:
|
|
142
121
|
with open(os.path.join(self._base, file)) as f: # noqa
|
143
122
|
src = f.read()
|
144
123
|
|
145
|
-
origins: ta.List[ManifestOrigin] = []
|
146
124
|
lines = src.splitlines(keepends=True)
|
147
|
-
for i, l in enumerate(lines):
|
148
|
-
if l.startswith('# ' + MANIFEST_MAGIC_KEY):
|
149
|
-
if (m := _MANIFEST_GLOBAL_PAT.match(nl := lines[i + 1])) is None:
|
150
|
-
raise Exception(nl)
|
151
125
|
|
152
|
-
|
126
|
+
magics = magic.find_magic(
|
127
|
+
magic.PY_MAGIC_STYLE,
|
128
|
+
lines,
|
129
|
+
file=file,
|
130
|
+
keys={MANIFEST_MAGIC_KEY},
|
131
|
+
)
|
132
|
+
|
133
|
+
origins: ta.List[ManifestOrigin] = []
|
134
|
+
targets: ta.List[dict] = []
|
135
|
+
for m in magics:
|
136
|
+
if m.body:
|
137
|
+
pat_match = check.not_none(_INLINE_MANIFEST_CLS_NAME_PAT.match(m.body))
|
138
|
+
cls_name = check.non_empty_str(pat_match.groupdict()['cls_name'])
|
139
|
+
has_cls_args = bool(pat_match.groupdict().get('cls_args'))
|
140
|
+
|
141
|
+
cls = check.isinstance(import_attr(cls_name), type)
|
142
|
+
check.state(dc.is_dataclass(cls))
|
143
|
+
|
144
|
+
cls_mod_name = cls.__module__
|
145
|
+
cls_qualname = cls.__qualname__
|
146
|
+
cls_reload = sys.modules[cls_mod_name]
|
147
|
+
for p in cls_qualname.split('.'):
|
148
|
+
cls_reload = getattr(cls_reload, p)
|
149
|
+
check.is_(cls_reload, cls)
|
150
|
+
|
151
|
+
if has_cls_args:
|
152
|
+
inl_init_src = m.body[len(cls_name):]
|
153
|
+
else:
|
154
|
+
inl_init_src = '()'
|
155
|
+
|
156
|
+
inl_kw: dict = {}
|
157
|
+
|
158
|
+
if issubclass(cls, ModAttrManifest):
|
159
|
+
attr_name = extract_manifest_target_name(lines[m.end_line])
|
160
|
+
inl_kw.update({
|
161
|
+
'mod_name': mod_name,
|
162
|
+
'attr_name': attr_name,
|
163
|
+
})
|
164
|
+
|
165
|
+
origin = ManifestOrigin(
|
166
|
+
module='.'.join(['', *mod_name.split('.')[1:]]),
|
167
|
+
attr=None,
|
168
|
+
|
169
|
+
file=file,
|
170
|
+
line=m.start_line,
|
171
|
+
)
|
172
|
+
|
173
|
+
origins.append(origin)
|
174
|
+
targets.append({
|
175
|
+
'origin': dc.asdict(origin), # noqa
|
176
|
+
'kind': 'inline',
|
177
|
+
'cls_mod_name': cls_mod_name,
|
178
|
+
'cls_qualname': cls_qualname,
|
179
|
+
'init_src': inl_init_src,
|
180
|
+
'kwargs': inl_kw,
|
181
|
+
})
|
182
|
+
|
183
|
+
else:
|
184
|
+
nl = lines[m.end_line]
|
185
|
+
attr_name = extract_manifest_target_name(nl)
|
186
|
+
|
187
|
+
origin = ManifestOrigin(
|
153
188
|
module='.'.join(['', *mod_name.split('.')[1:]]),
|
154
|
-
attr=
|
189
|
+
attr=attr_name,
|
155
190
|
|
156
191
|
file=file,
|
157
|
-
line=
|
158
|
-
)
|
192
|
+
line=m.start_line,
|
193
|
+
)
|
194
|
+
|
195
|
+
origins.append(origin)
|
196
|
+
targets.append({
|
197
|
+
'origin': dc.asdict(origin), # noqa
|
198
|
+
'kind': 'attr',
|
199
|
+
'attr': attr_name,
|
200
|
+
})
|
159
201
|
|
160
202
|
if not origins:
|
161
203
|
raise Exception('no manifests found')
|
@@ -163,11 +205,9 @@ class ManifestBuilder:
|
|
163
205
|
if (dups := [k for k, v in collections.Counter(o.attr for o in origins).items() if v > 1]):
|
164
206
|
raise Exception(f'Duplicate attrs: {dups}')
|
165
207
|
|
166
|
-
attrs = [o.attr for o in origins]
|
167
|
-
|
168
208
|
subproc_src = '\n\n'.join([
|
169
209
|
_payload_src(),
|
170
|
-
f'
|
210
|
+
f'_ModuleManifestDumper({mod_name!r})({", ".join(repr(tgt) for tgt in targets)})\n',
|
171
211
|
])
|
172
212
|
|
173
213
|
args = [
|
@@ -195,21 +235,21 @@ class ManifestBuilder:
|
|
195
235
|
if len(sp_lines) != 1:
|
196
236
|
raise Exception('Unexpected subprocess output')
|
197
237
|
|
198
|
-
|
199
|
-
|
200
|
-
|
238
|
+
sp_outs = json.loads(sp_lines[0])
|
239
|
+
# FIXME:
|
240
|
+
# if set(dct) != set(attrs):
|
241
|
+
# raise Exception('Unexpected subprocess output keys')
|
201
242
|
|
202
243
|
out: ta.List[Manifest] = []
|
203
|
-
|
204
|
-
|
205
|
-
value = dct[o.attr]
|
244
|
+
for sp_out in sp_outs:
|
245
|
+
value = sp_out['value']
|
206
246
|
|
207
247
|
if not (
|
208
248
|
isinstance(value, ta.Mapping) and
|
209
249
|
len(value) == 1 and
|
210
250
|
all(isinstance(k, str) and k.startswith('$') and len(k) > 1 for k in value)
|
211
251
|
):
|
212
|
-
raise TypeError(f'
|
252
|
+
raise TypeError(f'Manifest values must be mappings of strings starting with $: {value!r}')
|
213
253
|
|
214
254
|
[(key, value_dct)] = value.items()
|
215
255
|
kb, _, kr = key[1:].partition('.') # noqa
|
@@ -217,10 +257,10 @@ class ManifestBuilder:
|
|
217
257
|
key = f'$.{kr}'
|
218
258
|
value = {key: value_dct}
|
219
259
|
|
220
|
-
out.append(Manifest(
|
221
|
-
**
|
222
|
-
value=value,
|
223
|
-
))
|
260
|
+
out.append(Manifest(**{
|
261
|
+
**sp_out,
|
262
|
+
**dict(value=value),
|
263
|
+
}))
|
224
264
|
|
225
265
|
return out
|
226
266
|
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
|
5
|
+
class _ModuleManifestDumper:
|
6
|
+
def __init__(self, spec: str) -> None:
|
7
|
+
super().__init__()
|
8
|
+
|
9
|
+
self._spec = spec
|
10
|
+
|
11
|
+
def __call__(self, *targets: dict) -> None:
|
12
|
+
import collections.abc
|
13
|
+
import dataclasses as dc # noqa
|
14
|
+
import functools
|
15
|
+
import importlib
|
16
|
+
import json
|
17
|
+
|
18
|
+
mod = importlib.import_module(self._spec)
|
19
|
+
|
20
|
+
cls: ta.Any
|
21
|
+
|
22
|
+
out = []
|
23
|
+
for target in targets:
|
24
|
+
origin = target['origin']
|
25
|
+
|
26
|
+
if target['kind'] == 'attr':
|
27
|
+
attr = target['attr']
|
28
|
+
manifest = getattr(mod, attr)
|
29
|
+
|
30
|
+
if dc.is_dataclass(manifest):
|
31
|
+
# Support static dataclasses
|
32
|
+
if isinstance(manifest, type):
|
33
|
+
manifest = manifest()
|
34
|
+
|
35
|
+
cls = type(manifest)
|
36
|
+
manifest_json = json.dumps(dc.asdict(manifest))
|
37
|
+
manifest_dct = json.loads(manifest_json)
|
38
|
+
|
39
|
+
rt_manifest = cls(**manifest_dct)
|
40
|
+
if rt_manifest != manifest:
|
41
|
+
raise Exception(f'Manifest failed to roundtrip: {manifest} => {manifest_dct} != {rt_manifest}')
|
42
|
+
|
43
|
+
key = f'${cls.__module__}.{cls.__qualname__}'
|
44
|
+
out_value = {key: manifest_dct}
|
45
|
+
|
46
|
+
elif isinstance(manifest, collections.abc.Mapping):
|
47
|
+
[(key, manifest_dct)] = manifest.items()
|
48
|
+
if not key.startswith('$'): # noqa
|
49
|
+
raise Exception(f'Bad key: {key}')
|
50
|
+
|
51
|
+
if not isinstance(manifest_dct, collections.abc.Mapping):
|
52
|
+
raise Exception(f'Bad value: {manifest_dct}')
|
53
|
+
|
54
|
+
manifest_json = json.dumps(manifest_dct)
|
55
|
+
rt_manifest_dct = json.loads(manifest_json)
|
56
|
+
if manifest_dct != rt_manifest_dct:
|
57
|
+
raise Exception(f'Manifest failed to roundtrip: {manifest_dct} != {rt_manifest_dct}')
|
58
|
+
|
59
|
+
out_value = {key: manifest_dct}
|
60
|
+
|
61
|
+
else:
|
62
|
+
raise TypeError(f'Manifest must be dataclass or mapping: {manifest!r}')
|
63
|
+
|
64
|
+
elif target['kind'] == 'inline':
|
65
|
+
cls = importlib.import_module(target['cls_mod_name'])
|
66
|
+
for p in target['cls_qualname'].split('.'):
|
67
|
+
cls = getattr(cls, p)
|
68
|
+
if not isinstance(cls, type) or not dc.is_dataclass(cls):
|
69
|
+
raise TypeError(cls)
|
70
|
+
|
71
|
+
cls_fac = functools.partial(cls, **target['kwargs'])
|
72
|
+
eval_attr_name = '__manifest_factory__'
|
73
|
+
inl_glo = {
|
74
|
+
**mod.__dict__,
|
75
|
+
eval_attr_name: cls_fac,
|
76
|
+
}
|
77
|
+
inl_src = eval_attr_name + target['init_src']
|
78
|
+
inl_code = compile(inl_src, '<magic>', 'eval')
|
79
|
+
manifest = eval(inl_code, inl_glo) # noqa
|
80
|
+
manifest_json = json.dumps(dc.asdict(manifest))
|
81
|
+
manifest_dct = json.loads(manifest_json)
|
82
|
+
key = f'${cls.__module__}.{cls.__qualname__}'
|
83
|
+
out_value = {key: manifest_dct}
|
84
|
+
|
85
|
+
else:
|
86
|
+
raise ValueError(target)
|
87
|
+
|
88
|
+
out.append({
|
89
|
+
**origin,
|
90
|
+
'value': out_value,
|
91
|
+
})
|
92
|
+
|
93
|
+
out_json = json.dumps(out, indent=None, separators=(',', ':'))
|
94
|
+
print(out_json)
|
omdev/pip.py
CHANGED
@@ -1,23 +1,16 @@
|
|
1
1
|
import importlib.metadata
|
2
|
-
import
|
2
|
+
import json
|
3
3
|
import sys
|
4
4
|
import typing as ta
|
5
5
|
import urllib.request
|
6
6
|
|
7
7
|
from omlish import check
|
8
|
-
from omlish import lang
|
9
8
|
|
10
9
|
from .packaging.names import canonicalize_name
|
11
10
|
from .packaging.requires import RequiresVariable
|
12
11
|
from .packaging.requires import parse_requirement
|
13
12
|
|
14
13
|
|
15
|
-
if ta.TYPE_CHECKING:
|
16
|
-
import xml.etree.ElementTree as ET # noqa
|
17
|
-
else:
|
18
|
-
ET = lang.proxy_import('xml.etree.ElementTree')
|
19
|
-
|
20
|
-
|
21
14
|
##
|
22
15
|
|
23
16
|
|
@@ -30,11 +23,11 @@ def lookup_latest_package_version(
|
|
30
23
|
pypi_url: str = DEFAULT_PYPI_URL,
|
31
24
|
) -> str:
|
32
25
|
pkg_name = check.non_empty_str(package)
|
33
|
-
with urllib.request.urlopen(f'{pypi_url.rstrip("/")}/
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
return check.non_empty_str(
|
26
|
+
with urllib.request.urlopen(f'{pypi_url.rstrip("/")}/pypi/{pkg_name}/json') as resp: # noqa
|
27
|
+
buf = resp.read()
|
28
|
+
# https://github.com/python/cpython/blob/51d4bf1e0e5349090da72721c865b6c2b28277f3/Tools/scripts/checkpip.py
|
29
|
+
dct = json.loads(buf.decode('utf-8'))
|
30
|
+
return check.non_empty_str(dct['info']['version'])
|
38
31
|
|
39
32
|
|
40
33
|
##
|
omdev/scripts/pyproject.py
CHANGED
@@ -3059,7 +3059,11 @@ def find_magic(
|
|
3059
3059
|
*,
|
3060
3060
|
file: ta.Optional[str] = None,
|
3061
3061
|
preparer: ta.Callable[[str], ta.Any] = py_compile_magic_preparer,
|
3062
|
+
keys: ta.Optional[ta.Container[str]] = None,
|
3062
3063
|
) -> ta.List[Magic]:
|
3064
|
+
if keys is not None and isinstance(keys, str):
|
3065
|
+
raise TypeError(keys)
|
3066
|
+
|
3063
3067
|
out: ta.List[Magic] = []
|
3064
3068
|
|
3065
3069
|
start = 0
|
@@ -3123,7 +3127,9 @@ def find_magic(
|
|
3123
3127
|
if magic is None:
|
3124
3128
|
raise Exception(f'Failed to find magic block terminator : {file=} {start=} {end=}')
|
3125
3129
|
|
3126
|
-
|
3130
|
+
if keys is None or key in keys:
|
3131
|
+
out.append(magic)
|
3132
|
+
|
3127
3133
|
start = end + 1
|
3128
3134
|
|
3129
3135
|
return out
|
omdev/tools/git/cli.py
CHANGED
@@ -21,8 +21,8 @@ from omlish.subprocesses.sync import subprocesses
|
|
21
21
|
|
22
22
|
from ...git.status import GitStatusItem
|
23
23
|
from ...git.status import get_git_status
|
24
|
-
from ...home.
|
25
|
-
from ...home.
|
24
|
+
from ...home.paths import get_config_dir
|
25
|
+
from ...home.shadow import get_shadow_configs
|
26
26
|
from . import consts
|
27
27
|
from .messages import GitMessageGenerator
|
28
28
|
from .messages import TimestampGitMessageGenerator
|
@@ -74,7 +74,7 @@ class Cli(ap.Cli):
|
|
74
74
|
if (arg := self._config_file_path_arg) is not None:
|
75
75
|
return os.path.expanduser(arg)
|
76
76
|
else:
|
77
|
-
return os.path.join(
|
77
|
+
return os.path.join(get_config_dir(), 'tools', 'git.yml')
|
78
78
|
|
79
79
|
@cached.function
|
80
80
|
def load_home_config_content(self) -> ta.Any:
|
omdev/tools/git/messages.py
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
import abc
|
2
|
-
import dataclasses as dc
|
3
2
|
import os
|
4
3
|
import typing as ta
|
5
4
|
|
6
5
|
from omlish import cached
|
7
6
|
from omlish import check
|
7
|
+
from omlish import dataclasses as dc
|
8
8
|
from omlish import lang
|
9
9
|
from omlish.manifests import load as manifest_load
|
10
10
|
from omlish.manifests.base import ModAttrManifest
|
11
11
|
from omlish.manifests.base import NameAliasesManifest
|
12
|
+
from omlish.manifests.static import StaticModAttrManifest
|
12
13
|
|
13
14
|
from . import consts
|
14
15
|
|
@@ -44,6 +45,13 @@ class GitMessageGeneratorManifest(NameAliasesManifest, ModAttrManifest):
|
|
44
45
|
return check.issubclass(self.load(), GitMessageGenerator)
|
45
46
|
|
46
47
|
|
48
|
+
class StaticGitMessageGeneratorManifest(StaticModAttrManifest, GitMessageGeneratorManifest, abc.ABC):
|
49
|
+
pass
|
50
|
+
|
51
|
+
|
52
|
+
#
|
53
|
+
|
54
|
+
|
47
55
|
@cached.function
|
48
56
|
def load_message_generator_manifests() -> ta.Sequence[GitMessageGeneratorManifest]:
|
49
57
|
ldr = manifest_load.MANIFEST_LOADER
|
@@ -75,9 +83,7 @@ class TimestampGitMessageGenerator(GitMessageGenerator):
|
|
75
83
|
|
76
84
|
|
77
85
|
# @omlish-manifest
|
78
|
-
_TIMESTAMP_GIT_MESSAGE_GENERATOR_MANIFEST
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
aliases=['ts'],
|
83
|
-
)
|
86
|
+
class _TIMESTAMP_GIT_MESSAGE_GENERATOR_MANIFEST(StaticGitMessageGeneratorManifest): # noqa
|
87
|
+
attr_name = 'TimestampGitMessageGenerator'
|
88
|
+
name = 'timestamp'
|
89
|
+
aliases = ['ts'] # noqa
|
omdev/tools/shadow.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""
|
2
2
|
TODO:
|
3
3
|
- 'edit', default cwd - use git's
|
4
|
+
- git var GIT_EDITOR
|
4
5
|
- delete?
|
5
6
|
- 'purge'?
|
6
7
|
- 'validate' - at least formats
|
@@ -13,7 +14,7 @@ from omlish.argparse import all as ap
|
|
13
14
|
from omlish.configs.shadow import FileShadowConfigs
|
14
15
|
|
15
16
|
from ..cli.types import CliModule
|
16
|
-
from ..home.
|
17
|
+
from ..home.shadow import get_shadow_configs
|
17
18
|
|
18
19
|
|
19
20
|
##
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: omdev
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev239
|
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.dev239
|
16
16
|
Provides-Extra: all
|
17
17
|
Requires-Dist: black~=25.1; extra == "all"
|
18
18
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
@@ -1,4 +1,4 @@
|
|
1
|
-
omdev/.manifests.json,sha256=
|
1
|
+
omdev/.manifests.json,sha256=NP2sLr8MwlA0AKzDiFihSzLlqzYFENtN4MsjwQLPit4,9798
|
2
2
|
omdev/__about__.py,sha256=Iect_SBD2EXgx7QcFGiOqTHkOWD-bWOyvzgReDOY4Es,1214
|
3
3
|
omdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
omdev/bracepy.py,sha256=I8EdqtDvxzAi3I8TuMEW-RBfwXfqKbwp06CfOdj3L1o,2743
|
@@ -6,7 +6,7 @@ omdev/classdot.py,sha256=YOvgy6x295I_8NKBbBlRVd3AN7Osirm_Lqt4Wj0j9rY,1631
|
|
6
6
|
omdev/cmake.py,sha256=oBAp1K8h-iCDd9uCn-OpNpZ6n36oYFkWLIiTyQw4irU,4573
|
7
7
|
omdev/findimports.py,sha256=2t8QP852saEEJFeXySEzhi_nxRSxghlkXz2jVdvy08M,2392
|
8
8
|
omdev/imgur.py,sha256=Uyz8nkORlhfXXK5Sty16tX8ro8s-b7LrxjOECv4_sB0,3005
|
9
|
-
omdev/pip.py,sha256=
|
9
|
+
omdev/pip.py,sha256=PqzAWDO_CbiZvXzJAZcCkFqWynUDls1jIgBWlrswQyA,2012
|
10
10
|
omdev/tagstrings.py,sha256=zIP7nzcsZf5te0lphu6k36ND_cOvNFRg00neoTcoCs8,5484
|
11
11
|
omdev/amalg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
omdev/amalg/__main__.py,sha256=1sZH8SLAueWxMxK9ngvndUW3L_rw7f-s_jK3ZP1yAH8,170
|
@@ -119,9 +119,9 @@ omdev/git/revisions.py,sha256=XJDs4LAnSuETSUpV6Nv_4iDFqdzMHSixWgrH8UiP09w,1171
|
|
119
119
|
omdev/git/shallow.py,sha256=pu2Dro9P7oUa-cpFkcscbay1bM6jLFfV5mevICzbjcE,2530
|
120
120
|
omdev/git/status.py,sha256=7KKiNSgEa93TsLp54xshwEuVO-3hRiUItBEBnen-8Gg,8111
|
121
121
|
omdev/home/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
122
|
-
omdev/home/
|
123
|
-
omdev/home/
|
124
|
-
omdev/home/
|
122
|
+
omdev/home/paths.py,sha256=3nGs1LOnNiVBtnF3JeKJ0dqnK8uu9KtMiZHWIQuO9RU,774
|
123
|
+
omdev/home/secrets.py,sha256=TeSCcVj1cm8cIQBKbkccNtPa0D0Ruxrcx0QuRwBB4fw,859
|
124
|
+
omdev/home/shadow.py,sha256=r8YQDp_uimeHOejRNi6mHlwgY8J3AEDAwiV_wxeDd4s,284
|
125
125
|
omdev/interp/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
126
126
|
omdev/interp/__main__.py,sha256=GMCqeGYltgt5dlJzHxY9gqisa8cRkrPfmZYuZnjg4WI,162
|
127
127
|
omdev/interp/cli.py,sha256=xVap7jd5EGS-5lKj2bw6EdUf61eI7oPHRAQkMvYci60,2369
|
@@ -149,13 +149,14 @@ omdev/interp/uv/uv.py,sha256=O1fArTkjwddVYyFe0hL1tB2TIUoCX8CD0FCRRfnD9T0,1773
|
|
149
149
|
omdev/magic/__init__.py,sha256=CBzRB71RLyylkrj8dph6JUEddA8KSMJvDgriHqFfJGU,478
|
150
150
|
omdev/magic/__main__.py,sha256=1_BAKDtA6Rn5hswyl4S5J78BPRbynX4is_wQsD0U7jI,161
|
151
151
|
omdev/magic/cli.py,sha256=puL5Snnc-i9Dpa3AU8DtaCp5qUd_7RXwv-qWU_B2fa8,1184
|
152
|
-
omdev/magic/find.py,sha256=
|
152
|
+
omdev/magic/find.py,sha256=bbaKs8VWb6hVRt3me_kaQWzChSuiv-M2cC1YxEkSFlM,6217
|
153
153
|
omdev/magic/magic.py,sha256=h1nxoW6CV1MRCiHjDt3sO4kmG0qTtTRbkDNiPLGo2BE,224
|
154
154
|
omdev/magic/prepare.py,sha256=V5jYT2AeFmazzPwk9sNismSouLwFXEoik6FwKcWCNUY,589
|
155
155
|
omdev/magic/styles.py,sha256=YQ-HgwfvFWPj-o_705E7A-yehEn1G1hRNLPWpeWCK0U,605
|
156
156
|
omdev/manifests/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
157
157
|
omdev/manifests/__main__.py,sha256=JqyVDyV7_jo-NZ3wSs5clDU_xCMlxzJv-XFohoZWQ7E,174
|
158
|
-
omdev/manifests/build.py,sha256=
|
158
|
+
omdev/manifests/build.py,sha256=eVWP1tLKsnG0nLlLW5OiBGwyePLzId4HmE1-_u7N2-s,9995
|
159
|
+
omdev/manifests/dumping.py,sha256=mYXO58oXWQdTIn7A9XTnGv2-3LRPvO_uQmqkwPn9cMw,3470
|
159
160
|
omdev/manifests/main.py,sha256=7zRlyE0BDPqITEbChlTBRGulAvG1nUZPHXrerNExriE,2126
|
160
161
|
omdev/mypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
161
162
|
omdev/mypy/debug.py,sha256=WcZw-3Z1njg_KFGqi3DB6RuqbBa3dLArJnjVCuY1Mn0,3003
|
@@ -214,7 +215,7 @@ omdev/scripts/execrss.py,sha256=mR0G0wERBYtQmVIn63lCIIFb5zkCM6X_XOENDFYDBKc,651
|
|
214
215
|
omdev/scripts/exectime.py,sha256=S2O4MgtzTsFOY2IUJxsrnOIame9tEFc6aOlKP-F1JSg,1541
|
215
216
|
omdev/scripts/importtrace.py,sha256=oa7CtcWJVMNDbyIEiRHej6ICfABfErMeo4_haIqe18Q,14041
|
216
217
|
omdev/scripts/interp.py,sha256=H_WWqQ6ULe5cc976Q_9h2rhNTiKB0vg5PYJGBXWnfFY,150537
|
217
|
-
omdev/scripts/pyproject.py,sha256=
|
218
|
+
omdev/scripts/pyproject.py,sha256=EzOFUuETYkbcv5_p8jaLL-WkiMvAElIveycZFswisqw,258410
|
218
219
|
omdev/scripts/slowcat.py,sha256=lssv4yrgJHiWfOiHkUut2p8E8Tq32zB-ujXESQxFFHY,2728
|
219
220
|
omdev/scripts/tmpexec.py,sha256=WTYcf56Tj2qjYV14AWmV8SfT0u6Y8eIU6cKgQRvEK3c,1442
|
220
221
|
omdev/tokens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -233,13 +234,13 @@ omdev/tools/notebook.py,sha256=q1YMGwM1skHv-dPbtT_cM7UOGFNiMEAxjr6rr6rbobk,3494
|
|
233
234
|
omdev/tools/pip.py,sha256=eBD41hp-V3thGfhUBM3Erxl4CSG-5LG6Szo1sA76P2k,3459
|
234
235
|
omdev/tools/prof.py,sha256=hQakAsViJD4gLJpLLZnTkOqmTDAwM48Nx5q-O_aFlYM,1467
|
235
236
|
omdev/tools/qr.py,sha256=tm68lPwEAkEwIL2sUKPKBYfwwPtjVWG1DBZwur8_jY8,1737
|
236
|
-
omdev/tools/shadow.py,sha256=
|
237
|
+
omdev/tools/shadow.py,sha256=e0-R3Ss9CaZbGSUzSSr29OVj9mUQ-Oelh-66Dfkx5nk,1600
|
237
238
|
omdev/tools/sqlrepl.py,sha256=wAjrfXNrRV63-NJCC2HlGQnFh7lUH0bHMnOjYotQqFs,5753
|
238
239
|
omdev/tools/git/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
239
240
|
omdev/tools/git/__main__.py,sha256=gI87SBUgTkKUcUM-RtZWnei-UUDDqzbr5aPztb-gvbE,168
|
240
|
-
omdev/tools/git/cli.py,sha256=
|
241
|
+
omdev/tools/git/cli.py,sha256=POLpcnlvPgJuW14goo3feAHlEW33s9A-DfKKfUUmego,11771
|
241
242
|
omdev/tools/git/consts.py,sha256=JuXivUNDkNhM4pe97icjRVAKM8cNRbrODquHINNKqOE,40
|
242
|
-
omdev/tools/git/messages.py,sha256=
|
243
|
+
omdev/tools/git/messages.py,sha256=NWztIK0nAKJIOVzuVQcR_5LHZUgqyVkrOlpl7dFLMdU,2424
|
243
244
|
omdev/tools/json/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
244
245
|
omdev/tools/json/__main__.py,sha256=wqpkN_NsQyNwKW4qjVj8ADJ4_C98KhrFBtE-Z1UamfU,168
|
245
246
|
omdev/tools/json/cli.py,sha256=EubIMT-n2XsjWBZjSy2fWXqijlwrIhLsfbkg3SZzi28,9586
|
@@ -251,9 +252,9 @@ omdev/tools/json/rendering.py,sha256=tMcjOW5edfozcMSTxxvF7WVTsbYLoe9bCKFh50qyaGw
|
|
251
252
|
omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
252
253
|
omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
|
253
254
|
omdev/tools/pawk/pawk.py,sha256=zsEkfQX0jF5bn712uqPAyBSdJt2dno1LH2oeSMNfXQI,11424
|
254
|
-
omdev-0.0.0.
|
255
|
-
omdev-0.0.0.
|
256
|
-
omdev-0.0.0.
|
257
|
-
omdev-0.0.0.
|
258
|
-
omdev-0.0.0.
|
259
|
-
omdev-0.0.0.
|
255
|
+
omdev-0.0.0.dev239.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
256
|
+
omdev-0.0.0.dev239.dist-info/METADATA,sha256=3XYXer97Mb0xB0YOeak07aNO9s3G6tkhVUlXbq9ay2E,1636
|
257
|
+
omdev-0.0.0.dev239.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
258
|
+
omdev-0.0.0.dev239.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
|
259
|
+
omdev-0.0.0.dev239.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
|
260
|
+
omdev-0.0.0.dev239.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|