A note on **kwargs parsing#
[1]:
%load_ext autoreload
%autoreload 2
[2]:
from functools import wraps, update_wrapper
from majordome.parsing import FuncArguments
# import majordome.walang
Illustrating FuncArguments#
[3]:
def f(*args, **kwargs):
""" Arbitrary interface function for illustration. """
f.parser.update(*args, **kwargs)
try:
print(f"a = {f.parser.get("a")}, b = {f.parser.get("b")}")
f.parser.close()
except Exception as err:
print(err)
pass
Arguments are both positional-mandatory
[4]:
f.parser = FuncArguments()
f.parser.add("a", index=0)
f.parser.add("b", index=1)
f(3)
f(3, 4)
Cannot retrieve mandatory positional argument at position 1
a = 3, b = 4
Arguments are both keyword-only
[5]:
f.parser = FuncArguments()
f.parser.add("a", default="aaaa")
f.parser.add("b", default="bbbb")
f(3)
f(3, 4)
f(3, b=4)
f(a=3, b=4)
a = aaaa, b = bbbb
Too many positional arguments, got 1 but only 0 were used.
a = aaaa, b = bbbb
Too many positional arguments, got 2 but only 0 were used.
a = aaaa, b = 4
Too many positional arguments, got 1 but only 0 were used.
a = 3, b = 4
One positional and another (maybe) positional
[6]:
f.parser = FuncArguments()
f.parser.add("a", index=0)
f.parser.add("b", index=1, default=6)
f(3)
f(3, 4)
f(3, 4, b=4)
a = 3, b = 6
a = 3, b = 4
Cannot have both positional and keyword version of b (1) simultaneously
Badly configured
[7]:
f.parser = FuncArguments()
try:
f.parser.add("a")
f.parser.add("b")
except Exception as err:
print(err)
Argument must be either positional or keyword, cannot be neither: a
Creating class constructors#
[8]:
def _init_some_class(cls):
""" Decorator to enhance SomeClass with argument parsing. """
orig_init = cls.__init__
# Maybe stash for later use?
# cls.__orig_init__ = orig_init
parser = FuncArguments(greedy_args=False, pop_kw=True)
parser.add("a", 0)
parser.add("x", default=None)
@wraps(orig_init)
def new_init(self, *args, **kwargs):
parser.update(*args, **kwargs)
a = parser.get("a")
x = parser.get("x")
orig_init(self, *parser.args, **parser.kwargs)
parser.close()
# -- logic goes here
print(f"some a = {a}")
print(f"some x = {x}")
return None
cls.__init__ = update_wrapper(new_init, orig_init)
return cls
[9]:
class BaseClass:
def __init__(self, *args, **kwargs) -> None:
print(f"args = {args}")
print(f"kwargs = {kwargs}")
[10]:
@_init_some_class
class SomeClass(BaseClass):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
[11]:
some = SomeClass(1, 2, 3, x=1, y=2)
args = (1, 2, 3)
kwargs = {'y': 2}
some a = 1
some x = 1