There a couple ways you can do this. The quick and dirty is to just add it to your interpreter's path.
Here's my setup:
Matthews-MacBook-Pro:test_project matt$ tree
.
├── foo
│ └── bar
│ └── baz
│ └── target_module.py
└── python
└── foo
└── code.py
5 directories, 2 files
Here's the contents of target_module.py:
def my_func():
print("my func called.")
and how you can import this function into code.py:
import os
import sys
# Cheat and just add it to python interpreter's path
this_dir = os.path.dirname(__file__)
sys.path.append(os.path.join(this_dir, "..", "..", "foo", "bar", "baz"))
import target_module as tm
tm.my_func()
this outputs:
Matthews-MacBook-Pro:test_project matt$ python python/foo/code.py
my func called.
or you can call it from the foo directory and it'll still work fine:
Matthews-MacBook-Pro:test_project matt$ cd python/foo/
Matthews-MacBook-Pro:foo matt$ python code.py
my func called.
You can also just add the foo/bar/baz directory to your PYTHONPATH environment variable instead of calling sys.path.append. This syntax is shell dependent: so I'll let you google how to set environment variables for your particular shell.
Ideally you'd want to make your modules deployable (i.e. use setup.py and distutils or setuptools and put __init__.py in each module), and then you can import "normally" (kind of like you can "just" import numpy and it works). But since you claim it's legacy, maybe this might be hard for you to accomplish. I get it: in legacy systems all bets are off and sometimes the quick and dirty is fine (and maybe even ideal if you don't want to spend a lot of time fixing the issue).
I can expand this answer if you're interested in creating deployable python packages, and if not, the above should get the job done.
HTH.
__init__.pys) and it's just a bunch of directories with some python scripts. All bets are off in legacy