Python: Import via init.py it works in the IDE, but not on the command line

I have a bot that is based on a ready-made project, and now it's time to write my own. I decided to do the same import of plugins:

# содержимое /plugins/__init__.py
import importlib
import pkgutil

__all__ = []

def import_plugins(package):
    if isinstance(package, str):
    package = importlib.import_module(package)

    for loader, name, is_pkg in pkgutil.walk_packages(package.__path__):
        full_name = package.__name__ + '.' + name

        module = importlib.import_module(full_name)

        for name in dir(module):
            if name[0] == "_":
                continue

            e = module.__getattribute__(name)

            if e in __all__:
                continue

            if True:
                __all__.append(e.__name__)
                globals()[e.__name__] = e

        if is_pkg:
            import_plugins(full_name)


import_plugins(__name__)

So, there are no problems with running from PyCharm, but if you run it from the command line, it will give an error:

Traceback (most recent call last):
File "Camelia.py", line 12, in
settings = Settings.Settings()
File "C:\Users\ShadowOfLife\PycharmProjects\AeterrnoPy\Settings.py", line 10, in __init__
self.inner_data = InnerDataPlugin()
NameError: name 'InnerDataPlugin' is not defined

What am I doing wrong? Is it possible to make such an import work from the command line?

Project structure:

/Plugins /
-- /AeterrnoPy
-- /Base
-- /Data
-------- __init__.py
-------- InnerData.py # here is InnerDataPlugin()
-- /EzPy
-- __init__.py # here is the code for import
/utils
Camelia.py # bot
Settings.py # plugins are imported here

And the contents of Settings:

from Plugins import *


class Settings:
__slots__ = ("inner_data", "plugins", "user_plugins")

def __init__(self):
    self.plugins = ()
    self.user_plugins = ()
    self.inner_data = InnerDataPlugin()

    self.plugins = (
        AntiFloodPlugin(),
        self.inner_data,
        PairPlugin("pair test", "pt"),
        TestingPlugin("test", "tst"),
    )

    self.user_plugins = (
        PairUP("pair test", "pt"),
    )

UPD: Sorry for using images, corrected

Author: 501_K, 2018-12-13

2 answers

The problem is that Pycharm automatically adds all the directories with the project modules to PYTHONPATH. When you run the script from the console, it does not see the directories where your modules are scattered (there are many reasons for this). And there are two ways out here:

  1. Correct - just use relative import, for example:

    From ..Plugins import *

    Import .Plugins

(experiment with the paths to see for yourself how it all works works)

  1. Not very correct Create init.py in the main project directory and import all your internal modules into it Add the root directory of the project to the PYTHONPATH variable of your OS, or write directly at the top of the main file:

    Import sys

    Sys.path.append('/path/to_my_project')

 0
Author: Alex Zaharchuk, 2018-12-13 14:21:46

In general, Alex's answer did not help me, nothing has changed. I've already solved the problem, but I can't explain why or how. Imported to __init__.py the base plugin, from which the others are inherited, and instead of adding everything to __all__, I add only BasePlugin subclasses. Now it works both from the console, and from PyCharm, and from another device, too.
That is, instead of:

if True:
    __all__.append(e.__name__)
    globals()[e.__name__] = e

Now:

if isinstance(e, type) and issubclass(e, BasePlugin) and e.__module__ == module.__name__:
    __all__.append(e.__name__)
    globals()[e.__name__] = e

The necessary plugins were in the variable in both cases, but for some reason when if there is something extra, the import did not work on the command line.

 0
Author: 501_K, 2018-12-16 17:10:45