The decorator itself, assigns arguments as keyword-only and calculates sets for error checking. Args: wrapped: The function to decorate. Returns: A function wrapped so that it has keyword-only arguments.
(wrapped)
| 26 | |
| 27 | """ |
| 28 | def decorator(wrapped): |
| 29 | """The decorator itself, assigns arguments as keyword-only and |
| 30 | calculates sets for error checking. |
| 31 | |
| 32 | Args: |
| 33 | wrapped: The function to decorate. |
| 34 | |
| 35 | Returns: |
| 36 | A function wrapped so that it has keyword-only arguments. |
| 37 | |
| 38 | """ |
| 39 | |
| 40 | # Each Python 3 argument has two independent properties: it is |
| 41 | # positional-and-keyword *or* keyword-only, and it has a |
| 42 | # default value or it doesn't. |
| 43 | names, varargs, _, defaults = inspect.getargspec(wrapped) |
| 44 | |
| 45 | # If there are no default values getargpsec() returns None |
| 46 | # rather than an empty iterable for some reason. |
| 47 | if defaults is None: |
| 48 | defaults = () |
| 49 | names_with_defaults = frozenset(names[len(names) - len(defaults):]) |
| 50 | names_to_defaults = dict(zip(reversed(names), reversed(defaults))) |
| 51 | if kw_only_parameters: |
| 52 | kw_only_names = frozenset(kw_only_parameters) |
| 53 | else: |
| 54 | kw_only_names = names_with_defaults.copy() |
| 55 | |
| 56 | @functools.wraps(wrapped) |
| 57 | def wrapper(*args, **kws): |
| 58 | """Wrapper function, checks arguments with set operations, moves args |
| 59 | from **kws into *args, and then calls wrapped(). |
| 60 | |
| 61 | Args: |
| 62 | *args, **kws: The arguments passed to the original function. |
| 63 | |
| 64 | Returns: |
| 65 | The original function's result when it's called with the |
| 66 | modified arguments. |
| 67 | |
| 68 | Raises: |
| 69 | TypeError: When there is a mismatch between the supplied |
| 70 | and expected arguments. |
| 71 | |
| 72 | """ |
| 73 | |
| 74 | new_args = [] |
| 75 | args_index = 0 |
| 76 | for name in names: |
| 77 | if name in kws: |
| 78 | # Check first if there's a bound keyword for this name |
| 79 | new_args.append(kws.pop(name)) |
| 80 | elif name in kw_only_names: |
| 81 | # If this name is keyword-only, check for a |
| 82 | # default or raise. |
| 83 | if name in names_to_defaults: |
| 84 | new_args.append(names_to_defaults[name]) |
| 85 | else: |