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