diff --git a/comicapi/genericmetadata.py b/comicapi/genericmetadata.py index 159a07d..1a45349 100644 --- a/comicapi/genericmetadata.py +++ b/comicapi/genericmetadata.py @@ -230,9 +230,7 @@ class GenericMetadata: assign("scan_info", new_md.scan_info) assign("tags", new_md.tags) - print("before", self.pages, new_md.pages) assign("pages", new_md.pages) - print("after", self.pages, new_md.pages) assign("page_count", new_md.page_count) assign("characters", new_md.characters) diff --git a/comictaggerlib/cli.py b/comictaggerlib/cli.py index e20784c..5d9abd5 100644 --- a/comictaggerlib/cli.py +++ b/comictaggerlib/cli.py @@ -172,7 +172,7 @@ class CLI: else: notes = ( f"Tagged with ComicTagger {ctversion.version} using info from {self.current_talker().name} on" - f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {ct_md.issue_id}]" + f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {ct_md.issue_id}]" ) md.overlay(ct_md.replace(notes=utils.combine_notes(md.notes, notes, "Tagged with ComicTagger"))) @@ -584,7 +584,7 @@ class CLI: notes = ( f"Tagged with ComicTagger {ctversion.version} using info from {self.current_talker().name} on" - + f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {ct_md.issue_id}]" + + f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {ct_md.issue_id}]" ) md.overlay( ct_md.replace( diff --git a/comictaggerlib/ctsettings/plugin.py b/comictaggerlib/ctsettings/plugin.py index dc6d820..f4f604e 100644 --- a/comictaggerlib/ctsettings/plugin.py +++ b/comictaggerlib/ctsettings/plugin.py @@ -36,8 +36,8 @@ def archiver(manager: settngs.Manager) -> None: ) -def register_talker_settings(manager: settngs.Manager) -> None: - for talker in comictaggerlib.ctsettings.talkers.values(): +def register_talker_settings(manager: settngs.Manager, talkers: dict[str, ComicTalker]) -> None: + for talker in talkers.values(): def api_options(manager: settngs.Manager) -> None: # The default needs to be unset or None. @@ -76,10 +76,10 @@ def validate_archive_settings(config: settngs.Config[ct_ns]) -> settngs.Config[c return config -def validate_talker_settings(config: settngs.Config[ct_ns]) -> settngs.Config[ct_ns]: +def validate_talker_settings(config: settngs.Config[ct_ns], talkers: dict[str, ComicTalker]) -> settngs.Config[ct_ns]: # Apply talker settings from config file cfg = settngs.normalize_config(config, True, True) - for talker in list(comictaggerlib.ctsettings.talkers.values()): + for talker in list(talkers.values()): try: cfg[0][group_for_plugin(talker)] = talker.parse_settings(cfg[0][group_for_plugin(talker)]) except Exception as e: @@ -90,12 +90,12 @@ def validate_talker_settings(config: settngs.Config[ct_ns]) -> settngs.Config[ct return cast(settngs.Config[ct_ns], settngs.get_namespace(cfg, file=True, cmdline=True)) -def validate_plugin_settings(config: settngs.Config[ct_ns]) -> settngs.Config[ct_ns]: +def validate_plugin_settings(config: settngs.Config[ct_ns], talkers: dict[str, ComicTalker]) -> settngs.Config[ct_ns]: config = validate_archive_settings(config) - config = validate_talker_settings(config) + config = validate_talker_settings(config, talkers) return config -def register_plugin_settings(manager: settngs.Manager) -> None: +def register_plugin_settings(manager: settngs.Manager, talkers: dict[str, ComicTalker]) -> None: manager.add_persistent_group("Archive", archiver, False) - register_talker_settings(manager) + register_talker_settings(manager, talkers) diff --git a/comictaggerlib/issueidentifier.py b/comictaggerlib/issueidentifier.py index c6ea089..82c6d58 100644 --- a/comictaggerlib/issueidentifier.py +++ b/comictaggerlib/issueidentifier.py @@ -102,7 +102,7 @@ class IssueIdentifier: self.publisher_filter = [s.strip().casefold() for s in config.Issue_Identifier__publisher_filter] self.additional_metadata = GenericMetadata() - self.output_function: Callable[[str], None] = lambda x: print(x) + self.output_function: Callable[[str], None] = print self.progress_callback: Callable[[int, int], None] | None = None self.cover_url_callback: Callable[[bytes], None] | None = None self.search_result = self.result_no_matches @@ -271,7 +271,7 @@ class IssueIdentifier: self.output(msg) def output(self, *args: Any, file: Any = None, **kwargs: Any) -> None: - # We intercept the file argument otherwise everything is passed to self.output_function + # We intercept and discard the file argument otherwise everything is passed to self.output_function # Ensure args[0] is defined and is a string for logger.info if not args: @@ -289,6 +289,7 @@ class IssueIdentifier: if self.config.Runtime_Options__verbose > 0 or self.config.Runtime_Options__quiet: return + # default output is stdout self.output_function(*args, **kwargs) def get_issue_cover_match_score( @@ -347,7 +348,6 @@ class IssueIdentifier: if self.cancel: raise IssueIdentifierCancelled - if use_remote_alternates: self.log_msg(f"[{len(remote_cover_list) - 1} alt. covers]") score_list = [] diff --git a/comictaggerlib/main.py b/comictaggerlib/main.py index 72754fd..5d2af71 100644 --- a/comictaggerlib/main.py +++ b/comictaggerlib/main.py @@ -36,6 +36,7 @@ from comictaggerlib.ctsettings import ct_ns from comictaggerlib.ctversion import version from comictaggerlib.log import setup_logging from comictaggerlib.resulttypes import Action +from comictalker.comictalker import ComicTalker if sys.version_info < (3, 10): import importlib_metadata @@ -107,6 +108,7 @@ class App: self.config: settngs.Config[ct_ns] self.initial_arg_parser = ctsettings.initial_commandline_parser() self.config_load_success = False + self.talkers: dict[str, ComicTalker] def run(self) -> None: configure_locale() @@ -120,7 +122,7 @@ class App: def load_plugins(self, opts: argparse.Namespace) -> None: comicapi.comicarchive.load_archive_plugins() - ctsettings.talkers = comictalker.get_talkers(version, opts.config.user_cache_dir) + self.talkers = comictalker.get_talkers(version, opts.config.user_cache_dir) def list_plugins( self, talkers: list[comictalker.ComicTalker], archivers: list[type[comicapi.comicarchive.Archiver]] @@ -189,7 +191,7 @@ class App: ) ctsettings.register_commandline_settings(self.manager) ctsettings.register_file_settings(self.manager) - ctsettings.register_plugin_settings(self.manager) + ctsettings.register_plugin_settings(self.manager, getattr(self, "talkers", {})) def parse_settings(self, config_paths: ctsettings.ComicTaggerPaths, *args: str) -> settngs.Config[ct_ns]: cfg, self.config_load_success = ctsettings.parse_config( @@ -200,7 +202,7 @@ class App: config = ctsettings.validate_commandline_settings(config, self.manager) config = ctsettings.validate_file_settings(config) - config = ctsettings.validate_plugin_settings(config) + config = ctsettings.validate_plugin_settings(config, getattr(self, "talkers", {})) return config def initialize_dirs(self, paths: ctsettings.ComicTaggerPaths) -> None: @@ -220,10 +222,7 @@ class App: # config already loaded error = None - talkers = ctsettings.talkers - del ctsettings.talkers - - if len(talkers) < 1: + if len(self.talkers) < 1: error = error = ( "Failed to load any talkers, please re-install and check the log located in '" + str(self.config[0].Runtime_Options__config.user_log_dir) @@ -241,7 +240,7 @@ class App: update_publishers(self.config) if self.config[0].Commands__command == Action.list_plugins: - self.list_plugins(list(talkers.values()), comicapi.comicarchive.archivers) + self.list_plugins(list(self.talkers.values()), comicapi.comicarchive.archivers) return if self.config[0].Commands__command == Action.save_config: @@ -266,7 +265,7 @@ class App: if not gui.qt_available: raise gui.import_error - return gui.open_tagger_window(talkers, self.config, error) + return gui.open_tagger_window(self.talkers, self.config, error) except ImportError: self.config[0].Runtime_Options__no_gui = True logger.warning("PyQt5 is not available. ComicTagger is limited to command-line mode.") @@ -277,7 +276,7 @@ class App: raise SystemExit(1) try: - cli.CLI(self.config[0], talkers).run() + cli.CLI(self.config[0], self.talkers).run() except Exception: logger.exception("CLI mode failed") diff --git a/comictaggerlib/seriesselectionwindow.py b/comictaggerlib/seriesselectionwindow.py index 601bd6c..15abf8f 100644 --- a/comictaggerlib/seriesselectionwindow.py +++ b/comictaggerlib/seriesselectionwindow.py @@ -265,9 +265,11 @@ class SeriesSelectionWindow(QtWidgets.QDialog): def log_id_output(self, text: str) -> None: if self.iddialog is not None: - print(text, end=" ") # noqa: T201 + self.iddialog.textEdit.append(text.rstrip()) self.iddialog.textEdit.ensureCursorVisible() - self.iddialog.textEdit.insertPlainText(text) + QtCore.QCoreApplication.processEvents() + QtCore.QCoreApplication.processEvents() + QtCore.QCoreApplication.processEvents() def identify_progress(self, cur: int, total: int) -> None: if self.iddialog is not None: diff --git a/comictaggerlib/settingswindow.py b/comictaggerlib/settingswindow.py index f751821..92eff48 100644 --- a/comictaggerlib/settingswindow.py +++ b/comictaggerlib/settingswindow.py @@ -542,9 +542,7 @@ class SettingsWindow(QtWidgets.QDialog): QtWidgets.QDialog.accept(self) def update_talkers_config(self) -> None: - ctsettings.talkers = self.talkers - self.config = ctsettings.plugin.validate_talker_settings(self.config) - del ctsettings.talkers + self.config = ctsettings.plugin.validate_talker_settings(self.config, self.talkers) def select_rar(self) -> None: self.select_file(self.leRarExePath, "RAR") diff --git a/comictaggerlib/taggerwindow.py b/comictaggerlib/taggerwindow.py index cbd2df9..8a5601b 100644 --- a/comictaggerlib/taggerwindow.py +++ b/comictaggerlib/taggerwindow.py @@ -1089,7 +1089,7 @@ class TaggerWindow(QtWidgets.QMainWindow): notes = ( f"Tagged with ComicTagger {ctversion.version} using info from {self.current_talker().name} on" - f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {new_metadata.issue_id}]" + f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {new_metadata.issue_id}]" ) self.metadata.overlay( new_metadata.replace( @@ -1698,7 +1698,6 @@ class TaggerWindow(QtWidgets.QMainWindow): return ct_md def auto_tag_log(self, text: str) -> None: - print(text) if self.atprogdialog is not None: self.atprogdialog.textEdit.append(text.rstrip()) self.atprogdialog.textEdit.ensureCursorVisible() @@ -1845,7 +1844,7 @@ class TaggerWindow(QtWidgets.QMainWindow): else: notes = ( f"Tagged with ComicTagger {ctversion.version} using info from {self.current_talker().name} on" - f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {ct_md.issue_id}]" + f" {datetime.now():%Y-%m-%d %H:%M:%S}. [Issue ID {ct_md.issue_id}]" ) md.overlay(ct_md.replace(notes=utils.combine_notes(md.notes, notes, "Tagged with ComicTagger"))) diff --git a/setup.cfg b/setup.cfg index 9a0f235..508e7ea 100644 --- a/setup.cfg +++ b/setup.cfg @@ -289,7 +289,7 @@ deps = [flake8] max-line-length = 120 -extend-ignore = E203, E501, A003 +extend-ignore = E203, E501, A003, T202 extend-exclude = venv, scripts, build, dist, comictaggerlib/ctversion.py per-file-ignores = comictaggerlib/cli.py: T20 diff --git a/tests/conftest.py b/tests/conftest.py index c20e5ba..d2a4a44 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,9 +1,11 @@ from __future__ import annotations import copy +import datetime import io import shutil import unittest.mock +from argparse import Namespace from collections.abc import Generator from typing import Any @@ -15,6 +17,7 @@ from pyrate_limiter import Limiter, RequestRate import comicapi.comicarchive import comicapi.genericmetadata +import comictaggerlib.cli import comictaggerlib.ctsettings import comictalker import comictalker.comiccacher @@ -127,10 +130,22 @@ def comicvine_api(monkeypatch, cbz, comic_cache, mock_version, config) -> comict return cv +@pytest.fixture +def mock_now(monkeypatch): + class mydatetime: + time = datetime.datetime(2022, 4, 16, 15, 52, 26) + + @classmethod + def now(cls): + return cls.time + + monkeypatch.setattr(comictaggerlib.cli, "datetime", mydatetime) + + @pytest.fixture def mock_version(monkeypatch): - version = "1.4.4a9.dev20" - version_tuple = (1, 4, 4, "dev20") + version = "1.3.2a5" + version_tuple = (1, 3, 2) monkeypatch.setattr(comictaggerlib.ctversion, "version", version) monkeypatch.setattr(comictaggerlib.ctversion, "__version__", version) @@ -182,6 +197,24 @@ def config(tmp_path): yield defaults +@pytest.fixture +def plugin_config(tmp_path): + from comictaggerlib.main import App + + ns = Namespace(config=comictaggerlib.ctsettings.ComicTaggerPaths(tmp_path / "config")) + app = App() + app.load_plugins(ns) + app.register_settings() + + defaults = app.parse_settings(ns.config, "") + defaults[0].Runtime_Options__config.user_data_dir.mkdir(parents=True, exist_ok=True) + defaults[0].Runtime_Options__config.user_config_dir.mkdir(parents=True, exist_ok=True) + defaults[0].Runtime_Options__config.user_cache_dir.mkdir(parents=True, exist_ok=True) + defaults[0].Runtime_Options__config.user_state_dir.mkdir(parents=True, exist_ok=True) + defaults[0].Runtime_Options__config.user_log_dir.mkdir(parents=True, exist_ok=True) + yield (defaults, app.talkers) + + @pytest.fixture def comic_cache(config, mock_version) -> Generator[comictalker.comiccacher.ComicCacher, Any, None]: yield comictalker.comiccacher.ComicCacher(config[0].Runtime_Options__config.user_cache_dir, mock_version[0]) diff --git a/tests/integration_test.py b/tests/integration_test.py new file mode 100644 index 0000000..cc3850b --- /dev/null +++ b/tests/integration_test.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +import settngs + +import comicapi.comicarchive +import comicapi.comicinfoxml +import comicapi.genericmetadata +import comictaggerlib.resulttypes +from comictaggerlib import ctsettings +from comictaggerlib.cli import CLI +from comictalker.comictalker import ComicTalker + + +def test_save( + plugin_config: tuple[settngs.Config[ctsettings.ct_ns], dict[str, ComicTalker]], + tmp_comic, + comicvine_api, + md_saved, + mock_now, +) -> None: + # Overwrite the series so it has definitely changed + tmp_comic.write_cix(md_saved.replace(series="nothing")) + + md = tmp_comic.read_cix() + + # Check that it changed + assert md != md_saved + + # Clear the cached metadata + tmp_comic.reset_cache() + + # Setup the app + config = plugin_config[0] + talkers = plugin_config[1] + + # Save + config[0].Commands__command = comictaggerlib.resulttypes.Action.save + + # Check online, should be intercepted by comicvine_api + config[0].Runtime_Options__online = True + # Use the temporary comic we created + config[0].Runtime_Options__files = [tmp_comic.path] + # Save ComicRack tags + config[0].Runtime_Options__type = [comicapi.comicarchive.MetaDataStyle.CIX] + # Search using the correct series since we just put the wrong series name in the CBZ + config[0].Runtime_Options__metadata = comicapi.genericmetadata.GenericMetadata(series=md_saved.series) + # Run ComicTagger + CLI(config[0], talkers).run() + + # Read the CBZ + md = tmp_comic.read_cix() + + # Validate that we got the correct metadata back + assert md == md_saved + + +def test_delete( + plugin_config: tuple[settngs.Config[ctsettings.ct_ns], dict[str, ComicTalker]], + tmp_comic, + comicvine_api, + md_saved, + mock_now, +) -> None: + md = tmp_comic.read_cix() + + # Check that the metadata starts correct + assert md == md_saved + + # Clear the cached metadata + tmp_comic.reset_cache() + + # Setup the app + config = plugin_config[0] + talkers = plugin_config[1] + + # Delete + config[0].Commands__command = comictaggerlib.resulttypes.Action.delete + + # Use the temporary comic we created + config[0].Runtime_Options__files = [tmp_comic.path] + # Delete ComicRack tags + config[0].Runtime_Options__type = [comicapi.comicarchive.MetaDataStyle.CIX] + # Run ComicTagger + CLI(config[0], talkers).run() + + # Read the CBZ + md = tmp_comic.read_cix() + + # Currently we set the default page list on load + empty_md = comicapi.genericmetadata.GenericMetadata() + empty_md.set_default_page_list(tmp_comic.get_number_of_pages()) + + # Validate that we got an empty metadata back + assert md == empty_md diff --git a/tests/issueidentifier_test.py b/tests/issueidentifier_test.py index 978f037..4702ddb 100644 --- a/tests/issueidentifier_test.py +++ b/tests/issueidentifier_test.py @@ -69,7 +69,6 @@ def test_search(cbz, config, comicvine_api): url_image_hash=1747255366011518976, ) for r, e in zip(results, [cv_expected]): - # del r["url_image_hash"] assert r == e