4

I am trying type hint a protocol to encompass a small variety of similar API interfaces. I want to allow certain methods to be flexible and allow for extra arguments and keyword arguments, since different implementations have different 'bonus' args, but all of them share a common set of arguments at the first half of the signature.

This is awkward because I'm trying to write compatibility for some classes that I don't control directly, so I can't edit the implementation signatures.


from typing import Protocol

class ExampleProtocol(Protocol):
    def test(self, important_arg:str, *args, **kwargs):
        pass

class ExampleImplementation:
    def test(self, important_arg:str):
        pass

class ExampleImplementation2:
    def test(self, important_arg:str, unnessary_arg:bool):
        pass

implementation: ExampleProtocol = ExampleImplementation()
implementation2: ExampleProtocol = ExampleImplementation2()

Pylance gives me this:

"ExampleImplementation" is incompatible with protocol "ExampleProtocol"
    "test" is an incompatible type
      Type "(important_arg: str) -> None" cannot be assigned to type "(important_arg: str, *args: Unknown, **kwargs: Unknown) -> None"
        Parameter "**kwargs" has no corresponding parameter

Is it possible to type hint in this case, or do I need to just use Any instead of the protocol? Does python allow hinting "dynamic" signatures that have a few important arguments?

EDIT: It seems that this isn't possible, so the best solution I could come up with is to use the Callable type to at the very least indicate that a method with that name should exist, without enforcing any arguments, like so:

class ExampleProtocol(Protocol):
    test: Callable

This seems to work and not give any errors on the two examples.

4
  • These are completely distinct, incompatible signatures. A protocol is supposed to define ways in which instances of the protocol can be used in compatible ways, but these signatures are incompatible. Commented Jul 21, 2022 at 20:35
  • curious, is this for mypy or something? Commented Jul 21, 2022 at 20:36
  • Currently using pylint, but I was hoping to annotate enough to give better error messages and autocompletion in IDE regardless of what you're using Commented Jul 21, 2022 at 20:41
  • Two implementations you provide are incompatible and cannot implement the same protocol (doesn't matter how you define it, except for one that doesn't involve test args definition). It is not possible to call neither HypotheticalParent().test('foo') nor HypotheticalParent().test('foo', True). ExampleImplementation2 should have def test(self, important_arg: str, unnecessary_arg: bool = False) to be compatible, and then Protocol can define just def test(self, important_arg: str). This is what LSP is about. Commented Jul 23, 2022 at 20:57

1 Answer 1

1

The short answer here is 'no', mostly because your ExampleImplementation method test (or ExampleImplementation2) has a subset of the parameters allowed by ExampleProtocol. That is, there is some set of parameters that ExampleProtocol accepts that ExampleImplementation would break on - anything past that first argument.

Without knowing what you're trying to get at exactly, you're left with manually filtering the *agrs and **kwargs parameters for those that you care about. The former can be difficult because they're not named, they're only positional.

That said, the type-hint you're reaching for is Optional. It doesn't solve your problem on it's own, but it's a type that declares 'either this is None or it is of type x'. For instance:

def f(a: Optional[bool]) -> None:
    # a is either None or a boolean value

Any doesn't really do anything for you here, I think.

Sign up to request clarification or add additional context in comments.

1 Comment

I think I was unclear - Any would be in place of the protocol itself, not one of the method arguments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.