lockss-pybasic 0.2.0.dev7__py3-none-any.whl → 0.2.0.dev8__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 +70 -7
- {lockss_pybasic-0.2.0.dev7.dist-info → lockss_pybasic-0.2.0.dev8.dist-info}/METADATA +6 -5
- lockss_pybasic-0.2.0.dev8.dist-info/RECORD +10 -0
- lockss_pybasic-0.2.0.dev7.dist-info/RECORD +0 -10
- {lockss_pybasic-0.2.0.dev7.dist-info → lockss_pybasic-0.2.0.dev8.dist-info}/WHEEL +0 -0
- {lockss_pybasic-0.2.0.dev7.dist-info → lockss_pybasic-0.2.0.dev8.dist-info}/licenses/LICENSE +0 -0
lockss/pybasic/__init__.py
CHANGED
lockss/pybasic/cliutil.py
CHANGED
|
@@ -31,18 +31,21 @@
|
|
|
31
31
|
"""
|
|
32
32
|
Command line utilities.
|
|
33
33
|
"""
|
|
34
|
-
|
|
34
|
+
import pathlib
|
|
35
35
|
from collections.abc import Callable
|
|
36
36
|
import sys
|
|
37
37
|
from typing import Any, Dict, Generic, Optional, TypeVar
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
import click
|
|
40
|
+
from pydantic.v1 import BaseModel as BaseModel1
|
|
40
41
|
from pydantic_argparse import ArgumentParser
|
|
41
42
|
from pydantic_argparse.argparse.actions import SubParsersAction
|
|
42
43
|
from rich_argparse import RichHelpFormatter
|
|
43
44
|
|
|
45
|
+
from .fileutil import path
|
|
46
|
+
|
|
44
47
|
|
|
45
|
-
class ActionCommand(Callable,
|
|
48
|
+
class ActionCommand(Callable, BaseModel1):
|
|
46
49
|
"""
|
|
47
50
|
Base class for a pydantic-argparse style command.
|
|
48
51
|
"""
|
|
@@ -77,7 +80,7 @@ LICENSE_DESCRIPTION = 'print the software license and exit'
|
|
|
77
80
|
VERSION_DESCRIPTION = 'print the version number and exit'
|
|
78
81
|
|
|
79
82
|
|
|
80
|
-
BaseModelT = TypeVar('BaseModelT', bound=
|
|
83
|
+
BaseModelT = TypeVar('BaseModelT', bound=BaseModel1)
|
|
81
84
|
|
|
82
85
|
|
|
83
86
|
class BaseCli(Generic[BaseModelT]):
|
|
@@ -135,11 +138,11 @@ class BaseCli(Generic[BaseModelT]):
|
|
|
135
138
|
"""
|
|
136
139
|
self._dispatch_recursive(self._args, [])
|
|
137
140
|
|
|
138
|
-
def _dispatch_recursive(self, base_model:
|
|
141
|
+
def _dispatch_recursive(self, base_model: BaseModel1, subcommands: list[str]) -> None:
|
|
139
142
|
field_names = base_model.__class__.__fields__.keys()
|
|
140
143
|
for field_name in field_names:
|
|
141
144
|
field_value = getattr(base_model, field_name)
|
|
142
|
-
if issubclass(type(field_value),
|
|
145
|
+
if issubclass(type(field_value), BaseModel1):
|
|
143
146
|
self._dispatch_recursive(field_value, [*subcommands, field_name])
|
|
144
147
|
return
|
|
145
148
|
func_name = ''.join(f'_{sub}' for sub in subcommands)
|
|
@@ -237,7 +240,7 @@ def one_or_more(values: Dict[str, Any], *names: str):
|
|
|
237
240
|
return values
|
|
238
241
|
|
|
239
242
|
|
|
240
|
-
def option_name(model_cls: type[
|
|
243
|
+
def option_name(model_cls: type[BaseModel1], name: str) -> str:
|
|
241
244
|
if (info := model_cls.__fields__.get(name)) is None:
|
|
242
245
|
raise RuntimeError(f'invalid name: {name}')
|
|
243
246
|
if alias := info.alias:
|
|
@@ -247,3 +250,63 @@ def option_name(model_cls: type[BaseModel], name: str) -> str:
|
|
|
247
250
|
|
|
248
251
|
def _matchy_length(values: Dict[str, Any], *names: str) -> int:
|
|
249
252
|
return len([name for name in names if values.get(name)])
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def click_path(spec: Optional[str]) -> click.Path:
|
|
256
|
+
if spec is None:
|
|
257
|
+
spec = ''
|
|
258
|
+
allow_dash = False
|
|
259
|
+
dir_okay = True
|
|
260
|
+
executable = False
|
|
261
|
+
exists = False
|
|
262
|
+
file_okay = True
|
|
263
|
+
path_type = path
|
|
264
|
+
readable = True
|
|
265
|
+
resolve_path = False
|
|
266
|
+
writable = False
|
|
267
|
+
for char in spec:
|
|
268
|
+
if char == 'd':
|
|
269
|
+
if 'f' in spec:
|
|
270
|
+
raise ValueError(f'"d" and "f" are mutually exclusive: {spec}')
|
|
271
|
+
dir_okay = True
|
|
272
|
+
file_okay = False
|
|
273
|
+
elif char == 'e':
|
|
274
|
+
exists = True
|
|
275
|
+
elif char == 'f':
|
|
276
|
+
if 'd' in spec:
|
|
277
|
+
raise ValueError(f'"f" and "d" are mutually exclusive: {spec}')
|
|
278
|
+
dir_okay = False
|
|
279
|
+
file_okay = True
|
|
280
|
+
elif char == 'p':
|
|
281
|
+
if 'P' in spec or 's' in spec:
|
|
282
|
+
raise ValueError(f'"p", "P", and "s" are mutually exclusive: {spec}')
|
|
283
|
+
path_type = path
|
|
284
|
+
elif char == 'P':
|
|
285
|
+
if 'p' in spec or 's' in spec:
|
|
286
|
+
raise ValueError(f'"P", "p", and "s" are mutually exclusive: {spec}')
|
|
287
|
+
path_type = pathlib.Path
|
|
288
|
+
elif char == 'r':
|
|
289
|
+
readable = True
|
|
290
|
+
elif char == 's':
|
|
291
|
+
if 'p' in spec or 'P' in spec:
|
|
292
|
+
raise ValueError(f'"s", "p", and "P" are mutually exclusive: {spec}')
|
|
293
|
+
path_type = str
|
|
294
|
+
elif char == 'w':
|
|
295
|
+
writable = True
|
|
296
|
+
elif char == 'x':
|
|
297
|
+
executable = True
|
|
298
|
+
elif char == 'z':
|
|
299
|
+
resolve_path = True
|
|
300
|
+
elif char == '-':
|
|
301
|
+
allow_dash = True
|
|
302
|
+
else:
|
|
303
|
+
raise ValueError(f'unknown specification character "{char}": {spec}')
|
|
304
|
+
return click.Path(allow_dash=allow_dash,
|
|
305
|
+
dir_okay=dir_okay,
|
|
306
|
+
executable=executable,
|
|
307
|
+
exists=exists,
|
|
308
|
+
file_okay=file_okay,
|
|
309
|
+
path_type=path_type,
|
|
310
|
+
readable=readable,
|
|
311
|
+
resolve_path=resolve_path,
|
|
312
|
+
writable=writable)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lockss-pybasic
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev8
|
|
4
4
|
Summary: Basic Python utilities
|
|
5
5
|
License: BSD-3-Clause
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,7 +8,7 @@ Author: Thib Guicherd-Callin
|
|
|
8
8
|
Author-email: thib@cs.stanford.edu
|
|
9
9
|
Maintainer: Thib Guicherd-Callin
|
|
10
10
|
Maintainer-email: thib@cs.stanford.edu
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.10,<4.0
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Framework :: Pydantic :: 2
|
|
@@ -16,7 +16,8 @@ Classifier: Intended Audience :: Developers
|
|
|
16
16
|
Classifier: License :: OSI Approved :: BSD License
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
-
Requires-Dist:
|
|
19
|
+
Requires-Dist: click-extra (>=7.5.0,<7.6.0)
|
|
20
|
+
Requires-Dist: pydantic (>=2.11.0,<2.12.0)
|
|
20
21
|
Requires-Dist: pydantic-argparse (>=0.10.0,<0.11.0)
|
|
21
22
|
Requires-Dist: rich-argparse (>=1.7.0,<1.8.0)
|
|
22
23
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
@@ -27,8 +28,8 @@ Description-Content-Type: text/x-rst
|
|
|
27
28
|
lockss-pybasic
|
|
28
29
|
==============
|
|
29
30
|
|
|
30
|
-
.. |RELEASE| replace:: 0.
|
|
31
|
-
.. |RELEASE_DATE| replace::
|
|
31
|
+
.. |RELEASE| replace:: 0.2.0-dev8
|
|
32
|
+
.. |RELEASE_DATE| replace:: NOT YET RELEASED
|
|
32
33
|
|
|
33
34
|
**Latest release:** |RELEASE| (|RELEASE_DATE|)
|
|
34
35
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
lockss/pybasic/__init__.py,sha256=A-Y9xGDnzeI7ZG2J4KT3DCP7lDVCAzlvJ1dJD87420E,1678
|
|
2
|
+
lockss/pybasic/auidutil.py,sha256=o5IsRLEYROXRVS6oTO1VFtdzw7SImYSR5VcqAMHY4To,13921
|
|
3
|
+
lockss/pybasic/cliutil.py,sha256=vf8lxc-m6p6if5D7uWIBynIxvCiG6uZg44pHCMSiSzs,12866
|
|
4
|
+
lockss/pybasic/errorutil.py,sha256=XI84PScZ851_-gfoazivJ8ceieMYWaxQr7qih5ltga0,1951
|
|
5
|
+
lockss/pybasic/fileutil.py,sha256=BpdoPWL70xYTuhyQRBEurScRVnPQg0mX-XW8yyKPGjw,2958
|
|
6
|
+
lockss/pybasic/outpututil.py,sha256=8naQEZ1rM6vOFNL-9mWoK4dMBWokHmzQ0FkHaz8dyuM,2345
|
|
7
|
+
lockss_pybasic-0.2.0.dev8.dist-info/METADATA,sha256=xucIusdQQSQBwgcbNN2uS-6nb4hHDzBMxh_0m1_B7rs,4326
|
|
8
|
+
lockss_pybasic-0.2.0.dev8.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
9
|
+
lockss_pybasic-0.2.0.dev8.dist-info/licenses/LICENSE,sha256=O9ONND4uDxY_jucI4jZDf2liAk05ScEJaYu-Al7EOdQ,1506
|
|
10
|
+
lockss_pybasic-0.2.0.dev8.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
lockss/pybasic/__init__.py,sha256=zBCFbOy0mzMxX4ofmKT5pq7i2s5bTNX5ECUCi02W2M4,1678
|
|
2
|
-
lockss/pybasic/auidutil.py,sha256=o5IsRLEYROXRVS6oTO1VFtdzw7SImYSR5VcqAMHY4To,13921
|
|
3
|
-
lockss/pybasic/cliutil.py,sha256=BFOijSrTByMHno3bbDmtICLQfREJpD7lVGUAuzvrHBY,10697
|
|
4
|
-
lockss/pybasic/errorutil.py,sha256=XI84PScZ851_-gfoazivJ8ceieMYWaxQr7qih5ltga0,1951
|
|
5
|
-
lockss/pybasic/fileutil.py,sha256=BpdoPWL70xYTuhyQRBEurScRVnPQg0mX-XW8yyKPGjw,2958
|
|
6
|
-
lockss/pybasic/outpututil.py,sha256=8naQEZ1rM6vOFNL-9mWoK4dMBWokHmzQ0FkHaz8dyuM,2345
|
|
7
|
-
lockss_pybasic-0.2.0.dev7.dist-info/METADATA,sha256=ReyRdrU3vbGjOcdjkz4r2nqNCHXHWLK0tsN7g_2b2_s,4269
|
|
8
|
-
lockss_pybasic-0.2.0.dev7.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
9
|
-
lockss_pybasic-0.2.0.dev7.dist-info/licenses/LICENSE,sha256=O9ONND4uDxY_jucI4jZDf2liAk05ScEJaYu-Al7EOdQ,1506
|
|
10
|
-
lockss_pybasic-0.2.0.dev7.dist-info/RECORD,,
|
|
File without changes
|
{lockss_pybasic-0.2.0.dev7.dist-info → lockss_pybasic-0.2.0.dev8.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|