"""kwonly module
"""
def emulate_kwonly(kws, required, withdefaults, leftovers=False):
"""Emulate Python 3's kwonly arguments.
Parameters:
kws - the kwargs from which to extract the kwonly args.
required - an iterable holding the required kwonly args.
withdefaults - an iterable of pairs mapping names to defaults.
leftovers - allow kws to be non-empty when all the kwonly args
have already been popped off.
Returns:
The remainder of kws, followed by the values for the kwonly args
in the same order as they stand in required and then in
withdefaults.
Examples:
Below each "def" clause you'll find the clause that would be
equivalent in Python 3 to the use of emulate_kwonly().
>>> def f(a, **kwargs):
... #def f(a, *, b, c=5):
... kwargs, b, c = emulate_kwonly(kwargs, ("b",), (("c", 5),))
... # continue as normal
...
>>> def g(a, *args, **kwargs):
... #def f(a, *args, b, **kwargs):
... kwargs, b = emulate_kwonly(kwargs, ("b",), (), True)
... # continue as normal
"""
if hasattr(withdefaults, "items"):
# allows for OrderedDict to be passed
withdefaults = withdefaults.items()
kwonly = []
# extract the required keyword-only arguments
missing = []
for name in required:
if name not in kws:
missing.append(name)
else:
kwonly.append(kws.pop(name))
# validate required keyword-only arguments
if len(missing) > 2:
end = "s: %s, and %s" % (", ".join(missing[:-1]), missing[-1])
elif len(missing) == 2:
end = "s: %s and %s" % tuple(missing)
elif len(missing) == 1:
end = ": %s" % tuple(missing)
if missing:
msg = "missing %s required keyword-only argument%s"
raise TypeError(msg % (len(missing), end))
# handle the withdefaults
for name, value in withdefaults:
if name not in kws:
kwonly.append(value)
else:
kwonly.append(kws.pop(name))
# handle any leftovers
if not leftovers and kws:
msg = "got an unexpected keyword argument '%s'"
raise TypeError(msg % (kws.keys()[0]))
return [kws] + kwonly
if __name__ == "__main__":
def f(a, **kwargs):
#def f(a, *, b, c=5):
kwargs, b, c = emulate_kwonly(kwargs, ("b",), (("c", 5),))
return a, b, c
assert f(1, b=2) == (1, 2, 5)
assert f(1, b=2, c=3) == (1, 2, 3)
try: f(b=2)
except TypeError: pass
else: raise AssertionError
try: f(1, 2)
except TypeError: pass
else: raise AssertionError
try: f(1, c=2)
except TypeError: pass
else: raise AssertionError
try: f(1, b=2, d=4)
except TypeError: pass
else: raise AssertionError
def g(a, *args, **kwargs):
#def f(a, *args, b, **kwargs):
kwargs, b = emulate_kwonly(kwargs, ("b",), (), True)
return a, b, kwargs
assert g(1, b=2) == (1, 2, {})
assert g(1, b=2, c=3) == (1, 2, dict(c=3))