lockss-pybasic 0.1.0.dev23__py3-none-any.whl → 0.2.0.dev2__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.
- lockss/pybasic/__init__.py +1 -1
- lockss/pybasic/cliutil.py +26 -19
- {lockss_pybasic-0.1.0.dev23.dist-info → lockss_pybasic-0.2.0.dev2.dist-info}/METADATA +3 -6
- lockss_pybasic-0.2.0.dev2.dist-info/RECORD +9 -0
- lockss_pybasic-0.1.0.dev23.dist-info/RECORD +0 -9
- {lockss_pybasic-0.1.0.dev23.dist-info → lockss_pybasic-0.2.0.dev2.dist-info}/LICENSE +0 -0
- {lockss_pybasic-0.1.0.dev23.dist-info → lockss_pybasic-0.2.0.dev2.dist-info}/WHEEL +0 -0
lockss/pybasic/__init__.py
CHANGED
lockss/pybasic/cliutil.py
CHANGED
|
@@ -129,22 +129,25 @@ class BaseCli(Generic[BaseModelT]):
|
|
|
129
129
|
|
|
130
130
|
def dispatch(self) -> None:
|
|
131
131
|
"""
|
|
132
|
-
Dispatches from the first field ``x_y_z`` in ``self.
|
|
132
|
+
Dispatches from the first field ``x_y_z`` in ``self._args`` that is a
|
|
133
133
|
command (i.e. whose value derives from ``BaseModel``) to a method
|
|
134
134
|
called ``_x_y_z``.
|
|
135
135
|
"""
|
|
136
|
-
|
|
136
|
+
self._dispatch_recursive(self._args, [])
|
|
137
|
+
|
|
138
|
+
def _dispatch_recursive(self, base_model: BaseModel, subcommands: list[str]) -> None:
|
|
139
|
+
field_names = base_model.__class__.__fields__.keys()
|
|
137
140
|
for field_name in field_names:
|
|
138
|
-
field_value = getattr(
|
|
141
|
+
field_value = getattr(base_model, field_name)
|
|
139
142
|
if issubclass(type(field_value), BaseModel):
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
self._dispatch_recursive(field_value, [*subcommands, field_name])
|
|
144
|
+
return
|
|
145
|
+
func_name = ''.join(f'_{sub}' for sub in subcommands)
|
|
146
|
+
func = getattr(self, func_name)
|
|
147
|
+
if callable(func):
|
|
148
|
+
func(base_model) # FIXME?
|
|
146
149
|
else:
|
|
147
|
-
self._parser.
|
|
150
|
+
self._parser.exit(1, f'internal error: no {func_name} callable for the {" ".join(sub for sub in subcommands)} command')
|
|
148
151
|
|
|
149
152
|
def _initialize_rich_argparse(self) -> None:
|
|
150
153
|
"""
|
|
@@ -176,7 +179,7 @@ class BaseCli(Generic[BaseModelT]):
|
|
|
176
179
|
})
|
|
177
180
|
|
|
178
181
|
|
|
179
|
-
def at_most_one_from_enum(model_cls, values: Dict[str, Any], enum_cls) -> Dict[str, Any]:
|
|
182
|
+
def at_most_one_from_enum(model_cls: type[BaseModel], values: Dict[str, Any], enum_cls) -> Dict[str, Any]:
|
|
180
183
|
"""
|
|
181
184
|
Among the fields of a Pydantic-Argparse model whose ``Field`` definition is
|
|
182
185
|
tagged with the ``enum`` keyword set to the given ``Enum`` type, ensures
|
|
@@ -192,7 +195,7 @@ def at_most_one_from_enum(model_cls, values: Dict[str, Any], enum_cls) -> Dict[s
|
|
|
192
195
|
enum_names = [field_name for field_name, model_field in model_cls.__fields__.items() if model_field.field_info.extra.get('enum') == enum_cls]
|
|
193
196
|
ret = [field_name for field_name in enum_names if values.get(field_name)]
|
|
194
197
|
if (length := len(ret)) > 1:
|
|
195
|
-
raise ValueError(f'at most one of {', '.join([option_name(enum_name) for enum_name in enum_names])} is allowed, got {length} ({', '.join([option_name(enum_name) for enum_name in ret])})')
|
|
198
|
+
raise ValueError(f'at most one of {', '.join([option_name(model_cls, enum_name) for enum_name in enum_names])} is allowed, got {length} ({', '.join([option_name(enum_name) for enum_name in ret])})')
|
|
196
199
|
return values
|
|
197
200
|
|
|
198
201
|
|
|
@@ -216,25 +219,29 @@ def get_from_enum(model_inst, enum_cls, default=None):
|
|
|
216
219
|
return default
|
|
217
220
|
|
|
218
221
|
|
|
219
|
-
def at_most_one(values: Dict[str, Any], *names: str):
|
|
222
|
+
def at_most_one(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
|
|
220
223
|
if (length := _matchy_length(values, *names)) > 1:
|
|
221
|
-
raise ValueError(f'at most one of {', '.join([option_name(name) for name in names])} is allowed, got {length}')
|
|
224
|
+
raise ValueError(f'at most one of {', '.join([option_name(model_cls, name) for name in names])} is allowed, got {length}')
|
|
222
225
|
return values
|
|
223
226
|
|
|
224
227
|
|
|
225
|
-
def exactly_one(values: Dict[str, Any], *names: str):
|
|
228
|
+
def exactly_one(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
|
|
226
229
|
if (length := _matchy_length(values, *names)) != 1:
|
|
227
|
-
raise ValueError(f'exactly one of {', '.join([option_name(name) for name in names])} is required, got {length}')
|
|
230
|
+
raise ValueError(f'exactly one of {', '.join([option_name(model_cls, name) for name in names])} is required, got {length}')
|
|
228
231
|
return values
|
|
229
232
|
|
|
230
233
|
|
|
231
|
-
def one_or_more(values: Dict[str, Any], *names: str):
|
|
234
|
+
def one_or_more(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
|
|
232
235
|
if _matchy_length(values, *names) == 0:
|
|
233
|
-
raise ValueError(f'one or more of {', '.join([option_name(name) for name in names])} is required')
|
|
236
|
+
raise ValueError(f'one or more of {', '.join([option_name(model_cls, name) for name in names])} is required')
|
|
234
237
|
return values
|
|
235
238
|
|
|
236
239
|
|
|
237
|
-
def option_name(name: str) -> str:
|
|
240
|
+
def option_name(model_cls: type[BaseModel], name: str) -> str:
|
|
241
|
+
if (info := model_cls.__fields__.get(name)) is None:
|
|
242
|
+
raise RuntimeError(f'invalid name: {name}')
|
|
243
|
+
if alias := info.alias:
|
|
244
|
+
name = alias
|
|
238
245
|
return f'{('-' if len(name) == 1 else '--')}{name.replace('_', '-')}'
|
|
239
246
|
|
|
240
247
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: lockss-pybasic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0.dev2
|
|
4
4
|
Summary: Basic Python utilities
|
|
5
5
|
License: BSD-3-Clause
|
|
6
6
|
Author: Thib Guicherd-Callin
|
|
@@ -12,12 +12,9 @@ Classifier: Development Status :: 4 - Beta
|
|
|
12
12
|
Classifier: Environment :: Console
|
|
13
13
|
Classifier: Framework :: Pydantic :: 2
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
|
-
Classifier: Intended Audience :: System Administrators
|
|
16
15
|
Classifier: License :: OSI Approved :: BSD License
|
|
17
16
|
Classifier: Programming Language :: Python
|
|
18
17
|
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
-
Classifier: Topic :: System :: Archiving
|
|
20
|
-
Classifier: Topic :: Utilities
|
|
21
18
|
Requires-Dist: pydantic (>=2.11.0,<3.0.0)
|
|
22
19
|
Requires-Dist: pydantic-argparse (>=0.10.0,<0.11.0)
|
|
23
20
|
Requires-Dist: rich-argparse (>=1.7.0,<1.8.0)
|
|
@@ -29,8 +26,8 @@ Description-Content-Type: text/x-rst
|
|
|
29
26
|
lockss-pybasic
|
|
30
27
|
==============
|
|
31
28
|
|
|
32
|
-
.. |RELEASE| replace:: 0.1.0
|
|
33
|
-
.. |RELEASE_DATE| replace::
|
|
29
|
+
.. |RELEASE| replace:: 0.1.0
|
|
30
|
+
.. |RELEASE_DATE| replace:: 2025-07-01
|
|
34
31
|
|
|
35
32
|
**Latest release:** |RELEASE| (|RELEASE_DATE|)
|
|
36
33
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
lockss/pybasic/__init__.py,sha256=5Oqd-wtsasL0pAV0ZY1gPORFhc5DQCAVD4eJgG0J_z8,1678
|
|
2
|
+
lockss/pybasic/cliutil.py,sha256=oJ1j3y816i9Y6VlufP45I2h_k_bgCI51gehkPkuu_jQ,10842
|
|
3
|
+
lockss/pybasic/errorutil.py,sha256=XI84PScZ851_-gfoazivJ8ceieMYWaxQr7qih5ltga0,1951
|
|
4
|
+
lockss/pybasic/fileutil.py,sha256=BpdoPWL70xYTuhyQRBEurScRVnPQg0mX-XW8yyKPGjw,2958
|
|
5
|
+
lockss/pybasic/outpututil.py,sha256=JyXKXlkaCcCGvonUvmDGRdI6PxwN5t7DPVIk64S8-2g,2345
|
|
6
|
+
lockss_pybasic-0.2.0.dev2.dist-info/LICENSE,sha256=O9ONND4uDxY_jucI4jZDf2liAk05ScEJaYu-Al7EOdQ,1506
|
|
7
|
+
lockss_pybasic-0.2.0.dev2.dist-info/METADATA,sha256=PTqTPK5-cGs_NNTcyO6XnsFq4_GFoWeBsYMMvgZ-MdM,4247
|
|
8
|
+
lockss_pybasic-0.2.0.dev2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
9
|
+
lockss_pybasic-0.2.0.dev2.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
lockss/pybasic/__init__.py,sha256=jmOhJI5PiH3jLMWLGSCBYvv8hV2yG9PTPUfvYGtP1oU,1679
|
|
2
|
-
lockss/pybasic/cliutil.py,sha256=Q7WNFbtZzMBfEXjhqsUJlYOdsKYQm0Mgerf7aVe5VK8,10347
|
|
3
|
-
lockss/pybasic/errorutil.py,sha256=XI84PScZ851_-gfoazivJ8ceieMYWaxQr7qih5ltga0,1951
|
|
4
|
-
lockss/pybasic/fileutil.py,sha256=BpdoPWL70xYTuhyQRBEurScRVnPQg0mX-XW8yyKPGjw,2958
|
|
5
|
-
lockss/pybasic/outpututil.py,sha256=JyXKXlkaCcCGvonUvmDGRdI6PxwN5t7DPVIk64S8-2g,2345
|
|
6
|
-
lockss_pybasic-0.1.0.dev23.dist-info/LICENSE,sha256=O9ONND4uDxY_jucI4jZDf2liAk05ScEJaYu-Al7EOdQ,1506
|
|
7
|
-
lockss_pybasic-0.1.0.dev23.dist-info/METADATA,sha256=viCY_etc3kouRMBzEAcl44-zfDWo2Fkzk767I91jBKM,4372
|
|
8
|
-
lockss_pybasic-0.1.0.dev23.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
9
|
-
lockss_pybasic-0.1.0.dev23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|