33
44import json
55import os
6+ import re
67
78# import yaml
89from pathlib import Path
@@ -52,6 +53,33 @@ def str_or_none(value):
5253 return str (value )
5354
5455
56+ def compute_page_storage_path (
57+ working_dir : str ,
58+ domain_str : str ,
59+ page_name_as_filename : bool ,
60+ label_str : str = None ,
61+ top_level : str = None ,
62+ ) -> str :
63+ """Compute the folder that a page's slots are downloaded to / uploaded from.
64+
65+ Mirrors the folder-naming logic previously inlined in save_as_page_package: the
66+ page label is used when 'page_name_as_filename' is set and a label is known,
67+ otherwise the top-level page title is used. A domain sub folder is inserted so
68+ that pages from different OSW instances don't collide inside the same local
69+ working directory.
70+
71+ Both the '-DL-' (download) and '-UL-' (upload) event handlers call this helper
72+ so they always agree on where a given page's content is stored on disk.
73+ """
74+ if page_name_as_filename and label_str is not None :
75+ page_dir_name = label_str
76+ else :
77+ page_dir_name = top_level
78+ # Sanitize the domain for use as a directory name (invalid on Windows: \/:*?"<>|)
79+ domain_dir = re .sub (r'[\\/:*?"<>|]' , "_" , domain_str )
80+ return os .path .join (working_dir , domain_dir , page_dir_name )
81+
82+
5583def create_config_from_setting (settings_ : dict ) -> WtPage .PageDumpConfig :
5684 config_ = WtPage .PageDumpConfig (
5785 target_dir = settings_ ["local_working_directory" ],
@@ -66,6 +94,7 @@ def save_as_page_package(
6694 full_page_name_str ,
6795 wtsite_inst : WtSite ,
6896 dump_config_inst : WtPage .PageDumpConfig ,
97+ domain_str : str ,
6998 label_str : str = None ,
7099 top_level : str = None ,
71100 sub_level : str = None , # "content"
@@ -81,10 +110,13 @@ def save_as_page_package(
81110 package_branch = "deleteme"
82111 publisher = "Open Semantic World"
83112 working_dir = dump_config_inst .target_dir
84- if dump_config_inst .page_name_as_filename and label_str is not None :
85- target_dir = os .path .join (working_dir , label_str )
86- else :
87- target_dir = os .path .join (working_dir , top_level )
113+ target_dir = compute_page_storage_path (
114+ working_dir ,
115+ domain_str ,
116+ dump_config_inst .page_name_as_filename ,
117+ label_str ,
118+ top_level ,
119+ )
88120 if isinstance (author , list ):
89121 author_list = author
90122 elif isinstance (author , str ):
@@ -156,24 +188,46 @@ def save_as_page_package(
156188 }
157189 settings_read_from_file = False
158190
159- domains , accounts = read_domains_from_credentials_file (settings ["cred_filepath" ])
160- if "wiki-dev.open-semantic-lab.org" in domains :
161- domain = "wiki-dev.open-semantic-lab.org"
191+ # An empty/missing accounts.pwd.yaml must not prevent the window from opening.
192+ # The user can still type/select a domain once the window is up.
193+ domains , accounts , cred_load_error = [], {}, None
194+ try :
195+ domains , accounts = read_domains_from_credentials_file (
196+ settings ["cred_filepath" ]
197+ )
198+ except (FileNotFoundError , ValueError ) as e :
199+ cred_load_error = f"{ type (e ).__name__ } : { e } "
200+
201+ if domains :
202+ if "wiki-dev.open-semantic-lab.org" in domains :
203+ domain = "wiki-dev.open-semantic-lab.org"
204+ else :
205+ domain = domains [0 ]
206+ if settings_read_from_file :
207+ settings ["domain" ] = domain
162208 else :
163- domain = domains [0 ]
164- if settings_read_from_file :
165- settings ["domain" ] = domain
209+ domain = settings .get ("domain" , "" )
166210
167211 cm = CredentialManager (cred_filepath = settings ["cred_filepath" ])
168- osw_obj = OswExpress (domain = domain , cred_mngr = cm )
169- wtsite_obj = osw_obj .site
212+ osw_obj = None
213+ wtsite_obj = None
214+ if domain :
215+ osw_obj = OswExpress (domain = domain , cred_mngr = cm )
216+ wtsite_obj = osw_obj .site
170217
171218 full_page_name = settings ["target_page" ].split ("/" )[- 1 ].replace ("_" , " " )
172- page = wtsite_obj .get_page (WtSite .GetPageParam (titles = [full_page_name ])).pages [0 ]
219+ page = None
220+ if wtsite_obj is not None :
221+ page = wtsite_obj .get_page (WtSite .GetPageParam (titles = [full_page_name ])).pages [
222+ 0
223+ ]
173224 label_set = False
174225 label = None
175226 slots_downloaded = False
176227 dump_config = create_config_from_setting (settings )
228+ label_default_text = ""
229+ if cred_load_error is not None :
230+ label_default_text = f"Could not load credentials: { cred_load_error } "
177231
178232 # ----- GUI Definition -----
179233 # Setting the theme of the GUI
@@ -253,7 +307,12 @@ def save_as_page_package(
253307 ],
254308 [
255309 # A display element that will show the label of the OSW page
256- psg .Multiline (size = (50 , 1 ), key = "-LABEL-" , no_scrollbar = True )
310+ psg .Multiline (
311+ size = (50 , 1 ),
312+ key = "-LABEL-" ,
313+ no_scrollbar = True ,
314+ default_text = label_default_text ,
315+ )
257316 ],
258317 ]),
259318 ],
@@ -354,10 +413,17 @@ def save_as_page_package(
354413 json .dump (settings , f , indent = 4 )
355414 elif event == "-CREDENTIALS-" :
356415 settings ["cred_filepath" ] = values ["-CREDENTIALS-" ]
357- domains , accounts = read_domains_from_credentials_file (
358- settings ["cred_filepath" ]
359- )
360- window ["-DOMAIN-" ].update (values = domains )
416+ try :
417+ domains , accounts = read_domains_from_credentials_file (
418+ settings ["cred_filepath" ]
419+ )
420+ window ["-DOMAIN-" ].update (values = domains )
421+ except (FileNotFoundError , ValueError ) as e :
422+ # Keep the previously loaded domains/accounts, the user can retry
423+ # with a different file.
424+ window ["-LABEL-" ].update (
425+ f"Could not load credentials: { type (e ).__name__ } : { e } "
426+ )
361427 elif event == "-LWD-" :
362428 settings ["local_working_directory" ] = values ["-LWD-" ]
363429 elif event == "-DOMAIN-" :
@@ -368,51 +434,82 @@ def save_as_page_package(
368434 elif event == "Load page" :
369435 window ["-LABEL-" ].update ("Loading page..." )
370436 window ["-DL_RES-" ].update ("" )
371- full_page_name = values ["-ADDRESS-" ].split ("/" )[- 1 ].replace ("_" , " " )
372- if (values ["-ADDRESS-" ].find ("/wiki/" ) != - 1 ) or (
373- values ["-ADDRESS-" ].find ("/w/" ) != - 1
374- ):
375- settings ["target_page" ] = values ["-ADDRESS-" ]
376- else :
377- settings ["target_page" ] = (
378- "https://" + domain + "/wiki/" + full_page_name
437+ if wtsite_obj is None :
438+ window ["-LABEL-" ].update (
439+ "No domain selected. Load a credentials file or select a "
440+ "domain first."
379441 )
380- if values ["-ADDRESS-" ].find (settings ["domain" ]) == - 1 :
381- window ["-LABEL-" ].update ("Page not on selected domain!" )
382442 label_set = False
383443 else :
384- # use connection
385- page = wtsite_obj .get_page (
386- WtSite .GetPageParam (titles = [full_page_name ])
387- ).pages [0 ]
388- if page .exists :
389- jsondata = page .get_slot_content ("jsondata" )
390- if jsondata is None :
391- window ["-LABEL-" ].update ("Slot 'jsondata' is empty!" )
392- label_set = False
393- else :
394- label = jsondata ["label" ][0 ]["text" ]
395- window ["-LABEL-" ].update (label )
396- label_set = True
444+ full_page_name = values ["-ADDRESS-" ].split ("/" )[- 1 ].replace ("_" , " " )
445+ if (values ["-ADDRESS-" ].find ("/wiki/" ) != - 1 ) or (
446+ values ["-ADDRESS-" ].find ("/w/" ) != - 1
447+ ):
448+ settings ["target_page" ] = values ["-ADDRESS-" ]
397449 else :
398- window ["-LABEL-" ].update ("Page does not exist!" )
450+ settings ["target_page" ] = (
451+ "https://" + domain + "/wiki/" + full_page_name
452+ )
453+ if values ["-ADDRESS-" ].find (settings ["domain" ]) == - 1 :
454+ window ["-LABEL-" ].update ("Page not on selected domain!" )
399455 label_set = False
456+ else :
457+ # use connection
458+ page = wtsite_obj .get_page (
459+ WtSite .GetPageParam (titles = [full_page_name ])
460+ ).pages [0 ]
461+ if page .exists :
462+ jsondata = page .get_slot_content ("jsondata" )
463+ if jsondata is None :
464+ window ["-LABEL-" ].update ("Slot 'jsondata' is empty!" )
465+ label_set = False
466+ else :
467+ label = jsondata ["label" ][0 ]["text" ]
468+ window ["-LABEL-" ].update (label )
469+ label_set = True
470+ else :
471+ window ["-LABEL-" ].update ("Page does not exist!" )
472+ label_set = False
400473 elif event == "-EXC_EMPTY-" or event == "-INC_EMPTY-" :
401474 settings ["dump_empty_slots" ] = values ["-INC_EMPTY-" ]
402475 elif event == "-DL-" :
403476 window ["-DL_RES-" ].update ("Downloading slots..." )
404477 if label_set :
405- dump_config = create_config_from_setting (settings )
406- _ = save_as_page_package (
407- full_page_name_str = full_page_name ,
408- wtsite_inst = wtsite_obj ,
409- dump_config_inst = dump_config ,
410- label_str = label ,
411- sub_level = SUB_LEVEL ,
412- author = accounts [domains [0 ]]["username" ],
413- )
414- slots_downloaded = True
415- window ["-DL_RES-" ].update ("Slots downloaded!" )
478+ try :
479+ dump_config = create_config_from_setting (settings )
480+ target_dir = compute_page_storage_path (
481+ settings ["local_working_directory" ],
482+ domain ,
483+ settings ["page_name_as_filename" ],
484+ label ,
485+ full_page_name .split (":" )[- 1 ],
486+ )
487+ window ["-DL_RES-" ].update (
488+ f"Clearing '{ target_dir } ' and downloading slots..."
489+ )
490+ # Look up the author for the selected domain, not the first
491+ # one in the list, and degrade gracefully if there is no
492+ # credential entry for it (e.g. empty accounts.pwd.yaml).
493+ author = accounts .get (domain , {}).get ("username" )
494+ if author is None :
495+ window ["-DL_RES-" ].update (
496+ f"No credentials found for domain '{ domain } '; "
497+ "using default author."
498+ )
499+ author = "Open Semantic World"
500+ _ = save_as_page_package (
501+ full_page_name_str = full_page_name ,
502+ wtsite_inst = wtsite_obj ,
503+ dump_config_inst = dump_config ,
504+ domain_str = domain ,
505+ label_str = label ,
506+ sub_level = SUB_LEVEL ,
507+ author = author ,
508+ )
509+ slots_downloaded = True
510+ window ["-DL_RES-" ].update ("Slots downloaded!" )
511+ except Exception as e :
512+ window ["-DL_RES-" ].update (f"{ type (e ).__name__ } : { e } " )
416513 else :
417514 window ["-DL_RES-" ].update ("No page loaded!" )
418515 elif event == "-UL_SEL-" :
@@ -434,29 +531,45 @@ def save_as_page_package(
434531 elif len (slots_to_upload ) == 0 :
435532 window ["-UL_RES-" ].update ("No slots selected!" )
436533 else :
437- if not slots_downloaded :
438- window ["-UL_RES-" ].update ("No slots downloaded!" )
439- dump_config = create_config_from_setting (settings )
440- window ["-UL_RES-" ].update ("Uploading slots..." )
441- if SUB_LEVEL is None :
442- storage_path = Path (dump_config .target_dir )
443- else :
444- storage_path = Path (dump_config .target_dir ).parent
445- pages = wtsite_obj .read_page_package (
446- WtSite .ReadPagePackageParam (
447- storage_path = storage_path ,
448- packages_info_file_name = PACKAGE_INFO_FILE_NAME ,
449- selected_slots = slots_to_upload ,
450- debug = False ,
534+ try :
535+ # Recompute the storage path the same way the download path
536+ # does, instead of trusting a possibly stale dump_config.
537+ # This also makes upload work against a folder written by a
538+ # previous run, even if no download happened this session.
539+ storage_path = Path (
540+ compute_page_storage_path (
541+ settings ["local_working_directory" ],
542+ domain ,
543+ settings ["page_name_as_filename" ],
544+ label ,
545+ full_page_name .split (":" )[- 1 ],
546+ )
451547 )
452- ).pages
453- param = wtsite_obj .UploadPageParam (pages = pages , parallel = False )
454- wtsite_obj .upload_page (param )
455- # Success:
456- window ["-UL_RES-" ].update ("Slots uploaded!" )
457- # Report in the download section that the slots have been uploaded to
458- # remind the user that he eventually has to re-download the slots
459- window ["-DL_RES-" ].update ("Slots uploaded!" )
548+ if not slots_downloaded :
549+ window ["-UL_RES-" ].update (
550+ "No slots downloaded this session, trying folder from a "
551+ f"previous run at '{ storage_path } '..."
552+ )
553+ else :
554+ window ["-UL_RES-" ].update ("Uploading slots..." )
555+ pages = wtsite_obj .read_page_package (
556+ WtSite .ReadPagePackageParam (
557+ storage_path = storage_path ,
558+ packages_info_file_name = PACKAGE_INFO_FILE_NAME ,
559+ selected_slots = slots_to_upload ,
560+ debug = False ,
561+ )
562+ ).pages
563+ param = wtsite_obj .UploadPageParam (pages = pages , parallel = False )
564+ wtsite_obj .upload_page (param )
565+ # Success:
566+ window ["-UL_RES-" ].update ("Slots uploaded!" )
567+ # Report in the download section that the slots have been
568+ # uploaded to remind the user that he eventually has to
569+ # re-download the slots
570+ window ["-DL_RES-" ].update ("Slots uploaded!" )
571+ except Exception as e :
572+ window ["-UL_RES-" ].update (f"{ type (e ).__name__ } : { e } " )
460573
461574 # Some debugging output functionality
462575 if DEBUG :
0 commit comments