Skip to content

WIP: Mapping.{get,pop} can return default type #223

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

Merged
merged 2 commits into from
May 30, 2016

Conversation

tharvik
Copy link
Contributor

@tharvik tharvik commented May 25, 2016

Do not merge yet, it makes some tests from mypy fail, first merge it in mypy.

When using a Mapping, there is usually the idea to get or pop a key with a default of an existing guard object (instead of trying and expecting an exception). But in current typeshed, it is stated as

class Mapping(Generic[_KT, _VT]):
    def get(self, k: _KT, default: _VT = ...) -> _VT: ...

Wouldn't it be more correct to have something like this?

_DT = TypeVar('_DT')
class Mapping(Generic[_KT, _VT]):
    def get(self, k: _KT, default: _DT = ...) -> Union[_VT, _DT]: ...

thus also respecting the definition of dict.get which is stated in the documentation as

Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

@matthiaskramm
Copy link
Contributor

Yes, that looks better. That's what pytype has in its builtins, too: https://github.com/google/pytype/blob/master/pytype/pytd/builtins/__builtin__.pytd#L485

def get(self, k: _KT, default: _VT = None) -> _VT: ...
def pop(self, k: _KT, default: _VT = ...) -> _VT: ...
def get(self, k: _KT, default: _T = None) -> Union[_VT, _T]: ...
def pop(self, k: _KT, default: _T = ...) -> Union[_VT, _T]: ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think pop() will need to be overloaded -- with one arg there's no possibility of it returning the default value (unlike get()).

@tharvik tharvik force-pushed the fix_mapping_get_pop_default branch from ae7430e to cceebd5 Compare May 27, 2016 07:30
@tharvik
Copy link
Contributor Author

tharvik commented May 27, 2016

I took the path of overloading, it seems nicer (and clearer). We still need to merge the mypy PR though.

@overload
def get(self, k: _KT) -> Optional[_VT]: ...
@overload
def get(self, k: _KT, default: _T = ...) -> Union[_VT, _T]: ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This overload variant (and all the others like it) should no longer have a default = ....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ho, correct, thanks for reviewing.

@rwbarton
Copy link
Contributor

The overload will be needed under strict optional checking anyways, as otherwise there's no way to have the default default be None without always requiring the return type to contain None, even when a default is provided.

With this change we can also make Mapping covariant in its value type, as it should be.

@tharvik tharvik force-pushed the fix_mapping_get_pop_default branch from cceebd5 to 3de5d20 Compare May 28, 2016 08:54
@tharvik
Copy link
Contributor Author

tharvik commented May 28, 2016

With this change we can also make Mapping covariant in its value type, as it should be.

So I did, but, you may want to check it because I just replaced _VT to _VT_to.

@gvanrossum gvanrossum reopened this May 30, 2016
@gvanrossum gvanrossum merged commit d43adbe into python:master May 30, 2016
@gvanrossum
Copy link
Member

Sadly this broke more than mypy. Our two internal repos each showed several problems due to this. I think I'll go roll this back so that some other mypy developer doesn't accidentally release mypy with this incorporated.

gvanrossum pushed a commit that referenced this pull request May 30, 2016
This reverts commit d43adbe.

Here's a simple example of code that breaks with this PR:

from typing import Mapping, Dict, Tuple
a = {('0', '0'): 42}  # type: Mapping[Tuple[str, str], int]
b = a.get(('1', '1'), 0)

This gives an error on the last line:
error: No overload variant of "get" of "dict" matches argument types [Tuple[builtins.str, builtins.str], builtins.int]
@gvanrossum
Copy link
Member

Here's a simple repo: it seems to occur whenever the mapping keys are a tuple:

    from typing import Mapping, Dict, Tuple
    a = {('0', '0'): 42}  # type: Dict[Tuple[str, str], int]
    b = a.get(('1', '1'), 0)

This gives an error on the last line:

error: No overload variant of "get" of "dict" matches argument types [Tuple[builtins.str, builtins.str], builtins.int]

A similar error shows when the type uses Mapping instead of dict.

@gvanrossum
Copy link
Member

gvanrossum commented May 30, 2016

So python/mypy#1595 is fixed, but there are still some remaining issues with this PR in our internal repos. I will see if I can find the time to understand those.

@tharvik tharvik deleted the fix_mapping_get_pop_default branch May 31, 2016 16:37
@gvanrossum
Copy link
Member

Note to self: this was reverted, but I want to try again, because I still
think this is the right thing to do.

On Sat, May 28, 2016 at 2:09 AM, Valérian Rousset [email protected]
wrote:

With this change we can also make Mapping covariant in its value type, as
it should be.

So I did, but, you may want to check it because I just replaced _VT to
_VT_to.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#223 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/ACwrMonRrERcvt7XU2MvjxkjOcLv5-UHks5qGAZbgaJpZM4Imcv3
.

--Guido van Rossum (python.org/~guido)

@gnprice
Copy link
Contributor

gnprice commented Jun 8, 2016

Because this PR was merged, it'd be easy for us to lose track of there still being something to do here, so I filed a new issue #278 for round 2.

momandine pushed a commit to momandine/typeshed that referenced this pull request Jul 5, 2016
Fixes several issues related to subclass checks against
custom subclasses of generic collections.
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

Successfully merging this pull request may close these issues.

5 participants