lockss-pybasic 0.2.0.dev2__tar.gz → 0.2.0.dev3__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.
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/PKG-INFO +1 -1
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/pyproject.toml +1 -1
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/src/lockss/pybasic/__init__.py +1 -1
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/src/lockss/pybasic/cliutil.py +32 -29
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/CHANGELOG.rst +0 -0
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/LICENSE +0 -0
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/README.rst +0 -0
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/src/lockss/pybasic/errorutil.py +0 -0
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/src/lockss/pybasic/fileutil.py +0 -0
- {lockss_pybasic-0.2.0.dev2 → lockss_pybasic-0.2.0.dev3}/src/lockss/pybasic/outpututil.py +0 -0
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
[project]
|
|
30
30
|
name = "lockss-pybasic"
|
|
31
|
-
version = "0.2.0-
|
|
31
|
+
version = "0.2.0-dev3" # Always change in __init__.py, and at release time in README.rst and CHANGELOG.rst
|
|
32
32
|
description = "Basic Python utilities"
|
|
33
33
|
license = { text = "BSD-3-Clause" }
|
|
34
34
|
readme = "README.rst"
|
|
@@ -34,47 +34,50 @@ Command line utilities.
|
|
|
34
34
|
|
|
35
35
|
from collections.abc import Callable
|
|
36
36
|
import sys
|
|
37
|
-
from typing import Any, Dict, Generic, Optional, TypeVar
|
|
37
|
+
from typing import Any, ClassVar, Dict, Generic, Optional, TypeVar, TYPE_CHECKING
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from _typeshed import SupportsWrite
|
|
41
|
+
|
|
42
|
+
from pydantic.v1 import BaseModel, PrivateAttr, create_model
|
|
43
|
+
from pydantic.v1.fields import FieldInfo
|
|
40
44
|
from pydantic_argparse import ArgumentParser
|
|
41
45
|
from pydantic_argparse.argparse.actions import SubParsersAction
|
|
42
46
|
from rich_argparse import RichHelpFormatter
|
|
43
47
|
|
|
44
48
|
|
|
45
|
-
class
|
|
46
|
-
"""
|
|
47
|
-
Base class for a pydantic-argparse style command.
|
|
48
|
-
"""
|
|
49
|
-
pass
|
|
49
|
+
class StringCommand(BaseModel):
|
|
50
50
|
|
|
51
|
+
def display(self, file: SupportsWrite[str]=sys.stdout) -> None:
|
|
52
|
+
print(getattr(self, 'display_string'), file=file)
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
@staticmethod
|
|
55
|
+
def make(model_name: str, option_name: str, description: str, display_string: str):
|
|
56
|
+
return create_model(model_name,
|
|
57
|
+
__base__=StringCommand,
|
|
58
|
+
**{option_name: (Optional[bool], FieldInfo(False, description=description)),
|
|
59
|
+
display_string: PrivateAttr(display_string)})
|
|
55
60
|
|
|
56
|
-
Example of use:
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
class CopyrightCommand(StringCommand):
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
@staticmethod
|
|
65
|
+
def make(display_string: str):
|
|
66
|
+
return StringCommand.make('CopyrightCommand', 'copyright', 'print the copyright and exit', display_string)
|
|
62
67
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"""
|
|
68
|
+
|
|
69
|
+
class LicenseCommand(StringCommand):
|
|
66
70
|
|
|
67
71
|
@staticmethod
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
def __call__(self, file=sys.stdout, **kwargs):
|
|
71
|
-
print(display_str, file=file)
|
|
72
|
-
return _StringCommand
|
|
72
|
+
def make(display_string: str):
|
|
73
|
+
return StringCommand.make('LicenseCommand', 'license', 'print the software license and exit', display_string)
|
|
73
74
|
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
class VersionCommand(StringCommand):
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def make(display_string: str):
|
|
80
|
+
return StringCommand.make('VersionCommand', 'version', 'print the version number and exit', display_string)
|
|
78
81
|
|
|
79
82
|
|
|
80
83
|
BaseModelT = TypeVar('BaseModelT', bound=BaseModel)
|
|
@@ -195,7 +198,7 @@ def at_most_one_from_enum(model_cls: type[BaseModel], values: Dict[str, Any], en
|
|
|
195
198
|
enum_names = [field_name for field_name, model_field in model_cls.__fields__.items() if model_field.field_info.extra.get('enum') == enum_cls]
|
|
196
199
|
ret = [field_name for field_name in enum_names if values.get(field_name)]
|
|
197
200
|
if (length := len(ret)) > 1:
|
|
198
|
-
raise ValueError(f'at most one of {', '.join([option_name(model_cls, enum_name) for enum_name in enum_names])}
|
|
201
|
+
raise ValueError(f'at most one of {', '.join([option_name(model_cls, enum_name) for enum_name in enum_names])} allowed; got {length} ({', '.join([option_name(enum_name) for enum_name in ret])})')
|
|
199
202
|
return values
|
|
200
203
|
|
|
201
204
|
|
|
@@ -221,19 +224,19 @@ def get_from_enum(model_inst, enum_cls, default=None):
|
|
|
221
224
|
|
|
222
225
|
def at_most_one(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
|
|
223
226
|
if (length := _matchy_length(values, *names)) > 1:
|
|
224
|
-
raise ValueError(f'at most one of {', '.join([option_name(model_cls, name) for name in names])}
|
|
227
|
+
raise ValueError(f'at most one of {', '.join([option_name(model_cls, name) for name in names])} allowed; got {length}')
|
|
225
228
|
return values
|
|
226
229
|
|
|
227
230
|
|
|
228
231
|
def exactly_one(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
|
|
229
232
|
if (length := _matchy_length(values, *names)) != 1:
|
|
230
|
-
raise ValueError(f'exactly one of {', '.join([option_name(model_cls, name) for name in names])}
|
|
233
|
+
raise ValueError(f'exactly one of {', '.join([option_name(model_cls, name) for name in names])} required; got {length}')
|
|
231
234
|
return values
|
|
232
235
|
|
|
233
236
|
|
|
234
237
|
def one_or_more(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
|
|
235
238
|
if _matchy_length(values, *names) == 0:
|
|
236
|
-
raise ValueError(f'one or more of {', '.join([option_name(model_cls, name) for name in names])}
|
|
239
|
+
raise ValueError(f'one or more of {', '.join([option_name(model_cls, name) for name in names])} required')
|
|
237
240
|
return values
|
|
238
241
|
|
|
239
242
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|