@@ -217,6 +217,24 @@ def from_credentials(
217217 site = wt .create_site_object (_domain , "" , _credentials )
218218 return cls (WtSite .WtSiteLegacyConfig (site = site ))
219219
220+ def try_and_renew_token (func ):
221+ """ "Tries to execute the method call. If the auth token has expired already,
222+ the token is renewed and the method call is retried.
223+
224+ This decorator should be used closest to to the funciton definition (before
225+ any other decorator).
226+ """
227+
228+ def wrapper (self , * args , ** kwargs ):
229+ try :
230+ return func (self , * args , ** kwargs )
231+ except mwclient .errors .APIError :
232+ # Refresh token for longer taking processes
233+ self ._site .get_token ("csrf" , force = True )
234+ return func (self , * args , ** kwargs )
235+
236+ return wrapper
237+
220238 class GetPageParam (OswBaseModel ):
221239 titles : Union [str , List [str ]]
222240 """title string or list of title strings of the pages to download"""
@@ -252,6 +270,7 @@ class GetPageResult(OswBaseModel):
252270 class Config :
253271 arbitrary_types_allowed = True # allows to use WtPage in type hints
254272
273+ @try_and_renew_token
255274 def get_page (self , param : GetPageParam ) -> GetPageResult :
256275 """Downloads a page or a list of pages from the site.
257276
@@ -319,6 +338,7 @@ def get_page_(title: str, index: int = None):
319338 return self .GetPageResult (pages = pages , errors = exceptions )
320339
321340 @deprecated ("Use get_page instead" )
341+ @try_and_renew_token
322342 def get_WtPage (self , title : str = None ):
323343 """Creates a new WtPage object for the given title
324344 and loads the page from the site if the page already exists.
@@ -341,6 +361,7 @@ class GetPageContentResult(OswBaseModel):
341361 class Config :
342362 arbitrary_types_allowed = True
343363
364+ @try_and_renew_token
344365 def get_page_content (self , full_page_titles : List [str ]) -> GetPageContentResult :
345366 get_page_res = self .get_page (WtSite .GetPageParam (titles = full_page_titles ))
346367 contents_dict = {}
@@ -395,6 +416,7 @@ def _clear_cookies(self):
395416 class SearchParam (wt .SearchParam ):
396417 pass
397418
419+ @try_and_renew_token
398420 def prefix_search (self , text : Union [str , SearchParam ]):
399421 """Send a prefix search request to the site.
400422
@@ -409,6 +431,7 @@ def prefix_search(self, text: Union[str, SearchParam]):
409431 """
410432 return wt .prefix_search (self ._site , text )
411433
434+ @try_and_renew_token
412435 def semantic_search (self , query : Union [str , SearchParam ]):
413436 """Send a swm ask query to the site.
414437
@@ -437,6 +460,7 @@ class ModifySearchResultsParam(OswBaseModel):
437460 dryrun : bool = False
438461 """if True, no actual changes are made"""
439462
463+ @try_and_renew_token
440464 def modify_search_results (
441465 self ,
442466 mode : str ,
@@ -512,6 +536,7 @@ def __init__(self, **data):
512536 if self .parallel is None :
513537 self .parallel = False
514538
539+ @try_and_renew_token
515540 def upload_page (
516541 self ,
517542 param : Union [UploadPageParam , "WtPage" , List ["WtPage" ]],
@@ -579,6 +604,7 @@ def __init__(self, **data):
579604 if self .parallel is None :
580605 self .parallel = False
581606
607+ @try_and_renew_token
582608 def copy_pages (self , param : CopyPagesParam ):
583609 """Copies pages from a source site to this (target) site."""
584610
@@ -626,6 +652,7 @@ def __init__(self, **data):
626652 if len (self .page ) > 5 and self .parallel is None :
627653 self .parallel = True
628654
655+ @try_and_renew_token
629656 def delete_page (
630657 self ,
631658 param : Union ["WtPage" , List ["WtPage" ], str , List [str ], DeletePageParam ],
@@ -697,6 +724,7 @@ class CreatePagePackageParam(OswBaseModel):
697724 class Config :
698725 arbitrary_types_allowed = True
699726
727+ @try_and_renew_token
700728 def create_page_package (self , param : CreatePagePackageParam ):
701729 """Create a page package, which is a locally stored collection of wiki pages
702730 and their slots, based on a configuration object.
@@ -858,6 +886,7 @@ class ReadPagePackageResult(OswBaseModel):
858886 class Config :
859887 arbitrary_types_allowed = True
860888
889+ @try_and_renew_token
861890 def read_page_package (self , param : ReadPagePackageParam ) -> ReadPagePackageResult :
862891 """Read a page package, which is a locally stored collection of wiki pages and
863892 their slots' content.
@@ -1007,6 +1036,7 @@ class UploadPagePackageParam(OswBaseModel):
10071036 class Config :
10081037 arbitrary_types_allowed = True
10091038
1039+ @try_and_renew_token
10101040 def upload_page_package (self , param : UploadPagePackageParam ):
10111041 """Uploads a page package to the wiki defined by a list of WtPage objects or
10121042 a storage path.
@@ -1031,6 +1061,7 @@ def upload_page_package(self, param: UploadPagePackageParam):
10311061 for page in pages :
10321062 page .edit ()
10331063
1064+ @try_and_renew_token
10341065 def get_file_pages (self , limit : int = 1000000 ) -> List [str ]:
10351066 """Get all file pages in the wiki"""
10361067 full_page_titles = wt .prefix_search (
@@ -1039,6 +1070,7 @@ def get_file_pages(self, limit: int = 1000000) -> List[str]:
10391070 )
10401071 return full_page_titles
10411072
1073+ @try_and_renew_token
10421074 def get_file_info_and_usage (
10431075 self ,
10441076 page_titles : Union [str , List [str ], SearchParam ],
@@ -1156,6 +1188,7 @@ def _replace_jsonld_context_mapping(
11561188 )
11571189 return context
11581190
1191+ @try_and_renew_token
11591192 def get_jsonld_context_loader (self , params : JsonLdContextLoaderParams = None ):
11601193 if params is None :
11611194 params = self .JsonLdContextLoaderParams ()
@@ -1275,6 +1308,24 @@ def init(self):
12751308 # todo: set content for slots not in revision["slots"] (use
12761309 # SLOTS) --> create empty slots
12771310
1311+ def try_and_renew_token (func ):
1312+ """Tries to execute the method call. If the auth token has expired already,
1313+ the token is renewed and the method call is retried.
1314+
1315+ This decorator should be used closest to to the funciton definition (before
1316+ any other decorator).
1317+ """
1318+
1319+ def wrapper (self , * args , ** kwargs ):
1320+ try :
1321+ return func (self , * args , ** kwargs )
1322+ except mwclient .errors .APIError :
1323+ # Refresh token for longer taking processes
1324+ self .wtSite ._site .get_token ("csrf" , force = True )
1325+ return func (self , * args , ** kwargs )
1326+
1327+ return wrapper
1328+
12781329 def parse_main_slot (self ):
12791330 """Parses the main slot content of the page
12801331 Requires wikitext dependencies installed with 'pip install osw[wikitext]'
@@ -1646,6 +1697,7 @@ def _edit(
16461697 if changed :
16471698 self .changed = True
16481699
1700+ @try_and_renew_token
16491701 def delete (self , comment : str = None ):
16501702 """Deletes the page from the site
16511703
@@ -1656,6 +1708,7 @@ def delete(self, comment: str = None):
16561708 """
16571709 self ._page .delete (comment )
16581710
1711+ @try_and_renew_token
16591712 def move (self , new_title : str , comment : str = None , redirect : bool = True ):
16601713 """Moves (=renames) the page to a new title
16611714
@@ -1713,6 +1766,7 @@ class PageCopyResult(OswBaseModel):
17131766 class Config :
17141767 arbitrary_types_allowed = True
17151768
1769+ @try_and_renew_token
17161770 def copy (self , config : CopyPageConfig ) -> PageCopyResult :
17171771 if config .comment is None :
17181772 config .comment = f"[bot edit] Copied from { config .source_site .mw_site .host } "
@@ -1874,6 +1928,7 @@ def dump_slot_content(slot_key_, content_type_, content_):
18741928
18751929 return package_page
18761930
1931+ @try_and_renew_token
18771932 def get_file_info_and_usage (
18781933 self , debug : bool = False
18791934 ) -> Dict [str , Union [str , List [str ]]]:
@@ -1894,6 +1949,7 @@ def get_file_info_and_usage(
18941949 title = wt .SearchParam (query = self .title , debug = debug ),
18951950 )[0 ]
18961951
1952+ @try_and_renew_token
18971953 def find_file_page_refs_in_slots (self , slots : List [str ] = None ) -> List [str ]:
18981954 """Find all file page references in the content of the given slots."""
18991955 if slots is None :
@@ -1939,6 +1995,7 @@ def find_file_page_refs_in_slots(self, slots: List[str] = None) -> List[str]:
19391995 print ("Warning: Error while parsing uuid in editor template" )
19401996 return list (set (file_page_refs ))
19411997
1998+ @try_and_renew_token
19421999 def purge (self ):
19432000 """Purge the page from the site cache.
19442001 Triggers a rebuild / refresh of the page.
@@ -1962,6 +2019,7 @@ class ExportResult(OswBaseModel):
19622019 success : bool
19632020 """if true, the export was successful, else false"""
19642021
2022+ @try_and_renew_token
19652023 def export_xml (self , config : Optional [ExportConfig ] = None ) -> ExportResult :
19662024 """Exports the page to XML
19672025
@@ -2035,6 +2093,7 @@ class ImportResult(OswBaseModel):
20352093 imported_revisions : int
20362094 error_msg : Optional [str ] = None
20372095
2096+ @try_and_renew_token
20382097 def import_xml (self , config : ImportConfig ) -> ImportResult :
20392098 """Imports the page from an XML export
20402099
0 commit comments