there is a problem. there is a set of files in format:
|---- tg_ver
|---- tg.py
|---- m
|---- m_1
|---- main.py
|---- cookies.json
|---- state.txt
|---- m_2
|---- main.py
|---- cookies.json
|---- state.txt
|---- m_3
|---- main.py
|---- cookies.json
|---- state.txt
|---- m_n
|---- main.py
|---- cookies.json
|---- state.txt
After all, Import in the file "tg.py" files "main.py" do not see neighboring files such as "cookies.json", "state.txt", etc.
tg.py:
def start():
import m.m1.main as m
m.bot_start()
start()
# ----> EROR: no such file "cookies.json"
during operation, the "main.py" files create log files, they appear in the "tg_ver" directory
Initially, import was supposed to occur during operation, depending on user actions, through the __import__()
construction. Then I ran into this problem, tried it with standard import, got the same result.
When you open a file foo.txt
using a relative path (one that does not begin with a /
), python (or any program) will create an absolute path by joining the path with the current working directory. So if you are in a different working directory when you run your program, your program will need to use different paths to find the same file.
This example would print the contents of a file called /foo/bar/my/file.txt
.
$ cd /foo/bar
$ python3 -c 'print(open("my/file.txt").read())'
Even modules in packages and subpackages will look for files starting in the current working directory of the process and NOT the directory that the module source file can be found in.
A simple way to make sure you always find files by paths relative to your modules is to use the __file__
attribute present in every module loaded from a .py
file.
Let's say you have a file structure like:
|---- project
|---- main.py
|---- mypackage
|---- mymod.py
|---- some.json
To reliably always open some.json
from mymod.py
you could do.
from pathlib import Path
datafile = Path(__file__).parent / 'some.json'
contents = datafile.read_text()
print(contents)
importlib.resources
For more complex cases, you should use importlib.resources
. By complex, I mean where the module is not directly found on the filesystem. Perhaps it is packaged in a zip file.
from importlib.resources import read_text
parent_pkg, _ = __name__.rsplit('.', 1)
# if your file is a/b/c.py then __name__ is a.b.c
contents = read_text(parent_pkg, 'some.json')
print(contents)
From python 3.12 this becomes a bit simpler:
from importlib.resources import read_text
contents = read_text(__name__, 'some.json')
print(contents)
importlib.resources
provides a bunch of other functions than just read_text()
, so check out the documentation if you want the contents of a binary file, or want to be able to write data.