0

Note: I’m using Windows and this program will also have to run on Mac.

I'm writing a Python app that needs to read from and write to a JSON file, which I implemented in src/resources.py:

import json
def load_json():
    with open('saved_data.json', 'rt') as file_in:
        stored_text = file_in.read()
    stored_json = json.loads(stored_text)
    # parse stored_json & return created objects

At the beginning of the program it's supposed to load data from the file, but when I run main.py (where I’m usually running the program from) it's giving me a runtime error:

File "<project path>\src\resources.py", line 12, in load_json
    with open('saved_data.json', 'rt') as file_in:
FileNotFoundError: [Errno 2] No such file or directory: 'saved_data.json'

This is what my file structure looks like:

project/
    main.py
    saved_data.json
    src/
        __init__.py
        resources.py
        more files...

I've tried adding either '..\\' or '../' to the start of the filepath string thinking that it might be relative to resources.py instead of main.py but that resulted in an error as well. I'm not really sure what to do at this point because I don't see anywhere specific it could be going wrong. I'm pretty sure the file structure is okay. What am I missing or misunderstanding here?

redpepper74
  • 11
  • 1
  • 4
  • 1
    '../' should be fine. Does it give the same error or a different one? What OS are you using (not sure if it matter though)? – Sabsa Jul 22 '22 at 07:11
  • 1
    using above suggestion, possible duplicate or helpful https://stackoverflow.com/q/2753254/1248974 – chickity china chinese chicken Jul 22 '22 at 07:13
  • How are you running your program? `..` is relative to `cwd` not to the folder where your `.py` is – Ivan Jul 22 '22 at 07:15
  • Have you tried this? `filename = os.path.join( os.getcwd(), '..', 'saved_data.json' )` and `with open(filename, 'rt') as file_in:` – Sabsa Jul 22 '22 at 07:15
  • try `import os cwd = os.getcwd()` to see where exactly you are executing your code – Ivan Jul 22 '22 at 07:16
  • The result you get from running os.getcwd() depends on the directory you are standing in when you are running your script. What you can also do is os.path.dirname(os.path.abspath(__file__)) which gives you the absolute path of the directory of the file you are running. From that you can modify this path to match the location of your json. https://stackoverflow.com/questions/3430372/how-do-i-get-the-full-path-of-the-current-files-directory – mmarton Jul 22 '22 at 07:19
  • Oh, I didn’t know it mattered where you ran the script from. My thinking was that the directory I was working from was main.py’s directory. – redpepper74 Jul 22 '22 at 07:29
  • You can play around with it if you make a simple .py that only prints os.getcwd(). Try to run the file while standing in different locations and see the results. – mmarton Jul 22 '22 at 07:33

2 Answers2

0

Your question is about how to layout the structure of your project folder. This is a very hard topic for newbies.

Keep in mind that there are a lot of possible ways and styles to do this in Python. But looking into the setuptools documentation today the modern and most recommended style is the so called _src-layout.

Your layout is still on its way to it and just need a bit modification.

Let's assume the name of your project is "project". This results in the name of the repository (e.g. on a git server) or the project folder. It is also the name of your package. But package-folder and project-folder are different things.

Modify your layout to this

project/
    saved_data.json
    src/
        project/
            __main__.py
            __init__.py
            resources.py
            more files...

I created a new sub-folder project/src/project/ which is the package folder. The main.py file was moved into it and renamed to __main__.py (more details). This make the folder project/src/project/ runable.

The content of __main__.py could look like this

from .ressources import load_json

if __name__ == '__main__':
   load_json()
buhtz
  • 10,774
  • 18
  • 76
  • 149
  • Thanks for the tips on good file structure. I’m having a hard time running my project as a module though. I had to cd to it in order to get it to run. Will I have to do that every time I want to run it? (I was trying to do something like `python -m project/src/project`.) Also I’m still not sure what my filepath string should be. – redpepper74 Jul 22 '22 at 08:08
  • I would recommend to "install" your project via the `--editable` option of `pip`. You can see a small and easy real life example of it in [one of my projects](https://codeberg.org/buhtz/hyperorg/src/branch/main). Please feel free to ask further (maybe in the Issue section of my project). – buhtz Jul 22 '22 at 09:32
0

If you are running your program (effectively) like this:

python main.py

...then...

from os.path import join

with open(join(__file__, '..', 'saved_data.json')) as file_in:
  pass # process the file here

Thus your current working directory is irrelevant because file will be the absolute path to main.py

DarkKnight
  • 19,739
  • 3
  • 6
  • 22
  • I tried this and got another FileNotFound error, but changing the path to `__file__, '..', '..', 'stored_data.json'` (adding an extra `'..'`) did the trick. It seems like files are treated in a similar way to directories. – redpepper74 Jul 22 '22 at 08:42