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

TypedDict.get returns an object if a dictionary has more than one field and the types on those fields differ. #2612

Closed
rowillia opened this issue Dec 27, 2016 · 1 comment

Comments

@rowillia
Copy link
Contributor

rowillia commented Dec 27, 2016

This appears to be due to TypedDict relying on a fallback.

from typing import List, Optional
from mypy_extensions import TypedDict

TaggedPoint = TypedDict('TaggedPoint', {'type': str, 'x': int, 'y': int})
Point3D = TypedDict('Point3D', {'x': int, 'y': int, 'z': int})
BadPointSet = TypedDict('BadPointSet', {
    'total_length': int,
    'points': List[TaggedPoint]
})
OKPointSet = TypedDict('OKPointSet', {
    'points': List[TaggedPoint]
})

def foo(point_3d: Point3D,
        tagged_point: TaggedPoint,
        bad_points: BadPointSet,
        ok_points: OKPointSet) -> None:
    reveal_type(point_3d.get('x'))  # error: Revealed type is 'builtins.int*
    reveal_type(tagged_point.get('x'))  # error: Revealed type is 'builtins.object*
    reveal_type(bad_points.get('points'))  # error: Revealed type is 'builtins.object*'
    reveal_type(ok_points.get('points'))  # Revealed type is 'builtins.list*[TypedDict(x=builtins.int, y=builtins.int, _fallback=test_typed_dict_get.TaggedPoint)]'
@rowillia rowillia changed the title TypedDict.get returns an object if a dictionary has more than one field and one of those fields is a Generic TypedDict.get returns an object if a dictionary has more than one field and the types on those fields differ. Dec 28, 2016
rowillia pushed a commit to rowillia/mypy that referenced this issue Dec 28, 2016
Previously, `get` would simply fallback to the type of the underlying dictionary which made
TypedDicts hard to use with code that's parsing objects where fields may or may not be
present (for example, parsing a response).

This implementation _explicitly_ ignores the default parameter's type as it's quite useful to
chain together get calls (Until something like PEP 505 hits 😄)

```python
foo.get('a', {}).get('b', {}).get('c')
```

This fixes python#2612
rowillia pushed a commit to rowillia/mypy that referenced this issue Dec 28, 2016
Previously, `get` would simply fallback to the type of the underlying dictionary which made
TypedDicts hard to use with code that's parsing objects where fields may or may not be
present (for example, parsing a response).

This implementation _explicitly_ ignores the default parameter's type as it's quite useful to
chain together get calls (Until something like PEP 505 hits 😄)

```python
foo.get('a', {}).get('b', {}).get('c')
```

This fixes python#2612
rowillia pushed a commit to rowillia/mypy that referenced this issue Jan 6, 2017
Previously, `get` would simply fallback to the type of the underlying dictionary which made
TypedDicts hard to use with code that's parsing objects where fields may or may not be
present (for example, parsing a response).

This implementation _explicitly_ ignores the default parameter's type as it's quite useful to
chain together get calls (Until something like PEP 505 hits 😄)

```python
foo.get('a', {}).get('b', {}).get('c')
```

This fixes python#2612
rowillia pushed a commit to rowillia/mypy that referenced this issue Jan 7, 2017
Previously, `get` would simply fallback to the type of the underlying dictionary which made
TypedDicts hard to use with code that's parsing objects where fields may or may not be
present (for example, parsing a response).

This implementation _explicitly_ ignores the default parameter's type as it's quite useful to
chain together get calls (Until something like PEP 505 hits 😄)

```python
foo.get('a', {}).get('b', {}).get('c')
```

This fixes python#2612
rowillia pushed a commit to rowillia/mypy that referenced this issue Jan 11, 2017
Previously, `get` would simply fallback to the type of the underlying dictionary which made
TypedDicts hard to use with code that's parsing objects where fields may or may not be
present (for example, parsing a response).

This implementation _explicitly_ ignores the default parameter's type as it's quite useful to
chain together get calls (Until something like PEP 505 hits 😄)

```python
foo.get('a', {}).get('b', {}).get('c')
```

This fixes python#2612
rowillia pushed a commit to rowillia/mypy that referenced this issue Jan 11, 2017
Previously, `get` would simply fallback to the type of the underlying dictionary which made
TypedDicts hard to use with code that's parsing objects where fields may or may not be
present (for example, parsing a response).

This implementation _explicitly_ ignores the default parameter's type as it's quite useful to
chain together get calls (Until something like PEP 505 hits 😄)

```python
foo.get('a', {}).get('b', {}).get('c')
```

This fixes python#2612
rowillia pushed a commit to lyft/mypy that referenced this issue Jan 12, 2017
Previously, `get` would simply fallback to the type of the underlying dictionary which made
TypedDicts hard to use with code that's parsing objects where fields may or may not be
present (for example, parsing a response).

This implementation _explicitly_ ignores the default parameter's type as it's quite useful to
chain together get calls (Until something like PEP 505 hits 😄)

```python
foo.get('a', {}).get('b', {}).get('c')
```

This fixes python#2612
@gvanrossum gvanrossum assigned JukkaL and unassigned rowillia May 22, 2017
@gvanrossum
Copy link
Member

Jukka wants to redo this using a plugin.

JukkaL added a commit that referenced this issue Jun 7, 2017
…#3501)

Implement a general-purpose way of extending type inference of
methods. Also special case TypedDict get and `int.__pow__`.
Implement a new plugin system that can handle both module-level 
functions and methods.

This an alternative to #2620 by @rowillia. I borrowed some test
cases from that PR. This PR has a few major differences:

* Use the plugin system instead of full special casing.
* Don't support `d.get('x', {})` as it's not type safe. Once we
  have #2632 we can add support for this idiom safely.
* Code like `f = foo.get` loses the special casing for get.

Fixes #2612. Work towards #1240.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants