commit: a190b559640ce1b5fe67e5a4843dc58328503f3c
parent b2741f2654e6ddfebc1771b5d5fadb5fd6fe3863
Author: dirkf <fieldhouse@gmx.net>
Date: Wed, 19 Jul 2023 13:01:02 +0100
[utils] Fix broken Py 3.11+ compat in `traverse_obj()`
* inspect.getargspec is missing despite doc claiming backward compat
* replace with emulation of `Signature.bind()`
Diffstat:
1 file changed, 32 insertions(+), 4 deletions(-)
diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py
@@ -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: