Skip to content

Commit 6cdc3eb

Browse files
bastimeyerback-to
authored andcommitted
cli: fix order of config file deprecation log msgs
- Don't log when loading a config from a deprecated path when using the `--config` argument - Only load the first existing plugin-specific config file - Keep config file loading order - Add tests for setup_config_args
1 parent 79a4232 commit 6cdc3eb

File tree

7 files changed

+109
-13
lines changed

7 files changed

+109
-13
lines changed

src/streamlink_cli/main.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -633,12 +633,9 @@ def setup_args(parser: argparse.ArgumentParser, config_files: List[Path] = None,
633633
arglist = sys.argv[1:]
634634

635635
# Load arguments from config files
636-
for config_file in filter(lambda path: path.is_file(), config_files or []):
637-
if type(config_file) is DeprecatedPath:
638-
log.info(f"Loaded config from deprecated path, see CLI docs for how to migrate: {config_file}")
639-
arglist.insert(0, f"@{config_file}")
636+
configs = [f"@{config_file}" for config_file in config_files or []]
640637

641-
args, unknown = parser.parse_known_args(arglist)
638+
args, unknown = parser.parse_known_args(configs + arglist)
642639
if unknown and not ignore_unknown:
643640
msg = gettext('unrecognized arguments: %s')
644641
parser.error(msg % ' '.join(unknown))
@@ -654,20 +651,32 @@ def setup_args(parser: argparse.ArgumentParser, config_files: List[Path] = None,
654651
def setup_config_args(parser, ignore_unknown=False):
655652
config_files = []
656653

657-
if streamlink and args.url:
658-
with ignored(NoPluginError):
659-
plugin = streamlink.resolve_url(args.url)
660-
config_files += [path.with_name(f"{path.name}.{plugin.module}") for path in CONFIG_FILES]
661-
662654
if args.config:
663655
# We want the config specified last to get highest priority
664-
config_files += map(lambda path: Path(path).expanduser(), reversed(args.config))
656+
for config_file in map(lambda path: Path(path).expanduser(), reversed(args.config)):
657+
if config_file.is_file():
658+
config_files.append(config_file)
665659
else:
666660
# Only load first available default config
667661
for config_file in filter(lambda path: path.is_file(), CONFIG_FILES):
662+
if type(config_file) is DeprecatedPath:
663+
log.info(f"Loaded config from deprecated path, see CLI docs for how to migrate: {config_file}")
668664
config_files.append(config_file)
669665
break
670666

667+
if streamlink and args.url:
668+
# Only load first available plugin config
669+
with ignored(NoPluginError):
670+
plugin = streamlink.resolve_url(args.url)
671+
for config_file in CONFIG_FILES:
672+
config_file = config_file.with_name(f"{config_file.name}.{plugin.module}")
673+
if not config_file.is_file():
674+
continue
675+
if type(config_file) is DeprecatedPath:
676+
log.info(f"Loaded plugin config from deprecated path, see CLI docs for how to migrate: {config_file}")
677+
config_files.append(config_file)
678+
break
679+
671680
if config_files:
672681
setup_args(parser, config_files, ignore_unknown=ignore_unknown)
673682

tests/resources/cli/config/custom

Whitespace-only changes.

tests/resources/cli/config/primary

Whitespace-only changes.

tests/resources/cli/config/primary.testplugin

Whitespace-only changes.

tests/resources/cli/config/secondary

Whitespace-only changes.

tests/resources/cli/config/secondary.testplugin

Whitespace-only changes.

tests/test_cli_main.py

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@
99
import freezegun
1010

1111
import streamlink_cli.main
12+
import tests.resources
1213
from streamlink.plugin.plugin import Plugin
1314
from streamlink.session import Streamlink
14-
from streamlink_cli.compat import is_win32
15+
from streamlink_cli.compat import DeprecatedPath, is_win32
1516
from streamlink_cli.main import (
17+
NoPluginError,
1618
check_file_output,
1719
create_output,
1820
format_valid_streams,
1921
handle_stream,
2022
handle_url,
2123
log_current_arguments,
22-
resolve_stream_name
24+
resolve_stream_name,
25+
setup_config_args
2326
)
2427
from streamlink_cli.output import FileOutput, PlayerOutput
2528

@@ -269,6 +272,90 @@ def test_create_output_record_and_other_file_output(self):
269272
console.exit.assert_called_with("Cannot use record options with other file output options.")
270273

271274

275+
@patch("streamlink_cli.main.log")
276+
class TestCLIMainSetupConfigArgs(unittest.TestCase):
277+
configdir = Path(tests.resources.__path__[0], "cli", "config")
278+
parser = Mock()
279+
280+
@classmethod
281+
def subject(cls, config_files, **args):
282+
def resolve_url(name):
283+
if name == "noplugin":
284+
raise NoPluginError()
285+
return Mock(module="testplugin")
286+
287+
session = Mock()
288+
session.resolve_url.side_effect = resolve_url
289+
args.setdefault("url", "testplugin")
290+
291+
with patch("streamlink_cli.main.setup_args") as mock_setup_args, \
292+
patch("streamlink_cli.main.args", **args), \
293+
patch("streamlink_cli.main.streamlink", session), \
294+
patch("streamlink_cli.main.CONFIG_FILES", config_files):
295+
setup_config_args(cls.parser)
296+
return mock_setup_args
297+
298+
def test_no_plugin(self, mock_log):
299+
mock_setup_args = self.subject(
300+
[self.configdir / "primary", DeprecatedPath(self.configdir / "secondary")],
301+
config=None,
302+
url="noplugin"
303+
)
304+
expected = [self.configdir / "primary"]
305+
mock_setup_args.assert_called_once_with(self.parser, expected, ignore_unknown=False)
306+
self.assertEqual(mock_log.info.mock_calls, [])
307+
308+
def test_default_primary(self, mock_log):
309+
mock_setup_args = self.subject(
310+
[self.configdir / "primary", DeprecatedPath(self.configdir / "secondary")],
311+
config=None
312+
)
313+
expected = [self.configdir / "primary", self.configdir / "primary.testplugin"]
314+
mock_setup_args.assert_called_once_with(self.parser, expected, ignore_unknown=False)
315+
self.assertEqual(mock_log.info.mock_calls, [])
316+
317+
def test_default_secondary_deprecated(self, mock_log):
318+
mock_setup_args = self.subject(
319+
[self.configdir / "non-existent", DeprecatedPath(self.configdir / "secondary")],
320+
config=None
321+
)
322+
expected = [self.configdir / "secondary", self.configdir / "secondary.testplugin"]
323+
mock_setup_args.assert_called_once_with(self.parser, expected, ignore_unknown=False)
324+
self.assertEqual(mock_log.info.mock_calls, [
325+
call(f"Loaded config from deprecated path, see CLI docs for how to migrate: {expected[0]}"),
326+
call(f"Loaded plugin config from deprecated path, see CLI docs for how to migrate: {expected[1]}")
327+
])
328+
329+
def test_custom_with_primary_plugin(self, mock_log):
330+
mock_setup_args = self.subject(
331+
[self.configdir / "primary", DeprecatedPath(self.configdir / "secondary")],
332+
config=[str(self.configdir / "custom")]
333+
)
334+
expected = [self.configdir / "custom", self.configdir / "primary.testplugin"]
335+
mock_setup_args.assert_called_once_with(self.parser, expected, ignore_unknown=False)
336+
self.assertEqual(mock_log.info.mock_calls, [])
337+
338+
def test_custom_with_deprecated_plugin(self, mock_log):
339+
mock_setup_args = self.subject(
340+
[self.configdir / "non-existent", DeprecatedPath(self.configdir / "secondary")],
341+
config=[str(self.configdir / "custom")]
342+
)
343+
expected = [self.configdir / "custom", DeprecatedPath(self.configdir / "secondary.testplugin")]
344+
mock_setup_args.assert_called_once_with(self.parser, expected, ignore_unknown=False)
345+
self.assertEqual(mock_log.info.mock_calls, [
346+
call(f"Loaded plugin config from deprecated path, see CLI docs for how to migrate: {expected[1]}")
347+
])
348+
349+
def test_custom_multiple(self, mock_log):
350+
mock_setup_args = self.subject(
351+
[self.configdir / "primary", DeprecatedPath(self.configdir / "secondary")],
352+
config=[str(self.configdir / "non-existent"), str(self.configdir / "primary"), str(self.configdir / "secondary")]
353+
)
354+
expected = [self.configdir / "secondary", self.configdir / "primary", self.configdir / "primary.testplugin"]
355+
mock_setup_args.assert_called_once_with(self.parser, expected, ignore_unknown=False)
356+
self.assertEqual(mock_log.info.mock_calls, [])
357+
358+
272359
class _TestCLIMainLogging(unittest.TestCase):
273360
@classmethod
274361
def subject(cls, argv):

0 commit comments

Comments
 (0)