Skip to content

Commit a5d2212

Browse files
rgaudinbenoit74
authored andcommitted
Introducing Callback via new typing module
- Explicit callback definition - simplified delete_callback to be a dumb callback (not chaining)
1 parent 1a5db4b commit a5d2212

File tree

4 files changed

+49
-45
lines changed

4 files changed

+49
-45
lines changed

src/zimscraperlib/filesystem.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
import os
1111
import pathlib
12-
from collections.abc import Callable
13-
from typing import Any
1412

1513
import magic
1614

@@ -44,15 +42,7 @@ def get_content_mimetype(content: bytes | str) -> str:
4442
return MIME_OVERRIDES.get(detected_mime, detected_mime)
4543

4644

47-
def delete_callback(
48-
fpath: str | pathlib.Path,
49-
callback: Callable | None = None,
50-
*callback_args: Any,
51-
):
52-
"""helper deleting passed filepath, optionnaly calling an additional callback"""
45+
def delete_callback(fpath: str | pathlib.Path):
46+
"""helper deleting passed filepath"""
5347

5448
os.unlink(fpath)
55-
56-
# call the callback if requested
57-
if callback and callable(callback):
58-
callback.__call__(*callback_args)

src/zimscraperlib/typing.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Callable
4+
from typing import Any, NamedTuple
5+
6+
7+
class Callback(NamedTuple):
8+
func: Callable
9+
args: tuple[Any, ...] | None = None
10+
kwargs: dict[str, Any] | None = None
11+
12+
@property
13+
def callable(self) -> bool:
14+
return callable(self.func)
15+
16+
def get_args(self) -> tuple[Any, ...]:
17+
return self.args or ()
18+
19+
def get_kwargs(self) -> dict[str, Any]:
20+
return self.kwargs or {}
21+
22+
def call_with(self, *args, **kwargs):
23+
self.func.__call__(*args, **kwargs)
24+
25+
def call(self):
26+
self.call_with(*self.get_args(), **self.get_kwargs())

src/zimscraperlib/zim/creator.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
)
4141
from zimscraperlib.i18n import is_valid_iso_639_3
4242
from zimscraperlib.types import get_mime_for_name
43+
from zimscraperlib.typing import Callback
4344
from zimscraperlib.zim.indexing import IndexData
4445
from zimscraperlib.zim.items import StaticItem
4546
from zimscraperlib.zim.metadata import (
@@ -341,7 +342,7 @@ def add_item_for(
341342
should_compress: bool | None = None,
342343
delete_fpath: bool | None = False,
343344
duplicate_ok: bool | None = None,
344-
callback: Callable | tuple[Callable, Any] | None = None,
345+
callbacks: list[Callback] | Callback | None = None,
345346
index_data: IndexData | None = None,
346347
auto_index: bool = True,
347348
):
@@ -365,6 +366,11 @@ def add_item_for(
365366
if fpath is None and content is None:
366367
raise ValueError("One of fpath or content is required")
367368

369+
if isinstance(callbacks, Callback):
370+
callbacks = [callbacks]
371+
elif callbacks is None:
372+
callbacks = []
373+
368374
mimetype = mimetype_for(
369375
path=path, content=content, fpath=fpath, mimetype=mimetype
370376
)
@@ -377,12 +383,7 @@ def add_item_for(
377383
hints[libzim.writer.Hint.COMPRESS] = should_compress
378384

379385
if delete_fpath and fpath:
380-
cb = [delete_callback, fpath]
381-
if callback and callable(callback):
382-
cb.append(callback)
383-
elif callback:
384-
cb += list(callback)
385-
callback = tuple(cb)
386+
callbacks.append(Callback(func=delete_callback, args=(fpath,)))
386387

387388
self.add_item(
388389
StaticItem(
@@ -395,7 +396,7 @@ def add_item_for(
395396
index_data=index_data,
396397
auto_index=auto_index,
397398
),
398-
callback=callback,
399+
callbacks=callbacks,
399400
duplicate_ok=duplicate_ok,
400401
)
401402
return path
@@ -404,18 +405,23 @@ def add_item(
404405
self,
405406
item: libzim.writer.Item,
406407
duplicate_ok: bool | None = None,
407-
callback: Callable | tuple[Callable, Any] | None = None,
408+
callbacks: list[Callback] | Callback | None = None,
408409
):
409410
"""Add a libzim.writer.Item
410411
411412
callback: either a single callable or a tuple containing the callable
412413
as first element then the arguments to pass to the callable.
413414
Note: you must __not__ include the item itself in those arguments."""
414-
if callback:
415-
if callable(callback):
416-
weakref.finalize(item, callback)
417-
else:
418-
weakref.finalize(item, *callback)
415+
if isinstance(callbacks, Callback):
416+
callbacks = [callbacks]
417+
elif callbacks is None:
418+
callbacks = []
419+
420+
for callback in callbacks:
421+
if callback.callable:
422+
weakref.finalize(
423+
item, callback.func, *callback.get_args(), **callback.get_kwargs()
424+
)
419425

420426
duplicate_ok = duplicate_ok or self.ignore_duplicates
421427
try:

tests/filesystem/test_filesystem.py

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,7 @@ def test_mime_overrides(svg_image):
4343
assert get_content_mimetype(fh.read(64)) == expected_mime
4444

4545

46-
def test_delete_callback_with_cb(tmp_path):
47-
class Store:
48-
called = 0
49-
50-
def cb(*args): # noqa: ARG001
51-
Store.called += 1
52-
53-
fpath = tmp_path.joinpath("my-file")
54-
with open(fpath, "w") as fh:
55-
fh.write("content")
56-
57-
delete_callback(fpath, cb, fpath.name)
58-
59-
assert not fpath.exists()
60-
assert Store.called
61-
assert Store.called == 1
62-
63-
64-
def test_delete_callback_without_cb(tmp_path):
46+
def test_delete_callback(tmp_path):
6547
fpath = tmp_path.joinpath("my-file")
6648
with open(fpath, "w") as fh:
6749
fh.write("content")

0 commit comments

Comments
 (0)