8000 Parameter decorator factories shouldn't pop `cls` from `attrs` · Issue #2294 · pallets/click · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Parameter decorator factories shouldn't pop cls from attrs #2294
Closed
@janluke

Description

@janluke

Popping cls introduces a side-effect that prevents the reuse of the returned decorator. For example, consider the code below. The function my_shared_argument is a decorator that is expected to register an argument of type ArgumentWithHelp. Instead, what happens is:

  • the first time the decorator is used, cls=ArgumentWithHelp will be popped from attrs -> attrs is now modified in-place
  • the following times the decorator is used, cls won't be in attrs.
import click


class ArgumentWithHelp(click.Argument):
    def __init__(self, *args, help=None, **attrs):
        super().__init__(*args, **attrs)
        self.help = help


def argument_with_help(*args, cls=ArgumentWithHelp, **kwargs):
    return click.argument(*args, cls=cls, **kwargs)


my_shared_argument = argument_with_help("pippo", help="very useful help")


@click.command()
@my_shared_argument
def foo(pippo):
    print(pippo)


@click.command()
@my_shared_argument
def bar(pippo):
    print(pippo)

Running this file as it is:

Traceback (most recent call last):
  File "C:/Users/sboby/AppData/Roaming/JetBrains/PyCharmCE2022.1/scratches/scratch_4.py", line 27, in <module>
    def bar(pippo):
  File "H:\Repo\unbox\UnboxTranslate\venv\lib\site-packages\click\decorators.py", line 287, in decorator
    _param_memo(f, ArgumentClass(param_decls, **attrs))
  File "H:\Repo\unbox\UnboxTranslate\venv\lib\site-packages\click\core.py", line 2950, in __init__
    super().__init__(param_decls, required=required, **attrs)
TypeError: __init__() got an unexpected keyword argument 'help'

Process finished with exit code 1

The @option decorator is affected by the same problem but it won't crash in a similar situation because click.Option.__init__ ignore extra arguments: it will just silently use click.Option as class.

The @option decorator is actually not affected because attrs is copied. This copy is nonetheless unnecessary, since adding cls to the signature of the function would be a more straightforward solution.

Environment:

  • Python version: irrelevant
  • Click version: 8.1.3 (but all versions are affected)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0