From 420a50672067b1a736a30c2f671fcf43495c4df0 Mon Sep 17 00:00:00 2001 From: Cody Logan Date: Wed, 1 Nov 2023 13:33:39 -0700 Subject: Rename some symbols and functions to better match their purpose --- pyproject.toml | 2 +- src/wikiget/dl.py | 4 +-- src/wikiget/parse.py | 6 ++--- src/wikiget/wikiget.py | 6 ++--- tests/test_client.py | 6 ++--- tests/test_dl.py | 14 +++++----- tests/test_logging.py | 14 +++++----- tests/test_parse.py | 40 +++++++++++++-------------- tests/test_wikiget.py | 68 ---------------------------------------------- tests/test_wikiget_cli.py | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 115 insertions(+), 114 deletions(-) delete mode 100644 tests/test_wikiget.py create mode 100644 tests/test_wikiget_cli.py diff --git a/pyproject.toml b/pyproject.toml index edb5b5d..0ab61b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ Repository = "https://github.com/clpo13/wikiget" "Bug Reports" = "https://github.com/clpo13/wikiget/issues" [project.scripts] -wikiget = "wikiget.wikiget:main" +wikiget = "wikiget.wikiget:cli" [tool.hatch.version] path = "src/wikiget/version.py" diff --git a/src/wikiget/dl.py b/src/wikiget/dl.py index f39c355..a29e049 100644 --- a/src/wikiget/dl.py +++ b/src/wikiget/dl.py @@ -85,7 +85,7 @@ def batch_download(args: Namespace) -> int: # parse batch file try: - dl_list = read_batch_file(args.FILE) + dl_dict = read_batch_file(args.FILE) except OSError as e: logger.error(f"File could not be read: {e}") sys.exit(1) @@ -93,7 +93,7 @@ def batch_download(args: Namespace) -> int: # TODO: validate file contents before download process starts with ThreadPoolExecutor(max_workers=args.threads) as executor: futures = [] - for line_num, line in dl_list.items(): + for line_num, line in dl_dict.items(): # keep track of batch file line numbers for debugging/logging purposes logger.info(f"Processing '{line}' at line {line_num}") try: diff --git a/src/wikiget/parse.py b/src/wikiget/parse.py index 122c45f..892f0f0 100644 --- a/src/wikiget/parse.py +++ b/src/wikiget/parse.py @@ -60,7 +60,7 @@ def get_dest(dl: str, args: Namespace) -> File: def read_batch_file(batch_file: str) -> Dict[int, str]: - dl_list = {} + dl_dict = {} if batch_file == "-": logger.info("Using stdin for batch download") @@ -73,6 +73,6 @@ def read_batch_file(batch_file: str) -> Dict[int, str]: line_s = line.strip() # ignore blank lines and lines starting with "#" (for comments) if line_s and not line_s.startswith("#"): - dl_list[line_num] = line_s + dl_dict[line_num] = line_s - return dl_list + return dl_dict diff --git a/src/wikiget/wikiget.py b/src/wikiget/wikiget.py index ca655b0..db8ebf4 100644 --- a/src/wikiget/wikiget.py +++ b/src/wikiget/wikiget.py @@ -27,7 +27,7 @@ from wikiget.logging import configure_logging logger = logging.getLogger(__name__) -def construct_parser(argv: List[str]) -> argparse.Namespace: +def parse_args(argv: List[str]) -> argparse.Namespace: parser = argparse.ArgumentParser( description=""" A tool for downloading files from MediaWiki sites using the file name or @@ -120,9 +120,9 @@ def construct_parser(argv: List[str]) -> argparse.Namespace: return parser.parse_args(argv) -def main() -> None: +def cli() -> None: # setup our environment - args = construct_parser(sys.argv[1:]) + args = parse_args(sys.argv[1:]) configure_logging(verbosity=args.verbose, logfile=args.logfile, quiet=args.quiet) # log events are appended to the file if it already exists, so note the start of a diff --git a/tests/test_client.py b/tests/test_client.py index 650c2cf..9b1b8a4 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -22,7 +22,7 @@ import pytest from wikiget import USER_AGENT from wikiget.client import connect_to_site, query_api -from wikiget.wikiget import construct_parser +from wikiget.wikiget import parse_args # TODO: don't hit the actual API when doing tests @@ -37,7 +37,7 @@ class TestQueryApi: """ caplog.set_level(logging.DEBUG) mock_site.return_value = MagicMock() - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) _ = connect_to_site("commons.wikimedia.org", args) assert mock_site.called assert "Connecting to commons.wikimedia.org" in caplog.text @@ -49,7 +49,7 @@ class TestQueryApi: agent we're sending to the API. """ caplog.set_level(logging.DEBUG) - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) site = connect_to_site("commons.wikimedia.org", args) _ = query_api("Example.jpg", site) assert USER_AGENT in caplog.text diff --git a/tests/test_dl.py b/tests/test_dl.py index cbda95c..a57c3c1 100644 --- a/tests/test_dl.py +++ b/tests/test_dl.py @@ -22,7 +22,7 @@ import pytest from wikiget.dl import prep_download, process_download from wikiget.file import File -from wikiget.wikiget import construct_parser +from wikiget.wikiget import parse_args # TODO: don't hit the actual API when doing tests @@ -32,7 +32,7 @@ class TestPrepDownload: """ The prep_download function should create a file object. """ - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) file = prep_download(args.FILE, args) assert file is not None @@ -43,7 +43,7 @@ class TestPrepDownload: """ tmp_file = tmp_path / "File:Example.jpg" tmp_file.write_text("nothing") - args = construct_parser(["File:Example.jpg", "-o", str(tmp_file)]) + args = parse_args(["File:Example.jpg", "-o", str(tmp_file)]) with pytest.raises(FileExistsError): _ = prep_download(args.FILE, args) @@ -54,7 +54,7 @@ class TestProcessDownload: """ A successful batch download should not return any errors. """ - args = construct_parser(["-a", "batch.txt"]) + args = parse_args(["-a", "batch.txt"]) mock_batch_download.return_value = 0 exit_code = process_download(args) assert mock_batch_download.called @@ -68,7 +68,7 @@ class TestProcessDownload: Any errors during batch download should create a log message containing the number of errors and result in a non-zero exit code. """ - args = construct_parser(["-a", "batch.txt"]) + args = parse_args(["-a", "batch.txt"]) mock_batch_download.return_value = 4 exit_code = process_download(args) assert mock_batch_download.called @@ -83,7 +83,7 @@ class TestProcessDownload: """ A successful download should not return any errors. """ - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) mock_download.return_value = 0 mock_prep_download.return_value = MagicMock(File) exit_code = process_download(args) @@ -99,7 +99,7 @@ class TestProcessDownload: """ Any errors during download should result in a non-zero exit code. """ - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) mock_download.return_value = 1 mock_prep_download.return_value = MagicMock(File) exit_code = process_download(args) diff --git a/tests/test_logging.py b/tests/test_logging.py index 4e0428e..b189c28 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -21,7 +21,7 @@ from pathlib import Path from pytest import LogCaptureFixture from wikiget.logging import FileLogAdapter, configure_logging -from wikiget.wikiget import construct_parser +from wikiget.wikiget import parse_args logger = logging.getLogger() @@ -30,7 +30,7 @@ def test_custom_log_adapter(caplog: LogCaptureFixture) -> None: """ The custom log adapter should prepend the filename to log messages. """ - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) configure_logging(args.verbose, args.logfile, quiet=args.quiet) adapter = FileLogAdapter(logger, {"filename": "Example.jpg"}) adapter.warning("test log") @@ -42,7 +42,7 @@ def test_file_logging(tmp_path: Path) -> None: Logging to a file should create the file in the specified location. """ logfile_location = tmp_path / "test.log" - args = construct_parser(["File:Example.jpg", "-l", str(logfile_location)]) + args = parse_args(["File:Example.jpg", "-l", str(logfile_location)]) configure_logging(args.verbose, args.logfile, quiet=args.quiet) assert logfile_location.is_file() @@ -51,7 +51,7 @@ def test_default_logging() -> None: """ The default log level should be set to WARNING. """ - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) configure_logging(args.verbose, args.logfile, quiet=args.quiet) # each call of configure_logging() adds a new handler to the logger, so we need to # grab the most recently added one to test @@ -63,7 +63,7 @@ def test_verbose_logging() -> None: """ When -v is passed, the log level should be set to INFO. """ - args = construct_parser(["File:Example.jpg", "-v"]) + args = parse_args(["File:Example.jpg", "-v"]) configure_logging(args.verbose, args.logfile, quiet=args.quiet) handler = logger.handlers[-1] assert handler.level == logging.INFO @@ -73,7 +73,7 @@ def test_very_verbose_logging() -> None: """ When -vv is passed, the log level should be set to DEBUG. """ - args = construct_parser(["File:Example.jpg", "-vv"]) + args = parse_args(["File:Example.jpg", "-vv"]) configure_logging(args.verbose, args.logfile, quiet=args.quiet) handler = logger.handlers[-1] assert handler.level == logging.DEBUG @@ -83,7 +83,7 @@ def test_quiet_logging() -> None: """ When -q is passed, the log level should be set to ERROR. """ - args = construct_parser(["File:Example.jpg", "-q"]) + args = parse_args(["File:Example.jpg", "-q"]) configure_logging(args.verbose, args.logfile, quiet=args.quiet) handler = logger.handlers[-1] assert handler.level == logging.ERROR diff --git a/tests/test_parse.py b/tests/test_parse.py index 8d8b6a6..e767597 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -25,7 +25,7 @@ import pytest from wikiget.exceptions import ParseError from wikiget.file import File from wikiget.parse import get_dest, read_batch_file -from wikiget.wikiget import construct_parser +from wikiget.wikiget import parse_args class TestGetDest: @@ -35,7 +35,7 @@ class TestGetDest: When a filename is passed to get_dest, it should create a File object with the correct name and dest and the default site. """ - args = construct_parser(["File:Example.jpg"]) + args = parse_args(["File:Example.jpg"]) return get_dest(args.FILE, args) def test_get_dest_name_with_filename(self, file_with_filename: File) -> None: @@ -53,7 +53,7 @@ class TestGetDest: When a URL is passed to get_dest, it should create a File object with the correct name and dest and the site from the URL. """ - args = construct_parser(["https://en.wikipedia.org/wiki/File:Example.jpg"]) + args = parse_args(["https://en.wikipedia.org/wiki/File:Example.jpg"]) return get_dest(args.FILE, args) def test_get_dest_name_with_url(self, file_with_url: File) -> None: @@ -69,7 +69,7 @@ class TestGetDest: """ The get_dest function should raise a ParseError if the filename is invalid. """ - args = construct_parser(["Example.jpg"]) + args = parse_args(["Example.jpg"]) with pytest.raises(ParseError): _ = get_dest(args.FILE, args) @@ -80,7 +80,7 @@ class TestGetDest: If a URL is passed to get_dest and a site is also given on the command line, the site in the URL should be used and a warning log message created. """ - args = construct_parser( + args = parse_args( [ "https://commons.wikimedia.org/wiki/File:Example.jpg", "--site", @@ -93,7 +93,7 @@ class TestGetDest: class TestReadBatchFile: @pytest.fixture() - def dl_list(self, tmp_path: Path) -> Dict[int, str]: + def dl_dict(self, tmp_path: Path) -> Dict[int, str]: """ Create and process a test batch file with three lines, returning a dictionary. """ @@ -114,23 +114,23 @@ class TestReadBatchFile: _ = read_batch_file(str(tmp_file)) assert f"Using file '{tmp_file}' for batch download" in caplog.text - def test_batch_file_length(self, dl_list: Dict[int, str]) -> None: + def test_batch_file_length(self, dl_dict: Dict[int, str]) -> None: """ The processed batch dict should have the same number of items as lines in the batch file. """ - assert len(dl_list) == 3 + assert len(dl_dict) == 3 - def test_batch_file_contents(self, dl_list: Dict[int, str]) -> None: + def test_batch_file_contents(self, dl_dict: Dict[int, str]) -> None: """ The processed batch dict should have the correct line numbers and filenames as keys and values, respectively. """ expected_list = {1: "File:Foo.jpg", 2: "File:Bar.jpg", 3: "File:Baz.jpg"} - assert dl_list == expected_list + assert dl_dict == expected_list @pytest.fixture() - def dl_list_stdin(self, monkeypatch: pytest.MonkeyPatch) -> Dict[int, str]: + def dl_dict_stdin(self, monkeypatch: pytest.MonkeyPatch) -> Dict[int, str]: """ Pass three lines of filenames from stdin to read_batch_file and return a dict. """ @@ -150,23 +150,23 @@ class TestReadBatchFile: _ = read_batch_file("-") assert "Using stdin for batch download" in caplog.text - def test_batch_stdin_length(self, dl_list_stdin: Dict[int, str]) -> None: + def test_batch_stdin_length(self, dl_dict_stdin: Dict[int, str]) -> None: """ The processed batch dict should have the same number of items as lines in the input. """ - assert len(dl_list_stdin) == 3 + assert len(dl_dict_stdin) == 3 - def test_batch_stdin_contents(self, dl_list_stdin: Dict[int, str]) -> None: + def test_batch_stdin_contents(self, dl_dict_stdin: Dict[int, str]) -> None: """ The processed batch dict should have the correct line numbers and filenames as keys and values, respectively. """ expected_list = {1: "File:Foo.jpg", 2: "File:Bar.jpg", 3: "File:Baz.jpg"} - assert dl_list_stdin == expected_list + assert dl_dict_stdin == expected_list @pytest.fixture() - def dl_list_with_comment(self, tmp_path: Path) -> Dict[int, str]: + def dl_dict_with_comment(self, tmp_path: Path) -> Dict[int, str]: """ Create and process a test batch file with four lines, one of which is commented out and another of which is blank, and return a dictionary. @@ -176,20 +176,20 @@ class TestReadBatchFile: return read_batch_file(str(tmp_file)) def test_batch_file_with_comment_length( - self, dl_list_with_comment: Dict[int, str] + self, dl_dict_with_comment: Dict[int, str] ) -> None: """ The processed batch dict should contain the same number of items as uncommented and non-blank lines in the input. """ - assert len(dl_list_with_comment) == 2 + assert len(dl_dict_with_comment) == 2 def test_batch_file_with_comment_contents( - self, dl_list_with_comment: Dict[int, str] + self, dl_dict_with_comment: Dict[int, str] ) -> None: """ The processed batch dict should have the correct line numbers and filenames as keys and values, respectively, skipping any commented or blank lines. """ expected_list = {1: "File:Foo.jpg", 4: "File:Baz.jpg"} - assert dl_list_with_comment == expected_list + assert dl_dict_with_comment == expected_list diff --git a/tests/test_wikiget.py b/tests/test_wikiget.py deleted file mode 100644 index e254b8b..0000000 --- a/tests/test_wikiget.py +++ /dev/null @@ -1,68 +0,0 @@ -# wikiget - CLI tool for downloading files from Wikimedia sites -# Copyright (C) 2023 Cody Logan -# SPDX-License-Identifier: GPL-3.0-or-later -# -# Wikiget is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Wikiget is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Wikiget. If not, see . - -from unittest.mock import MagicMock, patch - -import pytest - -from wikiget import USER_AGENT -from wikiget.wikiget import main - - -def test_main_no_params(monkeypatch: pytest.MonkeyPatch): - monkeypatch.setattr("sys.argv", ["wikiget"]) - with pytest.raises(SystemExit) as e: - main() - assert e.value.code == 2 - - -@patch("wikiget.wikiget.process_download") -def test_main_success( - mock_process_download: MagicMock, monkeypatch: pytest.MonkeyPatch -) -> None: - monkeypatch.setattr("sys.argv", ["wikiget", "File:Example.jpg"]) - mock_process_download.return_value = 0 - with pytest.raises(SystemExit) as e: - main() - assert mock_process_download.called - assert e.value.code == 0 - - -@patch("wikiget.wikiget.process_download") -def test_main_failure( - mock_process_download: MagicMock, monkeypatch: pytest.MonkeyPatch -) -> None: - monkeypatch.setattr("sys.argv", ["wikiget", "File:Example.jpg"]) - mock_process_download.return_value = 1 - with pytest.raises(SystemExit) as e: - main() - assert mock_process_download.called - assert e.value.code == 1 - - -@patch("wikiget.wikiget.process_download") -def test_main_logs( - mock_process_download: MagicMock, - monkeypatch: pytest.MonkeyPatch, - caplog: pytest.LogCaptureFixture, -) -> None: - monkeypatch.setattr("sys.argv", ["wikiget", "File:Example.jpg"]) - mock_process_download.return_value = 0 - with pytest.raises(SystemExit): - main() - assert mock_process_download.called - assert USER_AGENT in caplog.text diff --git a/tests/test_wikiget_cli.py b/tests/test_wikiget_cli.py new file mode 100644 index 0000000..99d113e --- /dev/null +++ b/tests/test_wikiget_cli.py @@ -0,0 +1,69 @@ +# wikiget - CLI tool for downloading files from Wikimedia sites +# Copyright (C) 2023 Cody Logan +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Wikiget is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Wikiget is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Wikiget. If not, see . + +from unittest.mock import MagicMock, patch + +import pytest + +from wikiget import USER_AGENT, __version__ +from wikiget.wikiget import cli + + +def test_cli_no_params(monkeypatch: pytest.MonkeyPatch): + monkeypatch.setattr("sys.argv", ["wikiget"]) + with pytest.raises(SystemExit) as e: + cli() + assert e.value.code == 2 + + +@patch("wikiget.wikiget.process_download") +def test_cli_completed_successfully( + mock_process_download: MagicMock, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr("sys.argv", ["wikiget", "File:Example.jpg"]) + mock_process_download.return_value = 0 + with pytest.raises(SystemExit) as e: + cli() + assert mock_process_download.called + assert e.value.code == 0 + + +@patch("wikiget.wikiget.process_download") +def test_cli_completed_with_problems( + mock_process_download: MagicMock, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr("sys.argv", ["wikiget", "File:Example.jpg"]) + mock_process_download.return_value = 1 + with pytest.raises(SystemExit) as e: + cli() + assert mock_process_download.called + assert e.value.code == 1 + + +@patch("wikiget.wikiget.process_download") +def test_cli_logs( + mock_process_download: MagicMock, + monkeypatch: pytest.MonkeyPatch, + caplog: pytest.LogCaptureFixture, +) -> None: + monkeypatch.setattr("sys.argv", ["wikiget", "File:Example.jpg"]) + mock_process_download.return_value = 0 + with pytest.raises(SystemExit): + cli() + assert mock_process_download.called + assert f"Starting download session using wikiget {__version__}" in caplog.text + assert USER_AGENT in caplog.text -- cgit v1.2.3