about summary refs log tree commit diff
diff options
context:
space:
mode:
authordirkf <fieldhouse@gmx.net>2023-07-19 13:01:02 +0100
committerdirkf <fieldhouse@gmx.net>2023-07-19 22:14:50 +0100
commita190b559640ce1b5fe67e5a4843dc58328503f3c (patch)
treee9da95cb0bbffcc8ac9c83b2eb27c120e28e8e46
parentb2741f2654e6ddfebc1771b5d5fadb5fd6fe3863 (diff)
downloadyoutube-dl-a190b559640ce1b5fe67e5a4843dc58328503f3c.tar.gz
youtube-dl-a190b559640ce1b5fe67e5a4843dc58328503f3c.tar.xz
youtube-dl-a190b559640ce1b5fe67e5a4843dc58328503f3c.zip
[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()`
-rw-r--r--youtube_dl/utils.py36
1 files changed, 32 insertions, 4 deletions
diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py
index 0cbbec0f3..d52fa7a28 100644
--- 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: