理论上可以用更清晰和信息更丰富的内容来包装产生的TypeError。然而,有许多小细节我不知道如何解决。在
注意:下面的代码只是一个勉强可以工作的示例,不是一个完整的解决方案。在try:
fn(**data)
except TypeError as e:
## More-sane-than-default processing of a case `parameter ... was not specified`
## XXX: catch only top-level exceptions somehow?
## * through traceback?
if fn.func_code.co_flags & 0x04: ## XXX: check
# it accepts `*ar`, so not the case
raise
f_vars = fn.func_code.co_varnames
f_defvars_count = len(fn.func_defaults)
## XXX: is there a better way?
## * it catches `self` in a bound method as required. (also, classmethods?)
## * `inspect.getargspec`? Imprecise, too (for positional args)
## * also catches `**kwargs`.
f_posvars = f_vars[:-f_defvars_count]
extra_args = list(set(data.keys()) - set(f_vars))
missing_args = list(set(f_posvars) - set(data.keys()))
if missing_args: # is the case, raise it verbosely.
msg = "Required argument(s) not specified: %s" % (
', '.join(missing_args),)
if extra_args:
msg += "; additionally, there are extraneous arguments: %s" % (
', '.join(extra_args))
raise TypeError(msg, e)
#_log.error(msg)
#raise
raise