omdev 0.0.0.dev30__py3-none-any.whl → 0.0.0.dev32__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.
@@ -0,0 +1,149 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+ import importlib.machinery
4
+ import importlib.metadata
5
+ import importlib.resources
6
+ import json
7
+ import typing as ta
8
+
9
+ from .types import Manifest
10
+
11
+
12
+ ##
13
+
14
+
15
+ class ManifestLoader:
16
+ def __init__(
17
+ self,
18
+ *,
19
+ module_remap: ta.Optional[ta.Mapping[str, str]] = None,
20
+ ) -> None:
21
+ super().__init__()
22
+
23
+ self._module_remap = module_remap or {}
24
+ self._module_reverse_remap = {v: k for k, v in self._module_remap.items()}
25
+
26
+ self._cls_cache: ta.Dict[str, type] = {}
27
+ self._raw_cache: ta.Dict[str, ta.Optional[ta.Sequence[Manifest]]] = {}
28
+
29
+ @classmethod
30
+ def from_entry_point(
31
+ cls,
32
+ globals: ta.Mapping[str, ta.Any], # noqa
33
+ *,
34
+ module_remap: ta.Optional[ta.Mapping[str, str]] = None,
35
+ **kwargs: ta.Any,
36
+ ) -> 'ManifestLoader':
37
+ rm: ta.Dict[str, str] = {}
38
+
39
+ if module_remap:
40
+ rm.update(module_remap)
41
+
42
+ if '__name__' in globals and '__spec__' in globals:
43
+ name: str = globals['__name__']
44
+ spec: importlib.machinery.ModuleSpec = globals['__spec__']
45
+ if '__main__' not in rm and name == '__main__':
46
+ rm[spec.name] = '__main__'
47
+
48
+ return cls(module_remap=rm, **kwargs)
49
+
50
+ def load_cls(self, key: str) -> type:
51
+ try:
52
+ return self._cls_cache[key]
53
+ except KeyError:
54
+ pass
55
+
56
+ if not key.startswith('$'):
57
+ raise Exception(f'Bad key: {key}')
58
+
59
+ parts = key[1:].split('.')
60
+ pos = next(i for i, p in enumerate(parts) if p[0].isupper())
61
+
62
+ mod_name = '.'.join(parts[:pos])
63
+ mod_name = self._module_remap.get(mod_name, mod_name)
64
+ mod = importlib.import_module(mod_name)
65
+
66
+ obj: ta.Any = mod
67
+ for ca in parts[pos:]:
68
+ obj = getattr(obj, ca)
69
+
70
+ cls = obj
71
+ if not isinstance(cls, type):
72
+ raise TypeError(cls)
73
+
74
+ self._cls_cache[key] = cls
75
+ return cls
76
+
77
+ def load_raw(self, pkg_name: str) -> ta.Optional[ta.Sequence[Manifest]]:
78
+ try:
79
+ return self._raw_cache[pkg_name]
80
+ except KeyError:
81
+ pass
82
+
83
+ t = importlib.resources.files(pkg_name).joinpath('.manifests.json')
84
+ if not t.is_file():
85
+ self._raw_cache[pkg_name] = None
86
+ return None
87
+
88
+ src = t.read_text('utf-8')
89
+ obj = json.loads(src)
90
+ if not isinstance(obj, (list, tuple)):
91
+ raise TypeError(obj)
92
+
93
+ lst: ta.List[Manifest] = []
94
+ for e in obj:
95
+ m = Manifest(**e)
96
+
97
+ m = dc.replace(m, module=pkg_name + m.module)
98
+
99
+ [(key, value_dct)] = m.value.items()
100
+ if not key.startswith('$'):
101
+ raise Exception(f'Bad key: {key}')
102
+ if key.startswith('$.'):
103
+ key = f'${pkg_name}{key[1:]}'
104
+ m = dc.replace(m, value={key: value_dct})
105
+
106
+ lst.append(m)
107
+
108
+ self._raw_cache[pkg_name] = lst
109
+ return lst
110
+
111
+ def load(
112
+ self,
113
+ *pkg_names: str,
114
+ only: ta.Optional[ta.Iterable[type]] = None,
115
+ ) -> ta.Sequence[Manifest]:
116
+ only_keys: ta.Optional[ta.Set]
117
+ if only is not None:
118
+ only_keys = set()
119
+ for cls in only:
120
+ if not (isinstance(cls, type) and dc.is_dataclass(cls)):
121
+ raise TypeError(cls)
122
+ mod_name = cls.__module__
123
+ mod_name = self._module_reverse_remap.get(mod_name, mod_name)
124
+ only_keys.add(f'${mod_name}.{cls.__qualname__}')
125
+ else:
126
+ only_keys = None
127
+
128
+ lst: ta.List[Manifest] = []
129
+ for pn in pkg_names:
130
+ for manifest in (self.load_raw(pn) or []):
131
+ [(key, value_dct)] = manifest.value.items()
132
+ if only_keys is not None and key not in only_keys:
133
+ continue
134
+
135
+ cls = self.load_cls(key)
136
+ value = cls(**value_dct)
137
+
138
+ manifest = dc.replace(manifest, value=value)
139
+ lst.append(manifest)
140
+
141
+ return lst
142
+
143
+ ENTRY_POINT_GROUP = 'omlish.manifests'
144
+
145
+ def discover(self) -> ta.Sequence[str]:
146
+ return [
147
+ ep.value
148
+ for ep in importlib.metadata.entry_points(group=self.ENTRY_POINT_GROUP)
149
+ ]
@@ -0,0 +1,16 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+
5
+ @dc.dataclass(frozen=True)
6
+ class ManifestOrigin:
7
+ module: str
8
+ attr: str
9
+
10
+ file: str
11
+ line: int
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ class Manifest(ManifestOrigin):
16
+ value: ta.Any
@@ -2,6 +2,7 @@
2
2
  Tiny pre-commit
3
3
 
4
4
  TODO:
5
+ - ! manifests
5
6
  - global config
6
7
  - global analyses - FilesWithShebang
7
8
  - shebang files have no relative imports
@@ -26,6 +27,7 @@ import typing as ta
26
27
 
27
28
  from omlish import logs
28
29
 
30
+ from ..cli import CliModule
29
31
  from .base import Precheck
30
32
  from .base import PrecheckContext
31
33
  from .git import GitBlacklistPrecheck
@@ -85,6 +87,10 @@ def _build_parser() -> argparse.ArgumentParser:
85
87
  return parser
86
88
 
87
89
 
90
+ # @omlish-manifest
91
+ _CLI_MODULE = CliModule('precheck', __name__)
92
+
93
+
88
94
  def _main(argv: ta.Sequence[str] | None = None) -> None:
89
95
  logs.configure_standard_logging('INFO')
90
96
 
@@ -1,3 +1,10 @@
1
+ from ..cli import CliModule
2
+
3
+
4
+ # @omlish-manifest
5
+ _CLI_MODULE = CliModule('pyproject', __name__)
6
+
7
+
1
8
  if __name__ == '__main__':
2
9
  from .cli import _main
3
10
 
omdev/pyproject/cli.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- # @omdev-amalg ../scripts/pyproject.py
2
+ # @omlish-amalg ../scripts/pyproject.py
3
3
  # ruff: noqa: UP006 UP007
4
4
  """
5
5
  TODO:
@@ -9,7 +9,7 @@ TODO:
9
9
  - {pkg_name: [src_dirs]}, default excludes, generate MANIFST.in, ...
10
10
  - env vars - PYTHONPATH
11
11
 
12
- lookit:
12
+ See:
13
13
  - https://pdm-project.org/en/latest/
14
14
  - https://rye.astral.sh/philosophy/
15
15
  - https://github.com/indygreg/python-build-standalone/blob/main/pythonbuild/cpython.py
omdev/pyproject/pkg.py CHANGED
@@ -295,7 +295,13 @@ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
295
295
  **extras,
296
296
  }
297
297
 
298
- #
298
+ if (eps := prj.pop('entry_points', None)):
299
+ pyp_dct['project.entry-points'] = {TomlWriter.Literal(f"'{k}'"): v for k, v in eps.items()} # type: ignore # noqa
300
+
301
+ if (scs := prj.pop('scripts', None)):
302
+ pyp_dct['project.scripts'] = scs
303
+
304
+ ##
299
305
 
300
306
  st = dict(specs.setuptools)
301
307
  pyp_dct['tool.setuptools'] = st
@@ -420,7 +426,12 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
420
426
  prj = specs.pyproject
421
427
  prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
422
428
  prj['name'] += self._pkg_suffix
423
- prj.pop('optional_dependencies', None)
429
+ for k in [
430
+ 'optional_dependencies',
431
+ 'entry_points',
432
+ 'scripts',
433
+ ]:
434
+ prj.pop(k, None)
424
435
 
425
436
  pyp_dct['project'] = prj
426
437
 
omdev/pyproject/reqs.py CHANGED
@@ -22,7 +22,7 @@ class RequirementsRewriter:
22
22
  def _tmp_dir(self) -> str:
23
23
  return tempfile.mkdtemp('-omlish-reqs')
24
24
 
25
- VENV_MAGIC = '# @omdev-venv'
25
+ VENV_MAGIC = '# @omlish-venv'
26
26
 
27
27
  def rewrite_file(self, in_file: str) -> str:
28
28
  with open(in_file) as f:
omdev/scripts/interp.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # noinspection DuplicatedCode
3
3
  # @omlish-lite
4
4
  # @omlish-script
5
- # @omdev-amalg-output ../interp/cli.py
5
+ # @omlish-amalg-output ../interp/cli.py
6
6
  # ruff: noqa: N802 UP006 UP007 UP036
7
7
  """
8
8
  TODO:
@@ -1796,6 +1796,11 @@ class RunningInterpProvider(InterpProvider):
1796
1796
  """
1797
1797
  TODO:
1798
1798
  - custom tags
1799
+ - 'aliases'
1800
+ - https://github.com/pyenv/pyenv/pull/2966
1801
+ - https://github.com/pyenv/pyenv/issues/218 (lol)
1802
+ - probably need custom (temp?) definition file
1803
+ - *or* python-build directly just into the versions dir?
1799
1804
  - optionally install / upgrade pyenv itself
1800
1805
  - new vers dont need these custom mac opts, only run on old vers
1801
1806
  """
@@ -1892,8 +1897,33 @@ class PyenvInstallOpts:
1892
1897
  )
1893
1898
 
1894
1899
 
1895
- DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-s', '-v'])
1900
+ # TODO: https://github.com/pyenv/pyenv/blob/master/plugins/python-build/README.md#building-for-maximum-performance
1901
+ DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(
1902
+ opts=[
1903
+ '-s',
1904
+ '-v',
1905
+ '-k',
1906
+ ],
1907
+ conf_opts=[
1908
+ '--enable-loadable-sqlite-extensions',
1909
+
1910
+ # '--enable-shared',
1911
+
1912
+ '--enable-optimizations',
1913
+ '--with-lto',
1914
+
1915
+ # '--enable-profiling', # ?
1916
+
1917
+ # '--enable-ipv6', # ?
1918
+ ],
1919
+ cflags=[
1920
+ # '-march=native',
1921
+ # '-mtune=native',
1922
+ ],
1923
+ )
1924
+
1896
1925
  DEBUG_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-g'])
1926
+
1897
1927
  THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
1898
1928
 
1899
1929
 
@@ -1992,6 +2022,7 @@ class PyenvVersionInstaller:
1992
2022
  opts: ta.Optional[PyenvInstallOpts] = None,
1993
2023
  interp_opts: InterpOpts = InterpOpts(),
1994
2024
  *,
2025
+ install_name: ta.Optional[str] = None,
1995
2026
  no_default_opts: bool = False,
1996
2027
  pyenv: Pyenv = Pyenv(),
1997
2028
  ) -> None:
@@ -2012,6 +2043,7 @@ class PyenvVersionInstaller:
2012
2043
  self._version = version
2013
2044
  self._opts = opts
2014
2045
  self._interp_opts = interp_opts
2046
+ self._given_install_name = install_name
2015
2047
 
2016
2048
  self._no_default_opts = no_default_opts
2017
2049
  self._pyenv = pyenv
@@ -2026,6 +2058,8 @@ class PyenvVersionInstaller:
2026
2058
 
2027
2059
  @cached_nullary
2028
2060
  def install_name(self) -> str:
2061
+ if self._given_install_name is not None:
2062
+ return self._given_install_name
2029
2063
  return self._version + ('-debug' if self._interp_opts.debug else '')
2030
2064
 
2031
2065
  @cached_nullary
@@ -2045,11 +2079,26 @@ class PyenvVersionInstaller:
2045
2079
  v += ' ' + os.environ[k]
2046
2080
  env[k] = v
2047
2081
 
2048
- subprocess_check_call(
2049
- self._pyenv.exe(),
2050
- 'install',
2082
+ conf_args = [
2051
2083
  *self._opts.opts,
2052
2084
  self._version,
2085
+ ]
2086
+
2087
+ if self._given_install_name is not None:
2088
+ full_args = [
2089
+ os.path.join(check_not_none(self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'),
2090
+ *conf_args,
2091
+ self.install_dir(),
2092
+ ]
2093
+ else:
2094
+ full_args = [
2095
+ self._pyenv.exe(),
2096
+ 'install',
2097
+ *conf_args,
2098
+ ]
2099
+
2100
+ subprocess_check_call(
2101
+ *full_args,
2053
2102
  env=env,
2054
2103
  )
2055
2104
 
@@ -2407,9 +2456,13 @@ def _list_cmd(args) -> None:
2407
2456
 
2408
2457
 
2409
2458
  def _resolve_cmd(args) -> None:
2410
- r = DEFAULT_INTERP_RESOLVER
2459
+ if args.provider:
2460
+ p = INTERP_PROVIDER_TYPES_BY_NAME[args.provider]()
2461
+ r = InterpResolver([(p.name, p)])
2462
+ else:
2463
+ r = DEFAULT_INTERP_RESOLVER
2411
2464
  s = InterpSpecifier.parse(args.version)
2412
- print(check_not_none(r.resolve(s)).exe)
2465
+ print(check_not_none(r.resolve(s, install=bool(args.install))).exe)
2413
2466
 
2414
2467
 
2415
2468
  def _build_parser() -> argparse.ArgumentParser:
@@ -2419,12 +2472,14 @@ def _build_parser() -> argparse.ArgumentParser:
2419
2472
 
2420
2473
  parser_list = subparsers.add_parser('list')
2421
2474
  parser_list.add_argument('version')
2422
- parser_list.add_argument('--debug', action='store_true')
2475
+ parser_list.add_argument('-d', '--debug', action='store_true')
2423
2476
  parser_list.set_defaults(func=_list_cmd)
2424
2477
 
2425
2478
  parser_resolve = subparsers.add_parser('resolve')
2426
2479
  parser_resolve.add_argument('version')
2427
- parser_resolve.add_argument('--debug', action='store_true')
2480
+ parser_resolve.add_argument('-p', '--provider')
2481
+ parser_resolve.add_argument('-d', '--debug', action='store_true')
2482
+ parser_resolve.add_argument('-i', '--install', action='store_true')
2428
2483
  parser_resolve.set_defaults(func=_resolve_cmd)
2429
2484
 
2430
2485
  return parser
@@ -2,7 +2,7 @@
2
2
  # noinspection DuplicatedCode
3
3
  # @omlish-lite
4
4
  # @omlish-script
5
- # @omdev-amalg-output ../pyproject/cli.py
5
+ # @omlish-amalg-output ../pyproject/cli.py
6
6
  # ruff: noqa: N802 TCH003 UP006 UP007 UP036
7
7
  """
8
8
  TODO:
@@ -12,7 +12,7 @@ TODO:
12
12
  - {pkg_name: [src_dirs]}, default excludes, generate MANIFST.in, ...
13
13
  - env vars - PYTHONPATH
14
14
 
15
- lookit:
15
+ See:
16
16
  - https://pdm-project.org/en/latest/
17
17
  - https://rye.astral.sh/philosophy/
18
18
  - https://github.com/indygreg/python-build-standalone/blob/main/pythonbuild/cpython.py
@@ -104,7 +104,7 @@ CallableVersionOperator = ta.Callable[['Version', str], bool]
104
104
 
105
105
 
106
106
  class CextMagic:
107
- MAGIC = '@omdev-cext'
107
+ MAGIC = '@omlish-cext'
108
108
  MAGIC_COMMENT = f'// {MAGIC}'
109
109
 
110
110
  FILE_EXTENSIONS = ('c', 'cc', 'cpp')
@@ -1089,6 +1089,10 @@ def toml_make_safe_parse_float(parse_float: TomlParseFloat) -> TomlParseFloat:
1089
1089
 
1090
1090
 
1091
1091
  class TomlWriter:
1092
+ @dc.dataclass(frozen=True)
1093
+ class Literal:
1094
+ s: str
1095
+
1092
1096
  def __init__(self, out: ta.TextIO) -> None:
1093
1097
  super().__init__()
1094
1098
  self._out = out
@@ -1170,7 +1174,9 @@ class TomlWriter:
1170
1174
  self._w(']')
1171
1175
 
1172
1176
  def write_key(self, obj: ta.Any) -> None:
1173
- if isinstance(obj, str):
1177
+ if isinstance(obj, TomlWriter.Literal):
1178
+ self._w(obj.s)
1179
+ elif isinstance(obj, str):
1174
1180
  self._w(self._maybe_quote(obj.replace('_', '-')))
1175
1181
  elif isinstance(obj, int):
1176
1182
  self._w(repr(str(obj)))
@@ -2022,7 +2028,7 @@ class RequirementsRewriter:
2022
2028
  def _tmp_dir(self) -> str:
2023
2029
  return tempfile.mkdtemp('-omlish-reqs')
2024
2030
 
2025
- VENV_MAGIC = '# @omdev-venv'
2031
+ VENV_MAGIC = '# @omlish-venv'
2026
2032
 
2027
2033
  def rewrite_file(self, in_file: str) -> str:
2028
2034
  with open(in_file) as f:
@@ -3977,7 +3983,13 @@ class PyprojectPackageGenerator(BasePyprojectPackageGenerator):
3977
3983
  **extras,
3978
3984
  }
3979
3985
 
3980
- #
3986
+ if (eps := prj.pop('entry_points', None)):
3987
+ pyp_dct['project.entry-points'] = {TomlWriter.Literal(f"'{k}'"): v for k, v in eps.items()} # type: ignore # noqa
3988
+
3989
+ if (scs := prj.pop('scripts', None)):
3990
+ pyp_dct['project.scripts'] = scs
3991
+
3992
+ ##
3981
3993
 
3982
3994
  st = dict(specs.setuptools)
3983
3995
  pyp_dct['tool.setuptools'] = st
@@ -4102,7 +4114,12 @@ class _PyprojectCextPackageGenerator(BasePyprojectPackageGenerator):
4102
4114
  prj = specs.pyproject
4103
4115
  prj['dependencies'] = [f'{prj["name"]} == {prj["version"]}']
4104
4116
  prj['name'] += self._pkg_suffix
4105
- prj.pop('optional_dependencies', None)
4117
+ for k in [
4118
+ 'optional_dependencies',
4119
+ 'entry_points',
4120
+ 'scripts',
4121
+ ]:
4122
+ prj.pop(k, None)
4106
4123
 
4107
4124
  pyp_dct['project'] = prj
4108
4125
 
@@ -4233,6 +4250,11 @@ class RunningInterpProvider(InterpProvider):
4233
4250
  """
4234
4251
  TODO:
4235
4252
  - custom tags
4253
+ - 'aliases'
4254
+ - https://github.com/pyenv/pyenv/pull/2966
4255
+ - https://github.com/pyenv/pyenv/issues/218 (lol)
4256
+ - probably need custom (temp?) definition file
4257
+ - *or* python-build directly just into the versions dir?
4236
4258
  - optionally install / upgrade pyenv itself
4237
4259
  - new vers dont need these custom mac opts, only run on old vers
4238
4260
  """
@@ -4329,8 +4351,33 @@ class PyenvInstallOpts:
4329
4351
  )
4330
4352
 
4331
4353
 
4332
- DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-s', '-v'])
4354
+ # TODO: https://github.com/pyenv/pyenv/blob/master/plugins/python-build/README.md#building-for-maximum-performance
4355
+ DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(
4356
+ opts=[
4357
+ '-s',
4358
+ '-v',
4359
+ '-k',
4360
+ ],
4361
+ conf_opts=[
4362
+ '--enable-loadable-sqlite-extensions',
4363
+
4364
+ # '--enable-shared',
4365
+
4366
+ '--enable-optimizations',
4367
+ '--with-lto',
4368
+
4369
+ # '--enable-profiling', # ?
4370
+
4371
+ # '--enable-ipv6', # ?
4372
+ ],
4373
+ cflags=[
4374
+ # '-march=native',
4375
+ # '-mtune=native',
4376
+ ],
4377
+ )
4378
+
4333
4379
  DEBUG_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-g'])
4380
+
4334
4381
  THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
4335
4382
 
4336
4383
 
@@ -4429,6 +4476,7 @@ class PyenvVersionInstaller:
4429
4476
  opts: ta.Optional[PyenvInstallOpts] = None,
4430
4477
  interp_opts: InterpOpts = InterpOpts(),
4431
4478
  *,
4479
+ install_name: ta.Optional[str] = None,
4432
4480
  no_default_opts: bool = False,
4433
4481
  pyenv: Pyenv = Pyenv(),
4434
4482
  ) -> None:
@@ -4449,6 +4497,7 @@ class PyenvVersionInstaller:
4449
4497
  self._version = version
4450
4498
  self._opts = opts
4451
4499
  self._interp_opts = interp_opts
4500
+ self._given_install_name = install_name
4452
4501
 
4453
4502
  self._no_default_opts = no_default_opts
4454
4503
  self._pyenv = pyenv
@@ -4463,6 +4512,8 @@ class PyenvVersionInstaller:
4463
4512
 
4464
4513
  @cached_nullary
4465
4514
  def install_name(self) -> str:
4515
+ if self._given_install_name is not None:
4516
+ return self._given_install_name
4466
4517
  return self._version + ('-debug' if self._interp_opts.debug else '')
4467
4518
 
4468
4519
  @cached_nullary
@@ -4482,11 +4533,26 @@ class PyenvVersionInstaller:
4482
4533
  v += ' ' + os.environ[k]
4483
4534
  env[k] = v
4484
4535
 
4485
- subprocess_check_call(
4486
- self._pyenv.exe(),
4487
- 'install',
4536
+ conf_args = [
4488
4537
  *self._opts.opts,
4489
4538
  self._version,
4539
+ ]
4540
+
4541
+ if self._given_install_name is not None:
4542
+ full_args = [
4543
+ os.path.join(check_not_none(self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'),
4544
+ *conf_args,
4545
+ self.install_dir(),
4546
+ ]
4547
+ else:
4548
+ full_args = [
4549
+ self._pyenv.exe(),
4550
+ 'install',
4551
+ *conf_args,
4552
+ ]
4553
+
4554
+ subprocess_check_call(
4555
+ *full_args,
4490
4556
  env=env,
4491
4557
  )
4492
4558
 
omdev/secrets.py ADDED
@@ -0,0 +1,12 @@
1
+ import os.path
2
+ import typing as ta
3
+
4
+ import yaml
5
+
6
+
7
+ SECRETS_PATH = os.getenv('SECRETS_PATH', os.path.expanduser('~/Dropbox/.dotfiles/secrets.yml'))
8
+
9
+
10
+ def load_secrets() -> dict[str, ta.Any]:
11
+ with open(SECRETS_PATH) as f:
12
+ return yaml.safe_load(f)
omdev/toml/writer.py CHANGED
@@ -1,8 +1,13 @@
1
+ import dataclasses as dc
1
2
  import string
2
3
  import typing as ta
3
4
 
4
5
 
5
6
  class TomlWriter:
7
+ @dc.dataclass(frozen=True)
8
+ class Literal:
9
+ s: str
10
+
6
11
  def __init__(self, out: ta.TextIO) -> None:
7
12
  super().__init__()
8
13
  self._out = out
@@ -84,7 +89,9 @@ class TomlWriter:
84
89
  self._w(']')
85
90
 
86
91
  def write_key(self, obj: ta.Any) -> None:
87
- if isinstance(obj, str):
92
+ if isinstance(obj, TomlWriter.Literal):
93
+ self._w(obj.s)
94
+ elif isinstance(obj, str):
88
95
  self._w(self._maybe_quote(obj.replace('_', '-')))
89
96
  elif isinstance(obj, int):
90
97
  self._w(repr(str(obj)))
@@ -14,6 +14,8 @@ from omlish import lang
14
14
  from omlish import logs
15
15
  from omlish.formats import yaml
16
16
 
17
+ from ..cli import CliModule
18
+
17
19
 
18
20
  @lang.cached_function
19
21
  def docker_exe() -> str:
@@ -178,6 +180,10 @@ class Cli(ap.Cli):
178
180
  f.write(new_src)
179
181
 
180
182
 
183
+ # @omlish-manifest
184
+ _CLI_MODULE = CliModule('docker', __name__)
185
+
186
+
181
187
  if __name__ == '__main__':
182
188
  logs.configure_standard_logging('INFO')
183
189
  Cli()()
omdev/tools/gittools.py CHANGED
@@ -3,6 +3,8 @@ import subprocess
3
3
  from omlish import argparse as ap
4
4
  from omlish import logs
5
5
 
6
+ from ..cli import CliModule
7
+
6
8
 
7
9
  class Cli(ap.Cli):
8
10
  @ap.command()
@@ -17,6 +19,10 @@ class Cli(ap.Cli):
17
19
  )
18
20
 
19
21
 
22
+ # @omlish-manifest
23
+ _CLI_MODULE = CliModule('git', __name__)
24
+
25
+
20
26
  if __name__ == '__main__':
21
27
  logs.configure_standard_logging('INFO')
22
28
  Cli()()
omdev/tools/piptools.py CHANGED
@@ -5,6 +5,8 @@ import xml.etree.ElementTree as ET # noqa
5
5
  from omlish import argparse as ap
6
6
  from omlish import check
7
7
 
8
+ from ..cli import CliModule
9
+
8
10
 
9
11
  PYPI_URL = 'https://pypi.org/'
10
12
 
@@ -46,5 +48,9 @@ class Cli(ap.Cli):
46
48
  f.write(new_src)
47
49
 
48
50
 
51
+ # @omlish-manifest
52
+ _CLI_MODULE = CliModule('pip', __name__)
53
+
54
+
49
55
  if __name__ == '__main__':
50
56
  Cli()()