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

Please add documentation about needing to re-define inherited overload signatures #10699

Open
akpircher opened this issue Jun 23, 2021 · 1 comment

Comments

@akpircher
Copy link

akpircher commented Jun 23, 2021

Documentation

The documentation you have is pretty good, it usually saves me time.

I, unfortunately, spent too much time today trying to find the right keywords in your documentation, and the issues, trying to find the most pythonic solution for inherited overload signatures:

from __future__ import annotations

import abc
from typing import Literal, Mapping, overload


class AdapterBase(abc.ABC):
    @overload
    def get_map_or_value(self, *, as_dict: Literal[True]) -> Mapping[str, str]:
        ...

    @overload
    def get_map_or_value(self, *, as_dict: Literal[False] = ...) -> str:
        ...

    @overload
    def get_map_or_value(self, *, as_dict: bool = ...) -> Mapping[str, str] | str:
        ...

    @abc.abstractmethod
    def get_map_or_value(self, *, as_dict: bool = False) -> Mapping[str, str] | str:
        raise NotImplementedError


class ConcreteAdapter1(AdapterBase):
    # fails strict no-untyped-def checks
    def get_map_or_value(self, *, as_dict):
        if as_dict:
            return {"somekey": "somevalue"}
        return "somevalue"


class ConcreteAdapter2(AdapterBase):
    # Signature of "get_map_or_value" incompatible with supertype "AdapterBase" [override]
    def get_map_or_value(self, *, as_dict: bool = False) -> Mapping[str, str] | str:
        if as_dict:
            return {"someOtherKey": "someOtherValue"}
        return "someOtherValue"


class DoSomethingElse:
    def __init__(self, adapter: AdapterBase) -> None:
        # needs to know about function names, parameters, and return types
        self.adapter = adapter

My intuition in this scenario told me that the overloads could be inherited, and thus I just needed to provide the generic typedef and go on my merry way. That is, clearly, not the case and it took me a while to find #5146, and consequently, python/typing#269.

It would be nice if the documentation could mention that overload variants need to be re-defined in child/concrete classes. It would also clarify that this "edge case", or ones similar to it, is not an edge case, it's by design.

Here are some places where I went looking for answers, and perhaps someone else might too:

@akpircher
Copy link
Author

I guess a tangentially related issue is that I would expect the untyped child method to throw a signature override error (missing default value), but that seems to be solved by providing the overrides in the concrete classes (it complains when the new override definitions don't match)

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

No branches or pull requests

2 participants