Home > front end >  import from config file when using src subfolder
import from config file when using src subfolder

Time:05-31

I'd like to use my get_data() from /src/cool_api.py in:

  • a) cool_api.py's main block
  • b) main.py's main block

get_data() needs to import the API key from config/api_config.yaml which results in FileNotFoundError when trying b). Is there a default (non-hacky) solution for imports like this from src?

I have the following file structure:

|─ config
│  ├─ api_config.yaml
|─ src # marked as Sources Root folder in Pycharm 
│  ├─ cool_api.py
│  └─ ...
├─ tests
│  └─ test_cool_api.py
└─ main.py

my code:

# cool_api.py
def get_data():
    import yaml
    import requests

    with open("../config/api_config.yaml") as f:
        config = yaml.load(f, Loader=yaml.SafeLoader)
    return f"cool_api.org?key={config['api_key']}"


if __name__ == "__main__":
    print(get_data())

a) works.

# main.py
from cool_api.py import get_data

if __name__ == "__main__":
    print(get_data())

b) results in a FileNotFoundError. No such file or directory: '../config/api_config.yaml'

How to fix my import statements?

optionally: Is there a shortcut for Pycharm users?

CodePudding user response:

This has nothing to do with imports, since you're not importing the YAML file, you're opening it as a file, and you're using a relative path that is relative to the working directory of the Python process. You're getting a FileNotFound error because the working directory is the directory where main.py resides, and one directory up from there, there won't be a config/ directory.

If you know the configuration file will always be relative to cool_api.py like that, use __file__ (which is a builtin pointing to the absolute path to the module), and compute a path from there.

import os

config_dir = os.path.join(os.path.dirname(__file__), '..', 'config')
config_file = os.path.join(config_dir, 'config.yaml')

with open(config_file):
   ...

As for imports, I'd like to say your file structure is suboptimal; the only reason you can import cool_api in main.py right now is because PyCharm fixes up your Python sources path to include src/; if you try to python main.py in the console, it wouldn't work.

I would recommend structuring your code as a package in your project root:

cool_api/
  __init__.py  # likely mostly empty
  __main__.py  # main entry point
  config.py    # contains `get_data` and others

Packages with a __main__ module can be launched with (e.g.) python -m cool_api or the Run Configuration -> Target type: "Module Name" (instead of "Script Path") option in PyCharm.

Running with that option has the additional benefit that Python itself fixes up your module path so import cool_api.config always works, and from .config import get_data works within the package, etc.

CodePudding user response:

Could you add an empty __init__.py file inside the config folder

  • Related