python-poetry / poetry

Python packaging and dependency management made easy
https://python-poetry.org
MIT License
31.88k stars 2.28k forks source link

`poetry plugin show` crash with obscure error message #4345

Open Conchylicultor opened 3 years ago

Conchylicultor commented 3 years ago
[tool.poetry]
name = "nightly_release"
version = "0.1.0"
description = "Poetry plugin to setup automated release"
authors = ["Sunds team <sunds@google.com>"]

[tool.poetry.dependencies]
python = "^3.7"

[tool.poetry.dev-dependencies]
pytest = "*"

[tool.poetry.plugins."poetry.plugin"]
demo = "nightly_release:NightlyReleasePlugin"

[build-system]
requires = ["poetry-core>=1.1.0a6"]
build-backend = "poetry.core.masonry.api"

Issue

I'm trying to develop a poetry plugin locally. I'm trying a dummy plugin:

import cleo.io.io
import poetry.plugins
import poetry.poetry

class NightlyReleasePlugin(poetry.plugins.Plugin):

    def activate(self, poetry: poetry.poetry.Poetry, io: cleo.io.io.IO):
        io.write_line(repr(poetry))
        print(poetry)

As there is no good way to install package globally in development mode (like pip install -e), I'm forced to recompile the package every time (which is not a good developer experience):

pip uninstall -y nightly-release
poetry build
pip install .

After the plugin is installed, I'm trying to check if the plugin is correctly detected with poetry plugin show, but got the following error:

$ poetry plugin show

  KeyError

  'demo'

  at /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/poetry/console/commands/plugin/show.py:54 in handle
       50│             category = "plugins"
       51│             if issubclass(plugin, ApplicationPlugin):
       52│                 category = "application_plugins"
       53│ 
    →  54│             package = packages_by_name[canonicalize_name(entry_point.name)]
       55│             plugins[package.pretty_name]["package"] = package
       56│             plugins[package.pretty_name][category].append(entry_point)
       57│ 
       58│         for name, info in plugins.items():
Full stacktrace. Click to expand! ```python epot-macbookpro2:~ epot$ poetry plugin show -vvv Stack trace: 7 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cleo/application.py:330 in run 328│ 329│ try: → 330│ exit_code = self._run(io) 331│ except Exception as e: 332│ if not self._catch_exceptions: 6 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/poetry/console/application.py:180 in _run 178│ self._load_plugins(io) 179│ → 180│ return super()._run(io) 181│ 182│ def _configure_io(self, io: IO) -> None: 5 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cleo/application.py:425 in _run 423│ io.set_input(ArgvInput(argv)) 424│ → 425│ exit_code = self._run_command(command, io) 426│ self._running_command = None 427│ 4 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cleo/application.py:467 in _run_command 465│ 466│ if error is not None: → 467│ raise error 468│ 469│ return event.exit_code 3 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cleo/application.py:451 in _run_command 449│ 450│ if event.command_should_run(): → 451│ exit_code = command.run(io) 452│ else: 453│ exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED 2 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cleo/commands/base_command.py:118 in run 116│ io.input.validate() 117│ → 118│ status_code = self.execute(io) 119│ 120│ if status_code is None: 1 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/cleo/commands/command.py:85 in execute 83│ 84│ try: → 85│ return self.handle() 86│ except KeyboardInterrupt: 87│ return 1 KeyError 'demo' at /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/poetry/console/commands/plugin/show.py:54 in handle 50│ category = "plugins" 51│ if issubclass(plugin, ApplicationPlugin): 52│ category = "application_plugins" 53│ → 54│ package = packages_by_name[canonicalize_name(entry_point.name)] 55│ plugins[package.pretty_name]["package"] = package 56│ plugins[package.pretty_name][category].append(entry_point) 57│ 58│ for name, info in plugins.items(): ```

I'm confident that the entry point is correct and my plugin is correctly loaded:

I also get other error message when trying other commands:

$ poetry publish --dry-run

  AttributeError

  'IO' object has no attribute 'ask'

  at /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/poetry/publishing/publisher.py:82 in publish
       78│         )
       79│         # Requesting missing credentials but only if there is not a client cert defined.
       80│         if not resolved_client_cert:
       81│             if username is None:
    →  82│                 username = self._io.ask("Username:")
       83│ 
       84│             # skip password input if no username is provided, assume unauthenticated
       85│             if username and password is None:
       86│                 password = self._io.ask_hidden("Password:")

My cleo version installed is cleo==1.0.0a4

What is this error about ?

martinxsliu commented 3 years ago

I also get the 'IO' object has no attribute 'ask' error with poetry publish. I created a new issue to track that separately: https://github.com/python-poetry/poetry/issues/4349.

saisasidhar commented 3 years ago

I came across this problem. Although I might not be able to give you a concrete answer, I managed to go past this error and continue developing my plugin.

This snippet from poetry documentation about plugins does not work atm

[tool.poetry.plugins."poetry.plugin"]
demo = "poetry_demo_plugin.plugin:MyPlugin"

Instead, this works...

[tool.poetry.plugins."poetry.plugin"]
poetry-demo-plugin = "poetry_demo_plugin.plugin:MyPlugin"

list packages_by_name at poetry/console/commands/plugin/show.py:54 contains poetry_demo_plugin but canonicalize_name(entry_point.name) is demo. So, we gotta make entry_point.name match the actual package name.

In your case, this will work

[tool.poetry.plugins."poetry.plugin"]
nightly-release = "nightly_release:NightlyReleasePlugin"

Provided, nightly-release is the name of your package.


As far as I understand, the section

[tool.poetry.plugins."blogtool.parsers"]
".rst" = "some_module:SomeClass"

in pyproject.toml is meant to behave like setuptools entry points according to the documentation. Setup tools not only supports console scripts but also supports advertising behavior.

Haven't used blogtool but I'm guessing that in the above example the package advertises to blogtool.parsers that *.rst must be handled by some_module:SomeClass. and similarly [[tool.poetry.plugins."poetry.application.plugin"]] instructs poetry about plugins and the respective activate() method ?


@ developers could you please document the correct usage or implement a fix if this was indeed a bug ??

Conchylicultor commented 3 years ago

Thank you @saisasidhar , this fixed my issue. I'm still leaving this open as I think at least, the error messages and documentation should be improved.

ashemedai commented 2 years ago

To add to @saisasidhar's comment, the documentation currently talks about blogtool.parsers and links to the current setuptools documentation. That has no mention of blogtool anywhere anymore. The only place I found what the intent was was at the very old documentation from PEAK.