Skip to content

Commit 4cc4f3b

Browse files
Tidy up logging and settings
1 parent 1f142b6 commit 4cc4f3b

File tree

10 files changed

+61
-75
lines changed

10 files changed

+61
-75
lines changed

perdoo/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def setup_logging(debug: bool = False) -> None:
5858
omit_repeated_times=False,
5959
show_level=True,
6060
show_time=False,
61-
show_path=debug,
61+
show_path=True,
6262
console=CONSOLE,
6363
)
6464
console_handler.setLevel(logging.DEBUG if debug else logging.INFO)
@@ -72,4 +72,6 @@ def setup_logging(debug: bool = False) -> None:
7272
handlers=[console_handler, file_handler],
7373
)
7474

75-
logging.getLogger("PIL").setLevel(logging.WARNING)
75+
logging.getLogger("PIL").setLevel(logging.INFO if debug else logging.WARNING)
76+
logging.getLogger("httpx").setLevel(logging.INFO if debug else logging.WARNING)
77+
logging.getLogger("httpcore").setLevel(logging.INFO if debug else logging.WARNING)

perdoo/cli/process.py

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from perdoo.comic.metadata.metron_info import Id, InformationSource
1818
from perdoo.console import CONSOLE
1919
from perdoo.services import BaseService, Comicvine, Metron
20-
from perdoo.settings import Naming, Output, Service, Services, Settings
20+
from perdoo.settings import SETTINGS, Service
2121
from perdoo.utils import (
2222
IssueSearch,
2323
Search,
@@ -36,19 +36,19 @@ class SyncOption(str, Enum):
3636
SKIP = "Skip"
3737

3838

39-
def get_services(settings: Services) -> dict[Service, BaseService]:
39+
def get_services() -> dict[Service, BaseService]:
4040
output = {}
41-
if settings.comicvine.api_key:
42-
output[Service.COMICVINE] = Comicvine(api_key=settings.comicvine.api_key)
43-
if settings.metron.username and settings.metron.password:
41+
if SETTINGS.services.comicvine.api_key:
42+
output[Service.COMICVINE] = Comicvine(api_key=SETTINGS.services.comicvine.api_key)
43+
if SETTINGS.services.metron.username and SETTINGS.services.metron.password:
4444
output[Service.METRON] = Metron(
45-
username=settings.metron.username, password=settings.metron.password
45+
username=SETTINGS.services.metron.username, password=SETTINGS.services.metron.password
4646
)
4747
return output
4848

4949

5050
def setup_environment(
51-
clean_cache: bool, sync: SyncOption, settings: Settings, debug: bool = False
51+
clean_cache: bool, sync: SyncOption, debug: bool = False
5252
) -> tuple[dict[Service, BaseService], SyncOption]:
5353
setup_logging(debug=debug)
5454
LOGGER.info("Python v%s", python_version())
@@ -58,7 +58,7 @@ def setup_environment(
5858
LOGGER.info("Cleaning Cache")
5959
recursive_delete(path=get_cache_root())
6060

61-
services = get_services(settings=settings.services)
61+
services = get_services()
6262
if not services and sync is not SyncOption.SKIP:
6363
LOGGER.warning("No external services configured")
6464
sync = SyncOption.SKIP
@@ -76,9 +76,9 @@ def load_comics(target: Path) -> list[Comic]:
7676
return comics
7777

7878

79-
def prepare_comic(entry: Comic, settings: Settings, skip_convert: bool) -> bool:
79+
def prepare_comic(entry: Comic, skip_convert: bool) -> bool:
8080
if not skip_convert:
81-
entry.convert_to(settings.output.format)
81+
entry.convert_to(SETTINGS.output.format)
8282
if not entry.archive.IS_WRITEABLE:
8383
LOGGER.warning("Archive format %s is not writeable", entry.archive.EXTENSION)
8484
return False
@@ -163,29 +163,23 @@ def sync_metadata(
163163

164164

165165
def resolve_metadata(
166-
entry: Comic,
167-
session: ArchiveSession,
168-
services: dict[Service, BaseService],
169-
settings: Services,
170-
sync: SyncOption,
166+
entry: Comic, session: ArchiveSession, services: dict[Service, BaseService], sync: SyncOption
171167
) -> tuple[MetronInfo | None, ComicInfo | None]:
172168
metron_info, comic_info = entry.read_metadata(session=session)
173169
if not should_sync_metadata(sync=sync, metron_info=metron_info):
174170
return metron_info, comic_info
175171
search = build_search(
176172
metron_info=metron_info, comic_info=comic_info, filename=entry.filepath.stem
177173
)
178-
return sync_metadata(search=search, services=services, service_order=settings.order)
174+
return sync_metadata(search=search, services=services, service_order=SETTINGS.services.order)
179175

180176

181-
def generate_naming(
182-
settings: Naming, metron_info: MetronInfo | None, comic_info: ComicInfo | None
183-
) -> str | None:
177+
def generate_naming(metron_info: MetronInfo | None, comic_info: ComicInfo | None) -> str | None:
184178
filepath = None
185179
if metron_info:
186-
filepath = metron_info.get_filename(settings=settings)
180+
filepath = metron_info.get_filename()
187181
if not filepath and comic_info:
188-
filepath = comic_info.get_filename(settings=settings)
182+
filepath = comic_info.get_filename()
189183
return filepath.lstrip("/") if filepath else None
190184

191185

@@ -196,7 +190,6 @@ def apply_changes(
196190
comic_info: ComicInfo | None,
197191
skip_clean: bool,
198192
skip_rename: bool,
199-
settings: Output,
200193
) -> str | None:
201194
local_metron_info, local_comic_info = entry.read_metadata(session=session)
202195
if local_metron_info != metron_info:
@@ -212,16 +205,14 @@ def apply_changes(
212205
session.delete(filename=ComicInfo.FILENAME)
213206

214207
if not skip_clean:
215-
for extra in entry.list_extras():
208+
for extra in entry.list_extras(image_extensions=SETTINGS.output.image_extensions):
216209
session.delete(filename=extra.name)
217210

218211
naming = None
219212
if not skip_rename and (
220-
naming := generate_naming(
221-
settings=settings.naming, metron_info=metron_info, comic_info=comic_info
222-
)
213+
naming := generate_naming(metron_info=metron_info, comic_info=comic_info)
223214
):
224-
images = entry.list_images()
215+
images = entry.list_images(image_extensions=SETTINGS.output.image_extensions)
225216
stem = Path(naming).stem
226217
pad = len(str(len(images)))
227218
for idx, img in enumerate(images):
@@ -268,11 +259,7 @@ def process(
268259
bool, Option("--debug", help="Enable debug mode to show extra information.")
269260
] = False,
270261
) -> None:
271-
settings = Settings.load()
272-
settings.save()
273-
services, sync = setup_environment(
274-
clean_cache=clean_cache, sync=sync, settings=settings, debug=debug
275-
)
262+
services, sync = setup_environment(clean_cache=clean_cache, sync=sync, debug=debug)
276263

277264
comics = load_comics(target=target)
278265
total = len(comics)
@@ -281,15 +268,11 @@ def process(
281268
f"[{index}/{total}] Importing {entry.filepath.name}", align="left", style="subtitle"
282269
)
283270

284-
if not prepare_comic(entry=entry, settings=settings, skip_convert=skip_convert):
271+
if not prepare_comic(entry=entry, skip_convert=skip_convert):
285272
continue
286273
with entry.open_session() as session:
287274
metron_info, comic_info = resolve_metadata(
288-
entry=entry,
289-
session=session,
290-
services=services,
291-
settings=settings.services,
292-
sync=sync,
275+
entry=entry, session=session, services=services, sync=sync
293276
)
294277
naming = apply_changes(
295278
entry=entry,
@@ -298,10 +281,9 @@ def process(
298281
comic_info=comic_info,
299282
skip_clean=skip_clean,
300283
skip_rename=skip_rename,
301-
settings=settings.output,
302284
)
303285
if naming:
304-
entry.move_to(naming=naming, output_folder=settings.output.folder)
286+
entry.move_to(naming=naming, output_folder=SETTINGS.output.folder)
305287
with CONSOLE.status("Cleaning up empty folders"):
306288
delete_empty_folders(folder=target)
307289

perdoo/cli/settings.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
__all__ = []
22

33
from perdoo.cli._typer import app
4-
from perdoo.settings import Settings
4+
from perdoo.settings import SETTINGS
55

66

77
@app.command(help="Display app settings and defaults.")
88
def settings() -> None:
9-
settings = Settings.load()
10-
settings.display()
9+
SETTINGS.display()

perdoo/comic/comic.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__all__ = ["IMAGE_EXTENSIONS", "Comic"]
1+
__all__ = ["Comic"]
22

33
import logging
44
import shutil
@@ -13,7 +13,6 @@
1313
LOGGER = logging.getLogger(__name__)
1414

1515
METADATA_FILENAMES: Final[frozenset[str]] = frozenset([MetronInfo.FILENAME, ComicInfo.FILENAME])
16-
IMAGE_EXTENSIONS: Final[frozenset[str]] = frozenset([".png", ".jpg", ".jpeg", ".webp", ".jxl"])
1716

1817

1918
class Comic:
@@ -45,33 +44,38 @@ def read_metadata(self, session: ArchiveSession) -> tuple[MetronInfo | None, Com
4544
comic_info = ComicInfo.from_bytes(content=session.read(filename=ComicInfo.FILENAME))
4645
return metron_info, comic_info
4746

48-
def list_images(self) -> list[Path]:
47+
def list_images(self, image_extensions: tuple[str, ...]) -> list[Path]:
4948
return humansorted(
5049
[
5150
Path(name)
5251
for name in self.archive.list_filenames()
53-
if Path(name).suffix.lower() in IMAGE_EXTENSIONS
52+
if Path(name).suffix.lower() in image_extensions
5453
],
5554
alg=ns.NA | ns.G | ns.P,
5655
)
5756

58-
def list_extras(self) -> list[Path]:
57+
def list_extras(self, image_extensions: tuple[str, ...]) -> list[Path]:
5958
return humansorted(
6059
[
6160
Path(name)
6261
for name in self.archive.list_filenames()
6362
if name not in METADATA_FILENAMES
64-
and Path(name).suffix.lower() not in IMAGE_EXTENSIONS
63+
and Path(name).suffix.lower() not in image_extensions
6564
],
6665
alg=ns.NA | ns.G | ns.P,
6766
)
6867

69-
def validate_naming(self, naming: str) -> bool:
68+
def validate_naming(self, naming: str, image_extensions: tuple[str, ...]) -> bool:
7069
template = Path(naming).stem
71-
return all(img.name.startswith(template) for img in self.list_images())
70+
return all(
71+
img.name.startswith(template)
72+
for img in self.list_images(image_extensions=image_extensions)
73+
)
7274

7375
def move_to(self, naming: str, output_folder: Path) -> None:
7476
output = output_folder / (naming + self.archive.EXTENSION)
77+
if output == self.archive.filepath.resolve():
78+
return
7579
if output.exists():
7680
LOGGER.warning("'%s' already exists, skipping", output)
7781
return

perdoo/comic/metadata/_base.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from rich.panel import Panel
1414

1515
from perdoo.console import CONSOLE
16-
from perdoo.settings import Naming
1716
from perdoo.utils import flatten_dict
1817

1918
try:
@@ -52,7 +51,7 @@ class Metadata(PascalModel, ABC):
5251
FILENAME: ClassVar[str] = ""
5352

5453
@abstractmethod
55-
def get_filename(self, settings: Naming) -> str: ...
54+
def get_filename(self) -> str: ...
5655

5756
@classmethod
5857
def from_bytes(cls, content: bytes) -> Self:

perdoo/comic/metadata/comic_info.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pydantic_xml import attr, computed_attr, element, wrapped
1212

1313
from perdoo.comic.metadata._base import Metadata, PascalModel
14-
from perdoo.settings import Naming
14+
from perdoo.settings import SETTINGS
1515

1616
LOGGER = logging.getLogger(__name__)
1717

@@ -280,9 +280,11 @@ def story_arc_list(self) -> list[str]:
280280
def story_arc_list(self, value: list[str]) -> None:
281281
self.story_arc = list_to_str(value=value)
282282

283-
def get_filename(self, settings: Naming) -> str:
283+
def get_filename(self) -> str:
284284
from perdoo.comic.metadata.metron_info import Format # noqa: PLC0415
285285

286+
settings = SETTINGS.output.naming
287+
286288
return self.evaluate_pattern(
287289
pattern_map=PATTERN_MAP,
288290
pattern={

perdoo/comic/metadata/metron_info.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from pydantic_xml import attr, computed_attr, element, wrapped
2929

3030
from perdoo.comic.metadata._base import Metadata, PascalModel
31-
from perdoo.settings import Naming
31+
from perdoo.settings import SETTINGS
3232

3333
LOGGER = logging.getLogger(__name__)
3434
T = TypeVar("T")
@@ -369,7 +369,9 @@ class MetronInfo(Metadata):
369369
def schema_location(self) -> str:
370370
return "https://raw.githubusercontent.com/Metron-Project/metroninfo/master/schema/v1.0/MetronInfo.xsd"
371371

372-
def get_filename(self, settings: Naming) -> str:
372+
def get_filename(self) -> str:
373+
settings = SETTINGS.output.naming
374+
373375
return self.evaluate_pattern(
374376
pattern_map=PATTERN_MAP,
375377
pattern={

perdoo/services/metron.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def _search_series(
4444
try:
4545
options = sorted(
4646
self.session.list_series(name=name, volume=volume, year_began=year),
47-
key=lambda x: (x.display_name, x.volume),
47+
key=lambda x: (x.name, x.volume),
4848
)
4949
if options:
5050
search = name
@@ -56,7 +56,7 @@ def _search_series(
5656
Choice(
5757
title=[
5858
("class:dim", f"{x.id} | "),
59-
("class:title", f"{x.display_name} v{x.volume}"),
59+
("class:title", f"{x.name} v{x.volume}"),
6060
],
6161
description=f"https://metron.cloud/series/{x.id}",
6262
value=x,
@@ -124,13 +124,13 @@ def _search_issue(self, series_id: int, number: str | None, filename: str) -> in
124124
try:
125125
options = humansorted(
126126
self.session.list_issues(series_id=series_id, number=number),
127-
key=lambda x: (x.number, x.issue_name),
127+
key=lambda x: (x.number, x.name),
128128
alg=ns.NA | ns.G,
129129
)
130130
if options:
131131
choices = [
132132
Choice(
133-
title=[("class:dim", f"{x.id} | "), ("class:title", x.issue_name)],
133+
title=[("class:dim", f"{x.id} | "), ("class:title", x.name)],
134134
description=f"https://metron.cloud/issues/{x.id}",
135135
value=x,
136136
)

perdoo/settings.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,4 @@
1-
__all__ = [
2-
"ComicInfo",
3-
"Comicvine",
4-
"Metron",
5-
"MetronInfo",
6-
"Naming",
7-
"Output",
8-
"Service",
9-
"Services",
10-
"Settings",
11-
]
1+
__all__ = ["SETTINGS"]
122

133
from enum import Enum
144
from pathlib import Path
@@ -75,6 +65,7 @@ class Output(SettingsModel):
7565
comic_info: ComicInfo = ComicInfo()
7666
folder: Path = get_data_root()
7767
format: Literal["cbz", "cbt", "cb7"] = "cbz"
68+
image_extensions: tuple[str, ...] = (".png", ".jpg", ".jpeg", ".webp", ".jxl")
7869
metron_info: MetronInfo = MetronInfo()
7970
naming: Naming = Naming()
8071

@@ -163,3 +154,6 @@ def display(cls) -> None:
163154

164155
CONSOLE.print(Panel.fit("\n".join(default_vals), title="Default"))
165156
CONSOLE.print(Panel.fit("\n".join(override_vals), title=str(cls._file)))
157+
158+
159+
SETTINGS = Settings.load().save()

tests/comic/comic_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ def test_clean_archive(cbz_comic: Comic) -> None:
3737
)
3838
cbz_comic.archive.delete_file = MagicMock()
3939
with cbz_comic.open_session() as session:
40-
for extra in cbz_comic.list_extras():
40+
for extra in cbz_comic.list_extras(
41+
image_extensions=(".png", ".jpg", ".jpeg", ".webp", ".jxl")
42+
):
4143
session.delete(filename=extra.name)
4244
cbz_comic.archive.delete_file.assert_called_once_with(filename="info.txt")
4345

0 commit comments

Comments
 (0)