Skip to content

Commit

Permalink
cli: list all dependencies in debug output
Browse files Browse the repository at this point in the history
- Require importlib-metadata as fallback on Python < 3.8
- Add importlib_metadata to streamlink_cli.compat
- List all dependencies in `log_current_versions`
- Update tests
  • Loading branch information
bastimeyer committed Jun 5, 2022
1 parent 68e6017 commit 0b539fd
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 43 deletions.
1 change: 1 addition & 0 deletions setup.cfg
Expand Up @@ -38,6 +38,7 @@ package_dir =
=src
packages = find:
install_requires =
importlib-metadata <4.3 ; python_version<"3.8"
isodate
lxml >=4.6.4,<5.0
pycountry
Expand Down
5 changes: 5 additions & 0 deletions src/streamlink_cli/compat.py
Expand Up @@ -3,6 +3,11 @@
from pathlib import Path
from typing import BinaryIO, TYPE_CHECKING

try:
import importlib.metadata as importlib_metadata # type: ignore[import] # noqa: F401
except ImportError: # pragma: no cover
import importlib_metadata # type: ignore[import] # noqa: F401


is_darwin = sys.platform == "darwin"
is_win32 = os.name == "nt"
Expand Down
19 changes: 13 additions & 6 deletions src/streamlink_cli/main.py
Expand Up @@ -3,6 +3,7 @@
import logging
import os
import platform
import re
import signal
import sys
from contextlib import closing
Expand All @@ -15,8 +16,6 @@
from typing import Any, Dict, List, Optional, Type, Union

import requests
from socks import __version__ as socks_version # type: ignore[import]
from websocket import __version__ as websocket_version # type: ignore[import]

import streamlink.logger as logger
from streamlink import NoPluginError, PluginError, StreamError, Streamlink, __version__ as streamlink_version
Expand All @@ -26,7 +25,7 @@
from streamlink.stream.stream import Stream, StreamIO
from streamlink.utils.named_pipe import NamedPipe
from streamlink_cli.argparser import build_parser
from streamlink_cli.compat import DeprecatedPath, is_win32, stdout
from streamlink_cli.compat import DeprecatedPath, importlib_metadata, is_win32, stdout
from streamlink_cli.console import ConsoleOutput, ConsoleUserInputRequester
from streamlink_cli.constants import CONFIG_FILES, DEFAULT_STREAM_METADATA, LOG_DIR, PLUGIN_DIRS, STREAM_SYNONYMS
from streamlink_cli.output import FileOutput, PlayerOutput
Expand Down Expand Up @@ -943,9 +942,17 @@ def log_current_versions():
log.debug(f"OS: {os_version}")
log.debug(f"Python: {platform.python_version()}")
log.debug(f"Streamlink: {streamlink_version}")
log.debug(f"Requests({requests.__version__}), "
f"Socks({socks_version}), "
f"Websocket({websocket_version})")

# https://peps.python.org/pep-0508/#names
re_name = re.compile(r"[A-Z\d][A-Z\d._-]*[A-Z\d]", re.IGNORECASE)
log.debug("Dependencies:")
for match in filter(bool, map(re_name.match, importlib_metadata.requires("streamlink"))):
name = match.group(0)
try:
version = importlib_metadata.version(name)
except importlib_metadata.PackageNotFoundError:
continue
log.debug(f" {name}: {version}")


def log_current_arguments(session, parser):
Expand Down
90 changes: 53 additions & 37 deletions tests/test_cli_main.py
Expand Up @@ -574,18 +574,18 @@ def test_custom_multiple(self, mock_log):


class _TestCLIMainLogging(unittest.TestCase):
# stop test execution at the setup_signals() call, as we're not interested in what comes afterwards
class StopTest(Exception):
pass

@classmethod
def subject(cls, argv, **kwargs):
session = Streamlink()
session.load_plugins(os.path.join(os.path.dirname(__file__), "plugin"))

# stop test execution at the setup_signals() call, as we're not interested in what comes afterwards
class StopTest(Exception):
pass

with patch("streamlink_cli.main.os.geteuid", create=True, new=Mock(return_value=kwargs.get("euid", 1000))), \
patch("streamlink_cli.main.streamlink", session), \
patch("streamlink_cli.main.setup_signals", side_effect=StopTest), \
patch("streamlink_cli.main.setup_signals", side_effect=cls.StopTest), \
patch("streamlink_cli.main.CONFIG_FILES", []), \
patch("streamlink_cli.main.setup_streamlink"), \
patch("streamlink_cli.main.setup_plugins"), \
Expand All @@ -595,7 +595,7 @@ class StopTest(Exception):
mock_argv.__getitem__.side_effect = lambda x: argv[x]
try:
streamlink_cli.main.main()
except StopTest:
except cls.StopTest:
pass

def tearDown(self):
Expand Down Expand Up @@ -712,55 +712,71 @@ def test_log_root_warning(self, mock_log):

@patch("streamlink_cli.main.log")
@patch("streamlink_cli.main.streamlink_version", "streamlink")
@patch("streamlink_cli.main.requests.__version__", "requests")
@patch("streamlink_cli.main.socks_version", "socks")
@patch("streamlink_cli.main.websocket_version", "websocket")
@patch("streamlink_cli.main.importlib_metadata")
@patch("streamlink_cli.main.log_current_arguments", Mock(side_effect=_TestCLIMainLogging.StopTest))
@patch("platform.python_version", Mock(return_value="python"))
def test_log_current_versions(self, mock_log):
def test_log_current_versions(self, mock_importlib_metadata: Mock, mock_log: Mock):
class FakePackageNotFoundError(Exception):
pass

def version(dist):
if dist == "foo":
return "1.2.3"
if dist == "bar-baz":
return "2.0.0"
raise FakePackageNotFoundError()

mock_importlib_metadata.PackageNotFoundError = FakePackageNotFoundError
mock_importlib_metadata.requires.return_value = ["foo>1", "bar-baz==2", "qux~=3"]
mock_importlib_metadata.version.side_effect = version

self.subject(["streamlink", "--loglevel", "info"])
self.assertEqual(mock_log.debug.mock_calls, [], "Doesn't log anything if not debug logging")

with patch("sys.platform", "linux"), \
patch("platform.platform", Mock(return_value="linux")):
self.subject(["streamlink", "--loglevel", "debug"])
self.assertEqual(
mock_log.debug.mock_calls[:4],
[
call("OS: linux"),
call("Python: python"),
call("Streamlink: streamlink"),
call("Requests(requests), Socks(socks), Websocket(websocket)")
]
)
assert mock_importlib_metadata.requires.mock_calls == [call("streamlink")]
assert mock_log.debug.mock_calls == [
call("OS: linux"),
call("Python: python"),
call("Streamlink: streamlink"),
call("Dependencies:"),
call(" foo: 1.2.3"),
call(" bar-baz: 2.0.0"),
]
mock_importlib_metadata.requires.reset_mock()
mock_log.debug.reset_mock()

with patch("sys.platform", "darwin"), \
patch("platform.mac_ver", Mock(return_value=["0.0.0"])):
self.subject(["streamlink", "--loglevel", "debug"])
self.assertEqual(
mock_log.debug.mock_calls[:4],
[
call("OS: macOS 0.0.0"),
call("Python: python"),
call("Streamlink: streamlink"),
call("Requests(requests), Socks(socks), Websocket(websocket)")
]
)
assert mock_importlib_metadata.requires.mock_calls == [call("streamlink")]
assert mock_log.debug.mock_calls == [
call("OS: macOS 0.0.0"),
call("Python: python"),
call("Streamlink: streamlink"),
call("Dependencies:"),
call(" foo: 1.2.3"),
call(" bar-baz: 2.0.0"),
]
mock_importlib_metadata.requires.reset_mock()
mock_log.debug.reset_mock()

with patch("sys.platform", "win32"), \
patch("platform.system", Mock(return_value="Windows")), \
patch("platform.release", Mock(return_value="0.0.0")):
self.subject(["streamlink", "--loglevel", "debug"])
self.assertEqual(
mock_log.debug.mock_calls[:4],
[
call("OS: Windows 0.0.0"),
call("Python: python"),
call("Streamlink: streamlink"),
call("Requests(requests), Socks(socks), Websocket(websocket)")
]
)
assert mock_importlib_metadata.requires.mock_calls == [call("streamlink")]
assert mock_log.debug.mock_calls == [
call("OS: Windows 0.0.0"),
call("Python: python"),
call("Streamlink: streamlink"),
call("Dependencies:"),
call(" foo: 1.2.3"),
call(" bar-baz: 2.0.0"),
]
mock_importlib_metadata.requires.reset_mock()
mock_log.debug.reset_mock()

@patch("streamlink_cli.main.log")
Expand Down

0 comments on commit 0b539fd

Please sign in to comment.