aboutsummaryrefslogtreecommitdiffstats
path: root/yt_dlp/compat/compat_utils.py
blob: 938daf926cf272d9fdb0d2804b5ddba371a041e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import contextlib
import importlib
import sys
import types


def _is_package(module):
    try:
        module.__getattribute__('__path__')
    except AttributeError:
        return False
    return True


_NO_ATTRIBUTE = object()


def passthrough_module(parent, child, *, callback=lambda _: None):
    parent_module = importlib.import_module(parent)
    child_module = importlib.import_module(child, parent)

    class PassthroughModule(types.ModuleType):
        def __getattr__(self, attr):
            if _is_package(parent_module):
                with contextlib.suppress(ImportError):
                    return importlib.import_module(f'.{attr}', parent)

            ret = _NO_ATTRIBUTE
            with contextlib.suppress(AttributeError):
                ret = getattr(child_module, attr)

            if _is_package(child_module):
                with contextlib.suppress(ImportError):
                    ret = importlib.import_module(f'.{attr}', child)

            if ret is _NO_ATTRIBUTE:
                raise AttributeError(f'module {parent} has no attribute {attr}')

            callback(attr)
            return ret

    # Python 3.6 does not have module level __getattr__
    # https://peps.python.org/pep-0562/
    sys.modules[parent].__class__ = PassthroughModule