diff --git a/kohya_gui/basic_caption_gui.py b/kohya_gui/basic_caption_gui.py index be66821..ee834a3 100644 --- a/kohya_gui/basic_caption_gui.py +++ b/kohya_gui/basic_caption_gui.py @@ -8,7 +8,6 @@ from .common_gui import ( list_dirs, setup_environment, ) -from .class_gui_config import KohyaSSGUIConfig # Added import import os import sys @@ -122,7 +121,7 @@ def caption_images( # Gradio UI -def gradio_basic_caption_gui_tab(headless=False, default_images_dir=None, config: KohyaSSGUIConfig = {}): # Added config +def gradio_basic_caption_gui_tab(headless=False, default_images_dir=None): """ Creates a Gradio tab for basic image captioning. @@ -192,7 +191,7 @@ def gradio_basic_caption_gui_tab(headless=False, default_images_dir=None, config ) # Event handler for button click folder_button.click( - lambda: get_folder_path(config=config), # Added config + get_folder_path, outputs=images_dir, show_progress=False, ) diff --git a/kohya_gui/blip2_caption_gui.py b/kohya_gui/blip2_caption_gui.py index 3ee3b15..036211c 100644 --- a/kohya_gui/blip2_caption_gui.py +++ b/kohya_gui/blip2_caption_gui.py @@ -6,7 +6,6 @@ import os from .common_gui import get_folder_path, scriptdir, list_dirs from .custom_logging import setup_logging -from .class_gui_config import KohyaSSGUIConfig # Added import # Set up logging log = setup_logging() @@ -209,7 +208,7 @@ def caption_images_nucleus( ) -def gradio_blip2_caption_gui_tab(headless=False, directory_path=None, config: KohyaSSGUIConfig = {}): # Added config +def gradio_blip2_caption_gui_tab(headless=False, directory_path=None): from .common_gui import create_refresh_button directory_path = ( @@ -250,7 +249,7 @@ def gradio_blip2_caption_gui_tab(headless=False, directory_path=None, config: Ko visible=(not headless), ) button_directory_path_dir_input.click( - lambda: get_folder_path(config=config), # Added config + get_folder_path, outputs=directory_path_dir, show_progress=False, ) diff --git a/kohya_gui/blip_caption_gui.py b/kohya_gui/blip_caption_gui.py index 5ac1b6b..058a8de 100644 --- a/kohya_gui/blip_caption_gui.py +++ b/kohya_gui/blip_caption_gui.py @@ -4,7 +4,6 @@ import os import sys from .common_gui import get_folder_path, add_pre_postfix, scriptdir, list_dirs, setup_environment from .custom_logging import setup_logging -from .class_gui_config import KohyaSSGUIConfig # Added import # Set up logging log = setup_logging() @@ -113,7 +112,7 @@ def caption_images( ### -def gradio_blip_caption_gui_tab(headless=False, default_train_dir=None, config: KohyaSSGUIConfig = {}): # Added config +def gradio_blip_caption_gui_tab(headless=False, default_train_dir=None): from .common_gui import create_refresh_button default_train_dir = ( @@ -153,7 +152,7 @@ def gradio_blip_caption_gui_tab(headless=False, default_train_dir=None, config: visible=(not headless), ) button_train_data_dir_input.click( - lambda: get_folder_path(config=config), # Added config + get_folder_path, outputs=train_data_dir, show_progress=False, ) diff --git a/kohya_gui/class_folders.py b/kohya_gui/class_folders.py index 6662ae4..a0467fb 100644 --- a/kohya_gui/class_folders.py +++ b/kohya_gui/class_folders.py @@ -126,7 +126,7 @@ class Folders: ) # Output directory button click event self.output_dir_folder.click( - lambda: get_folder_path(config=self.config), + get_folder_path, outputs=self.output_dir, show_progress=False, ) @@ -161,7 +161,7 @@ class Folders: ) # Regularisation directory button click event self.reg_data_dir_folder.click( - lambda: get_folder_path(config=self.config), + get_folder_path, outputs=self.reg_data_dir, show_progress=False, ) @@ -192,7 +192,7 @@ class Folders: ) # Logging directory button click event self.logging_dir_folder.click( - lambda: get_folder_path(config=self.config), + get_folder_path, outputs=self.logging_dir, show_progress=False, ) diff --git a/kohya_gui/class_gui_config.py b/kohya_gui/class_gui_config.py index 25e5bd0..33064a9 100644 --- a/kohya_gui/class_gui_config.py +++ b/kohya_gui/class_gui_config.py @@ -16,8 +16,6 @@ class KohyaSSGUIConfig: Initialize the KohyaSSGUIConfig class. """ self.config = self.load_config(config_file_path=config_file_path) - # Initialize last_used_folder during class initialization - self.get_last_used_folder() def load_config(self, config_file_path: str = "./config.toml") -> dict: """ @@ -37,11 +35,6 @@ class KohyaSSGUIConfig: f"No configuration file found at {config_file_path}. Initializing empty configuration." ) - # Ensure last_used_folder is present, defaulting to scriptdir - if "last_used_folder" not in config: - config["last_used_folder"] = scriptdir - log.debug(f"Initialized 'last_used_folder' to '{scriptdir}'") - return config def save_config(self, config: dict, config_file_path: str = "./config.toml"): @@ -98,37 +91,3 @@ class KohyaSSGUIConfig: is_loaded = self.config != {} log.debug(f"Configuration was loaded from file: {is_loaded}") return is_loaded - - def get_last_used_folder(self) -> str: - """ - Retrieves the last used folder from the configuration. - - Returns: - str: The last used folder path. - """ - folder = self.config.get("last_used_folder", scriptdir) - # Ensure that the returned path is a string, even if it's empty or None from config - if not isinstance(folder, str): - folder = str(folder) if folder is not None else scriptdir - # Update the config if the type was wrong. - self.config["last_used_folder"] = folder - log.debug(f"Retrieved last_used_folder: {folder}") - return folder - - def set_last_used_folder(self, folder_path: str): - """ - Sets the last used folder in the configuration. - - Parameters: - - folder_path (str): The path to the folder to be set. - """ - if not isinstance(folder_path, str): - log.error(f"Attempted to set last_used_folder with non-string value: {folder_path}") - # Optionally, raise an error or convert, for now, let's default to scriptdir - # or handle as an error appropriately depending on desired behavior. - # For robustness, let's ensure it's always a string or default if invalid. - folder_path = scriptdir - self.config["last_used_folder"] = folder_path - log.debug(f"Set last_used_folder to: {folder_path}") - # Note: Saving the config should be handled explicitly by the caller if needed immediately. - # For example, by calling gui_config.save_config(gui_config.config) diff --git a/kohya_gui/common_gui.py b/kohya_gui/common_gui.py index 529b118..f55a618 100644 --- a/kohya_gui/common_gui.py +++ b/kohya_gui/common_gui.py @@ -3,13 +3,10 @@ try: except ImportError: pass from easygui import msgbox, ynbox -from typing import Optional, TYPE_CHECKING +from typing import Optional from .custom_logging import setup_logging from .sd_modeltype import SDModelType -if TYPE_CHECKING: - from .class_gui_config import KohyaSSGUIConfig - import os import re import gradio as gr @@ -460,12 +457,11 @@ def get_dir_and_file(file_path): def get_file_path( - file_path="", default_extension=".json", extension_name="Config files", config: "KohyaSSGUIConfig" = None + file_path="", default_extension=".json", extension_name="Config files" ): """ Opens a file dialog to select a file, allowing the user to navigate and choose a file with a specific extension. If no file is selected, returns the initially provided file path or an empty string if not provided. - Uses and updates last_used_folder from the config if provided. This function is conditioned to skip the file dialog on macOS or if specific environment variables are present, indicating a possible automated environment where a dialog cannot be displayed. @@ -496,16 +492,11 @@ def get_file_path( if not any(var in os.environ for var in ENV_EXCLUSION) and sys.platform != "darwin": current_file_path = file_path # Backup in case no file is selected - initial_dir_to_use, initial_file = get_dir_and_file(file_path) - - if config: - last_used = config.get_last_used_folder() - if last_used and os.path.isdir(last_used): - initial_dir_to_use = last_used - - if not initial_dir_to_use or not os.path.isdir(initial_dir_to_use): # Check if valid dir - initial_dir_to_use = scriptdir - + if not os.path.dirname(file_path): + initial_dir = scriptdir + else: + initial_dir = os.path.dirname(file_path) + initial_file = os.path.basename(file_path) # Initialize a hidden Tkinter window for the file dialog root = Tk() @@ -513,38 +504,27 @@ def get_file_path( root.withdraw() # Hide the root window to show only the dialog # Open the file dialog and capture the selected file path - returned_path = filedialog.askopenfilename( + file_path = filedialog.askopenfilename( filetypes=((extension_name, f"*{default_extension}"), ("All files", "*.*")), defaultextension=default_extension, initialfile=initial_file, - initialdir=initial_dir_to_use, + initialdir=initial_dir, ) root.destroy() # Cleanup by destroying the Tkinter root window - if returned_path: # User selected a file - file_path = returned_path - if config: - config.set_last_used_folder(os.path.dirname(file_path)) - else: # User cancelled dialog + # Fallback to the initial path if no selection is made + if not file_path: file_path = current_file_path - # Do not update last_used_folder if dialog is cancelled - else: - # For non-dialog environments (headless/macOS) - # If a file_path is provided, is a file, and config is available, - # update last_used_folder based on its directory. - if file_path and os.path.isfile(file_path) and config: - config.set_last_used_folder(os.path.dirname(file_path)) # Return the selected or fallback file path return file_path -def get_any_file_path(file_path: str = "", config: "KohyaSSGUIConfig" = None) -> str: +def get_any_file_path(file_path: str = "") -> str: """ Opens a file dialog to select any file, allowing the user to navigate and choose a file. If no file is selected, returns the initially provided file path or an empty string if not provided. - Uses and updates last_used_folder from the config if provided. This function is conditioned to skip the file dialog on macOS or if specific environment variables are present, indicating a possible automated environment where a dialog cannot be displayed. @@ -575,15 +555,7 @@ def get_any_file_path(file_path: str = "", config: "KohyaSSGUIConfig" = None) -> ): current_file_path: str = file_path - initial_dir_to_use, initial_file = get_dir_and_file(file_path) - if config: - last_used = config.get_last_used_folder() - if last_used and os.path.isdir(last_used): - initial_dir_to_use = last_used - - if not initial_dir_to_use or not os.path.isdir(initial_dir_to_use): # Check if valid dir - initial_dir_to_use = scriptdir - + initial_dir, initial_file = get_dir_and_file(file_path) # Initialize a hidden Tkinter window for the file dialog root = Tk() @@ -592,8 +564,8 @@ def get_any_file_path(file_path: str = "", config: "KohyaSSGUIConfig" = None) -> try: # Open the file dialog and capture the selected file path - returned_path = filedialog.askopenfilename( - initialdir=initial_dir_to_use, # Use determined initial_dir + file_path = filedialog.askopenfilename( + initialdir=initial_dir, initialfile=initial_file, ) except Exception as e: @@ -601,17 +573,9 @@ def get_any_file_path(file_path: str = "", config: "KohyaSSGUIConfig" = None) -> finally: root.destroy() - if returned_path: # User selected a file - file_path = returned_path - if config: - config.set_last_used_folder(os.path.dirname(file_path)) - else: # User cancelled dialog + # Fallback to the initial path if no selection is made + if not file_path: file_path = current_file_path - # Do not update last_used_folder if dialog is cancelled - else: - # For non-dialog environments - if file_path and os.path.isfile(file_path) and config: - config.set_last_used_folder(os.path.dirname(file_path)) except KeyError as e: raise EnvironmentError(f"Failed to access environment variables: {e}") @@ -619,11 +583,10 @@ def get_any_file_path(file_path: str = "", config: "KohyaSSGUIConfig" = None) -> return file_path -def get_folder_path(folder_path: str = "", config: "KohyaSSGUIConfig" = None) -> str: +def get_folder_path(folder_path: str = "") -> str: """ Opens a folder dialog to select a folder, allowing the user to navigate and choose a folder. If no folder is selected, returns the initially provided folder path or an empty string if not provided. - Uses and updates last_used_folder from the config if provided. This function is conditioned to skip the folder dialog on macOS or if specific environment variables are present, indicating a possible automated environment where a dialog cannot be displayed. @@ -646,109 +609,70 @@ def get_folder_path(folder_path: str = "", config: "KohyaSSGUIConfig" = None) -> if not isinstance(folder_path, str): raise TypeError("folder_path must be a string") - initial_dir_to_use = scriptdir # Default initial directory - - if config: - last_used = config.get_last_used_folder() - if last_used and os.path.isdir(last_used): - initial_dir_to_use = last_used - elif folder_path and os.path.isdir(folder_path): # Fallback to folder_path if last_used is invalid - initial_dir_to_use = folder_path - # If both last_used and folder_path are invalid or not provided, scriptdir is used as already set - elif folder_path and os.path.isdir(folder_path): # No config, but folder_path is valid - initial_dir_to_use = folder_path - - try: - # Check for environment variable conditions to skip dialog + # Check for environment variable conditions if any(var in os.environ for var in ENV_EXCLUSION) or sys.platform == "darwin": - # Even if dialog is skipped, if a valid folder_path is given and config is present, - # consider it as the "selected" path for updating last_used_folder. - if folder_path and os.path.isdir(folder_path) and config: - config.set_last_used_folder(folder_path) return folder_path or "" root = Tk() root.withdraw() root.wm_attributes("-topmost", 1) - # Use initial_dir_to_use, which has been determined based on config or folder_path - selected_folder = filedialog.askdirectory(initialdir=initial_dir_to_use) + selected_folder = filedialog.askdirectory(initialdir=folder_path or ".") root.destroy() - - if selected_folder: # User selected a folder - if config: - config.set_last_used_folder(selected_folder) - return selected_folder - else: # User cancelled dialog - # Return the original folder_path or empty string, do not update last_used_folder - return folder_path + return selected_folder or folder_path except Exception as e: - # Log the exception or handle it as per application's error handling policy - log.error(f"Error initializing folder dialog: {e}") - # Fallback to returning the original folder_path in case of an unexpected error - return folder_path + raise RuntimeError(f"Error initializing folder dialog: {e}") from e def get_saveasfile_path( file_path: str = "", defaultextension: str = ".json", extension_name: str = "Config files", - config: "KohyaSSGUIConfig" = None, ) -> str: - """ - Opens a file dialog to select a file name for saving, allowing the user to specify a file name and location. - If no file is selected, returns the initially provided file path or an empty string if not provided. - Uses and updates last_used_folder from the config if provided. - Note: This function now uses asksaveasfilename for consistency. - """ # Check if the current environment is not macOS and if the environment variables do not match the exclusion list if not any(var in os.environ for var in ENV_EXCLUSION) and sys.platform != "darwin": + # Store the initial file path to use as a fallback in case no file is selected current_file_path = file_path - initial_dir_to_use, initial_file = get_dir_and_file(file_path) - if config: - last_used = config.get_last_used_folder() - if last_used and os.path.isdir(last_used): - initial_dir_to_use = last_used + # Logging the current file path for debugging purposes; helps in tracking the flow of file selection + # log.info(f'current file path: {current_file_path}') - if not initial_dir_to_use or not os.path.isdir(initial_dir_to_use): # Check if valid dir - initial_dir_to_use = scriptdir + # Split the file path into directory and file name for setting the file dialog start location and filename + initial_dir, initial_file = get_dir_and_file(file_path) + # Initialize a hidden Tkinter window to act as the parent for the file dialog, ensuring it appears on top root = Tk() root.wm_attributes("-topmost", 1) root.withdraw() - - # Using asksaveasfilename to get the path string directly - returned_path = filedialog.asksaveasfilename( + save_file_path = filedialog.asksaveasfile( filetypes=( - (f"{extension_name}", f"*{defaultextension}"), # Ensure wildcard for extension - ("All files", "*.*"), + (f"{extension_name}", f"{defaultextension}"), + ("All files", "*"), ), defaultextension=defaultextension, - initialdir=initial_dir_to_use, + initialdir=initial_dir, initialfile=initial_file, ) + # Close the Tkinter root window to clean up the UI root.destroy() - if returned_path: # User selected a path - file_path = returned_path - if config: - config.set_last_used_folder(os.path.dirname(file_path)) - else: # User cancelled dialog + # Logging the save file path for auditing purposes; useful in confirming the user's file choice + # log.info(save_file_path) + + # Default to the current file path if no file is selected, ensuring there's always a valid file path + if save_file_path == None: file_path = current_file_path - # Do not update last_used_folder if dialog is cancelled - else: - # For non-dialog environments - # If a file_path is provided (even if it doesn't exist yet, its dir might be valid) - # and config is available, update last_used_folder. - if file_path and config: - dir_name = os.path.dirname(file_path) - if dir_name and os.path.isdir(dir_name): # Check if directory is valid - config.set_last_used_folder(dir_name) - elif not dir_name: # Path is likely just a filename, use scriptdir - config.set_last_used_folder(scriptdir) + else: + # Log the selected file name for transparency and tracking user actions + # log.info(save_file_path.name) + # Update the file path with the user-selected file name, facilitating the save operation + file_path = save_file_path.name + # Log the final file path for verification, ensuring the intended file is being used + # log.info(file_path) + + # Return the final file path, either the user-selected file or the fallback path return file_path @@ -756,12 +680,10 @@ def get_saveasfilename_path( file_path: str = "", extensions: str = "*", extension_name: str = "Config files", - config: "KohyaSSGUIConfig" = None, ) -> str: """ Opens a file dialog to select a file name for saving, allowing the user to specify a file name and location. If no file is selected, returns the initially provided file path or an empty string if not provided. - Uses and updates last_used_folder from the config if provided. This function is conditioned to skip the file dialog on macOS or if specific environment variables are present, indicating a possible automated environment where a dialog cannot be displayed. @@ -786,48 +708,36 @@ def get_saveasfilename_path( if not any(var in os.environ for var in ENV_EXCLUSION) and sys.platform != "darwin": # Store the initial file path to use as a fallback in case no file is selected current_file_path: str = file_path + # log.info(f'current file path: {current_file_path}') - initial_dir_to_use, initial_file = get_dir_and_file(file_path) - if config: - last_used = config.get_last_used_folder() - if last_used and os.path.isdir(last_used): - initial_dir_to_use = last_used - - if not initial_dir_to_use or not os.path.isdir(initial_dir_to_use): # Check if valid dir - initial_dir_to_use = scriptdir + # Split the file path into directory and file name for setting the file dialog start location and filename + initial_dir, initial_file = get_dir_and_file(file_path) # Initialize a hidden Tkinter window to act as the parent for the file dialog, ensuring it appears on top root = Tk() root.wm_attributes("-topmost", 1) root.withdraw() # Open the file dialog and capture the selected file path - returned_path = filedialog.asksaveasfilename( + save_file_path = filedialog.asksaveasfilename( filetypes=( - (f"{extension_name}", f"{extensions}"), # Corrected: uses extensions parameter - ("All files", "*.*"), + (f"{extension_name}", f"{extensions}"), + ("All files", "*"), ), - defaultextension=extensions, # Corrected: uses extensions parameter - initialdir=initial_dir_to_use, + defaultextension=extensions, + initialdir=initial_dir, initialfile=initial_file, ) # Close the Tkinter root window to clean up the UI root.destroy() - if returned_path: # User selected a path - file_path = returned_path - if config: - config.set_last_used_folder(os.path.dirname(file_path)) - else: # User cancelled dialog + # Default to the current file path if no file is selected, ensuring there's always a valid file path + if save_file_path == "": file_path = current_file_path - # Do not update last_used_folder if dialog is cancelled - else: - # For non-dialog environments - if file_path and config: - dir_name = os.path.dirname(file_path) - if dir_name and os.path.isdir(dir_name): - config.set_last_used_folder(dir_name) - elif not dir_name: # Path is likely just a filename, use scriptdir - config.set_last_used_folder(scriptdir) + else: + # Logging the save file path for auditing purposes; useful in confirming the user's file choice + # log.info(save_file_path) + # Update the file path with the user-selected file name, facilitating the save operation + file_path = save_file_path # Return the final file path, either the user-selected file or the fallback path return file_path diff --git a/kohya_gui/git_caption_gui.py b/kohya_gui/git_caption_gui.py index 7d412a7..f1b1003 100644 --- a/kohya_gui/git_caption_gui.py +++ b/kohya_gui/git_caption_gui.py @@ -3,7 +3,6 @@ import subprocess import os import sys from .common_gui import get_folder_path, add_pre_postfix, scriptdir, list_dirs, setup_environment -from .class_gui_config import KohyaSSGUIConfig # Added import from .custom_logging import setup_logging @@ -86,7 +85,7 @@ def caption_images( def gradio_git_caption_gui_tab( - headless=False, default_train_dir=None, config: KohyaSSGUIConfig = {} # Added config + headless=False, default_train_dir=None, ): from .common_gui import create_refresh_button @@ -127,7 +126,7 @@ def gradio_git_caption_gui_tab( visible=(not headless), ) button_train_data_dir_input.click( - lambda: get_folder_path(config=config), # Added config + get_folder_path, outputs=train_data_dir, show_progress=False, ) diff --git a/kohya_gui/manual_caption_gui.py b/kohya_gui/manual_caption_gui.py index 07f4817..0a31e08 100644 --- a/kohya_gui/manual_caption_gui.py +++ b/kohya_gui/manual_caption_gui.py @@ -1,7 +1,6 @@ import gradio as gr from easygui import msgbox, boolbox from .common_gui import get_folder_path, scriptdir, list_dirs -from .class_gui_config import KohyaSSGUIConfig # Added import from math import ceil import os import re @@ -251,7 +250,7 @@ def update_images( # Gradio UI -def gradio_manual_caption_gui_tab(headless=False, default_images_dir=None, config: KohyaSSGUIConfig = {}): # Added config +def gradio_manual_caption_gui_tab(headless=False, default_images_dir=None): from .common_gui import create_refresh_button default_images_dir = ( @@ -294,7 +293,7 @@ def gradio_manual_caption_gui_tab(headless=False, default_images_dir=None, confi visible=(not headless), ) folder_button.click( - lambda: get_folder_path(config=config), # Added config + get_folder_path, outputs=images_dir, show_progress=False, ) diff --git a/kohya_gui/utilities.py b/kohya_gui/utilities.py index e4883d1..143b033 100644 --- a/kohya_gui/utilities.py +++ b/kohya_gui/utilities.py @@ -20,12 +20,12 @@ def utilities_tab( config: KohyaSSGUIConfig = {}, ): with gr.Tab("Captioning"): - gradio_basic_caption_gui_tab(headless=headless, config=config) - gradio_blip_caption_gui_tab(headless=headless, config=config) - gradio_blip2_caption_gui_tab(headless=headless, config=config) - gradio_git_caption_gui_tab(headless=headless, config=config) + gradio_basic_caption_gui_tab(headless=headless) + gradio_blip_caption_gui_tab(headless=headless) + gradio_blip2_caption_gui_tab(headless=headless) + gradio_git_caption_gui_tab(headless=headless) gradio_wd14_caption_gui_tab(headless=headless, config=config) - gradio_manual_caption_gui_tab(headless=headless, config=config) + gradio_manual_caption_gui_tab(headless=headless) gradio_convert_model_tab(headless=headless) gradio_group_images_gui_tab(headless=headless) diff --git a/kohya_gui/wd14_caption_gui.py b/kohya_gui/wd14_caption_gui.py index 32c7783..3456f70 100644 --- a/kohya_gui/wd14_caption_gui.py +++ b/kohya_gui/wd14_caption_gui.py @@ -190,7 +190,7 @@ def gradio_wd14_caption_gui_tab( visible=(not headless), ) button_train_data_dir_input.click( - lambda: get_folder_path(config=config), + get_folder_path, outputs=train_data_dir, show_progress=False, ) diff --git a/test_script_1.py b/test_script_1.py deleted file mode 100644 index 8bf91a6..0000000 --- a/test_script_1.py +++ /dev/null @@ -1,61 +0,0 @@ -from kohya_gui.class_gui_config import KohyaSSGUIConfig -from kohya_gui.common_gui import get_folder_path, scriptdir -import os - -# Ensure the target directory exists -os.makedirs("/tmp/test_folder1", exist_ok=True) - -# 1. Create config (simulating app launch) -config_handler = KohyaSSGUIConfig(config_file_path="/app/config.toml") -print(f"Initial last_used_folder from config: {config_handler.get_last_used_folder()}") # Should be scriptdir - -# 2. Simulate get_folder_path -# Normally, tkinter dialog would run. We simulate its effect. -# get_folder_path internally calls config.set_last_used_folder -# Let's assume the dialog was opened with initialdir=scriptdir and user selected /tmp/test_folder1 -# For the test, we'll directly set it after a simulated selection to mimic the function's behavior -# In a real scenario, get_folder_path would be called, and it would call set_last_used_folder. -# Here, we simplify by directly manipulating for test verification. - -# Simulate call to get_folder_path where user selects /tmp/test_folder1 -# This is a simplified mock of what would happen: -# initial_dir = config_handler.get_last_used_folder() # This would be scriptdir -# print(f"Dialog would open with initial_dir: {initial_dir}") -# selected_path_by_user = "/tmp/test_folder1" # User selects this -# if selected_path_by_user: -# config_handler.set_last_used_folder(selected_path_by_user) -# print(f"Set last_used_folder to: {selected_path_by_user}") -# This is what happens inside get_folder_path: -def mock_get_folder_path(current_path_in_field, cfg_obj, simulated_user_selection): - # Logic from common_gui.get_folder_path for initial_dir_to_use - initial_dir_to_use = scriptdir - if cfg_obj: - last_used = cfg_obj.get_last_used_folder() - if last_used and os.path.isdir(last_used): - initial_dir_to_use = last_used - elif current_path_in_field and os.path.isdir(current_path_in_field): - initial_dir_to_use = current_path_in_field - elif current_path_in_field and os.path.isdir(current_path_in_field): - initial_dir_to_use = current_path_in_field - print(f"Dialog would open with initial_dir: {initial_dir_to_use}") - - # Simulate user selection - if simulated_user_selection: - if cfg_obj: - cfg_obj.set_last_used_folder(simulated_user_selection) - print(f"Set last_used_folder to: {simulated_user_selection}") - return simulated_user_selection - return current_path_in_field - -# Simulate the scenario: field is empty, user selects /tmp/test_folder1 -returned_path = mock_get_folder_path("", config_handler, "/tmp/test_folder1") -print(f"Returned path: {returned_path}") - - -# 3. Save config -config_handler.save_config(config=config_handler.config, config_file_path="/app/config.toml") -print("Config saved.") - -# Verify by reloading -config_handler_verify = KohyaSSGUIConfig(config_file_path="/app/config.toml") -print(f"After save, last_used_folder from new config: {config_handler_verify.get_last_used_folder()}") diff --git a/test_script_1_mocked.py b/test_script_1_mocked.py deleted file mode 100644 index cfe1c20..0000000 --- a/test_script_1_mocked.py +++ /dev/null @@ -1,135 +0,0 @@ -import os -import sys -import unittest.mock as mock - -# Mock easygui and its problematic dependencies before they are imported by kohya_gui -sys.modules['easygui'] = mock.MagicMock() -sys.modules['tkinter'] = mock.MagicMock() -sys.modules['Tkinter'] = mock.MagicMock() # For Python 2 fallback in easygui - -# Attempt to preemptively mock parts of easygui that might still load -# This is to handle the "global_state" not found if easygui's __init__ tries to import its own modules -# that might then fail on tkinter not being truly available. -mock_easygui = mock.MagicMock() -mock_easygui.msgbox = mock.MagicMock() -mock_easygui.ynbox = mock.MagicMock() -sys.modules['easygui'] = mock_easygui - - -# Set an env var to simulate a non-interactive environment (though mocking should handle most UI calls) -os.environ["COLAB_GPU"] = "True" - -from kohya_gui.class_gui_config import KohyaSSGUIConfig -from kohya_gui.common_gui import get_folder_path, scriptdir, get_file_path, get_saveasfilename_path # Import other functions as needed - -print(f"Scriptdir resolved to: {scriptdir}") -# Ensure scriptdir is an absolute path for consistency, as it's used for defaults -if not os.path.isabs(scriptdir): - scriptdir = os.path.abspath(scriptdir) - print(f"Updated scriptdir to absolute path: {scriptdir}") - - -# --- Test 1: Initial state and first folder operation --- -print("--- Test 1: Initial Folder Operation ---") -config_handler = KohyaSSGUIConfig(config_file_path="/app/config.toml") -initial_last_folder = config_handler.get_last_used_folder() -print(f"Initial last_used_folder from new config object: {initial_last_folder}") -# Depending on KohyaSSGUIConfig implementation, initial value might be scriptdir or empty string -# before first save. get_last_used_folder itself initializes it to scriptdir if not in config. -assert initial_last_folder == scriptdir, f"Expected {scriptdir}, got {initial_last_folder}" - - -# Simulate selecting /tmp/test_folder1 for a folder operation -# In non-dialog mode (due to COLAB_GPU=True), get_folder_path should use the provided 'folder_path' -# and update the config. -returned_path = get_folder_path(folder_path="/tmp/test_folder1", config=config_handler) -print(f"Returned path from get_folder_path: {returned_path}") -assert returned_path == "/tmp/test_folder1" -current_last_folder = config_handler.get_last_used_folder() -print(f"Last used folder after get_folder_path: {current_last_folder}") -assert current_last_folder == "/tmp/test_folder1", f"Expected /tmp/test_folder1, got {current_last_folder}" - -config_handler.save_config(config=config_handler.config, config_file_path="/app/config.toml") -print("Config saved.") - -with open("/app/config.toml", "r") as f: - content = f.read() - print(f"config.toml content:\n{content}") - assert 'last_used_folder = "/tmp/test_folder1"' in content -print("--- Test 1 Passed ---") - -# --- Test 2: Relaunch and second folder operation --- -print("\n--- Test 2: Relaunch and Second Folder Operation ---") -config_handler_relaunch = KohyaSSGUIConfig(config_file_path="/app/config.toml") -relaunch_last_folder = config_handler_relaunch.get_last_used_folder() -print(f"On relaunch, last_used_folder is: {relaunch_last_folder}") -assert relaunch_last_folder == "/tmp/test_folder1", f"Expected /tmp/test_folder1, got {relaunch_last_folder}" - -# Simulate selecting /tmp/test_folder2 -returned_path_2 = get_folder_path(folder_path="/tmp/test_folder2", config=config_handler_relaunch) -print(f"Returned path from second get_folder_path: {returned_path_2}") -assert returned_path_2 == "/tmp/test_folder2" -current_last_folder_2 = config_handler_relaunch.get_last_used_folder() -print(f"Last used folder after second get_folder_path: {current_last_folder_2}") -assert current_last_folder_2 == "/tmp/test_folder2", f"Expected /tmp/test_folder2, got {current_last_folder_2}" - -config_handler_relaunch.save_config(config=config_handler_relaunch.config, config_file_path="/app/config.toml") -print("Config saved for second operation.") - -with open("/app/config.toml", "r") as f: - content_2 = f.read() - print(f"config.toml content after second operation:\n{content_2}") - assert 'last_used_folder = "/tmp/test_folder2"' in content_2 -print("--- Test 2 Passed ---") - -print("\nInitial State Check (Folders) successful.") - -# --- Test 3: File open operation --- -print("\n--- Test 3: File Open Operation ---") -# Ensure target directory for file exists -os.makedirs("/tmp/test_config_folder", exist_ok=True) # Changed from /projects to /tmp -dummy_file_path = "/tmp/test_config_folder/my_config.json" # Changed from /projects to /tmp -if not os.path.exists(dummy_file_path): - with open(dummy_file_path, "w") as f: f.write("{}") - -# Config handler is config_handler_relaunch, which has last_used_folder = /tmp/test_folder2 -# Simulate opening a file -# In non-dialog mode, get_file_path will set last_used_folder to dirname of 'file_path' -returned_file_path = get_file_path(file_path=dummy_file_path, config=config_handler_relaunch) -print(f"Returned path from get_file_path: {returned_file_path}") -assert returned_file_path == dummy_file_path -current_last_folder_3 = config_handler_relaunch.get_last_used_folder() -print(f"Last used folder after get_file_path: {current_last_folder_3}") -assert current_last_folder_3 == "/tmp/test_config_folder", f"Expected /tmp/test_config_folder, got {current_last_folder_3}" # Changed from /projects to /tmp - -config_handler_relaunch.save_config(config=config_handler_relaunch.config, config_file_path="/app/config.toml") -with open("/app/config.toml", "r") as f: - content_3 = f.read() - print(f"config.toml content after file open:\n{content_3}") - assert 'last_used_folder = "/tmp/test_config_folder"' in content_3 # Changed from /projects to /tmp -print("--- Test 3 Passed ---") - -# --- Test 4: File save operation --- -print("\n--- Test 4: File Save Operation ---") -# Ensure target directory for save exists -os.makedirs("/tmp/another_save_folder", exist_ok=True) # Changed from /projects to /tmp -save_file_as_path = "/tmp/another_save_folder/my_new_config.json" # Changed from /projects to /tmp - -# Config handler still has last_used_folder = /tmp/test_config_folder -# Simulate saving a file -# In non-dialog mode, get_saveasfilename_path will set last_used_folder to dirname of 'file_path' -returned_save_path = get_saveasfilename_path(file_path=save_file_as_path, config=config_handler_relaunch) -print(f"Returned path from get_saveasfilename_path: {returned_save_path}") -assert returned_save_path == save_file_as_path # In non-dialog mode, it returns the path given -current_last_folder_4 = config_handler_relaunch.get_last_used_folder() -print(f"Last used folder after get_saveasfilename_path: {current_last_folder_4}") -assert current_last_folder_4 == "/tmp/another_save_folder", f"Expected /tmp/another_save_folder, got {current_last_folder_4}" # Changed from /projects to /tmp - -config_handler_relaunch.save_config(config=config_handler_relaunch.config, config_file_path="/app/config.toml") -with open("/app/config.toml", "r") as f: - content_4 = f.read() - print(f"config.toml content after file save:\n{content_4}") - assert 'last_used_folder = "/tmp/another_save_folder"' in content_4 # Changed from /projects to /tmp -print("--- Test 4 Passed ---") - -print("\nAll Initial State and basic operations tests passed.") diff --git a/test_script_1_mocked_v2.py b/test_script_1_mocked_v2.py deleted file mode 100644 index f85bb3a..0000000 --- a/test_script_1_mocked_v2.py +++ /dev/null @@ -1,126 +0,0 @@ -import os -import sys -import unittest.mock as mock - -# Mock easygui and its problematic dependencies -sys.modules['easygui'] = mock.MagicMock() -sys.modules['tkinter'] = mock.MagicMock() -sys.modules['Tkinter'] = mock.MagicMock() -mock_easygui = mock.MagicMock() -mock_easygui.msgbox = mock.MagicMock() -mock_easygui.ynbox = mock.MagicMock() -sys.modules['easygui'] = mock_easygui - -os.environ["COLAB_GPU"] = "True" # Simulate non-interactive environment - -# Check if config.toml exists before KohyaSSGUIConfig is initialized -CONFIG_PATH = "/app/config.toml" -if os.path.exists(CONFIG_PATH): - print(f"WARNING: {CONFIG_PATH} exists before test! Content:") - with open(CONFIG_PATH, "r") as f: - print(f.read()) - # Attempt to remove it again just in case - os.remove(CONFIG_PATH) - print(f"WARNING: Removed pre-existing {CONFIG_PATH}") -else: - print(f"{CONFIG_PATH} does not exist before test, as expected.") - -from kohya_gui.class_gui_config import KohyaSSGUIConfig -from kohya_gui.common_gui import get_folder_path, scriptdir, get_file_path, get_saveasfilename_path - -print(f"Scriptdir resolved to: {scriptdir}") -# Ensure scriptdir is an absolute path for consistency -if not os.path.isabs(scriptdir): # This should not happen if common_gui.py defines it as absolute - scriptdir = os.path.abspath(scriptdir) # Make it absolute for safety in test logic - print(f"Updated scriptdir to absolute path: {scriptdir}") - - -# --- Test 1: Initial state and first folder operation --- -print("--- Test 1: Initial Folder Operation ---") -config_handler = KohyaSSGUIConfig(config_file_path=CONFIG_PATH) -initial_last_folder = config_handler.get_last_used_folder() -print(f"Initial last_used_folder from new config object: {initial_last_folder}") -assert initial_last_folder == scriptdir, f"Expected {scriptdir}, got {initial_last_folder}" - -returned_path = get_folder_path(folder_path="/tmp/test_folder1", config=config_handler) -print(f"Returned path from get_folder_path: {returned_path}") -assert returned_path == "/tmp/test_folder1" -current_last_folder = config_handler.get_last_used_folder() -print(f"Last used folder after get_folder_path: {current_last_folder}") -assert current_last_folder == "/tmp/test_folder1", f"Expected /tmp/test_folder1, got {current_last_folder}" - -config_handler.save_config(config=config_handler.config, config_file_path=CONFIG_PATH) -print("Config saved.") - -with open(CONFIG_PATH, "r") as f: - content = f.read() - print(f"config.toml content:\n{content}") - assert 'last_used_folder = "/tmp/test_folder1"' in content -print("--- Test 1 Passed ---") - -# --- Test 2: Relaunch and second folder operation --- -print("\n--- Test 2: Relaunch and Second Folder Operation ---") -config_handler_relaunch = KohyaSSGUIConfig(config_file_path=CONFIG_PATH) -relaunch_last_folder = config_handler_relaunch.get_last_used_folder() -print(f"On relaunch, last_used_folder is: {relaunch_last_folder}") -assert relaunch_last_folder == "/tmp/test_folder1", f"Expected /tmp/test_folder1, got {relaunch_last_folder}" - -returned_path_2 = get_folder_path(folder_path="/tmp/test_folder2", config=config_handler_relaunch) -print(f"Returned path from second get_folder_path: {returned_path_2}") -assert returned_path_2 == "/tmp/test_folder2" -current_last_folder_2 = config_handler_relaunch.get_last_used_folder() -print(f"Last used folder after second get_folder_path: {current_last_folder_2}") -assert current_last_folder_2 == "/tmp/test_folder2", f"Expected /tmp/test_folder2, got {current_last_folder_2}" - -config_handler_relaunch.save_config(config=config_handler_relaunch.config, config_file_path=CONFIG_PATH) -print("Config saved for second operation.") - -with open(CONFIG_PATH, "r") as f: - content_2 = f.read() - print(f"config.toml content after second operation:\n{content_2}") - assert 'last_used_folder = "/tmp/test_folder2"' in content_2 -print("--- Test 2 Passed ---") - -print("\nInitial State Check (Folders) successful.") - -# --- Test 3: File open operation --- -print("\n--- Test 3: File Open Operation ---") -os.makedirs("/tmp/test_config_folder", exist_ok=True) -dummy_file_path = "/tmp/test_config_folder/my_config.json" -if not os.path.exists(dummy_file_path): - with open(dummy_file_path, "w") as f: f.write("{}") - -returned_file_path = get_file_path(file_path=dummy_file_path, config=config_handler_relaunch) -print(f"Returned path from get_file_path: {returned_file_path}") -assert returned_file_path == dummy_file_path -current_last_folder_3 = config_handler_relaunch.get_last_used_folder() -print(f"Last used folder after get_file_path: {current_last_folder_3}") -assert current_last_folder_3 == "/tmp/test_config_folder", f"Expected /tmp/test_config_folder, got {current_last_folder_3}" - -config_handler_relaunch.save_config(config=config_handler_relaunch.config, config_file_path=CONFIG_PATH) -with open(CONFIG_PATH, "r") as f: - content_3 = f.read() - print(f"config.toml content after file open:\n{content_3}") - assert 'last_used_folder = "/tmp/test_config_folder"' in content_3 -print("--- Test 3 Passed ---") - -# --- Test 4: File save operation --- -print("\n--- Test 4: File Save Operation ---") -os.makedirs("/tmp/another_save_folder", exist_ok=True) -save_file_as_path = "/tmp/another_save_folder/my_new_config.json" - -returned_save_path = get_saveasfilename_path(file_path=save_file_as_path, config=config_handler_relaunch) -print(f"Returned path from get_saveasfilename_path: {returned_save_path}") -assert returned_save_path == save_file_as_path -current_last_folder_4 = config_handler_relaunch.get_last_used_folder() -print(f"Last used folder after get_saveasfilename_path: {current_last_folder_4}") -assert current_last_folder_4 == "/tmp/another_save_folder", f"Expected /tmp/another_save_folder, got {current_last_folder_4}" - -config_handler_relaunch.save_config(config=config_handler_relaunch.config, config_file_path=CONFIG_PATH) -with open(CONFIG_PATH, "r") as f: - content_4 = f.read() - print(f"config.toml content after file save:\n{content_4}") - assert 'last_used_folder = "/tmp/another_save_folder"' in content_4 -print("--- Test 4 Passed ---") - -print("\nAll Initial State and basic operations tests passed.") diff --git a/test_script_1_modified.py b/test_script_1_modified.py deleted file mode 100644 index 7968457..0000000 --- a/test_script_1_modified.py +++ /dev/null @@ -1,73 +0,0 @@ -import os -# Set an env var to simulate a non-interactive environment -os.environ["COLAB_GPU"] = "True" - -from kohya_gui.class_gui_config import KohyaSSGUIConfig -from kohya_gui.common_gui import get_folder_path, scriptdir # scriptdir is used by get_last_used_folder as a default - -# --- Test 1: Initial state and first operation --- -print("--- Test 1 ---") -# 1. Create config (simulating app launch, config file doesn't exist yet) -config_handler = KohyaSSGUIConfig(config_file_path="/app/config.toml") -# Ensure last_used_folder defaults to scriptdir (or an empty string, depending on implementation details) -# get_last_used_folder initializes it to scriptdir if not in config -print(f"Initial last_used_folder from new config object: {config_handler.get_last_used_folder()}") - -# 2. Simulate get_folder_path where user "selects" /tmp/test_folder1 -# In non-dialog mode, get_folder_path will set last_used_folder if folder_path is valid and config is present. -# We pass folder_path="/tmp/test_folder1" as if it was typed into a field and then an action triggered. -# Or, as if it's the path being "opened" or "selected". -returned_path = get_folder_path(folder_path="/tmp/test_folder1", config=config_handler) -print(f"Returned path from get_folder_path: {returned_path}") -print(f"Last used folder after get_folder_path: {config_handler.get_last_used_folder()}") - -# 3. Save config -config_handler.save_config(config=config_handler.config, config_file_path="/app/config.toml") -print("Config saved.") - -# Verify by reading the file content -with open("/app/config.toml", "r") as f: - content = f.read() - print(f"config.toml content:\n{content}") - assert 'last_used_folder = "/tmp/test_folder1"' in content - -print("--- Test 1 Passed ---") - -# --- Test 2: Relaunch and second operation --- -print("\n--- Test 2 ---") -# 1. Simulate relaunch (load existing config) -config_handler_relaunch = KohyaSSGUIConfig(config_file_path="/app/config.toml") -print(f"On relaunch, last_used_folder is: {config_handler_relaunch.get_last_used_folder()}") -assert config_handler_relaunch.get_last_used_folder() == "/tmp/test_folder1" - -# 2. Simulate opening the same dialog again. get_folder_path will determine initial_dir. -# We are interested in what initial_dir would be. -# The common_gui.get_folder_path function has this logic: -# initial_dir_to_use = scriptdir -# if config: -# last_used = config.get_last_used_folder() -# if last_used and os.path.isdir(last_used): -# initial_dir_to_use = last_used -# So, initial_dir_to_use should become /tmp/test_folder1. -# (This part is harder to directly assert without refactoring get_folder_path to return initial_dir for testing, -# or by checking logs if we had more verbose logging for initial_dir decision) -# For now, we trust that get_last_used_folder returning /tmp/test_folder1 means the dialog would use it. - -# 3. Simulate selecting another folder: /tmp/test_folder2 -returned_path_2 = get_folder_path(folder_path="/tmp/test_folder2", config=config_handler_relaunch) -print(f"Returned path from second get_folder_path: {returned_path_2}") -print(f"Last used folder after second get_folder_path: {config_handler_relaunch.get_last_used_folder()}") - -# 4. Save config again -config_handler_relaunch.save_config(config=config_handler_relaunch.config, config_file_path="/app/config.toml") -print("Config saved for second operation.") - -# Verify by reading the file content -with open("/app/config.toml", "r") as f: - content_2 = f.read() - print(f"config.toml content after second operation:\n{content_2}") - assert 'last_used_folder = "/tmp/test_folder2"' in content_2 - -print("--- Test 2 Passed ---") - -print("\nInitial State Check successful.") diff --git a/test_script_2_edge_cases.py b/test_script_2_edge_cases.py deleted file mode 100644 index 1bbd95f..0000000 --- a/test_script_2_edge_cases.py +++ /dev/null @@ -1,97 +0,0 @@ -import os -import sys -import unittest.mock as mock - -# Mock UI elements -sys.modules['easygui'] = mock.MagicMock() -sys.modules['tkinter'] = mock.MagicMock() -sys.modules['Tkinter'] = mock.MagicMock() -mock_easygui = mock.MagicMock() -mock_easygui.msgbox = mock.MagicMock() -mock_easygui.ynbox = mock.MagicMock() -sys.modules['easygui'] = mock_easygui - -os.environ["COLAB_GPU"] = "True" # Simulate non-interactive environment - -from kohya_gui.class_gui_config import KohyaSSGUIConfig -from kohya_gui.common_gui import get_folder_path, scriptdir # Assuming scriptdir is /app - -CONFIG_PATH = "/app/config.toml" - -print(f"Scriptdir is: {scriptdir}") - -# --- Test 3: Corrupted last_used_folder path --- -print("\n--- Test 3: Corrupted last_used_folder path ---") -# 1. Create config.toml with a corrupted path -with open(CONFIG_PATH, "w") as f: - f.write('last_used_folder = "this/is/not/a/valid/path"\n') -print(f"Created corrupted {CONFIG_PATH}") - -# 2. Load config -config_corrupted = KohyaSSGUIConfig(config_file_path=CONFIG_PATH) -corrupted_val = config_corrupted.get_last_used_folder() -print(f"get_last_used_folder() with corrupted path returned: {corrupted_val}") -# get_last_used_folder itself just returns the value if it's a string. -assert corrupted_val == "this/is/not/a/valid/path" - -# 3. Simulate a folder operation. common_gui.get_folder_path should handle invalid path gracefully. -# It should default to scriptdir because "this/is/not/a/valid/path" is not a valid directory. -# We can't directly check initial_dir_to_use without modifying common_gui, -# but we can infer it by checking that last_used_folder is NOT updated if the dialog was "cancelled" (empty input path) -# and that it IS updated if a new path is "selected". - -# Simulate calling get_folder_path, where it would try to use the corrupted path, fail, and use scriptdir. -# If user then cancels (empty string for folder_path), it should not update the corrupted value. -# However, our non-dialog mode logic in get_folder_path for COLAB_GPU is: -# if folder_path and os.path.isdir(folder_path) and config: config.set_last_used_folder(folder_path) -# So, if folder_path is empty, it won't update. -returned_path_corr1 = get_folder_path(folder_path="", config=config_corrupted) # Simulate empty input or cancel -assert config_corrupted.get_last_used_folder() == "this/is/not/a/valid/path", "Corrupted path should not change on empty selection" -print("Graceful handling of corrupted path (no selection) passed.") - -# 4. Simulate selecting a valid folder -returned_path_corr2 = get_folder_path(folder_path="/tmp/good_folder", config=config_corrupted) -assert returned_path_corr2 == "/tmp/good_folder" -assert config_corrupted.get_last_used_folder() == "/tmp/good_folder", "Path should update to /tmp/good_folder" -print("Graceful handling of corrupted path (new selection) passed.") - -# 5. Save and verify config file -config_corrupted.save_config(config=config_corrupted.config, config_file_path=CONFIG_PATH) -with open(CONFIG_PATH, "r") as f: - content = f.read() - print(f"config.toml content after fixing corrupted path:\n{content}") - assert 'last_used_folder = "/tmp/good_folder"' in content -print("--- Test 3 Passed ---") - - -# --- Test 4: last_used_folder key missing --- -print("\n--- Test 4: last_used_folder key missing ---") -# 1. Create config.toml without the key (or with other keys) -with open(CONFIG_PATH, "w") as f: - f.write('another_key = "some_value"\n') # No last_used_folder -print(f"Created {CONFIG_PATH} with missing last_used_folder key.") - -# 2. Load config. load_config() should add last_used_folder = scriptdir -config_missing = KohyaSSGUIConfig(config_file_path=CONFIG_PATH) -val_after_load = config_missing.get_last_used_folder() -print(f"get_last_used_folder() after loading config with missing key: {val_after_load}") -# The get_last_used_folder() itself ensures it returns scriptdir if key is missing or value is bad type, -# and load_config also initializes it. -assert val_after_load == scriptdir, f"Expected scriptdir, got {val_after_load}" - -# 3. Simulate a folder operation -returned_path_miss = get_folder_path(folder_path="/tmp/another_good_folder", config=config_missing) -assert returned_path_miss == "/tmp/another_good_folder" -assert config_missing.get_last_used_folder() == "/tmp/another_good_folder" -print("Graceful handling of missing key (new selection) passed.") - -# 4. Save and verify -config_missing.save_config(config=config_missing.config, config_file_path=CONFIG_PATH) -with open(CONFIG_PATH, "r") as f: - content = f.read() - print(f"config.toml content after fixing missing key:\n{content}") - assert 'last_used_folder = "/tmp/another_good_folder"' in content - assert 'another_key = "some_value"' in content # Ensure other keys are preserved -print("--- Test 4 Passed ---") - -print("\nAll Edge Case tests passed.")