lockss-pybasic 0.2.0.dev2__tar.gz → 0.2.0.dev4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: lockss-pybasic
3
- Version: 0.2.0.dev2
3
+ Version: 0.2.0.dev4
4
4
  Summary: Basic Python utilities
5
5
  License: BSD-3-Clause
6
6
  Author: Thib Guicherd-Callin
@@ -28,7 +28,7 @@
28
28
 
29
29
  [project]
30
30
  name = "lockss-pybasic"
31
- version = "0.2.0-dev2" # Always change in __init__.py, and at release time in README.rst and CHANGELOG.rst
31
+ version = "0.2.0-dev4" # 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"
@@ -36,4 +36,4 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
36
  POSSIBILITY OF SUCH DAMAGE.
37
37
  '''.strip()
38
38
 
39
- __version__ = '0.2.0-dev2'
39
+ __version__ = '0.2.0-dev4'
@@ -34,47 +34,52 @@ 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
- from pydantic.v1 import BaseModel
39
+ from pydantic.v1 import BaseModel, PrivateAttr, create_model
40
+ from pydantic.v1.fields import FieldInfo
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
+ if TYPE_CHECKING:
46
+ from _typeshed import SupportsWrite as SupportsWriteStr
47
+ else:
48
+ SupportsWriteStr = Any
44
49
 
45
- class ActionCommand(Callable, BaseModel):
46
- """
47
- Base class for a pydantic-argparse style command.
48
- """
49
- pass
50
50
 
51
+ class StringCommand(BaseModel):
51
52
 
52
- class StringCommand(ActionCommand):
53
- """
54
- A pydantic-argparse style command that prints a string.
53
+ def display(self, file: SupportsWriteStr=sys.stdout) -> None:
54
+ print(getattr(self, 'display_string'), file=file)
55
55
 
56
- Example of use:
56
+ @staticmethod
57
+ def make(model_name: str, option_name: str, description: str, display_string: str):
58
+ return create_model(model_name,
59
+ __base__=StringCommand,
60
+ **{option_name: (Optional[bool], FieldInfo(False, description=description)),
61
+ display_string: PrivateAttr(display_string)})
57
62
 
58
- .. code-block:: python
59
63
 
60
- class MyCliModel(BaseModel):
61
- copyright: Optional[StringCommand.type(my_copyright_string)] = Field(description=COPYRIGHT_DESCRIPTION)
64
+ class CopyrightCommand(StringCommand):
62
65
 
63
- See also the convenience constants ``COPYRIGHT_DESCRIPTION``,
64
- ``LICENSE_DESCRIPTION``, and ``VERSION_DESCRIPTION``.
65
- """
66
+ @staticmethod
67
+ def make(display_string: str):
68
+ return StringCommand.make('CopyrightCommand', 'copyright', 'print the copyright and exit', display_string)
69
+
70
+
71
+ class LicenseCommand(StringCommand):
66
72
 
67
73
  @staticmethod
68
- def type(display_str: str):
69
- class _StringCommand(StringCommand):
70
- def __call__(self, file=sys.stdout, **kwargs):
71
- print(display_str, file=file)
72
- return _StringCommand
74
+ def make(display_string: str):
75
+ return StringCommand.make('LicenseCommand', 'license', 'print the software license and exit', display_string)
73
76
 
74
77
 
75
- COPYRIGHT_DESCRIPTION = 'print the copyright and exit'
76
- LICENSE_DESCRIPTION = 'print the software license and exit'
77
- VERSION_DESCRIPTION = 'print the version number and exit'
78
+ class VersionCommand(StringCommand):
79
+
80
+ @staticmethod
81
+ def make(display_string: str):
82
+ return StringCommand.make('VersionCommand', 'version', 'print the version number and exit', display_string)
78
83
 
79
84
 
80
85
  BaseModelT = TypeVar('BaseModelT', bound=BaseModel)
@@ -195,7 +200,7 @@ def at_most_one_from_enum(model_cls: type[BaseModel], values: Dict[str, Any], en
195
200
  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
201
  ret = [field_name for field_name in enum_names if values.get(field_name)]
197
202
  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])} is allowed, got {length} ({', '.join([option_name(enum_name) for enum_name in ret])})')
203
+ 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
204
  return values
200
205
 
201
206
 
@@ -221,19 +226,19 @@ def get_from_enum(model_inst, enum_cls, default=None):
221
226
 
222
227
  def at_most_one(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
223
228
  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])} is allowed, got {length}')
229
+ raise ValueError(f'at most one of {', '.join([option_name(model_cls, name) for name in names])} allowed; got {length}')
225
230
  return values
226
231
 
227
232
 
228
233
  def exactly_one(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
229
234
  if (length := _matchy_length(values, *names)) != 1:
230
- raise ValueError(f'exactly one of {', '.join([option_name(model_cls, name) for name in names])} is required, got {length}')
235
+ raise ValueError(f'exactly one of {', '.join([option_name(model_cls, name) for name in names])} required; got {length}')
231
236
  return values
232
237
 
233
238
 
234
239
  def one_or_more(model_cls: type[BaseModel], values: Dict[str, Any], *names: str):
235
240
  if _matchy_length(values, *names) == 0:
236
- raise ValueError(f'one or more of {', '.join([option_name(model_cls, name) for name in names])} is required')
241
+ raise ValueError(f'one or more of {', '.join([option_name(model_cls, name) for name in names])} required')
237
242
  return values
238
243
 
239
244