How to persist user config data to SNAP_USER_DATA?

the [ sign is a symlink to the “test” command in shell … so take a look at man test … what you actually want above is something like:

# [ -e "..." ] -> does the file exist at all ? "||" -> if not ... "echo something to a new file with that name"
[ -e "$SNAP_USER_DATA/foo.json" ] || echo "{}" > "$SNAP_USER_DATA/foo.json"

regarding your python question … just create a valid path from filenames and the snap_userdata variable the way you typically do that (merging strings, using path.join() or whatever else you typically do in python.

Thank you very much, I also already came up with same solution:

#! /bin/sh

[ -e "$SNAP_USER_DATA/config.toml" ] || touch $SNAP_USER_DATA/config.toml

[ -e "$SNAP_USER_DATA/energy-data.json" ] || echo "{}" >> $SNAP_USER_DATA/energy-data.json

[ -e "$SNAP_USER_DATA/power-data.json" ] || echo "{}" >> $SNAP_USER_DATA/power-data.json

exec "$@"

just one more thing to ask, it that possible for some function to keep writing to these json files later on? or is it just one time

not sure what you mean here … they are files, indeed your app can do with them what apps can do with files :slight_smile: (open, write ,delete, parse, modify, younameit)

I’m confused with echo and touch.
as files are created every time I run the app, are they still available to write for later functions?
or they just closed are write protected after the initial app run?
thanks

I’m trying to write the file but getting this error:

Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/snap/olibox-core/x1/lib/python3.6/site-packages/olibox_core/olibox_core/olibox_core.py", line 22, in main
    print_user()
  File "/snap/olibox-core/x1/lib/python3.6/site-packages/olibox_core/olibox_core/olibox_core.py", line 16, in print_user
    user = pkg.get_user()
  File "/snap/olibox-core/x1/lib/python3.6/site-packages/olibox_core/olibox_core/olibox_pkg/user.py", line 20, in get_user
    write_values('power-data.json', payload_power)
  File "/snap/olibox-core/x1/lib/python3.6/site-packages/olibox_core/olibox_core/olibox_pkg/write_json.py", line 22, in write_values
    with open(file_to_write, 'w+', encoding='utf-8') as f:
OSError: [Errno 30] Read-only file system: '/power-data.json'

This is my write_values function:

snap_userdata = os.environ['SNAP_USER_DATA']


def write_values(file, new_data):
    """
    The function uses json.dump method to write the data object to a file.
    """
    file_to_write = os.path.join(snap_userdata, '/', file)
    if os.path.isfile(file_to_write):
        with open(file_to_write) as f:
            data = json.load(f)

        data.update(new_data)
        with open(file_to_write, 'w+', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=4)
    else:
        with open(file_to_write, 'w+', encoding='utf-8') as f:
            json.dump(new_data, f, ensure_ascii=False, indent=4)

and I’m calling this like:

write_values('power-data.json', payload_power)

they are only created if they do not exist …

you are not writing to $SNAP_USER_DATA but to / please read up about os.path.join() and how to use it …

these are all pretty basic python features/questions that are kind of going beyond the purpose of this forum … i.e. not really related to snap packaging…

Thank you very much.
I’ll look path systems more deeply.
I just wanted to confirm that files created with script are not write protected for the later functions.

if you could write to them at the start of your app because you used a writable location, why would they become un-writable later ? as long as they are staying in that location and you do not change their permissions they indeed stay writable like any other file :slight_smile:

Alright, thank you very much for your help.

sorry to bother you again.
I can see files are created being written in both current and x1 directory.
can you please say a few words what is the difference between current and x1?
thanks

It was my bad:
If we use “/”, it tells Python that we’re using absolute path, and it overrides the path before it
More…

x1 is the versioned dir assigned to the x1 install of your snap … if you install a new version or update a snap from the store there will be a new directory (x2 for locally installed snaps, a (revision)number for snaps from the store). snapd copies all content from x1 to x2 during the update.

current is always a symlink to the currently running snap … i.e. if you have x1 installed and install x2, the current symlink gets moved to point to x2 after the above copying has happened.

in case you would use snap revert ... to go back to the former version, the symlink would be pointed back to x1. that way a user accessing data in ~/snap will not need to know which revision is the current one, but can just use ~/snap/<snapname>/current/ to access any data of the running app.

Thank you very much!:+1:

I summarized my experience of building snaps here:
https://medium.com/oli-systems/the-joy-of-building-snaps-for-python-applications-4fa35c36b1a3