|
|
|
@ -6109,6 +6109,37 @@ def clean_podcast_url(url): |
|
|
|
|
)/''', '', url) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __debug__: |
|
|
|
|
# Raise TypeError if args can't be bound |
|
|
|
|
# needs compat owing to unstable inspect API, thanks PSF :-( |
|
|
|
|
try: |
|
|
|
|
inspect.signature |
|
|
|
|
|
|
|
|
|
def _try_bind_args(fn, *args, **kwargs): |
|
|
|
|
inspect.signature(fn).bind(*args, **kwargs) |
|
|
|
|
except AttributeError: |
|
|
|
|
# Py < 3.3 |
|
|
|
|
def _try_bind_args(fn, *args, **kwargs): |
|
|
|
|
fn_args = inspect.getargspec(fn) |
|
|
|
|
# Py2: ArgInfo(args, varargs, keywords, defaults) |
|
|
|
|
# Py3: ArgSpec(args, varargs, keywords, defaults) |
|
|
|
|
if not fn_args.keywords: |
|
|
|
|
for k in kwargs: |
|
|
|
|
if k not in (fn_args.args or []): |
|
|
|
|
raise TypeError("got an unexpected keyword argument: '{0}'".format(k)) |
|
|
|
|
if not fn_args.varargs: |
|
|
|
|
args_to_bind = len(args) |
|
|
|
|
bindable = len(fn_args.args or []) |
|
|
|
|
if args_to_bind > bindable: |
|
|
|
|
raise TypeError('too many positional arguments') |
|
|
|
|
bindable -= len(fn_args.defaults or []) |
|
|
|
|
if args_to_bind < bindable: |
|
|
|
|
if kwargs: |
|
|
|
|
bindable -= len(set(fn_args.args or []) & set(kwargs)) |
|
|
|
|
if bindable > args_to_bind: |
|
|
|
|
raise TypeError("missing a required argument: '{0}'".format(fn_args.args[args_to_bind])) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def traverse_obj(obj, *paths, **kwargs): |
|
|
|
|
""" |
|
|
|
|
Safely traverse nested `dict`s and `Iterable`s |
|
|
|
@ -6327,10 +6358,7 @@ def traverse_obj(obj, *paths, **kwargs): |
|
|
|
|
|
|
|
|
|
if __debug__ and callable(key): |
|
|
|
|
# Verify function signature |
|
|
|
|
args = inspect.getargspec(key) |
|
|
|
|
if len(args.args) != 2: |
|
|
|
|
# crash differently in 2.6 ! |
|
|
|
|
inspect.getcallargs(key, None, None) |
|
|
|
|
_try_bind_args(key, None, None) |
|
|
|
|
|
|
|
|
|
new_objs = [] |
|
|
|
|
for obj in objs: |
|
|
|
|