/
PluginsArgumentParser.py
104 lines (86 loc) · 4.06 KB
/
PluginsArgumentParser.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
104
import argfork as argparse
from PluginHandler import AnotherPlugin
class ParserMetaclass(type):
def __new__(mcs, name, bases, dct):
if name != "ArgumentParser":
if not dct.get("_PluginLink"):
raise LookupError(f"Link in {mcs} for parent class not found. Terminating")
if not dct.get("__plugin_name__"):
dct["__plugin_name__"] = name
print(name)
parser_object = type.__new__(mcs, name, bases, dct)
return parser_object
class ArgumentParser(metaclass=ParserMetaclass):
"""
# Every plugin class should have:
# _PluginLink = Plugin, where
# _PluginLink is basic link to object
# __plugin_name__ -> name, that could
# allow you to use your own parser
# from parent one.
# Every class should have
# __parser__name__
# otherwise plugin subparser
# call name will be generated
# from className
# The only problem is in conflict
# The only way (as i think) is to use
# conflict_handler='resolve' handler
# that will by default resolve all
# conflicts in the program.
# If you don't want to auto editing, <- TODO
# just inherit from this class and change
# parser options like this:
# https://docs.python.org/3/library/argparse.html#other-utilities
"""
test = "test"
def __init__(self):
self.parent_parser = argparse.ArgumentParser(conflict_handler='resolve')
def __recreate_parser(self, created_parsers: dict):
"""
Example parser ._actions:
_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None,
choices=None, help='show this help message and exit', metavar=None)
_StoreAction(option_strings=['-t', '--test'], dest='test', nargs=None, const=None, default=None, type=None,
choices=None, help=None, metavar=None)
_StoreAction(option_strings=['-p', '--plugin'], dest='plugin', nargs=None, const=None, default=None, type=None,
choices=None, help=None, metavar=None)
So this method is created for recreation of parser to insert it into the "parent"
:param created_parser:
:return:
"""
subparsers = self.parent_parser.add_subparsers()
for parser, name in created_parsers.items():
if isinstance(parser, argparse.ArgumentParser):
"""
We could use parser._option_string_actions
But afterwards there is pretty hard way to resolve
all argparse objects. So that's is optimal way
"""
parser_actions = parser._actions
if parser_actions:
plugin_subparser = subparsers.add_parser(name=name)
for action in parser_actions:
action_kwargs = dict(action._get_kwargs())
if isinstance(action, argparse._HelpAction):
"""
Passing this _HelpAction because of every
_*StoreAction is linked to it's own _HelpAction
"""
continue
"""
From lib source:
# if no positional args are supplied or only one is supplied and
# it doesn't look like an option string, parse a positional
# argument
>> return dict(kwargs, dest=dest, option_strings=[])
So option_strings will be empty.
"""
options = action_kwargs['option_strings']
action_kwargs.pop('option_strings')
plugin_subparser.add_argument(*options, **action_kwargs)
def setup(self, created_parsers: dict):
self.__recreate_parser(created_parsers)
class TestParser(ArgumentParser):
_PluginLink = AnotherPlugin
__plugin_name__ = "very_cool_plugin"