[python] Python - Get path of root project structure

Here's my take on this issue.

I have a simple use-case that bugged me for a while. Tried a few solutions, but I didn't like either of them flexible enough.

So here's what I figured out.

  • create a blank python file in the root dir -> I call this beacon.py
    (assuming that the project root is in the PYTHONPATH so it can be imported)
  • add a few lines to my module/class which I call here not_in_root.py.
    This will import the beacon.py module and get the path to that module

Here's an example project structure

this_project
+-- beacon.py
+-- lv1
¦   +-- __init__.py
¦   +-- lv2
¦       +-- __init__.py
¦       +-- not_in_root.py
...

The content of the not_in_root.py

import os
from pathlib import Path


class Config:
    try:
        import beacon
        print(f"'import beacon' -> {os.path.dirname(os.path.abspath(beacon.__file__))}")  # only for demo purposes
        print(f"'import beacon' -> {Path(beacon.__file__).parent.resolve()}")  # only for demo purposes
    except ModuleNotFoundError as e:
        print(f"ModuleNotFoundError: import beacon failed with {e}. "
              f"Please. create a file called beacon.py and place it to the project root directory.")

    project_root = Path(beacon.__file__).parent.resolve()
    input_dir = project_root / 'input'
    output_dir = project_root / 'output'


if __name__ == '__main__':
    c = Config()
    print(f"Config.project_root: {c.project_root}")
    print(f"Config.input_dir: {c.input_dir}")
    print(f"Config.output_dir: {c.output_dir}")

The output would be

/home/xyz/projects/this_project/venv/bin/python /home/xyz/projects/this_project/lv1/lv2/not_in_root.py
'import beacon' -> /home/xyz/projects/this_project
'import beacon' -> /home/xyz/projects/this_project
Config.project_root: /home/xyz/projects/this_project
Config.input_dir: /home/xyz/projects/this_project/input
Config.output_dir: /home/xyz/projects/this_project/output

Of course, it doesn't need to be called beacon.py nor need to be empty, essentially any python file (importable) file would do as long as it's in the root directory.

Using an empty .py file sort of guarantees that it will not be moved elsewhere due to some future refactoring.

Cheers