]> jfr.im git - yt-dlp.git/blobdiff - yt_dlp/jsinterp.py
[cleanup] Misc cleanup and refactor (#2173)
[yt-dlp.git] / yt_dlp / jsinterp.py
index 001836887a0711e157c4d083d731f5100613267b..70857b79816812be79bc9c4d4a32deda3a8834e1 100644 (file)
@@ -1,7 +1,8 @@
+import collections
+import contextlib
 import json
 import operator
 import re
-from collections.abc import MutableMapping
 
 from .utils import ExtractorError, remove_quotes
 
@@ -35,38 +36,17 @@ def __init__(self):
         ExtractorError.__init__(self, 'Invalid continue')
 
 
-class LocalNameSpace(MutableMapping):
-    def __init__(self, *stack):
-        self.stack = tuple(stack)
-
-    def __getitem__(self, key):
-        for scope in self.stack:
-            if key in scope:
-                return scope[key]
-        raise KeyError(key)
-
+class LocalNameSpace(collections.ChainMap):
     def __setitem__(self, key, value):
-        for scope in self.stack:
+        for scope in self.maps:
             if key in scope:
                 scope[key] = value
-                break
-        else:
-            self.stack[0][key] = value
-        return value
+                return
+        self.maps[0][key] = value
 
     def __delitem__(self, key):
         raise NotImplementedError('Deleting is not supported')
 
-    def __iter__(self):
-        for scope in self.stack:
-            yield from scope
-
-    def __len__(self, key):
-        return len(iter(self))
-
-    def __repr__(self):
-        return f'LocalNameSpace{self.stack}'
-
 
 class JSInterpreter:
     def __init__(self, code, objects=None):
@@ -302,10 +282,8 @@ def interpret_expression(self, expr, local_vars, allow_recursion):
         if var_m:
             return local_vars[var_m.group('name')]
 
-        try:
+        with contextlib.suppress(ValueError):
             return json.loads(expr)
-        except ValueError:
-            pass
 
         m = re.match(
             r'(?P<in>%s)\[(?P<idx>.+)\]$' % _NAME_RE, expr)
@@ -521,14 +499,13 @@ def call_function(self, funcname, *args):
 
     def build_function(self, argnames, code, *global_stack):
         global_stack = list(global_stack) or [{}]
-        local_vars = global_stack.pop(0)
 
         def resf(args, **kwargs):
-            local_vars.update({
+            global_stack[0].update({
                 **dict(zip(argnames, args)),
                 **kwargs
             })
-            var_stack = LocalNameSpace(local_vars, *global_stack)
+            var_stack = LocalNameSpace(*global_stack)
             for stmt in self._separate(code.replace('\n', ''), ';'):
                 ret, should_abort = self.interpret_statement(stmt, var_stack)
                 if should_abort: