Source code for jgdv.cli.param_spec.extra

  1#!/usr/bin/env python3
  2"""
  3
  4"""
  5# Imports:
  6from __future__ import annotations
  7
  8# ##-- stdlib imports
  9import datetime
 10import enum
 11import functools as ftz
 12import itertools as itz
 13import logging as logmod
 14import pathlib as pl
 15import re
 16import time
 17import collections
 18import contextlib
 19import hashlib
 20from copy import deepcopy
 21from uuid import UUID, uuid1
 22from weakref import ref
 23import atexit # for @atexit.register
 24import faulthandler
 25# ##-- end stdlib imports
 26
 27from .param_spec import ParamSpec
 28from .core import AssignParam, ToggleParam, KeyParam, LiteralParam
 29
 30# ##-- types
 31# isort: off
 32# General
 33import abc
 34import collections.abc
 35import typing
 36import types
 37from typing import cast, assert_type, assert_never
 38from typing import Generic, NewType, Never
 39from typing import no_type_check, final, override, overload
 40# Protocols and Interfaces:
 41from typing import Protocol, runtime_checkable
 42if typing.TYPE_CHECKING:
 43    from typing import Final, ClassVar, Any, Self
 44    from typing import Literal, LiteralString
 45    from typing import TypeGuard
 46    from collections.abc import Iterable, Iterator, Callable, Generator
 47    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 48
 49    from jgdv import Maybe
 50
 51# isort: on
 52# ##-- end types
 53
 54##-- logging
 55logging = logmod.getLogger(__name__)
 56##-- end logging
 57
 58# Vars:
 59
 60# Body:
 61
[docs] 62class RepeatToggleParam(ToggleParam): 63 """ TODO A repeatable toggle 64 eg: -verbose -verbose -verbose 65 """ 66 desc : str = "A Repeat Toggle" 67 pass
68
[docs] 69class WildcardParam(AssignParam): 70 """ TODO a wildcard param that matches any --{key}={val} """ 71 72 desc : str = "A Wildcard" 73 74 def __init__(self, *args:Any, **kwargs:Any) -> None: # noqa: ANN401, ARG002 75 kwargs.setdefault("type", str) 76 kwargs['name'] = "*" 77 super().__init__(**kwargs) 78
[docs] 79 def matches_head(self, val:str) -> bool: 80 assert(isinstance(self.separator, str)) 81 match self.prefix: 82 case str() as p: 83 return (val.startswith(p) 84 and self.separator in val) 85 case _: 86 return False
87
[docs] 88 def next_value(self, args:list) -> tuple[str, list, int]: 89 logging.debug("Getting Wildcard Key Assingment: %s", args) 90 assert(self.separator in args[0]), (self.separator, args[0]) 91 key,val = self._processor.split_assignment(self, args[0]) 92 match self.prefix: 93 case str(): 94 return key.removeprefix(self.prefix), [val], 1 95 case int(): 96 return key, [val], 1
97 98
[docs] 99class ImplicitParam(ParamSpec): 100 """ 101 A Parameter that is implicit, so doesn't give a help description unless 102 forced to 103 """ 104 desc : str = "An Implicit Parameter" 105
[docs] 106 def help_str(self, *, force:bool=False) -> str: 107 return ""
108
[docs] 109class RepeatableParam(KeyParam): 110 """ TODO a repeatable key param 111 -key val -key val2 -key val3 112 """ 113 114 type_ : type 115 desc : str = "A Repeatable Key" 116 117 def __init__(self, *args, **kwargs) -> None: 118 super().__init__(*args, **kwargs) 119 self.type_ = list 120
[docs] 121 def next_value(self, args:list) -> tuple[str, list, int]: 122 """ Get as many values as match 123 eg: args[-test, 2, -test, 3, -test, 5, -nottest, 6] 124 -> [2,3,5], [-nottest, 6] 125 """ 126 logging.debug("Getting until no more matches: %s : %s", self.name, args) 127 assert(self.repeatable) 128 result, consumed, remaining = [], 0, args[:] 129 while bool(remaining): 130 head, val, *rest = remaining 131 if not self.matches_head(head): 132 break 133 else: 134 result.append(val) 135 remaining = rest 136 consumed += 2 137 138 return self.name, result, consumed
139
[docs] 140class ChoiceParam(LiteralParam): 141 """ TODO A param that must be from a choice of literals 142 eg: ChoiceParam([blah, bloo, blee]) : blah | bloo | blee 143 144 """ 145 146 desc : str = "A Choice" 147 148 def __init__(self, name, choices:list[str], **kwargs) -> None: 149 super().__init__(name=name, **kwargs) 150 self._choices = choices 151
[docs] 152 def matches_head(self, val) -> bool: 153 """ test to see if a cli argument matches this param 154 155 Matchs {self.prefix}{self.name} if not an assignment 156 Matches {self.prefix}{self.name}{separator} if an assignment 157 """ 158 return val in self._choices
159
[docs] 160class EntryParam(LiteralParam): 161 """ TODO a parameter that if it matches, 162 returns list of more params to parse 163 """ 164 desc : str = "An expandable Param" 165 pass
166
[docs] 167class ConstrainedParam(ParamSpec): 168 """ 169 TODO a type of parameter which is constrained in the values it can take, beyond just type. 170 171 eg: {name:amount, constraints={min=0, max=10}} 172 """ 173 constraints : list[Any] 174 desc : str = "A Constrained Param"