streamlink/tests/test_session.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

570 lines
23 KiB
Python
Raw Normal View History

import re
import unittest
import warnings
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
from pathlib import Path
from socket import AF_INET, AF_INET6
from unittest.mock import Mock, call, patch
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
import pytest
import requests_mock
import urllib3
2012-11-19 03:47:13 +01:00
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
import tests.plugin
from streamlink.exceptions import NoPluginError, StreamlinkDeprecationWarning
from streamlink.plugin import HIGH_PRIORITY, LOW_PRIORITY, NO_PRIORITY, NORMAL_PRIORITY, Plugin, pluginmatcher
from streamlink.session import Streamlink
2021-09-20 09:46:12 +02:00
from streamlink.stream.hls import HLSStream
from streamlink.stream.http import HTTPStream
2012-11-19 03:47:13 +01:00
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
PATH_TESTPLUGINS = Path(tests.plugin.__path__[0])
PATH_TESTPLUGINS_OVERRIDE = PATH_TESTPLUGINS / "override"
2022-05-21 00:38:18 +02:00
_original_allowed_gai_family = urllib3.util.connection.allowed_gai_family # type: ignore[attr-defined]
class EmptyPlugin(Plugin):
def _get_streams(self):
pass # pragma: no cover
# TODO: rewrite using pytest
2012-11-19 03:47:13 +01:00
class TestSession(unittest.TestCase):
mocker: requests_mock.Mocker
def setUp(self):
self.mocker = requests_mock.Mocker()
self.mocker.register_uri(requests_mock.ANY, requests_mock.ANY, text="")
self.mocker.start()
def tearDown(self):
self.mocker.stop()
Streamlink.resolve_url.cache_clear()
def subject(self, load_plugins=True):
session = Streamlink()
if load_plugins:
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
session.load_plugins(str(PATH_TESTPLUGINS))
session.load_plugins(str(PATH_TESTPLUGINS_OVERRIDE))
return session
2012-11-19 03:47:13 +01:00
# ----
2012-11-19 03:47:13 +01:00
def test_load_plugins(self):
session = self.subject()
plugins = session.get_plugins()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert "testplugin" in plugins
assert "testplugin_missing" not in plugins
assert "testplugin_invalid" not in plugins
2012-11-19 03:47:13 +01:00
def test_load_plugins_builtin(self):
session = self.subject()
plugins = session.get_plugins()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert "twitch" in plugins
assert plugins["twitch"].__module__ == "streamlink.plugins.twitch"
@patch("streamlink.session.log")
def test_load_plugins_override(self, mock_log):
session = self.subject()
plugins = session.get_plugins()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert "testplugin" in plugins
assert "testplugin_override" not in plugins
assert plugins["testplugin"].__name__ == "TestPluginOverride"
assert plugins["testplugin"].__module__ == "streamlink.plugins.testplugin"
assert mock_log.debug.call_args_list == [
call(f"Plugin testplugin is being overridden by {PATH_TESTPLUGINS_OVERRIDE / 'testplugin.py'}"),
]
@patch("streamlink.session.load_module")
@patch("streamlink.session.log")
def test_load_plugins_importerror(self, mock_log, mock_load_module):
mock_load_module.side_effect = ImportError()
session = self.subject()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert not session.get_plugins()
assert len(mock_log.exception.call_args_list) > 0
@patch("streamlink.session.load_module")
@patch("streamlink.session.log")
def test_load_plugins_syntaxerror(self, mock_log, mock_load_module):
mock_load_module.side_effect = SyntaxError()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
with pytest.raises(SyntaxError):
self.subject()
2012-11-19 03:47:13 +01:00
def test_resolve_url(self):
session = self.subject()
plugins = session.get_plugins()
with warnings.catch_warnings(record=True) as record_warnings:
pluginname, pluginclass, resolved_url = session.resolve_url("http://test.se/channel")
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert issubclass(pluginclass, Plugin)
assert pluginclass is plugins["testplugin"]
assert resolved_url == "http://test.se/channel"
assert hasattr(session.resolve_url, "cache_info"), "resolve_url has a lookup cache"
assert record_warnings == []
2012-11-19 03:47:13 +01:00
def test_resolve_url__noplugin(self):
session = self.subject()
self.mocker.get("http://invalid2", status_code=301, headers={"Location": "http://invalid3"})
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
with pytest.raises(NoPluginError):
session.resolve_url("http://invalid1")
with pytest.raises(NoPluginError):
session.resolve_url("http://invalid2")
def test_resolve_url__redirected(self):
session = self.subject()
plugins = session.get_plugins()
self.mocker.head("http://redirect1", status_code=501)
self.mocker.get("http://redirect1", status_code=301, headers={"Location": "http://redirect2"})
self.mocker.head("http://redirect2", status_code=301, headers={"Location": "http://test.se/channel"})
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
pluginname, pluginclass, resolved_url = session.resolve_url("http://redirect1")
assert issubclass(pluginclass, Plugin)
assert pluginclass is plugins["testplugin"]
assert resolved_url == "http://test.se/channel"
def test_resolve_url_no_redirect(self):
session = self.subject()
plugins = session.get_plugins()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
pluginname, pluginclass, resolved_url = session.resolve_url_no_redirect("http://test.se/channel")
assert issubclass(pluginclass, Plugin)
assert pluginclass is plugins["testplugin"]
assert resolved_url == "http://test.se/channel"
def test_resolve_url_no_redirect__noplugin(self):
session = self.subject()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
with pytest.raises(NoPluginError):
session.resolve_url_no_redirect("http://invalid")
def test_resolve_url_scheme(self):
@pluginmatcher(re.compile("http://insecure"))
class PluginHttp(EmptyPlugin):
pass
@pluginmatcher(re.compile("https://secure"))
class PluginHttps(EmptyPlugin):
pass
session = self.subject(load_plugins=False)
session.plugins = {
"insecure": PluginHttp,
"secure": PluginHttps,
}
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
with pytest.raises(NoPluginError):
session.resolve_url("insecure")
assert session.resolve_url("http://insecure")[1] is PluginHttp
with pytest.raises(NoPluginError):
session.resolve_url("https://insecure")
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert session.resolve_url("secure")[1] is PluginHttps
with pytest.raises(NoPluginError):
session.resolve_url("http://secure")
assert session.resolve_url("https://secure")[1] is PluginHttps
def test_resolve_url_priority(self):
@pluginmatcher(priority=HIGH_PRIORITY, pattern=re.compile(
"https://(high|normal|low|no)$",
))
class HighPriority(EmptyPlugin):
pass
@pluginmatcher(priority=NORMAL_PRIORITY, pattern=re.compile(
"https://(normal|low|no)$",
))
class NormalPriority(EmptyPlugin):
pass
@pluginmatcher(priority=LOW_PRIORITY, pattern=re.compile(
"https://(low|no)$",
))
class LowPriority(EmptyPlugin):
pass
@pluginmatcher(priority=NO_PRIORITY, pattern=re.compile(
"https://(no)$",
))
class NoPriority(EmptyPlugin):
pass
session = self.subject(load_plugins=False)
session.plugins = {
"high": HighPriority,
"normal": NormalPriority,
"low": LowPriority,
"no": NoPriority,
}
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
no = session.resolve_url_no_redirect("no")[1]
low = session.resolve_url_no_redirect("low")[1]
normal = session.resolve_url_no_redirect("normal")[1]
high = session.resolve_url_no_redirect("high")[1]
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert no is HighPriority
assert low is HighPriority
assert normal is HighPriority
assert high is HighPriority
session.resolve_url.cache_clear()
session.plugins = {
"no": NoPriority,
}
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
with pytest.raises(NoPluginError):
session.resolve_url_no_redirect("no")
def test_resolve_deprecated(self):
@pluginmatcher(priority=LOW_PRIORITY, pattern=re.compile(
"https://low",
))
class LowPriority(EmptyPlugin):
pass
class DeprecatedNormalPriority(EmptyPlugin):
# noinspection PyUnusedLocal
@classmethod
def can_handle_url(cls, url):
return True
class DeprecatedHighPriority(DeprecatedNormalPriority):
# noinspection PyUnusedLocal
@classmethod
def priority(cls, url):
return HIGH_PRIORITY
session = self.subject(load_plugins=False)
session.plugins = {
"empty": EmptyPlugin,
"low": LowPriority,
"dep-normal-one": DeprecatedNormalPriority,
"dep-normal-two": DeprecatedNormalPriority,
"dep-high": DeprecatedHighPriority,
}
with pytest.warns() as recwarn:
plugin = session.resolve_url_no_redirect("low")[1]
assert plugin is DeprecatedHighPriority
assert [(record.category, str(record.message)) for record in recwarn.list] == [
(StreamlinkDeprecationWarning, "Resolved plugin dep-normal-one with deprecated can_handle_url API"),
(StreamlinkDeprecationWarning, "Resolved plugin dep-high with deprecated can_handle_url API"),
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
]
2012-11-19 03:47:13 +01:00
def test_options(self):
session = self.subject()
session.set_option("test_option", "option")
2023-02-16 00:51:25 +01:00
assert session.get_option("test_option") == "option"
assert session.get_option("non_existing") is None
2012-11-19 03:47:13 +01:00
2023-02-16 00:51:25 +01:00
assert session.get_plugin_option("testplugin", "a_option") == "default"
session.set_plugin_option("testplugin", "another_option", "test")
2023-02-16 00:51:25 +01:00
assert session.get_plugin_option("testplugin", "another_option") == "test"
assert session.get_plugin_option("non_existing", "non_existing") is None
assert session.get_plugin_option("testplugin", "non_existing") is None
2012-11-19 03:47:13 +01:00
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
def test_streams(self):
session = self.subject()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
streams = session.streams("http://test.se/channel")
2012-11-19 03:47:13 +01:00
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
assert "best" in streams
assert "worst" in streams
assert streams["best"] is streams["1080p"]
assert streams["worst"] is streams["350k"]
assert isinstance(streams["http"], HTTPStream)
assert isinstance(streams["hls"], HLSStream)
2012-11-19 03:47:13 +01:00
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
def test_streams_stream_types(self):
session = self.subject()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
streams = session.streams("http://test.se/channel", stream_types=["http", "hls"])
assert isinstance(streams["480p"], HTTPStream)
assert isinstance(streams["480p_hls"], HLSStream)
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
streams = session.streams("http://test.se/channel", stream_types=["hls", "http"])
assert isinstance(streams["480p"], HLSStream)
assert isinstance(streams["480p_http"], HTTPStream)
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
def test_streams_stream_sorting_excludes(self):
session = self.subject()
plugin: remove Plugin.bind() This changes the way how the Streamlink session and other objects like the plugin cache and logger are stored on each plugin. Previously, those objects were set as class attributes on every `Plugin` class via `Plugin.bind()` when loading plugins via the session's `load_plugins()` method that gets called on initialization. This meant that whenever a new Streamlink session was initialized, references to it (including a dict of every loaded plugin) were set on each `Plugin` class as a class attribute, and Python's garbage collector could not get rid of this memory when deleting the session instance that was created last. Removing `Plugin.bind()`, passing the session via the `Plugin.__init__` constructor, and setting the cache, logger, etc. on `Plugin` instances instead (only one gets initialized by `streamlink_cli`), removes those static references that prevent the garbage collector to work. Since the plugin "module" name now doesn't get set via `Plugin.bind()` anymore, it derives its name via `self.__class__.__module__` on its own, which means a change of the return type of `Streamlink.resolve_url()` is necessary in order to pass the plugin name to `streamlink_cli`, so that it can load config files and initialize plugin arguments, etc. Breaking changes: - Remove `Plugin.bind()` - Pass the `session` instance via the Plugin constructor and set the `module`, `cache` and `logger` on the plugin instance instead. Derive `module` from the actual module name. - Change the return type of `Session.resolve_url()` and include the resolved plugin name in the returned tuple Other changes: - Remove `pluginclass.bind()` call from `Session.load_plugins()` and use the loader's module name directly on the `Session.plugins` dict - Remove initialization check from `Plugin` cookie methods - Update streamlink_cli.main module according to breaking changes - Update tests respectively - Add explicit plugin initialization test - Update tests with plugin constructors and custom plugin names - Move testplugin override module, so that it shares the same module name as the main testplugin module. Rel `Session.load_plugins()` - Refactor most session tests and replace unneeded `resolve_url()` wrappers in favor of calling `session.streams()`
2022-08-25 10:55:38 +02:00
streams = session.streams("http://test.se/channel", sorting_excludes=[])
assert "best" in streams
assert "worst" in streams
assert "best-unfiltered" not in streams
assert "worst-unfiltered" not in streams
assert streams["worst"] is streams["350k"]
assert streams["best"] is streams["1080p"]
streams = session.streams("http://test.se/channel", sorting_excludes=["1080p", "3000k"])
assert "best" in streams
assert "worst" in streams
assert "best-unfiltered" not in streams
assert "worst-unfiltered" not in streams
assert streams["worst"] is streams["350k"]
assert streams["best"] is streams["1500k"]
streams = session.streams("http://test.se/channel", sorting_excludes=[">=1080p", ">1500k"])
assert streams["best"] is streams["1500k"]
streams = session.streams("http://test.se/channel", sorting_excludes=lambda q: not q.endswith("p"))
assert streams["best"] is streams["3000k"]
streams = session.streams("http://test.se/channel", sorting_excludes=lambda q: False)
assert "best" not in streams
assert "worst" not in streams
assert "best-unfiltered" in streams
assert "worst-unfiltered" in streams
assert streams["worst-unfiltered"] is streams["350k"]
assert streams["best-unfiltered"] is streams["1080p"]
streams = session.streams("http://test.se/UnsortableStreamNames")
assert "best" not in streams
assert "worst" not in streams
assert "best-unfiltered" not in streams
assert "worst-unfiltered" not in streams
assert "vod" in streams
assert "vod_alt" in streams
assert "vod_alt2" in streams
def test_set_and_get_locale(self):
session = Streamlink()
session.set_option("locale", "en_US")
2023-02-16 00:51:25 +01:00
assert session.localization.country.alpha2 == "US"
assert session.localization.language.alpha2 == "en"
assert session.localization.language_code == "en_US"
@patch("streamlink.session.HTTPSession")
def test_interface(self, mock_httpsession):
adapter_http = Mock(poolmanager=Mock(connection_pool_kw={}))
adapter_https = Mock(poolmanager=Mock(connection_pool_kw={}))
adapter_foo = Mock(poolmanager=Mock(connection_pool_kw={}))
mock_httpsession.return_value = Mock(adapters={
"http://": adapter_http,
"https://": adapter_https,
"foo://": adapter_foo,
})
session = self.subject(load_plugins=False)
2023-02-16 00:51:25 +01:00
assert session.get_option("interface") is None
session.set_option("interface", "my-interface")
2023-02-16 00:51:25 +01:00
assert adapter_http.poolmanager.connection_pool_kw == {"source_address": ("my-interface", 0)}
assert adapter_https.poolmanager.connection_pool_kw == {"source_address": ("my-interface", 0)}
assert adapter_foo.poolmanager.connection_pool_kw == {}
assert session.get_option("interface") == "my-interface"
session.set_option("interface", None)
2023-02-16 00:51:25 +01:00
assert adapter_http.poolmanager.connection_pool_kw == {}
assert adapter_https.poolmanager.connection_pool_kw == {}
assert adapter_foo.poolmanager.connection_pool_kw == {}
assert session.get_option("interface") is None
@patch("streamlink.session.urllib3_util_connection", allowed_gai_family=_original_allowed_gai_family)
def test_ipv4_ipv6(self, mock_urllib3_util_connection):
session = self.subject(load_plugins=False)
assert session.get_option("ipv4") is False
assert session.get_option("ipv6") is False
assert mock_urllib3_util_connection.allowed_gai_family is _original_allowed_gai_family
session.set_option("ipv4", True)
assert session.get_option("ipv4") is True
assert session.get_option("ipv6") is False
assert mock_urllib3_util_connection.allowed_gai_family is not _original_allowed_gai_family
assert mock_urllib3_util_connection.allowed_gai_family() is AF_INET
session.set_option("ipv4", False)
assert session.get_option("ipv4") is False
assert session.get_option("ipv6") is False
assert mock_urllib3_util_connection.allowed_gai_family is _original_allowed_gai_family
session.set_option("ipv6", True)
assert session.get_option("ipv4") is False
assert session.get_option("ipv6") is True
assert mock_urllib3_util_connection.allowed_gai_family is not _original_allowed_gai_family
assert mock_urllib3_util_connection.allowed_gai_family() is AF_INET6
session.set_option("ipv6", False)
assert session.get_option("ipv4") is False
assert session.get_option("ipv6") is False
assert mock_urllib3_util_connection.allowed_gai_family is _original_allowed_gai_family
session.set_option("ipv4", True)
session.set_option("ipv6", False)
assert session.get_option("ipv4") is True
assert session.get_option("ipv6") is False
assert mock_urllib3_util_connection.allowed_gai_family is _original_allowed_gai_family
@patch("streamlink.session.urllib3_util_ssl", DEFAULT_CIPHERS="foo:!bar:baz")
def test_http_disable_dh(self, mock_urllib3_util_ssl):
session = self.subject(load_plugins=False)
assert mock_urllib3_util_ssl.DEFAULT_CIPHERS == "foo:!bar:baz"
session.set_option("http-disable-dh", True)
assert mock_urllib3_util_ssl.DEFAULT_CIPHERS == "foo:!bar:baz:!DH"
session.set_option("http-disable-dh", True)
assert mock_urllib3_util_ssl.DEFAULT_CIPHERS == "foo:!bar:baz:!DH"
session.set_option("http-disable-dh", False)
assert mock_urllib3_util_ssl.DEFAULT_CIPHERS == "foo:!bar:baz"
class TestSessionOptionHttpProxy:
@pytest.fixture()
2023-02-16 00:51:04 +01:00
def _no_deprecation(self, recwarn: pytest.WarningsRecorder):
yield
assert recwarn.list == []
@pytest.fixture()
2023-02-16 00:51:04 +01:00
def _logs_deprecation(self, recwarn: pytest.WarningsRecorder):
yield
assert [(record.category, str(record.message), record.filename) for record in recwarn.list] == [
(
StreamlinkDeprecationWarning,
"The `https-proxy` option has been deprecated in favor of a single `http-proxy` option",
__file__,
),
]
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_no_deprecation")
def test_https_proxy_default(self, session: Streamlink):
session.set_option("http-proxy", "http://testproxy.com")
assert session.http.proxies["http"] == "http://testproxy.com"
assert session.http.proxies["https"] == "http://testproxy.com"
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_logs_deprecation")
def test_https_proxy_set_first(self, session: Streamlink):
session.set_option("https-proxy", "https://testhttpsproxy.com")
session.set_option("http-proxy", "http://testproxy.com")
assert session.http.proxies["http"] == "http://testproxy.com"
assert session.http.proxies["https"] == "http://testproxy.com"
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_logs_deprecation")
def test_https_proxy_default_override(self, session: Streamlink):
session.set_option("http-proxy", "http://testproxy.com")
session.set_option("https-proxy", "https://testhttpsproxy.com")
assert session.http.proxies["http"] == "https://testhttpsproxy.com"
assert session.http.proxies["https"] == "https://testhttpsproxy.com"
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_logs_deprecation")
def test_https_proxy_set_only(self, session: Streamlink):
session.set_option("https-proxy", "https://testhttpsproxy.com")
assert session.http.proxies["http"] == "https://testhttpsproxy.com"
assert session.http.proxies["https"] == "https://testhttpsproxy.com"
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_no_deprecation")
def test_http_proxy_socks(self, session: Streamlink):
session.set_option("http-proxy", "socks5://localhost:1234")
assert session.http.proxies["http"] == "socks5://localhost:1234"
assert session.http.proxies["https"] == "socks5://localhost:1234"
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_logs_deprecation")
def test_https_proxy_socks(self, session: Streamlink):
session.set_option("https-proxy", "socks5://localhost:1234")
assert session.http.proxies["http"] == "socks5://localhost:1234"
assert session.http.proxies["https"] == "socks5://localhost:1234"
2022-09-05 14:58:23 +02:00
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_no_deprecation")
def test_get_http_proxy(self, session: Streamlink):
session.http.proxies["http"] = "http://testproxy1.com"
session.http.proxies["https"] = "http://testproxy2.com"
assert session.get_option("http-proxy") == "http://testproxy1.com"
2023-02-16 00:51:04 +01:00
@pytest.mark.usefixtures("_logs_deprecation")
def test_get_https_proxy(self, session: Streamlink):
session.http.proxies["http"] = "http://testproxy1.com"
session.http.proxies["https"] = "http://testproxy2.com"
assert session.get_option("https-proxy") == "http://testproxy2.com"
@pytest.mark.usefixtures("_logs_deprecation")
def test_https_proxy_get_directly(self, session: Streamlink):
# The DeprecationWarning's origin must point to this call, even without the set_option() wrapper
session.options.get("https-proxy")
@pytest.mark.usefixtures("_logs_deprecation")
def test_https_proxy_set_directly(self, session: Streamlink):
# The DeprecationWarning's origin must point to this call, even without the set_option() wrapper
session.options.set("https-proxy", "https://foo")
2022-09-05 14:58:23 +02:00
class TestOptionsKeyEqualsValue:
@pytest.fixture()
def option(self, request, session: Streamlink):
option, attr = request.param
httpsessionattr = getattr(session.http, attr)
assert session.get_option(option) is httpsessionattr
assert "foo" not in httpsessionattr
assert "bar" not in httpsessionattr
yield option
assert httpsessionattr.get("foo") == "foo=bar"
assert httpsessionattr.get("bar") == "123"
@pytest.mark.parametrize(
"option",
[
pytest.param(("http-cookies", "cookies"), id="http-cookies"),
pytest.param(("http-headers", "headers"), id="http-headers"),
pytest.param(("http-query-params", "params"), id="http-query-params"),
],
indirect=["option"],
)
2022-09-05 14:58:23 +02:00
def test_dict(self, session: Streamlink, option: str):
session.set_option(option, {"foo": "foo=bar", "bar": "123"})
@pytest.mark.parametrize(
("option", "value"),
[
pytest.param(("http-cookies", "cookies"), "foo=foo=bar;bar=123;baz", id="http-cookies"),
pytest.param(("http-headers", "headers"), "foo=foo=bar;bar=123;baz", id="http-headers"),
pytest.param(("http-query-params", "params"), "foo=foo=bar&bar=123&baz", id="http-query-params"),
],
indirect=["option"],
)
def test_string(self, session: Streamlink, option: str, value: str):
session.set_option(option, value)
2023-02-23 22:06:26 +01:00
@pytest.mark.parametrize(
("option", "attr", "default", "value"),
[
("http-ssl-cert", "cert", None, "foo"),
("http-ssl-verify", "verify", True, False),
("http-trust-env", "trust_env", True, False),
("http-timeout", "timeout", 20.0, 30.0),
],
)
def test_options_http_other(session: Streamlink, option: str, attr: str, default, value):
httpsessionattr = getattr(session.http, attr)
assert httpsessionattr == default
assert session.get_option(option) == httpsessionattr
session.set_option(option, value)
assert session.get_option(option) == value
class TestOptionsDocumentation:
@pytest.fixture()
def docstring(self, session: Streamlink):
docstring = session.set_option.__doc__
assert docstring is not None
return docstring
def test_default_option_is_documented(self, session: Streamlink, docstring: str):
assert session.options.keys()
for option in session.options:
assert f"* - {option}" in docstring, f"Option '{option}' is documented"
def test_documented_option_exists(self, session: Streamlink, docstring: str):
options = session.options
setters = options._MAP_SETTERS.keys()
documented = re.compile(r"\* - (\S+)").findall(docstring)[1:]
assert documented
for option in documented:
assert option in options or option in setters, f"Documented option '{option}' exists"