Выборочная загрузка точки входа в python выдает ошибку ImportError: модуль не имеет атрибута - PullRequest
0 голосов
/ 07 мая 2020

У меня есть требование, согласно которому мой подключаемый модуль приложения на основе кликов должен иметь возможность загружать точки входа только из одного предоставленного имени пакета. Раньше я пробовал pkg_resources.iter_entry_points (), и он отлично работает. Проблема с функцией pkg_resources.get_entry_map (). Если вы поместите точку отладки, точка входа отлично загрузится с EntryPoint.load () с get_entry_map (). Но если вы запустите его с использованием python, он вызовет ImportError.


# click_demo/loader_failing.py
import click
from pkg_resources import iter_entry_points

EP_NAME = 'click_demo_plugins'


class MyCLI(click.Group):

    def list_commands(self, ctx):
        rv = {a.name: a.load() for a in list(iter_entry_points(EP_NAME))}
        return sorted(list(rv.keys()))

    def get_command(self, ctx, name):
        ep: list = list(iter_entry_points(EP_NAME, name=name))[0]
        ep = None if not ep else ep.load()
        return ep


@click.command(cls=MyCLI)
def cli():
    pass


if __name__ == '__main__':
    cli()


# click_demo/plugin.py
import click

from click_demo.loader_failing import cli


@cli.command()
@click.option('--name', default='Dummy Value')
def main(name):
    click.echo(f'Hello from click demo plugin MPKG {name}')


if __name__ == '__main__':
    main()


#setup.py
from setuptools import setup, find_packages
setup(
    name="click_demo",
    version="0.0.1",
    packages=find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
        "Operating System :: OS Independent",
        "Development Status :: 1 - Planning",
        "Intended Audience :: Developers",
    ],
    python_requires='>=3.6',
    tests_require=test_deps,
    install_requires=
    [
        'click>=7.0',
    ],
    entry_points={
        'console_scripts': [
            'main_cli_1=click_demo.loader_failing:cli',
            'main_cli_2=click_demo.loader_failing_2:cli',
        ],
        'click_demo_plugins': [
            # This entry point fails no matter what
            'plugin=click_demo.plugin:main',
        ]
    }
)

на bash:

python3.6 -m venv venv
source venv/scripts/activate
pip3.6 install click
pip3.6 install .
python3.6 click_demo/loader_failing.py plugin

Сообщение об ошибке:


<proj_root>/click_demo/venv/bin/python <proj_root>/click_demo/click_demo/loader_failing.py plugin
Traceback (most recent call last):
  File "<proj_root>/click_demo/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2458, in resolve
    return functools.reduce(getattr, self.attrs, module)
AttributeError: module 'click_demo.plugin' has no attribute 'main'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<proj_root>/click_demo/click_demo/loader_failing.py", line 15, in <module>
    @click.group(commands=get_plugin_entrypoints('click_demo'))
  File "<proj_root>/click_demo/click_demo/loader_failing.py", line 10, in get_plugin_entrypoints
    ep_map = {k: v.load() for k, v in ep_map.items()}
  File "<proj_root>/click_demo/click_demo/loader_failing.py", line 10, in <dictcomp>
    ep_map = {k: v.load() for k, v in ep_map.items()}
  File "<proj_root>/click_demo/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2450, in load
    return self.resolve()
  File "<proj_root>/click_demo/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2456, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "<proj_root>/click_demo/click_demo/plugin.py", line 4, in <module>
    from click_demo.loader_failing import cli
  File "<proj_root>/click_demo/click_demo/loader_failing.py", line 15, in <module>
    @click.group(commands=get_plugin_entrypoints('click_demo'))
  File "<proj_root>/click_demo/click_demo/loader_failing.py", line 10, in get_plugin_entrypoints
    ep_map = {k: v.load() for k, v in ep_map.items()}
  File "<proj_root>/click_demo/click_demo/loader_failing.py", line 10, in <dictcomp>
    ep_map = {k: v.load() for k, v in ep_map.items()}
  File "<proj_root>/click_demo/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2450, in load
    return self.resolve()
  File "<proj_root>/click_demo/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2460, in resolve
    raise ImportError(str(exc))
ImportError: module 'click_demo.plugin' has no attribute 'main'

Process finished with exit code 1
...