]>
Commit | Line | Data |
---|---|---|
1d485a1a | 1 | import collections |
9196cbfe | 2 | import contextlib |
3 | import importlib | |
4 | import sys | |
5 | import types | |
6 | ||
1d485a1a | 7 | _NO_ATTRIBUTE = object() |
8 | ||
9 | _Package = collections.namedtuple('Package', ('name', 'version')) | |
10 | ||
11 | ||
12 | def 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 | 25 | def _is_package(module): |
26 | try: | |
27 | module.__getattribute__('__path__') | |
28 | except AttributeError: | |
29 | return False | |
30 | return True | |
31 | ||
32 | ||
3c5386cd | 33 | def 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 |