kaidrick
kaidrick

Reputation: 35

Python import a module, receive a system cannot find the path specified error

I am using python 3.7.1 and have a structure like these in my project

project/
├── plugins
│   ├── __init__.py
│   └── plugin_one
│       ├── __init__.py
│       ├── process_json.py
│       └── data
│           └── cities
│               └── paris.json
│               └── new_york.json
└── test1.py

when I write the "process_json.py" I read the json files from the "data/cities" directory one by one and print out json string.

# do_plugin_one.py
import json
import os

def process_json_string():
    file_path = 'data/cities'
    for filename in os.listdir(file_path):
        if filename.endswith('.json'):
            with open(os.path.join(search_path, filename)) as f:
                print(json.load(f))

process_json_string()
# output is a json string

If I run this script file directly, it works fine. But what I am trying to achieve is to import process_json.py to test1.py like this:

# test1.py

from plugins.plugin_one.process_json import process_json_string
process_json_string()

and when I tried to do so I got:

FileNotFoundError: [WinError 3] The system cannot find the path specified: 'data/cities'

If I understand it correctly, when imported by the "test1.py", the working path is at where "test1.py" is. So I tried:

# process_json.py

...

def process_json_string():
    file_path = 'plugins/plugin_one/data/cities'

...

And it finally works. However, I'd like to keep the file to be able to run separately. After searching through docs and pages I still have no clue how to achieve this. I've even tried:

# process_json.py

...

file_path = 'plugins/plugin_one/data/cities'

...

if __name__ == '__main__':
    file_path = 'data/cities'

...

I don't think something like this is optimal though.

I have also tried to use relative path but still no luck. Any help would be appreciated! Thanks!

Upvotes: 0

Views: 772

Answers (2)

Ahmad Khan
Ahmad Khan

Reputation: 2703

You're using relative path. While running a python project, the present working directory is considered to be the directory of the file you run.

So, when you run process_json.py directly, it searches data/cities in project/plugins/plugin_one, and when you import process_json.py in test1.py, it searches data/cities in project/. If you use absolute path, you'll not have this problem.

But, in most cases, you don't want to put absolute path directly, so you can just join directory name of __file__ to data/cities, and you'll get absolute path:

file_path = os.path.join(os.path.dirname(__file__), 'data', 'cities')

Upvotes: 1

9769953
9769953

Reputation: 12221

If you want a path relative to process_json.py, you could use the file attribute of that module, and build the path from there:

# process_json.py
import os

datadir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data', 'cities')

Of course, you may also consider moving your data directory somewhere else on the file system, not in the package itself (on *nix, somewhere under share/ could be good), and use an environment variable to set the path as necessary.

Upvotes: 0

Related Questions