omdev 0.0.0.dev77__tar.gz → 0.0.0.dev79__tar.gz

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

Potentially problematic release.


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

Files changed (136) hide show
  1. {omdev-0.0.0.dev77/omdev.egg-info → omdev-0.0.0.dev79}/PKG-INFO +4 -4
  2. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/.manifests.json +6 -6
  3. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/__about__.py +1 -1
  4. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/classdot.py +1 -1
  5. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cli/_pathhack.py +1 -1
  6. omdev-0.0.0.dev79/omdev/cli/main.py +288 -0
  7. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/scripts/execrss.py +1 -1
  8. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/scripts/exectime.py +1 -1
  9. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/scripts/importtrace.py +1 -1
  10. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/scripts/interp.py +28 -2
  11. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/scripts/pyproject.py +28 -2
  12. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/importscan.py +1 -1
  13. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/mkrelimp.py +1 -1
  14. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79/omdev.egg-info}/PKG-INFO +4 -4
  15. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev.egg-info/requires.txt +3 -3
  16. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/pyproject.toml +4 -4
  17. omdev-0.0.0.dev77/omdev/cli/main.py +0 -167
  18. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/LICENSE +0 -0
  19. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/MANIFEST.in +0 -0
  20. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/README.rst +0 -0
  21. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/__init__.py +0 -0
  22. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/amalg/__init__.py +0 -0
  23. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/amalg/__main__.py +0 -0
  24. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/amalg/amalg.py +0 -0
  25. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/antlr/__init__.py +0 -0
  26. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/antlr/_antlr/__init__.py +0 -0
  27. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/antlr/consts.py +0 -0
  28. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/antlr/gen.py +0 -0
  29. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/bracepy.py +0 -0
  30. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/__init__.py +0 -0
  31. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/__init__.py +0 -0
  32. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/cache.py +0 -0
  33. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/contexts.py +0 -0
  34. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/currents.py +0 -0
  35. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/fns.py +0 -0
  36. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/resolvers.py +0 -0
  37. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/storage.py +0 -0
  38. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/compute/types.py +0 -0
  39. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/data/__init__.py +0 -0
  40. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/data/actions.py +0 -0
  41. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/data/cache.py +0 -0
  42. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/data/consts.py +0 -0
  43. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/data/defaults.py +0 -0
  44. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/data/manifests.py +0 -0
  45. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cache/data/specs.py +0 -0
  46. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/__init__.py +0 -0
  47. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_boilerplate.cc +0 -0
  48. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/LICENSE +0 -0
  49. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/__init__.py +0 -0
  50. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/build_ext.py +0 -0
  51. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
  52. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
  53. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/compilers/options.py +0 -0
  54. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
  55. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/dir_util.py +0 -0
  56. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/errors.py +0 -0
  57. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/extension.py +0 -0
  58. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/file_util.py +0 -0
  59. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/modified.py +0 -0
  60. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/spawn.py +0 -0
  61. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/sysconfig.py +0 -0
  62. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/util.py +0 -0
  63. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/_distutils/version.py +0 -0
  64. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/build.py +0 -0
  65. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/cmake.py +0 -0
  66. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/importhook.py +0 -0
  67. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/magic.py +0 -0
  68. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cexts/scan.py +0 -0
  69. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cli/__init__.py +0 -0
  70. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cli/__main__.py +0 -0
  71. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cli/clicli.py +0 -0
  72. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cli/install.py +0 -0
  73. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cli/managers.py +0 -0
  74. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cli/types.py +0 -0
  75. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/cmake.py +0 -0
  76. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/findimports.py +0 -0
  77. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/findmagic.py +0 -0
  78. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/git.py +0 -0
  79. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/imgur.py +0 -0
  80. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/__init__.py +0 -0
  81. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/__main__.py +0 -0
  82. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/cli.py +0 -0
  83. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/inspect.py +0 -0
  84. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/providers.py +0 -0
  85. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/pyenv.py +0 -0
  86. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/resolvers.py +0 -0
  87. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/standalone.py +0 -0
  88. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/system.py +0 -0
  89. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/interp/types.py +0 -0
  90. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/manifests/__init__.py +0 -0
  91. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/manifests/build.py +0 -0
  92. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/manifests/load.py +0 -0
  93. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/manifests/types.py +0 -0
  94. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/mypy/__init__.py +0 -0
  95. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/mypy/debug.py +0 -0
  96. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/packaging/__init__.py +0 -0
  97. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/packaging/names.py +0 -0
  98. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/packaging/requires.py +0 -0
  99. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/packaging/specifiers.py +0 -0
  100. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/packaging/versions.py +0 -0
  101. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/precheck/__init__.py +0 -0
  102. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/precheck/__main__.py +0 -0
  103. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/precheck/base.py +0 -0
  104. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/precheck/git.py +0 -0
  105. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/precheck/lite.py +0 -0
  106. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/precheck/precheck.py +0 -0
  107. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/precheck/scripts.py +0 -0
  108. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/pyproject/__init__.py +0 -0
  109. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/pyproject/__main__.py +0 -0
  110. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/pyproject/cexts.py +0 -0
  111. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/pyproject/cli.py +0 -0
  112. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/pyproject/configs.py +0 -0
  113. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/pyproject/pkg.py +0 -0
  114. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/pyproject/reqs.py +0 -0
  115. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/revisions.py +0 -0
  116. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/scripts/__init__.py +0 -0
  117. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/scripts/bumpversion.py +0 -0
  118. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/secrets.py +0 -0
  119. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tokens.py +0 -0
  120. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/toml/__init__.py +0 -0
  121. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/toml/parser.py +0 -0
  122. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/toml/writer.py +0 -0
  123. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/__init__.py +0 -0
  124. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/dockertools.py +0 -0
  125. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/gittools.py +0 -0
  126. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/nbtools.py +0 -0
  127. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/piptools.py +0 -0
  128. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/proftools.py +0 -0
  129. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/rsttool.py +0 -0
  130. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/tools/sqlrepl.py +0 -0
  131. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev/wheelfile.py +0 -0
  132. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev.egg-info/SOURCES.txt +0 -0
  133. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev.egg-info/dependency_links.txt +0 -0
  134. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev.egg-info/entry_points.txt +0 -0
  135. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/omdev.egg-info/top_level.txt +0 -0
  136. {omdev-0.0.0.dev77 → omdev-0.0.0.dev79}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev77
3
+ Version: 0.0.0.dev79
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.dev77
15
+ Requires-Dist: omlish==0.0.0.dev79
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=24.10; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -21,7 +21,7 @@ Requires-Dist: pcpp~=1.30; extra == "all"
21
21
  Requires-Dist: docutils~=0.21; extra == "all"
22
22
  Requires-Dist: mypy~=1.11; extra == "all"
23
23
  Requires-Dist: gprof2dot~=2024.6; extra == "all"
24
- Requires-Dist: tokenize_rt~=6.0; extra == "all"
24
+ Requires-Dist: tokenize_rt~=6.1; extra == "all"
25
25
  Requires-Dist: wheel~=0.44; extra == "all"
26
26
  Provides-Extra: black
27
27
  Requires-Dist: black~=24.10; extra == "black"
@@ -36,6 +36,6 @@ Requires-Dist: mypy~=1.11; extra == "mypy"
36
36
  Provides-Extra: prof
37
37
  Requires-Dist: gprof2dot~=2024.6; extra == "prof"
38
38
  Provides-Extra: tokens
39
- Requires-Dist: tokenize_rt~=6.0; extra == "tokens"
39
+ Requires-Dist: tokenize_rt~=6.1; extra == "tokens"
40
40
  Provides-Extra: wheel
41
41
  Requires-Dist: wheel~=0.44; extra == "wheel"
@@ -30,7 +30,7 @@
30
30
  "line": 62,
31
31
  "value": {
32
32
  "$.cli.types.CliModule": {
33
- "cmd_name": "classdot",
33
+ "cmd_name": "py/classdot",
34
34
  "mod_name": "omdev.classdot"
35
35
  }
36
36
  }
@@ -102,7 +102,7 @@
102
102
  "line": 11,
103
103
  "value": {
104
104
  "$.cli.types.CliModule": {
105
- "cmd_name": "execrss",
105
+ "cmd_name": "py/execrss",
106
106
  "mod_name": "omdev.scripts.execrss"
107
107
  }
108
108
  }
@@ -114,7 +114,7 @@
114
114
  "line": 7,
115
115
  "value": {
116
116
  "$.cli.types.CliModule": {
117
- "cmd_name": "exectime",
117
+ "cmd_name": "py/exectime",
118
118
  "mod_name": "omdev.scripts.exectime"
119
119
  }
120
120
  }
@@ -126,7 +126,7 @@
126
126
  "line": 481,
127
127
  "value": {
128
128
  "$.cli.types.CliModule": {
129
- "cmd_name": "importtrace",
129
+ "cmd_name": "py/importtrace",
130
130
  "mod_name": "omdev.scripts.importtrace"
131
131
  }
132
132
  }
@@ -162,7 +162,7 @@
162
162
  "line": 166,
163
163
  "value": {
164
164
  "$.cli.types.CliModule": {
165
- "cmd_name": "importscan",
165
+ "cmd_name": "py/importscan",
166
166
  "mod_name": "omdev.tools.importscan"
167
167
  }
168
168
  }
@@ -174,7 +174,7 @@
174
174
  "line": 148,
175
175
  "value": {
176
176
  "$.cli.types.CliModule": {
177
- "cmd_name": "mkrelimp",
177
+ "cmd_name": "py/mkrelimp",
178
178
  "mod_name": "omdev.tools.mkrelimp"
179
179
  }
180
180
  }
@@ -35,7 +35,7 @@ class Project(ProjectBase):
35
35
  ],
36
36
 
37
37
  'tokens': [
38
- 'tokenize_rt ~= 6.0',
38
+ 'tokenize_rt ~= 6.1',
39
39
  ],
40
40
 
41
41
  'wheel': [
@@ -60,7 +60,7 @@ def _main() -> None:
60
60
 
61
61
 
62
62
  # @omlish-manifest
63
- _CLI_MODULE = CliModule('classdot', __name__)
63
+ _CLI_MODULE = CliModule('py/classdot', __name__)
64
64
 
65
65
 
66
66
  if __name__ == '__main__':
@@ -2,7 +2,7 @@
2
2
  Python is insistent on prepending sys.path with an empty string (translating to the current working directory), which
3
3
  leads to problems when using the cli in directories containing python packages (such as within this very source tree).
4
4
  This can't be done in cli main as the code frequently spawns other sys.executable processes which wouldn't know to do
5
- that, so a .pth file hack is used. Cleaning sys.path solely there is also insufficient as that code runs before thej
5
+ that, so a .pth file hack is used. Cleaning sys.path solely there is also insufficient as that code runs before the
6
6
  problematic empty string is added, so a sys.meta_path hook is prepended.
7
7
 
8
8
  See:
@@ -0,0 +1,288 @@
1
+ """
2
+ TODO:
3
+ - py/foo - root command 'py'
4
+ - cache ldr.discover() somehow if in uvx/pipx - very slow
5
+ - <venv-root>/.omdev-cli-manifest-cache.json - {pkg_name: manifests_json}
6
+ - allow manually specifying manifest packages
7
+ """
8
+ import argparse
9
+ import dataclasses as dc
10
+ import os
11
+ import runpy
12
+ import sys
13
+ import typing as ta
14
+
15
+ from omlish import check
16
+ from omlish.lite.cached import cached_nullary
17
+
18
+ from ..manifests.load import ManifestLoader
19
+ from .types import CliCmd
20
+ from .types import CliFunc
21
+ from .types import CliModule
22
+
23
+
24
+ ##
25
+
26
+
27
+ def _post_install(cli_pkg: str) -> None:
28
+ from .managers import setup_install_manager
29
+
30
+ setup_install_manager(cli_pkg)
31
+
32
+
33
+ ##
34
+
35
+
36
+ _CLI_FUNCS: ta.Sequence[CliFunc] = [
37
+ CliFunc('_post_install', _post_install),
38
+ ]
39
+
40
+
41
+ ##
42
+
43
+
44
+ StrTuple: ta.TypeAlias = tuple[str, ...]
45
+ RecStrMap: ta.TypeAlias = ta.Mapping[str, ta.Union[str, 'RecStrMap']]
46
+ RecCmdMap: ta.TypeAlias = ta.Mapping[str, ta.Union[CliCmd, 'RecCmdMap']]
47
+
48
+
49
+ class CliCmdSet:
50
+ def __init__(self, cmds: ta.Iterable[CliCmd]) -> None:
51
+ super().__init__()
52
+
53
+ self._cmds = list(cmds)
54
+
55
+ @dc.dataclass(frozen=True)
56
+ class Entry:
57
+ cmd: CliCmd
58
+
59
+ exec_paths: ta.Sequence[StrTuple] # len > 1, len([0]) > 1
60
+ help_path: StrTuple | None
61
+
62
+ def _make_entry(self, cmd: CliCmd) -> Entry:
63
+ help_path: StrTuple | None
64
+
65
+ if isinstance(cmd.cmd_name, str):
66
+ ns = [cmd.cmd_name]
67
+ else:
68
+ ns = list(cmd.cmd_name)
69
+ exec_paths = [tuple(n.split('/')) for n in ns]
70
+
71
+ if isinstance(cmd.cmd_name, str) and cmd.cmd_name[0] == '_':
72
+ help_path = None
73
+
74
+ elif isinstance(cmd, CliFunc):
75
+ help_path = ('-', *exec_paths[0])
76
+
77
+ elif isinstance(cmd, CliModule):
78
+ help_path = (cmd.mod_name.partition('.')[0], *exec_paths[0])
79
+
80
+ else:
81
+ raise TypeError(cmd)
82
+
83
+ return CliCmdSet.Entry(
84
+ cmd,
85
+
86
+ exec_paths=exec_paths,
87
+ help_path=help_path,
88
+ )
89
+
90
+ @cached_nullary
91
+ def entries(self) -> ta.Sequence[Entry]:
92
+ return [self._make_entry(c) for c in self._cmds]
93
+
94
+ @cached_nullary
95
+ def exec_tree(self) -> RecCmdMap:
96
+ d: dict = {}
97
+ for e in self.entries():
98
+ for ep in e.exec_paths:
99
+ c = d
100
+ for p in ep[:-1]:
101
+ n = c.setdefault(p, {})
102
+ if not isinstance(n, dict):
103
+ raise NameError(e) # noqa
104
+ c = n
105
+
106
+ h = ep[-1]
107
+ if h in c:
108
+ raise NameError(e) # noqa
109
+
110
+ c[h] = e.cmd
111
+
112
+ return d
113
+
114
+ @cached_nullary
115
+ def help_tree(self) -> RecStrMap:
116
+ d: dict = {}
117
+ for e in self.entries():
118
+ if not e.help_path:
119
+ continue
120
+
121
+ c = d
122
+ for p in e.help_path[:-1]:
123
+ n = c.setdefault(p, {})
124
+ if not isinstance(n, dict):
125
+ raise NameError(e) # noqa
126
+ c = n
127
+
128
+ h = e.help_path[-1]
129
+ if h in c:
130
+ raise NameError(e)
131
+
132
+ if isinstance(e.cmd.cmd_name, str):
133
+ l = [e.cmd.cmd_name]
134
+ else:
135
+ l = list(e.cmd.cmd_name)
136
+
137
+ s = (
138
+ f'{l[0].split("/")[-1]}'
139
+ f'{(" (" + ", ".join(l[1:]) + ")") if len(l) > 1 else ""}'
140
+ )
141
+
142
+ c[h] = s
143
+
144
+ return d
145
+
146
+ class SelectedCmd(ta.NamedTuple):
147
+ cmd: CliCmd
148
+ args: ta.Sequence[str]
149
+
150
+ class InvalidCmd(ta.NamedTuple):
151
+ path: ta.Sequence[str]
152
+
153
+ def select_cmd(self, args: ta.Sequence[str]) -> SelectedCmd | InvalidCmd:
154
+ check.not_isinstance(args, str)
155
+
156
+ d = self.exec_tree()
157
+ for i in range(len(args)):
158
+ n = args[i]
159
+ if n not in d:
160
+ return CliCmdSet.InvalidCmd(args[:i + 1])
161
+
162
+ c = d[n]
163
+
164
+ if isinstance(c, CliCmd):
165
+ return CliCmdSet.SelectedCmd(c, args[i + 1:])
166
+ elif isinstance(c, ta.Mapping):
167
+ d = c
168
+ else:
169
+ raise TypeError(c)
170
+
171
+ return CliCmdSet.InvalidCmd([])
172
+
173
+
174
+ ##
175
+
176
+
177
+ def _build_arg_parser() -> argparse.ArgumentParser:
178
+ parser = argparse.ArgumentParser()
179
+ parser.add_argument('--cli-pkg-root', action='append')
180
+ parser.add_argument('--cli-debug', action='store_true')
181
+ parser.add_argument('cmd', nargs='?')
182
+ parser.add_argument('args', nargs=argparse.REMAINDER)
183
+ return parser
184
+
185
+
186
+ def _build_cmd_set(args: ta.Any) -> CliCmdSet:
187
+ ldr = ManifestLoader.from_entry_point(globals())
188
+
189
+ pkgs: list[str] = []
190
+
191
+ def scan_pkg_root(r: str) -> None:
192
+ r = os.path.expanduser(r)
193
+ for n in os.listdir(r):
194
+ if os.path.isdir(p := os.path.join(r, n)) and os.path.exists(os.path.join(p, '__init__.py')):
195
+ pkgs.append(n)
196
+
197
+ if args.cli_pkg_root:
198
+ for r in args.cli_pkg_root:
199
+ scan_pkg_root(r)
200
+
201
+ else:
202
+ pkgs.extend(ldr.discover())
203
+
204
+ if not pkgs:
205
+ scan_pkg_root(os.getcwd())
206
+
207
+ #
208
+
209
+ lst: list[CliCmd] = []
210
+
211
+ for m in ldr.load(*pkgs, only=[CliModule]):
212
+ lst.append(check.isinstance(m.value, CliModule))
213
+
214
+ lst.extend(_CLI_FUNCS)
215
+
216
+ #
217
+
218
+ return CliCmdSet(lst)
219
+
220
+
221
+ def _select_cmd(args: ta.Any, cmds: CliCmdSet) -> CliCmdSet.SelectedCmd | int:
222
+ def print_err(*args, **kwargs): # noqa
223
+ print(*args, **kwargs, file=sys.stderr)
224
+
225
+ if args.cmd:
226
+ sel_cmd = cmds.select_cmd([args.cmd, *args.args])
227
+ if isinstance(sel_cmd, CliCmdSet.SelectedCmd):
228
+ return sel_cmd
229
+ elif isinstance(sel_cmd, CliCmdSet.InvalidCmd):
230
+ print_err(f'Invalid command: {" ".join(sel_cmd.path)}\n')
231
+ else:
232
+ raise TypeError(sel_cmd)
233
+ rc = 1
234
+ else:
235
+ rc = 0
236
+
237
+ print_err('Subcommands:\n')
238
+
239
+ def rec(d, pfx=''):
240
+ for k, v in sorted(d.items(), key=lambda t: t[0]):
241
+ if isinstance(v, str):
242
+ print_err(pfx + v)
243
+ else:
244
+ print_err(pfx + k)
245
+ rec(v, pfx + ' ')
246
+ if not pfx:
247
+ print_err('')
248
+
249
+ rec(cmds.help_tree())
250
+
251
+ return rc
252
+
253
+
254
+ def _main() -> ta.Any:
255
+ parser = _build_arg_parser()
256
+ args = parser.parse_args()
257
+
258
+ def inner():
259
+ cmds = _build_cmd_set(args)
260
+ sel = _select_cmd(args, cmds)
261
+
262
+ if isinstance(sel, int):
263
+ return sel
264
+
265
+ cmd = sel.cmd
266
+ if isinstance(cmd, CliModule):
267
+ sys.argv = [args.cmd, *(sel.args or ())]
268
+ runpy._run_module_as_main(cmd.mod_name) # type: ignore # noqa
269
+ return 0
270
+
271
+ elif isinstance(cmd, CliFunc):
272
+ return cmd.fn(*(sel.args or ()))
273
+
274
+ else:
275
+ raise TypeError(cmd)
276
+
277
+ if args.cli_debug:
278
+ from omlish.diag.debug import debugging_on_exception
279
+
280
+ with debugging_on_exception():
281
+ return inner()
282
+
283
+ else:
284
+ return inner()
285
+
286
+
287
+ if __name__ == '__main__':
288
+ sys.exit(rc if isinstance(rc := _main(), int) else 0)
@@ -10,7 +10,7 @@ def _get_rss() -> int:
10
10
 
11
11
  # @omlish-manifest
12
12
  _CLI_MODULE = {'$omdev.cli.types.CliModule': {
13
- 'cmd_name': 'execrss',
13
+ 'cmd_name': 'py/execrss',
14
14
  'mod_name': __name__,
15
15
  }}
16
16
 
@@ -6,7 +6,7 @@ import time
6
6
 
7
7
  # @omlish-manifest
8
8
  _CLI_MODULE = {'$omdev.cli.types.CliModule': {
9
- 'cmd_name': 'exectime',
9
+ 'cmd_name': 'py/exectime',
10
10
  'mod_name': __name__,
11
11
  }}
12
12
 
@@ -480,7 +480,7 @@ class SqliteWriter:
480
480
 
481
481
  # @omlish-manifest
482
482
  _CLI_MODULE = {'$omdev.cli.types.CliModule': {
483
- 'cmd_name': 'importtrace',
483
+ 'cmd_name': 'py/importtrace',
484
484
  'mod_name': __name__,
485
485
  }}
486
486
 
@@ -527,6 +527,23 @@ def check_state(v: bool, msg: str = 'Illegal state') -> None:
527
527
  raise ValueError(msg)
528
528
 
529
529
 
530
+ def check_equal(l: T, r: T) -> T:
531
+ if l != r:
532
+ raise ValueError(l, r)
533
+ return l
534
+
535
+
536
+ def check_not_equal(l: T, r: T) -> T:
537
+ if l == r:
538
+ raise ValueError(l, r)
539
+ return l
540
+
541
+
542
+ def check_single(vs: ta.Iterable[T]) -> T:
543
+ [v] = vs
544
+ return v
545
+
546
+
530
547
  ########################################
531
548
  # ../../../omlish/lite/json.py
532
549
 
@@ -609,8 +626,13 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
609
626
  # ../../../omlish/lite/strings.py
610
627
 
611
628
 
612
- def camel_case(name: str) -> str:
613
- return ''.join(map(str.capitalize, name.split('_'))) # noqa
629
+ def camel_case(name: str, lower: bool = False) -> str:
630
+ if not name:
631
+ return ''
632
+ s = ''.join(map(str.capitalize, name.split('_'))) # noqa
633
+ if lower:
634
+ s = s[0].lower() + s[1:]
635
+ return s
614
636
 
615
637
 
616
638
  def snake_case(name: str) -> str:
@@ -636,6 +658,10 @@ def is_sunder(name: str) -> bool:
636
658
  )
637
659
 
638
660
 
661
+ def attr_repr(obj: ta.Any, *attrs: str) -> str:
662
+ return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
663
+
664
+
639
665
  ########################################
640
666
  # ../../packaging/specifiers.py
641
667
  # Copyright (c) Donald Stufft and individual contributors.
@@ -1908,6 +1908,23 @@ def check_state(v: bool, msg: str = 'Illegal state') -> None:
1908
1908
  raise ValueError(msg)
1909
1909
 
1910
1910
 
1911
+ def check_equal(l: T, r: T) -> T:
1912
+ if l != r:
1913
+ raise ValueError(l, r)
1914
+ return l
1915
+
1916
+
1917
+ def check_not_equal(l: T, r: T) -> T:
1918
+ if l == r:
1919
+ raise ValueError(l, r)
1920
+ return l
1921
+
1922
+
1923
+ def check_single(vs: ta.Iterable[T]) -> T:
1924
+ [v] = vs
1925
+ return v
1926
+
1927
+
1911
1928
  ########################################
1912
1929
  # ../../../omlish/lite/json.py
1913
1930
 
@@ -1990,8 +2007,13 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
1990
2007
  # ../../../omlish/lite/strings.py
1991
2008
 
1992
2009
 
1993
- def camel_case(name: str) -> str:
1994
- return ''.join(map(str.capitalize, name.split('_'))) # noqa
2010
+ def camel_case(name: str, lower: bool = False) -> str:
2011
+ if not name:
2012
+ return ''
2013
+ s = ''.join(map(str.capitalize, name.split('_'))) # noqa
2014
+ if lower:
2015
+ s = s[0].lower() + s[1:]
2016
+ return s
1995
2017
 
1996
2018
 
1997
2019
  def snake_case(name: str) -> str:
@@ -2017,6 +2039,10 @@ def is_sunder(name: str) -> bool:
2017
2039
  )
2018
2040
 
2019
2041
 
2042
+ def attr_repr(obj: ta.Any, *attrs: str) -> str:
2043
+ return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
2044
+
2045
+
2020
2046
  ########################################
2021
2047
  # ../../packaging/specifiers.py
2022
2048
  # Copyright (c) Donald Stufft and individual contributors.
@@ -164,7 +164,7 @@ def run(
164
164
 
165
165
 
166
166
  # @omlish-manifest
167
- _CLI_MODULE = CliModule('importscan', __name__)
167
+ _CLI_MODULE = CliModule('py/importscan', __name__)
168
168
 
169
169
 
170
170
  def _main() -> None:
@@ -146,7 +146,7 @@ class Processor:
146
146
 
147
147
 
148
148
  # @omlish-manifest
149
- _CLI_MODULE = CliModule('mkrelimp', __name__)
149
+ _CLI_MODULE = CliModule('py/mkrelimp', __name__)
150
150
 
151
151
 
152
152
  def _main() -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev77
3
+ Version: 0.0.0.dev79
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.dev77
15
+ Requires-Dist: omlish==0.0.0.dev79
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=24.10; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -21,7 +21,7 @@ Requires-Dist: pcpp~=1.30; extra == "all"
21
21
  Requires-Dist: docutils~=0.21; extra == "all"
22
22
  Requires-Dist: mypy~=1.11; extra == "all"
23
23
  Requires-Dist: gprof2dot~=2024.6; extra == "all"
24
- Requires-Dist: tokenize_rt~=6.0; extra == "all"
24
+ Requires-Dist: tokenize_rt~=6.1; extra == "all"
25
25
  Requires-Dist: wheel~=0.44; extra == "all"
26
26
  Provides-Extra: black
27
27
  Requires-Dist: black~=24.10; extra == "black"
@@ -36,6 +36,6 @@ Requires-Dist: mypy~=1.11; extra == "mypy"
36
36
  Provides-Extra: prof
37
37
  Requires-Dist: gprof2dot~=2024.6; extra == "prof"
38
38
  Provides-Extra: tokens
39
- Requires-Dist: tokenize_rt~=6.0; extra == "tokens"
39
+ Requires-Dist: tokenize_rt~=6.1; extra == "tokens"
40
40
  Provides-Extra: wheel
41
41
  Requires-Dist: wheel~=0.44; extra == "wheel"
@@ -1,4 +1,4 @@
1
- omlish==0.0.0.dev77
1
+ omlish==0.0.0.dev79
2
2
 
3
3
  [all]
4
4
  black~=24.10
@@ -8,7 +8,7 @@ pcpp~=1.30
8
8
  docutils~=0.21
9
9
  mypy~=1.11
10
10
  gprof2dot~=2024.6
11
- tokenize_rt~=6.0
11
+ tokenize_rt~=6.1
12
12
  wheel~=0.44
13
13
 
14
14
  [black]
@@ -29,7 +29,7 @@ mypy~=1.11
29
29
  gprof2dot~=2024.6
30
30
 
31
31
  [tokens]
32
- tokenize_rt~=6.0
32
+ tokenize_rt~=6.1
33
33
 
34
34
  [wheel]
35
35
  wheel~=0.44
@@ -12,7 +12,7 @@ authors = [
12
12
  urls = {source = 'https://github.com/wrmsr/omlish'}
13
13
  license = {text = 'BSD-3-Clause'}
14
14
  requires-python = '~=3.12'
15
- version = '0.0.0.dev77'
15
+ version = '0.0.0.dev79'
16
16
  classifiers = [
17
17
  'License :: OSI Approved :: BSD License',
18
18
  'Development Status :: 2 - Pre-Alpha',
@@ -22,7 +22,7 @@ classifiers = [
22
22
  ]
23
23
  description = 'omdev'
24
24
  dependencies = [
25
- 'omlish == 0.0.0.dev77',
25
+ 'omlish == 0.0.0.dev79',
26
26
  ]
27
27
 
28
28
  [project.optional-dependencies]
@@ -34,7 +34,7 @@ all = [
34
34
  'docutils ~= 0.21',
35
35
  'mypy ~= 1.11',
36
36
  'gprof2dot ~= 2024.6',
37
- 'tokenize_rt ~= 6.0',
37
+ 'tokenize_rt ~= 6.1',
38
38
  'wheel ~= 0.44',
39
39
  ]
40
40
  black = [
@@ -55,7 +55,7 @@ prof = [
55
55
  'gprof2dot ~= 2024.6',
56
56
  ]
57
57
  tokens = [
58
- 'tokenize_rt ~= 6.0',
58
+ 'tokenize_rt ~= 6.1',
59
59
  ]
60
60
  wheel = [
61
61
  'wheel ~= 0.44',