Let's say I have an add-on consisting of several modules located in the same directory like this:
addon_folder\ __init__.py support.py addon.py
and I need to import all content from
addon.py. As all files are in the same folder which contains
__init__.py I expect Python interpreter to consider it a package, so in
addon.py I use relative import and write:
from .support import *
addon_folderis located in Blender add-ons folder
- there aren't any other errors
- add-on is enabled in Blender properties
add-on loads without any error on Blender load. So in this case relative import works just fine and I would like to keep it while working on add-on in PyCharm IDE. So I do the following:
- Open add-on's folder as PyCharm project
- Specify Python from
C:\Program Files\Blender Foundation\Blender 3.3.1\3.3\python\bin\python.exeas PyCharm project interpreter
At this stage I expect
addon.py launched from PyCharm to have the same behavior as it shows as Blender add-on, however it raises:
ImportError: attempted relative import with no known parent package
For some reason when the script is called from PyCharm using presumably the same Python interpreter as Blender does, it doesn't consider current folder a package.
I've got two assumptions:
- Python interpreter in the Blender installation folder is not Blender embedded Python interpreter mentioned in the documentation. The main reason which makes me think so is that when I launch this Python executable from the command line and try e.g.
import bpyit raises
ModuleNotFoundError. If I am using wrong Python interpreter, how do I use exactly the same as Blender uses?
- PyCharm project is configured unproperly. Actually even if I create
python packagein PyCharm and place
addon.pyin it, interpreter still raises
ImportError. Than how do I tell PyCharm or Python interpreter or whichever cause this error that it is actually a package?
My goal is to have the same nice code with the same behavior as a part of PyCharm project and as Blender add-on. I am not expecting PyCharm to move Default Cube around or execute any other
bpy methods, I understand that
bpy may work only together with Blender itself. But I do expect proper package behavior in general.
I made some Google research: I've read this and this topics related to the relative import in Python in common and in PyCharm particularly. The only semi-working suggestion I found is to add the following to every module in package which uses relative import:
import sys, os rootdir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) if rootdir not in sys.path: sys.path.append(rootdir)
This allows to use
addon_folder as module like this:
from addon_folder.support import *
When executed it works both in Blender and PyCharm. But for Blender add-on this is unnecessary and quite ugly solution comparing to simple and elegant relative import. And for PyCharm there is even worse problem: PyCharm as IDE doesn't recognize
addon_folder as module before scripts actually starts running, because
addon_folder's parent folder is appended to the
sys.path only directly in the script itself. So while the script is not running PyCharm marks
addon_folder as unknown module and doesn't recognize its content which kills the most benefits of using IDE.
What works perfectly for PyCharm is:
from support import *
but unfortunately it raises
ModuleNotFoundError when launched as Blender add-on.
By the way, if the same scripts are called from Blender Text Editor it shows the third behavior which is different from both, but it is not directly related to the question which is already too long.
For my previous add-ons I found a solution in writing several
except constructions to run the same scripts without errors from PyCharm, from Blender Text Editor and as Blender add-on:
if __name__ == '__main__': import sys import os rootdir = os.path.dirname(os.path.realpath(__file__)) if rootdir not in sys.path: sys.path.append(rootdir) try: # Pycharm import from support import * except ModuleNotFoundError: # Blender Text Editor import from addon_folder.support import * else: # Add-on import from .support import *
But is there more elegant and straightforward way to use the same import for all cases, or at least for PyCharm and Blender add-on? Ideally is there a way to convenience PyCharm or Python interpreter or whichever causes
addon.py is a part of
addon_folder package to be able to keep relative import?