Source code for charger.argtype
from argparse import ArgumentTypeError
from pathlib import Path
from typing import Callable, Dict, Optional, Union
try:
from typing import Final
except ImportError:
# Backport additional typings prior to python 3.8
from typing_extensions import Final # type: ignore
[docs]class PathType:
"""Parse file path arguments as a :class:`pathlib.Path` object.
Type factory for ArgumentParser.add_argument() that validates the file path arguments.
Adapted from https://stackoverflow.com/a/33181083
Args:
exists: The path must exist when `True`, and the path must not exist when `False`.
Skip the check when `None`.
type: ``file`` will be checked by :meth:`~pathlib.Path.is_file`.
``dir`` will be checked by :meth:`~pathlib.Path.is_dir`.
It also accepts a function that takes :class:`~pathlib.Path` object
and returns `True` for valid paths.
Skip the check when `None`.
Examples:
>>> parser = argparse.ArgumentParser()
Add an argument that must be an existing file, but can also be specified as a dash
(``-``) in the command,
>>> parser.add_argument('existing_file', type=PathType(exists=True, type='file'))
Add an argument for a new path that must NOT exist, but the parent folder exists,
>>> from pathlib import Path
>>> CreatablePathType = PathType(exists=False, type=lambda p: p.parent.is_dir())
>>> parser.add_argument('non_existing_folder', type=CreatablePathType)
"""
def __init__(
self,
exists: Optional[bool] = None,
type: Union[None, str, Callable[[Path], bool]] = None,
):
self._exists = exists
self._type = type
def __call__(self, pth: str) -> Path:
p = Path(pth)
if self._exists is not None:
# Check if the path must or must not exist
pth_exists = p.exists()
if self._exists:
if not pth_exists:
raise ArgumentTypeError(f"Path does not exist: {pth}")
elif pth_exists:
raise ArgumentTypeError(f"Path already exists: {pth}")
if self._type is None:
pass
elif isinstance(self._type, str):
# Check if the path is the asserted type
if self._type == "file":
if not p.is_file():
raise ArgumentTypeError(f"Path is not a file: {pth}")
elif self._type == "dir":
if not p.is_dir():
raise ArgumentTypeError(f"Path is not a directory: {pth}")
else:
raise ValueError(f"Unknown type {self._type!r}")
elif not self._type(p):
# Use the given function to check the path type
raise ArgumentTypeError(f"Path is invalid: {pth}")
return p
[docs]class ModuleScoreOverrideType:
"""Integrate override arguments to new scores of all modules.
Examples:
>>> default_scores = {'A': 5, 'B': -2}
>>> override_score = ModuleScoreOverrideType(default_scores)
>>> override_score('A=7 B=-4')
{'A': 7, 'B': -4}
"""
def __init__(self, defaults: Dict[str, int]):
self._defaults: Final = defaults
def __call__(self, overrides: str) -> Dict[str, int]:
module_scores = self._defaults.copy()
for override in overrides.split(" "):
module, new_score_str = override.split("=", 1)
if module not in self._defaults:
raise ArgumentTypeError(f"Module does not exist: {module}")
try:
new_score = int(new_score_str)
except ValueError:
raise ArgumentTypeError(
f"New score of module {module} is not an integer: {new_score_str}"
)
module_scores[module] = new_score
return module_scores