2
$\begingroup$

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 contains bl_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:

  1. 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 raises ModuleNotFoundError. If I am using wrong Python interpreter, how do I use exactly the same as Blender uses?
  2. PyCharm project is configured unproperly. Actually even if I create python package in PyCharm and place support.py and addon.py in 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 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?

$\endgroup$
1

1 Answer 1

0
$\begingroup$

You could try this solution for adding directory to sys.path permanently.

When I add an OS environment variable "PYTHONPATH" with a path to some folder, Python from Blender and my system Python both import stuff from it with no problems.

Pycharm seems to create virtual environment so like one of the answers suggests you can add paths to .pth file and there is one in Pycharm project's virtual environment: _virtualenv.pth

On a new project on my PC it's located in: C:\Users\m\PycharmProjects\pythonProject\venv\Lib\site-packages\_virtualenv.pth

If I add a new line in it C:\Users\m\AppData\Roaming\Blender Foundation\Blender\3.4\scripts\addons it seems to work.

$\endgroup$
6
  • $\begingroup$ Sorry, I can not understand how it solves the problem. I create new project in PyCharm with Venv, I add a new line line to the _virtualenv.pth with the path to the package I'm working on or to the directory this package lays in, but still get ImportError: attempted relative import with no known parent package when try to use relative import from one module to another. What it suppose to change? On the other hand, it doesn't affect Blender's embedded Python and add-ons behavior, as it changes only Venv which is the copy of the original Python. Could you clarify, please? $\endgroup$ Feb 4, 2023 at 20:50
  • $\begingroup$ I don't think virtual environment is set up for Python that comes with Blender. If you are using Python that comes with Blender, maybe try adding PYTHONPATH to your OS' environment variables. $\endgroup$ Feb 4, 2023 at 20:57
  • $\begingroup$ I still can not understand the purpose. I can add a path to the folder with the package to the environment variable, but it doesn't solve relative import error in PyCharm. As for Blender, this approach allows direct import of the modules, but only on my computer. All other add-on users would have to do the same on theirs and they won't. Probably changing or adding system environment variable could be written in the code itself, but I don't think that changing users' OS settings just to fix PyCharm import issue is a good practice. Or am I missing something? $\endgroup$ Feb 4, 2023 at 21:52
  • $\begingroup$ I think I didn't understand the question then. I thought the code works in Blender and you only have problems while developing in Pycharm. $\endgroup$ Feb 4, 2023 at 22:46
  • $\begingroup$ Relative import, e.g. from . import support works in Blender add-ons, but it raises ImportError in PyCharm. On the other hand, direct import e.g. import support works in PyCharm but raises ModuleNotFoundError in Blender add-ons. Adding path to environment variable does not fix relative import error in PyCharm, it could only fix direct import error in Blender add-on, but all add-on users would also have to add path to their environment variables then. Thank you for your suggestions anyway. $\endgroup$ Feb 6, 2023 at 12:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .