Search code examples
pythonpyinstaller

pyinstaller adding editable file



I created a simple Tkinter app that creates an ssh tunnel,
What is the best way to save the inputs from the user for the next launch of the app?

I tried to create a JSON/pickle file to save the data,
I opened the file before closing and saw that it changed,
however, when relaunching the app, the file content returns to as it was before the modification.

install.bat

.\.venv\Scripts\pyinstaller.exe ^
    --clean ^
    --onefile ^
    --name %OUTPUT_NAME% ^
    --add-data default_values.json;.^
    --win-private-assemblies ^
    .\main.py

I tried to add play around with the flags with no help, e.g. --noupx, --debug all

First App open:

on app start
{
    "ssh_address_or_host": "192.168.1.1",
    "ssh_username": "username",
    "ssh_password": "password",
    "local_bind_address_address": "localhost", 
    "local_bind_address_port": 5902,
    "remote_bind_address_address": "localhost",
    "remote_bind_address_port": 5902
}
before app close:
{
    "ssh_address_or_host": "192.168.1.100",   
    "ssh_username": "username",
    "ssh_password": "password",
    "local_bind_address_address": "localhost", 
    "local_bind_address_port": 5902,
    "remote_bind_address_address": "localhost",
    "remote_bind_address_port": 5902
}
elapsed: 0.46

Second App open:

on app start
{
    "ssh_address_or_host": "192.168.1.1",
    "ssh_username": "username",
    "ssh_password": "password",
    "local_bind_address_address": "localhost",
    "local_bind_address_port": 5902,
    "remote_bind_address_address": "localhost",
    "remote_bind_address_port": 5902
}

What can I do?


Solution

  • PyInstaller's onefile option works by packing the Python interpreter, scripts, and dependencies into a single executable that, when executed, is unpacked into a new temporary directory. Files written to that directory won't exist the next time the application is launched, since everything will be unpacked into a different temporary directory.

    You should instead read/write your settings file to the App Data directory:

    import os
    import pathlib
    import json
    
    # e.g. C:\Users\Onson Sweemey\AppData\Roaming\Ramis App
    settings_dir = pathlib.Path(os.getenv("APPDATA"), "Ramis App")
    
    # e.g. C:\Users\Onson Sweemey\AppData\Roaming\Ramis App\settings.json
    settings_filepath = settings_dir.joinpath("settings.json")
    
    # On start-up, load the saved settings if they exist, or use the default settings
    try:
        with open(settings_filepath) as f:
            settings = json.load(f)
    except FileNotFoundError:
        settings = {
            "ssh_address_or_host": "192.168.1.1",
            "ssh_username": "username",
            "ssh_password": "password",
            "local_bind_address_address": "localhost", 
            "local_bind_address_port": 5902,
            "remote_bind_address_address": "localhost",
            "remote_bind_address_port": 5902
        }
    
    # On application exit, save the settings
    # Create the directory, since it might not exist
    settings_dir.mkdir(parents=True, exist_ok=True)
    with open(settings_filepath, "w") as f:
        json.dump(settings, f)