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 support.py
to 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 *
Now, if:
- the
addon_folder
is located in Blender add-ons folder __init__.py
containsbl_info
dictionary- 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.exe
as 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 bpy
it raisesModuleNotFoundError
. 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 package
in PyCharm and placesupport.py
andaddon.py
in it, interpreter still raisesImportError
. 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 try
/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 ImportError
that addon.py
is a part of addon_folder
package to be able to keep relative import?