mirror of https://github.com/streamlink/streamlink
plugin: drop deprecated Plugin constructor wrapper
Streamlink 5.0.0 added this compatibility wrapper for the Plugin class constructor after its signature got changed.
This commit is contained in:
parent
7f2ea447b2
commit
b0982df271
|
@ -1,10 +1,8 @@
|
|||
import ast
|
||||
import inspect
|
||||
import logging
|
||||
import operator
|
||||
import re
|
||||
import time
|
||||
import warnings
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
from http.cookiejar import Cookie
|
||||
|
@ -218,16 +216,6 @@ class Matches(_MCollection[Optional[Match]]):
|
|||
return next(((matcher.pattern, match) for matcher, match in matches if match is not None), (None, None))
|
||||
|
||||
|
||||
# Add front- and back-wrappers to the deprecated plugin's method resolution order (see Plugin.__new__)
|
||||
class PluginWrapperMeta(type):
|
||||
def mro(cls):
|
||||
# cls.__base__ is the PluginWrapperFront which is based on the deprecated plugin class
|
||||
mro = list(cls.__base__.__mro__)
|
||||
# cls is the PluginWrapperBack and needs to be inserted after the deprecated plugin class
|
||||
mro.insert(2, cls)
|
||||
return mro
|
||||
|
||||
|
||||
class Plugin:
|
||||
"""
|
||||
Plugin base class for retrieving streams and metadata from the URL specified.
|
||||
|
@ -277,45 +265,6 @@ class Plugin:
|
|||
# deprecated
|
||||
priority: Callable[[str], int]
|
||||
|
||||
# Handle deprecated plugin constructors which only take the url argument
|
||||
def __new__(cls, *args, **kwargs):
|
||||
# Ignore plugins without custom constructors or wrappers
|
||||
if cls.__init__ is Plugin.__init__ or hasattr(cls, "_IS_DEPRECATED_PLUGIN_WRAPPER"):
|
||||
return super().__new__(cls)
|
||||
|
||||
# Ignore custom constructors which have a formal "session" parameter or a variable positional parameter
|
||||
sig = inspect.signature(cls.__init__).parameters
|
||||
if "session" in sig or any(param.kind == inspect.Parameter.VAR_POSITIONAL for param in sig.values()):
|
||||
return super().__new__(cls)
|
||||
|
||||
# Wrapper class which overrides the very first constructor in the MRO
|
||||
# noinspection PyAbstractClass
|
||||
class PluginWrapperFront(cls):
|
||||
_IS_DEPRECATED_PLUGIN_WRAPPER = True
|
||||
|
||||
# The __module__ value needs to be copied
|
||||
__module__ = cls.__module__
|
||||
|
||||
def __init__(self, session, url):
|
||||
# Take any arguments, but only pass the URL to the custom constructor of the deprecated plugin
|
||||
# noinspection PyArgumentList
|
||||
super().__init__(url)
|
||||
warnings.warn(
|
||||
f"Initialized {self.module} plugin with deprecated constructor",
|
||||
FutureWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
# Wrapper class which comes after the deprecated plugin in the MRO
|
||||
# noinspection PyAbstractClass
|
||||
class PluginWrapperBack(PluginWrapperFront, metaclass=PluginWrapperMeta):
|
||||
def __init__(self, *_, **__):
|
||||
# Take any arguments from the super() call of the constructor of the deprecated plugin,
|
||||
# but pass the right args and keywords to the Plugin constructor
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
return cls.__new__(PluginWrapperBack, *args, **kwargs)
|
||||
|
||||
def __init__(self, session: "Streamlink", url: str, options: Optional[Options] = None):
|
||||
"""
|
||||
:param session: The Streamlink session instance
|
||||
|
|
|
@ -44,12 +44,6 @@ class CustomConstructorTwoPlugin(FakePlugin):
|
|||
super().__init__(session, url)
|
||||
|
||||
|
||||
class DeprecatedPlugin(FakePlugin):
|
||||
def __init__(self, url):
|
||||
super().__init__(url) # type: ignore[call-arg]
|
||||
self.custom_attribute = url.upper()
|
||||
|
||||
|
||||
class TestPlugin:
|
||||
@pytest.mark.parametrize(("pluginclass", "module", "logger"), [
|
||||
(Plugin, "plugin", "streamlink.plugin.plugin"),
|
||||
|
@ -79,35 +73,6 @@ class TestPlugin:
|
|||
|
||||
assert mock_load_cookies.call_args_list == [call()]
|
||||
|
||||
def test_constructor_wrapper(self, recwarn: pytest.WarningsRecorder):
|
||||
session = Mock()
|
||||
with patch("streamlink.plugin.plugin.Cache") as mock_cache, \
|
||||
patch.object(DeprecatedPlugin, "load_cookies") as mock_load_cookies:
|
||||
plugin = DeprecatedPlugin(session, "http://localhost") # type: ignore[call-arg]
|
||||
|
||||
assert isinstance(plugin, DeprecatedPlugin)
|
||||
assert plugin.custom_attribute == "HTTP://LOCALHOST"
|
||||
assert [(record.category, str(record.message), record.filename) for record in recwarn.list] == [
|
||||
(
|
||||
FutureWarning,
|
||||
"Initialized test_plugin plugin with deprecated constructor",
|
||||
__file__,
|
||||
),
|
||||
]
|
||||
|
||||
assert plugin.session is session
|
||||
assert plugin.url == "http://localhost"
|
||||
|
||||
assert plugin.module == "test_plugin"
|
||||
|
||||
assert isinstance(plugin.logger, logging.Logger)
|
||||
assert plugin.logger.name == "tests.test_plugin"
|
||||
|
||||
assert mock_cache.call_args_list == [call(filename="plugin-cache.json", key_prefix="test_plugin")]
|
||||
assert plugin.cache == mock_cache()
|
||||
|
||||
assert mock_load_cookies.call_args_list == [call()]
|
||||
|
||||
def test_constructor_options(self):
|
||||
one = FakePlugin(Mock(), "https://mocked", Options({"key": "val"}))
|
||||
two = FakePlugin(Mock(), "https://mocked")
|
||||
|
|
Loading…
Reference in New Issue