]> jfr.im git - yt-dlp.git/blame - yt_dlp/compat/compat_utils.py
[cleanup] Consistent style for file heads
[yt-dlp.git] / yt_dlp / compat / compat_utils.py
CommitLineData
1d485a1a 1import collections
9196cbfe 2import contextlib
3import importlib
4import sys
5import types
6
1d485a1a 7_NO_ATTRIBUTE = object()
8
9_Package = collections.namedtuple('Package', ('name', 'version'))
10
11
12def get_package_info(module):
13 parent = module.__name__.split('.')[0]
14 parent_module = None
15 with contextlib.suppress(ImportError):
16 parent_module = importlib.import_module(parent)
17
18 for attr in ('__version__', 'version_string', 'version'):
19 version = getattr(parent_module, attr, None)
20 if version is not None:
21 break
22 return _Package(getattr(module, '_yt_dlp__identifier', parent), str(version))
23
24
9196cbfe 25def _is_package(module):
26 try:
27 module.__getattribute__('__path__')
28 except AttributeError:
29 return False
30 return True
31
32
3c5386cd 33def passthrough_module(parent, child, allowed_attributes=None, *, callback=lambda _: None):
9196cbfe 34 parent_module = importlib.import_module(parent)
560738f3 35 child_module = None # Import child module only as needed
9196cbfe 36
37 class PassthroughModule(types.ModuleType):
38 def __getattr__(self, attr):
39 if _is_package(parent_module):
40 with contextlib.suppress(ImportError):
41 return importlib.import_module(f'.{attr}', parent)
42
3c5386cd 43 ret = self.__from_child(attr)
44 if ret is _NO_ATTRIBUTE:
45 raise AttributeError(f'module {parent} has no attribute {attr}')
46 callback(attr)
47 return ret
48
49 def __from_child(self, attr):
50 if allowed_attributes is None:
51 if attr.startswith('__') and attr.endswith('__'):
52 return _NO_ATTRIBUTE
53 elif attr not in allowed_attributes:
54 return _NO_ATTRIBUTE
55
560738f3 56 nonlocal child_module
57 child_module = child_module or importlib.import_module(child, parent)
58
9196cbfe 59 with contextlib.suppress(AttributeError):
3c5386cd 60 return getattr(child_module, attr)
9196cbfe 61
62 if _is_package(child_module):
63 with contextlib.suppress(ImportError):
3c5386cd 64 return importlib.import_module(f'.{attr}', child)
9196cbfe 65
3c5386cd 66 return _NO_ATTRIBUTE
9196cbfe 67
68 # Python 3.6 does not have module level __getattr__
69 # https://peps.python.org/pep-0562/
70 sys.modules[parent].__class__ = PassthroughModule