From ae20df2c7725cb113f5ad41920ef46fd4dbe6f98 Mon Sep 17 00:00:00 2001 From: Billy2011 Date: Sat, 27 Nov 2021 14:07:51 +0100 Subject: [PATCH] [PATCH] cli: prioritize --help and fix its output (#4213) --- src/streamlink_cli/argparser.py | 6 +-- src/streamlink_cli/main.py | 14 ++++-- tests/test_cli_main.py | 76 +++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/streamlink_cli/argparser.py b/src/streamlink_cli/argparser.py index 99a1c0ad0b9..27f6fc288d6 100644 --- a/src/streamlink_cli/argparser.py +++ b/src/streamlink_cli/argparser.py @@ -548,7 +548,7 @@ def build_parser(): Example: - %(prog)s --output "~/recordings/{author}/{category}/{id}-{time:%Y%m%d%H%M%S}.ts" [STREAM] + %(prog)s --output "~/recordings/{author}/{category}/{id}-{time:%%Y%%m%%d%%H%%M%%S}.ts" [STREAM] """ ) output.add_argument( @@ -587,7 +587,7 @@ def build_parser(): Example: - %(prog)s --record "~/recordings/{author}/{category}/{id}-{time:%Y%m%d%H%M%S}.ts" [STREAM] + %(prog)s --record "~/recordings/{author}/{category}/{id}-{time:%%Y%%m%%d%%H%%M%%S}.ts" [STREAM] """ ) output.add_argument( @@ -604,7 +604,7 @@ def build_parser(): Example: - %(prog)s --record-and-pipe "~/recordings/{author}/{category}/{id}-{time:%Y%m%d%H%M%S}.ts" [STREAM] + %(prog)s --record-and-pipe "~/recordings/{author}/{category}/{id}-{time:%%Y%%m%%d%%H%%M%%S}.ts" [STREAM] """ ) output.add_argument( diff --git a/src/streamlink_cli/main.py b/src/streamlink_cli/main.py index 1677f194ef5..6e6dd519250 100644 --- a/src/streamlink_cli/main.py +++ b/src/streamlink_cli/main.py @@ -1016,7 +1016,7 @@ def setup_logger_and_console(stream=sys.stdout, filename=None, level="info", jso datefmt="%H:%M:%S" ) - console = ConsoleOutput(streamhandler.stream, json) + console = ConsoleOutput(streamhandler.stream, streamlink, json) def main(): @@ -1064,7 +1064,9 @@ def main(): with ignored(Exception): check_version(force=args.version_check) - if args.plugins: + if args.help: + parser.print_help() + elif args.plugins: print_plugins() elif args.can_handle_url: try: @@ -1097,15 +1099,19 @@ def main(): stream_fd.close() except KeyboardInterrupt: error_code = 130 - elif args.help: - parser.print_help() else: usage = parser.format_usage() + """ msg = ( "{usage}\nUse -h/--help to see the available options or " "read the manual at https://Billy2011.github.io/streamlink-27" ).format(usage=usage) console.msg(msg) + """ + console.msg( + "{usage}\n" + "Use -h/--help to see the available options or read the manual at https://streamlink.github.io".format(usage=usage) + ) sys.exit(error_code) diff --git a/tests/test_cli_main.py b/tests/test_cli_main.py index 316a8bd55e8..b0f2bba7972 100644 --- a/tests/test_cli_main.py +++ b/tests/test_cli_main.py @@ -4,6 +4,7 @@ import sys import tempfile import unittest +from textwrap import dedent import streamlink_cli.main from streamlink.session import Streamlink @@ -470,3 +471,78 @@ def test_logfile_loglevel_none(self, mock_open, mock_stdout): self.assertEqual(streamlink_cli.main.console.output, sys.stdout) self.assertFalse(mock_open.called) self.assertEqual(mock_stdout.write.mock_calls, [call("bar\n")]) + + +class TestCLIMainPrint(unittest.TestCase): + def subject(self): + with patch.object(Streamlink, "load_builtin_plugins"), \ + patch.object(Streamlink, "resolve_url") as mock_resolve_url, \ + patch.object(Streamlink, "resolve_url_no_redirect") as mock_resolve_url_no_redirect: + session = Streamlink() + session.load_plugins(os.path.join(os.path.dirname(__file__), "plugin")) + with patch("streamlink_cli.main.streamlink", session), \ + patch("streamlink_cli.main.CONFIG_FILES", []), \ + patch("streamlink_cli.main.setup_streamlink"), \ + patch("streamlink_cli.main.setup_plugins"), \ + patch("streamlink_cli.main.setup_http_session"), \ + patch("streamlink_cli.main.setup_signals"), \ + patch("streamlink_cli.main.setup_options") as mock_setup_options: + with self.assertRaises(SystemExit) as cm: + streamlink_cli.main.main() + self.assertEqual(cm.exception.code, 0) + mock_resolve_url.assert_not_called() + mock_resolve_url_no_redirect.assert_not_called() + mock_setup_options.assert_not_called() + + @staticmethod + def get_stdout(mock_stdout): + return "".join([call_arg[0][0] for call_arg in mock_stdout.write.call_args_list]) + + @patch("sys.stdout") + @patch("sys.argv", ["streamlink"]) + def test_print_usage(self, mock_stdout): + self.subject() + self.assertEqual( + self.get_stdout(mock_stdout), + "usage: streamlink [OPTIONS] [STREAM]\n\n" + + "Use -h/--help to see the available options or read the manual at https://streamlink.github.io\n" + ) + + @patch("sys.stdout") + @patch("sys.argv", ["streamlink", "--help"]) + def test_print_help(self, mock_stdout): + self.subject() + output = self.get_stdout(mock_stdout) + self.assertIn( + "usage: streamlink [OPTIONS] [STREAM]", + output + ) + self.assertIn( + dedent(""" + Streamlink is a command-line utility that extracts streams from various + services and pipes them into a video player of choice. + """), + output + ) + self.assertIn( + dedent(""" + For more in-depth documentation see: + https://Billy2011.github.io/streamlink-27 + + Please report broken plugins or bugs to the issue tracker on Github: + https://github.com/streamlink/streamlink/issues + """), + output + ) + + @patch("sys.stdout") + @patch("sys.argv", ["streamlink", "--plugins"]) + def test_print_plugins(self, mock_stdout): + self.subject() + self.assertEqual(self.get_stdout(mock_stdout), "Loaded plugins: testplugin\n") + + @patch("sys.stdout") + @patch("sys.argv", ["streamlink", "--plugins", "--json"]) + def test_print_plugins_json(self, mock_stdout): + self.subject() + self.assertEqual(self.get_stdout(mock_stdout), """[\n "testplugin"\n]\n""")