Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typing support #443

Open
aspfohl opened this issue Jul 6, 2023 · 2 comments
Open

Typing support #443

aspfohl opened this issue Jul 6, 2023 · 2 comments

Comments

@aspfohl
Copy link

aspfohl commented Jul 6, 2023

Seeing typing issues in pyright:

error: Cannot assign member "completer" for type "Action"
    Member "completer" is unknown (reportGeneralTypeIssues)

with a set up like this:

class ExampleCompleter:

    def __init__(self):
        pass

    def __call__(sel, **kwargs):
        return {'foo', 'bar'}

parser.add_argument(
    '--arg',
    default=None,
).completer = ExampleCompleter()

Any pointers on calling completer in a type-safe way? This is with argcomplete==3.0.8 and Python 3.10.5

@djungelorm
Copy link

djungelorm commented Sep 20, 2023

I get a similar issue with mypy:

error: "Action" has no attribute "completer"  [attr-defined]

I don't see any way around this other than to define a subclass of argparse.Action with the additional completer attribute, and then cast the result of parser.add_argument to it, for example:

import argparse
from collections.abc import Iterable
from typing import cast
from argcomplete.completers import BaseCompleter


class Action(argparse.Action):
    completer: BaseCompleter | None


class ExampleCompleter(BaseCompleter):
    def __call__(
        self,
        prefix: str,
        action: argparse.Action,
        parser: argparse.ArgumentParser,
        parsed_args: argparse.Namespace,
    ) -> Iterable[str]:
        return {"foo", "bar"}


class ExampleCompleterWithHelp(BaseCompleter):
    def __call__(
        self,
        prefix: str,
        action: argparse.Action,
        parser: argparse.ArgumentParser,
        parsed_args: argparse.Namespace,
    ) -> dict[str, str]:
        return {"foo": "foo help", "bar": "bar help"}

cast(Action, parser.add_argument("--arg1")).completer = ExampleCompleter()
cast(Action, parser.add_argument("--arg2")).completer = ExampleCompleterWithHelp()

@Will-W
Copy link

Will-W commented Aug 30, 2024

Tidier (IMO) solution that uses the same approach:

import typing as t
import argparse

class ArgcompleteAction(argparse.Action):
    completer: t.Callable | None

class ArgcompleteArgumentParser(argparse.ArgumentParser):
    def add_argument(self, *args, **kwargs) -> ArgcompleteAction:
        return t.cast(ArgcompleteAction, super().add_argument(*args, **kwargs))

Then you can just replace the normal call to parser = argparse.ArgumentParser() with parser = ArgcompleteArgumentParser() and all the typing errors go away.

This class could go into argcomplete itself. If I have a minute I'll put together a PR for discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants