-
Notifications
You must be signed in to change notification settings - Fork 0
/
kwargparse.py
103 lines (94 loc) · 3.38 KB
/
kwargparse.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
from argparse import Namespace
#region Errors
class KwargParseError(Exception): pass
class ArgumentError(KwargParseError): pass
class ArgumentTypeError(ArgumentError): pass
class ArgumentRequiredError(ArgumentError): pass
#endregion
_type_class = type
#region Types
def AnyType(obj):
return obj
#endregion
def _run_action(action, kwargs):
if hasattr(action, '__call__'):
return action(kwargs)
elif hasattr(action, 'parse'):
return action.parse(kwargs)
elif hasattr(action, '_parse_as_arg'):
return action._parse_as_arg(kwargs)
class _NULL_RESULT: pass
#region Actions
class Action:
def __init__(self, names, dest=None, required=None, default=None, type=AnyType):
if dest is None: dest = names[0]
if required is None:
if default is None:
required = True
else: required = False
self.names = names
self.dest = dest
self.required = required
self.default = default
self.type = type
def parse(self): pass
def _parse_as_arg(self): pass
class _Argument(Action):
def __call__(self, kwargs):
for name in self.names:
if name in kwargs:
try: result = self.type(kwargs[name])
except Exception as e:
raise e from None
else: break
else:
if self.required:
raise ArgumentRequiredError('argument %s required to be passed' % self.names[0]) from None
else:
name = None
result = self.default
return name, result
#endregion
class KeywordArgumentParser:
def __init__(self):
self._args = []
# self._error_exception = None
@classmethod
def _init_as_subparser(cls, names, dest=None, required=None, default=None):
self = cls()
Action.__init__(self, names, dest, required, default)
return self
def parse_kwargs(self, kwargs) -> Namespace:
result = {}
all_names = set()
used = set()
for arg in self._args:
all_names.update(arg.names)
name, result[arg.dest] = _run_action(arg, kwargs)
if name is not None: used.add(name)
extras = used - all_names
if extras:
raise IndexError('extra arguments passed: %s' % ', '.join(str(extra) for extra in extras)) from None
return Namespace(**result)
# def _raise_none(self): pass
# def _raise(self, message): pass
# def set_error_exception(self, klass, message_format=''):
# self._error_exception = (klass, message_format)
def add_argument(self, *names, dest=None, required=None, default=None, type=AnyType, action=_Argument):
self._args.append(action(names, dest, required, default, type))
def add_subparser(self, *names, dest=None, required=None, default=None):
subparser = self.__class__._init_as_subparser(names, dest, required, default)
self._args.append(subparser)
return subparser
def _parse_as_arg(self, kwargs):
name, kwargs = _Argument.__call__(self, kwargs)
return name, self.parse_kwargs(kwargs)
#region Metadata
__version__ = '1.0.0'
__author__ = 'Gaming32'
__all__ = ['KwargParseError', 'ArgumentError', 'ArgumentTypeError', 'ArgumentRequiredError',
'AnyType',
'Action',
'KeywordArgumentParser',
'Namespace']
#endregion