mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-21 20:46:36 -05:00
[compat] Ensure submodules are correctly wrapped
This commit is contained in:
parent
9cd080508d
commit
9196cbfe8b
6 changed files with 73 additions and 22 deletions
|
@ -7,6 +7,7 @@
|
|||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
from yt_dlp import compat
|
||||
from yt_dlp.compat import (
|
||||
compat_etree_fromstring,
|
||||
compat_expanduser,
|
||||
|
@ -21,6 +22,12 @@
|
|||
|
||||
|
||||
class TestCompat(unittest.TestCase):
|
||||
def test_compat_passthrough(self):
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
compat.compat_basestring
|
||||
|
||||
compat.asyncio.events # Must not raise error
|
||||
|
||||
def test_compat_getenv(self):
|
||||
test_str = 'тест'
|
||||
compat_setenv('yt_dlp_COMPAT_GETENV', test_str)
|
||||
|
|
|
@ -2,11 +2,18 @@
|
|||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import types
|
||||
import warnings
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
from . import re
|
||||
from ._deprecated import * # noqa: F401, F403
|
||||
from .compat_utils import passthrough_module
|
||||
|
||||
|
||||
# XXX: Implement this the same way as other DeprecationWarnings without circular import
|
||||
passthrough_module(__name__, '._legacy', callback=lambda attr: warnings.warn(
|
||||
DeprecationWarning(f'{__name__}.{attr} is deprecated'), stacklevel=2))
|
||||
del passthrough_module
|
||||
|
||||
|
||||
# HTMLParseError has been deprecated in Python 3.3 and removed in
|
||||
|
@ -85,24 +92,3 @@ def windows_enable_vt_mode(): # TODO: Do this the proper way https://bugs.pytho
|
|||
with contextlib.suppress(Exception):
|
||||
subprocess.Popen('', shell=True, startupinfo=startupinfo).wait()
|
||||
WINDOWS_VT_MODE = True
|
||||
|
||||
|
||||
class _PassthroughLegacy(types.ModuleType):
|
||||
def __getattr__(self, attr):
|
||||
import importlib
|
||||
with contextlib.suppress(ImportError):
|
||||
return importlib.import_module(f'.{attr}', __name__)
|
||||
|
||||
legacy = importlib.import_module('._legacy', __name__)
|
||||
if not hasattr(legacy, attr):
|
||||
raise AttributeError(f'module {__name__} has no attribute {attr}')
|
||||
|
||||
# XXX: Implement this the same way as other DeprecationWarnings without circular import
|
||||
import warnings
|
||||
warnings.warn(DeprecationWarning(f'{__name__}.{attr} is deprecated'), stacklevel=2)
|
||||
return getattr(legacy, attr)
|
||||
|
||||
|
||||
# Python 3.6 does not have module level __getattr__
|
||||
# https://peps.python.org/pep-0562/
|
||||
sys.modules[__name__].__class__ = _PassthroughLegacy
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
from asyncio import * # noqa: F403
|
||||
|
||||
from . import tasks # noqa: F401
|
||||
from ..compat_utils import passthrough_module
|
||||
|
||||
passthrough_module(__name__, 'asyncio')
|
||||
del passthrough_module
|
||||
|
||||
try:
|
||||
run # >= 3.7
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
from asyncio.tasks import * # noqa: F403
|
||||
|
||||
from ..compat_utils import passthrough_module
|
||||
|
||||
passthrough_module(__name__, 'asyncio.tasks')
|
||||
del passthrough_module
|
||||
|
||||
try: # >= 3.7
|
||||
all_tasks
|
||||
except NameError:
|
||||
|
|
44
yt_dlp/compat/compat_utils.py
Normal file
44
yt_dlp/compat/compat_utils.py
Normal file
|
@ -0,0 +1,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
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
from re import * # F403
|
||||
|
||||
from .compat_utils import passthrough_module
|
||||
|
||||
passthrough_module(__name__, 're')
|
||||
del passthrough_module
|
||||
|
||||
try:
|
||||
Pattern # >= 3.7
|
||||
except NameError:
|
||||
|
|
Loading…
Reference in a new issue