20
20
21
21
import datetime
22
22
import pathlib
23
+ import re
23
24
import weakref
24
25
from typing import Any , Callable , Dict , Optional , Tuple , Union
25
26
30
31
from ..types import get_mime_for_name
31
32
from .items import StaticItem
32
33
34
+ DUPLICATE_EXC_STR = re .compile (
35
+ r"^Impossible to add(.+)"
36
+ r"dirent\'s title to add is(.+)"
37
+ r"existing dirent's title is(.+)" ,
38
+ re .MULTILINE | re .DOTALL ,
39
+ )
40
+
33
41
34
42
def mimetype_for (
35
43
path : str ,
@@ -76,6 +84,7 @@ def __init__(
76
84
language : Optional [str ] = "eng" ,
77
85
compression : Optional [str ] = None ,
78
86
workaround_nocancel : Optional [bool ] = True ,
87
+ ignore_duplicates : Optional [bool ] = False ,
79
88
** metadata : Dict [str , Union [str , datetime .date , datetime .datetime ]]
80
89
):
81
90
super ().__init__ (filename = filename )
@@ -103,6 +112,7 @@ def __init__(
103
112
self .metadata = metadata
104
113
105
114
self .workaround_nocancel = workaround_nocancel
115
+ self .ignore_duplicates = ignore_duplicates
106
116
107
117
def start (self ):
108
118
super ().__enter__ ()
@@ -129,6 +139,7 @@ def add_item_for(
129
139
is_front : Optional [bool ] = None ,
130
140
should_compress : Optional [bool ] = None ,
131
141
delete_fpath : Optional [bool ] = False ,
142
+ duplicate_ok : Optional [bool ] = None ,
132
143
callback : Optional [Union [callable , Tuple [callable , Any ]]] = None ,
133
144
):
134
145
"""Add a File or content at a specified path and get its path
@@ -178,12 +189,15 @@ def add_item_for(
178
189
cb += list (callback )
179
190
callback = tuple (cb )
180
191
181
- self .add_item (StaticItem (** kwargs ), callback )
192
+ self .add_item (
193
+ StaticItem (** kwargs ), callback = callback , duplicate_ok = duplicate_ok
194
+ )
182
195
return path
183
196
184
197
def add_item (
185
198
self ,
186
199
item : libzim .writer .Item ,
200
+ duplicate_ok : Optional [bool ] = None ,
187
201
callback : Optional [Union [Callable , Tuple [Callable , Any ]]] = None ,
188
202
):
189
203
"""Add a libzim.writer.Item
@@ -196,8 +210,14 @@ def add_item(
196
210
weakref .finalize (item , callback )
197
211
else :
198
212
weakref .finalize (item , * callback )
213
+
214
+ duplicate_ok = duplicate_ok or self .ignore_duplicates
199
215
try :
200
- super ().add_item (item )
216
+ try :
217
+ super ().add_item (item )
218
+ except RuntimeError as exc :
219
+ if not DUPLICATE_EXC_STR .match (str (exc )) or not duplicate_ok :
220
+ raise exc
201
221
except Exception :
202
222
if self .workaround_nocancel :
203
223
self .can_finish = False # pragma: no cover
@@ -209,6 +229,7 @@ def add_redirect(
209
229
target_path : str ,
210
230
title : Optional [str ] = "" ,
211
231
is_front : Optional [bool ] = None ,
232
+ duplicate_ok : Optional [bool ] = None ,
212
233
):
213
234
"""Add a redirect from path to target_path
214
235
@@ -217,7 +238,19 @@ def add_redirect(
217
238
hints = {}
218
239
if is_front is not None :
219
240
hints [libzim .writer .Hint .FRONT_ARTICLE ] = bool (is_front )
220
- super ().add_redirection (path , title , target_path , hints )
241
+
242
+ duplicate_ok = duplicate_ok or self .ignore_duplicates
243
+
244
+ try :
245
+ try :
246
+ super ().add_redirection (path , title , target_path , hints )
247
+ except RuntimeError as exc :
248
+ if not DUPLICATE_EXC_STR .match (str (exc )) or not duplicate_ok :
249
+ raise exc
250
+ except Exception :
251
+ if self .workaround_nocancel :
252
+ self .can_finish = False # pragma: no cover
253
+ raise
221
254
222
255
def add_default_illustration (self , content : bytes ):
223
256
self .add_illustration (48 , content )
0 commit comments