Pyinstaller app is accessing txt files, but not writing to them (works before app compilation)

Posted on

Question :

Pyinstaller app is accessing txt files, but not writing to them (works before app compilation)

settings.txt is stored and accessed within the compiled single file app, but it’s not being written to. This works prior to Pyinstaller compilation when the file is in the same directory as the script.

The app is compiled from the terminal:

pyinstaller script.spec --windowed --onefile

a.datas is set in the spec file as:

a.datas += [(‘settings.txt’,’/path/to/settings.txt’, "DATA”)]

and the file is read properly within the app:

with open(resource_path('settings.txt'), 'r') as f2

However, the file isn’t updated when attempting to overwrite the file:

def OnExit(self, event):
    with open(resource_path('settings.txt'), 'w') as f2:


resource_path is defined as:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.environ.get("_MEIPASS2", os.path.abspath("."))

    return os.path.join(base_path, relative_path)
Asked By: Phillip


Answer #1:

If you are on Windows, _MEIPASS returns the “short” name for the path in case that any component of it is more than 8 characters long. So, to test that this is the issue, try to make it a one-folder frozen app and then move it in a simple and short path: e.g., C:/test.

If this is the issue, you can workaround the problem by retrieving the long path using something like:

if hasattr(sys, '_MEIPASS'):
    import win32api
    sys_meipass = win32api.GetLongPathName(sys._MEIPASS)
Answered By: Phillip

Answer #2:

I wanted to share my solution, which simultaneously addresses many issues with relative paths in general (see function __doc__string).

I have a module named, with a modified function module_path as seen in other answers which takes a relative_path.

usage in other .py files:

from top_level_locator import module_path
resource_location = module_path(relative_path = 'resource.ext')

import sys
from pathlib import Path
from inspect import getsourcefile

def module_path(relative_path):
    Combine top level path location, in this project folder because it serves as main/entry_point, with user relative path.

    NOTE: should be in same folder as script 
    - TEST this with executable 
    - TEST this without executable 

    NOTE: care with use of __file__ as it comes with unwarranted side effects when:
    - running from IDLE (Python shell), no __file__ attribute
    - freezers, e.g. py2exe & pyinstaller do not have __file__ attribute! 

    NOTE: care with use of sys.argv[0]
    - unexpected result when you want current module path and get path where script/executable was run from! 

    NOTE: care with use of sys.executable
    - if non-frozen application/module/script: python/path/python.exe 
    - else                                   : standalone_application_executable_name.exe
    # 0 if this module next to ( else += 1 for every directory deeper
    n_deep = 1

    print('sys.executable:', sys.executable)
    print('   sys.argv[0]:', Path(sys.argv[0]).parents[n_deep].absolute() / sys.argv[0])
    print('      __file__:', __file__)
    print(' getsourcefile:', Path(getsourcefile(lambda:0)).parents[n_deep].absolute())
    if hasattr(sys, "frozen"):
        # retreive possible longpath if needed from _MEIPASS: import win32api; 
        # sys_meipass = win32api.GetLongPathName(sys._MEIPASS)
        base_path = getattr(sys, '_MEIPASS', Path(sys.executable).parent)
        print('      _MEIPASS:', base_path)
        return Path(base_path).joinpath(relative_path)
    return Path(getsourcefile(lambda:0)).parents[n_deep].absolute().joinpath(relative_path)

if __name__ == '__main__':

In non-frozen applications the output will (should) be as such:

  • sys.executable: C:Users<usr_name>AppDataLocalProgramsPythonPython37python.exe
  • sys.argv[0]: c:Users<usr_name>Desktop<project_name><project_code_folder>
  • __file__: c:Users<usr_name>Desktop<project_name><project_code_folder>
  • getsourcefile: c:Users<usr_name>Desktop<project_name><project_code_folder>

In frozen applications:

  • sys.executable: C:Users<usr_name>Desktop<project_name>distapp.exe
  • sys.argv[0]: C:Users<usr_name>Desktop<project_name>distapp.exe
  • __file__: C:Users<usr_name>AppDataLocalTemp_MEI155562utilstop_level_locator.pyc
  • getsourcefile: C:Users<usr_name>Desktop<project_name>
  • _MEIPASS: C:Users<usr_name>AppDataLocalTemp_MEI155562
Answered By: gmas80

Leave a Reply

Your email address will not be published. Required fields are marked *