We should make sure all config files etc are in some kind of user local data folder. The main app has to run from a protected c program files as it requires admin install rights. So any user generated configured data should be local to the user. We also want to run it locally eg from the root or the repo when in development. I guess we could look at OS and if frozen params.
To handle configuration files and user-generated data in a cross-platform manner, you can follow these steps:
Determine the appropriate directory based on the operating system and whether the application is running in development or as a frozen executable.
Create a helper function to get the correct path for storing user data.
Here's how you can implement this:
Step 1: Define a Helper Function
Define a helper function to get the appropriate directory for storing user data based on the operating system and execution context.
import os
import sys
import platform
def get_user_data_dir(app_name="MorseWriter"):
"""
Returns the appropriate directory for storing user data based on the OS and whether the app is frozen.
"""
if hasattr(sys, 'frozen'):
# If the application is frozen, use the appropriate platform-specific directory
if platform.system() == 'Windows':
return os.path.join(os.getenv('LOCALAPPDATA'), app_name)
elif platform.system() == 'Darwin':
return os.path.join(os.path.expanduser('~/Library/Application Support/'), app_name)
else:
return os.path.join(os.path.expanduser('~/.config/'), app_name)
else:
# Use a local directory when running in development
return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'user_data')
# Ensure the directory exists
user_data_dir = get_user_data_dir()
os.makedirs(user_data_dir, exist_ok=True)
Step 2: Use the Helper Function for Config Files
Use this helper function to determine where to load and save configuration files and user-generated data.
# Example of loading abbreviations from the user data directory
def load_abbreviations():
abbreviations_file = os.path.join(user_data_dir, 'abbreviations.txt')
abbreviations = {}
try:
with open(abbreviations_file, 'r') as f:
for line in f:
if line.strip():
abbr, expansion = line.strip().split('\t')
abbreviations[abbr] = expansion
except FileNotFoundError:
logging.warning(f"Abbreviations file not found: {abbreviations_file}")
except Exception as e:
logging.error(f"Failed to load abbreviations: {e}")
return abbreviations
Step 3: Modify ConfigManager to Use the User Data Directory
Modify your ConfigManager class to use the user data directory for configuration files.
class ConfigManager:
def __init__(self, config_file=None, default_config=DEFAULT_CONFIG):
self.key_data = { ... } # Your existing key_data
self.config_file = config_file or os.path.join(user_data_dir, 'config.json')
self.default_config = default_config
self.keystrokemap, self.keystrokes = self.initKeystrokeMap()
self.config = self.read_config()
self.actions = {}
def read_config(self):
if self.config_file and os.path.exists(self.config_file):
try:
with open(self.config_file, "r") as file:
data = json.load(file)
self.update_keystrokes(data)
self.convert_types(data)
return data
except (FileNotFoundError, json.JSONDecodeError, ValueError) as e:
logging.warning(f"Error loading configuration: {e}")
return self.default_config.copy()
def save_config(self):
try:
with open(self.config_file, "w") as file:
json.dump(self.config, file, indent=4)
except Exception as e:
logging.warning(f"Error saving configuration: {e}")
# Other methods remain the same
Step 4: Ensure Cross-Platform Compatibility
Make sure your application correctly handles different platforms by using the platform module and the paths defined in the helper function.
Step 5: Handle Running in Development
Ensure that when running in development, the application uses a local directory:
if __name__ == '__main__':
# Initialize the user data directory
user_data_dir = get_user_data_dir()
os.makedirs(user_data_dir, exist_ok=True)
app = CustomApplication(sys.argv)
if not QSystemTrayIcon.isSystemTrayAvailable():
QMessageBox.critical(None, "MorseWriter", "I couldn't detect any system tray on this system.")
sys.exit(1)
QApplication.setQuitOnLastWindowClosed(False)
# Initialize managers
configmanager = ConfigManager(default_config=DEFAULT_CONFIG)
layoutmanager = LayoutManager(os.path.join(os.path.dirname(os.path.realpath(__file__)), "layouts.json"))
# Create main window
window = Window(layoutManager=layoutmanager, configManager=configmanager)
# Now that we have the window, initialize actions that may require window reference
actions = configmanager.initActions(window)
layoutmanager.set_actions(actions)
# Finish initializing the window if needed (after actions are available)
window.postInit()
# Show or hide the window based on the configuration
if configmanager.config.get("autostart", False):
window.hide()
window.start()
else:
window.show()
# Start the application event loop
sys.exit(app.exec_())
We should make sure all config files etc are in some kind of user local data folder. The main app has to run from a protected c program files as it requires admin install rights. So any user generated configured data should be local to the user. We also want to run it locally eg from the root or the repo when in development. I guess we could look at OS and if frozen params.
To handle configuration files and user-generated data in a cross-platform manner, you can follow these steps:
Here's how you can implement this:
Step 1: Define a Helper Function
Define a helper function to get the appropriate directory for storing user data based on the operating system and execution context.
Step 2: Use the Helper Function for Config Files
Use this helper function to determine where to load and save configuration files and user-generated data.
Step 3: Modify ConfigManager to Use the User Data Directory
Modify your
ConfigManager
class to use the user data directory for configuration files.Step 4: Ensure Cross-Platform Compatibility
Make sure your application correctly handles different platforms by using the
platform
module and the paths defined in the helper function.Step 5: Handle Running in Development
Ensure that when running in development, the application uses a local directory:
We also need to work up the installer