Solved 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 by os.getcwd which returns that working directory:

704df48c-6fec-4acc-95e8-f60405424558-image.png

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() = }")

f70c2a1b-3fdf-41ee-9408-1cdbb16219a1-image.png

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

MAXON SDK Specialist
developers.maxon.net

@spedler @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 calling GeGetPluginPath 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

MAXON SDK Specialist
developers.maxon.net