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:
bastimeyer 2023-06-28 01:32:18 +02:00 committed by Sebastian Meyer
parent 7f2ea447b2
commit b0982df271
2 changed files with 0 additions and 86 deletions

View File

@ -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

View File

@ -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")