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 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": 77,
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": 63,
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 get_home_dir
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(os.getenv(SECRETS_FILE_ENV_VAR, os.path.join(get_home_dir(), DEFAULT_SECRETS_FILE_NAME)))
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 get_home_dir
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
- os.path.join(get_home_dir(), 'shadow'),
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
- out.append(magic)
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
- def _dump_module_manifests(spec: str, *attrs: str) -> None:
50
- import collections.abc
51
- import dataclasses as dc # noqa
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
- out = {}
58
- for attr in attrs:
59
- manifest = getattr(mod, attr)
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
- rt_manifest = cls(**manifest_dct) # type: ignore
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
- elif isinstance(manifest, collections.abc.Mapping):
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(_dump_module_manifests)
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
- origins.append(ManifestOrigin(
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=m.groupdict()['name'],
189
+ attr=attr_name,
155
190
 
156
191
  file=file,
157
- line=i + 1,
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'_dump_module_manifests({mod_name!r}, {", ".join(repr(a) for a in attrs)})\n',
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
- dct = json.loads(sp_lines[0])
199
- if set(dct) != set(attrs):
200
- raise Exception('Unexpected subprocess output keys')
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
- for o in origins:
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'Manifests must be mappings of strings starting with $: {value!r}')
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
- **dc.asdict(o),
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 io
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("/")}/rss/project/{pkg_name}/releases.xml') as resp: # noqa
34
- rss = resp.read()
35
- doc = ET.parse(io.BytesIO(rss)) # noqa
36
- latest = check.not_none(doc.find('./channel/item/title')).text
37
- return check.non_empty_str(latest)
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
  ##
@@ -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
- out.append(magic)
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.configs import get_shadow_configs
25
- from ...home.paths import get_home_dir
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(get_home_dir(), 'tools', 'git.yml')
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:
@@ -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 = GitMessageGeneratorManifest(
79
- mod_name=__name__,
80
- attr_name='TimestampGitMessageGenerator',
81
- name='timestamp',
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.configs import get_shadow_configs
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.dev237
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.dev237
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=LmJlGLGHC1icR876hQcV2MUvKNnAglRKeIO6uBV2Wx0,9798
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=7cZ_IOpekQvgPm_gKnX3Pr8xjqUid50PPScTlZCYVlM,2118
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/configs.py,sha256=Vg7fo6UuhMxhW_6pPg-jgVysJBpQJpLPTkJ8wHl2W_c,315
123
- omdev/home/paths.py,sha256=UJMIIxvDooOOJpCjfN4gn038BtPTGXWZ-prr3NeWbLY,402
124
- omdev/home/secrets.py,sha256=a460IvsgaJoaeXMnhcsvi11g15rrg8QhPQUcZTxFbs0,800
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=lnVWO4Ux0BkatBihVloZ7XrsOJ4Tsc-YRhGd4ENL3Ro,6037
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=yX0QM6c60aauiF-8oDxrXhkrhhwHcRw_qft_IIW6LD8,8767
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=6g3NmQfUaxtLhEizAEyewmuhjlEyQht_u9QTIkWMeJs,258230
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=a22OMBqVa35UAdhjp54FtEaNcn5OAhgNLY4Yn-tcelk,1578
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=g1ViLqisliuQbacZg3Vr3MaMd4Acxlv79L8pqv8aMTI,11768
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=jrZuKtE8Nbb-E_FqkiOuUEHypix-rzJqmTln5iPcYMk,2232
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.dev237.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
255
- omdev-0.0.0.dev237.dist-info/METADATA,sha256=WskhQEERuCpPSMzmgF-CsyuZZtG4T3_IucEwfalGb_E,1636
256
- omdev-0.0.0.dev237.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
257
- omdev-0.0.0.dev237.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
258
- omdev-0.0.0.dev237.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
259
- omdev-0.0.0.dev237.dist-info/RECORD,,
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,,