123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- import collections
- import contextlib
- import importlib
- import sys
- import types
- _NO_ATTRIBUTE = object()
- _Package = collections.namedtuple('Package', ('name', 'version'))
- def get_package_info(module):
- parent = module.__name__.split('.')[0]
- parent_module = None
- with contextlib.suppress(ImportError):
- parent_module = importlib.import_module(parent)
- for attr in ('__version__', 'version_string', 'version'):
- version = getattr(parent_module, attr, None)
- if version is not None:
- break
- return _Package(getattr(module, '_yt_dlp__identifier', parent), str(version))
- def _is_package(module):
- try:
- module.__getattribute__('__path__')
- except AttributeError:
- return False
- return True
- def passthrough_module(parent, child, *, callback=lambda _: None):
- parent_module = importlib.import_module(parent)
- child_module = None # Import child module only as needed
- class PassthroughModule(types.ModuleType):
- def __getattr__(self, attr):
- if _is_package(parent_module):
- with contextlib.suppress(ImportError):
- return importlib.import_module(f'.{attr}', parent)
- nonlocal child_module
- child_module = child_module or importlib.import_module(child, 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
|