I have a tkinter app with about 1000 users which is collecting data from a game. Every 30 seconds, it saves the collected data to a json
file. After having a couple of users experiencing corrupted save files after power outages, I tried implementing a safe json saving function that would always ensure an intact file.
However, after implementing this function a few other users (maybe 1 out of 100) are now getting permission errors during the autosave function. I am not able to replicate the bug on my own machine.
I use the function below for saving, which was inspired from this thread How to make file creation an atomic operation?
def json_dump(dest_file: str, data: [dict, list]) -> None:
tmp_file = dest_file[:-5] + '_tmp.json'
with open(tmp_file, 'w') as fo:
json.dump(data, fo, indent=2)
fo.flush()
os.fsync(fo.fileno())
os.replace(tmp_file, dest_file)
Error message that a user sent me (that I cannot replicate myself, and that most users are not experiencing)
19:46:02,481 root ERROR (<class 'PermissionError'>, PermissionError(13, 'Access is denied'), <traceback object at 0x0000019E641C6700>)
Traceback (most recent call last):
File "tkinter\__init__.py", line 1883, in __call__
File "main_frame.py", line 168, in <lambda>
File "main_frame.py", line 432, in notebook_tab_change
File "main_frame.py", line 541, in SaveActiveState
File "utils\other_utils.py", line 60, in json_dump
PermissionError: [WinError 5] Access is denied: 'Profiles/PIT_tmp.json' -> 'Profiles/PIT.json'
The save to file function can be reached by multiple threads (run through tkinters after
method). The main thread handles user interaction with the UI, which can result in a call to the save function (when modifying data manually, or when quitting the app). Another thread is autosaving every 30 seconds, and thus calling the save function as well.
I wonder if the error happens because multiple threads are trying to save to file at the same time? But then again I don't understand why it was not happening when I just did a standard json dump...