Relative File Path Not Recognize by Plug-in?
-
Hi,
I have a plug-in directory that goes like this:
myPlugin.pyp config.json
In my pyp file, I have this code block
import json json_file = r"config.json" with open(json_file, "r") as f: data = json.load(f)
but it gives me an error of
FileNotFoundError:[Errno 2] No such file or directory: 'config.json
Is there a way around this?
-
In C++ - I expect it's the same in Python - I would call GeGetPluginPath() to find the absolute path to the plugin, then append the filename to that path. This should work no matter where the user has installed your plugin.
Steve
-
Hello @bentraje,
Thank you for reaching out to us. The reason for this behavior is that you are here using a Python interpreter in a shared environment. When you launch a Python script with a standalone Python interpreter, e.g., CPython 3.11, the working directory of the interpreter is set to be the directory of the interpreted
py
file. This is then expressed byos.getcwd
which returns that working directory:Python then makes all its magic relative path thing happen with this path; all relative paths are relative to it. But for a Cinema 4D plugin, the working directory is the application directory and not the plugin directory because here a shared interpreter is running.
import os print(f"{os.getcwd() = }")
One must construct local paths manually in this case. The common way to do this is the
__file__
attribute of a module, it will always contain the location of the module file, no matter where it is on a machine.import os ROOT_PATH: str = os.path.dirname(__file__) CONFIG_FILE_PATH: str = os.path.join(ROOT_PATH, "config.json") print (f"{__file__ = }") print(f"{ROOT_PATH = }") print(f"{CONFIG_FILE_PATH = }")
__file__ = 'C:\\Users\\f_hoppe\\OneDrive - MAXON Computer GmbH\\support\\pc14379\\pc14379.pyp' ROOT_PATH = 'C:\\Users\\f_hoppe\\OneDrive - MAXON Computer GmbH\\support\\pc14379' CONFIG_FILE_PATH = 'C:\\Users\\f_hoppe\\OneDrive - MAXON Computer GmbH\\support\\pc14379\\config.json'
Cheers,
Ferdinand -
Thanks for the response! Just checked the documentation, can't use
GeGetPluginPath()
. Per documentation, it does not behave the same with as C++. So I ended up using the__file__
method.Works as expected. Thanks for the illustration code!
-
Hello @bentraje,
Yes, the Python variant of
GeGetPluginPath
is not that useful as it just calls the C++ implementation which will then return the Python module path because the Python module is the C++ plugin which is callingGeGetPluginPath
in that case. I will make the function description a bit more clear about that and also add a little example snippet for the module attribute__file__
.And as what I would consider a fun fact:
The
__file__
attribute of modules is one of the many things where the language Python took inspiration from C/C++. In C++,__FILE__
is the macro which refers to the source file it is referenced in. I used this for example recently in the C++ Color Management examples to load an ICC file which is located next to a source file. But since users are usually not in the habit of compiling their C++ code themselves, or if they do, then want to move the resulting binary to a different place,__FILE__
is much less useful than__file__
as C++ there is a difference between the source and the executable.Cheers,
Ferdinand