Skip to content

Implement class syntax for TypedDict - #2808

Merged
JukkaL merged 5 commits into
python:masterfrom
ilevkivskyi:class-typeddict
Feb 7, 2017
Merged

JukkaL merged 5 commits into
python:masterfrom
ilevkivskyi:class-typeddict

Conversation

@ilevkivskyi

Copy link
Copy Markdown
Member

Fixes #2740

This allows the following:

class Point(TypedDict):
    x: int
    y: int
class Label(TypedDict):
    label: str

class LabeledPoint3D(Point, Label):
    z: int

p: Point
p3D = LabeledPoint3D(x=1, y=2, z=42, label='Good point!')

(Side note: I spent an hour figuring out what are anonymous and named TypedDict's, maybe better call them explicit/implicit, or explicit/ihferred, if I understood them correctly?)

@JukkaL JukkaL left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the PR! Looks good, just some minor things:

Comment thread mypy/semanal.py Outdated
if any(not isinstance(expr, RefExpr) or
expr.fullname != 'mypy_extensions.TypedDict' and
not self.is_typeddict(expr) for expr in defn.base_type_exprs):
self.fail("All bases of a new TypedDict must be TypedDict's", defn)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Grammar nit: Replace TypedDict's with TypedDict types or similar.

Comment thread mypy/semanal.py Outdated
tpdict = None # type: OrderedDict[str, Type]
for base in typeddict_bases:
# mypy doesn't yet understand predicates like is_typeddict
tpdict = base.node.typeddict_type.items # type: ignore

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'd recommend using a cast instead of # type: ignore, since it's more specific about where mypy gets confused.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It required me three casts to convince mypy that everything is OK and it became unreadable, I used asserts instead.

Comment thread mypy/semanal.py Outdated
else:
name = stmt.lvalues[0].name
if name in (oldfields or []):
self.fail('Cannot overwrite TypedDict field {} while extending'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Use double quotes around field name (e.g., ... TypedDict field "x" ...).

# flags: --python-version 3.6
from mypy_extensions import TypedDict

class Point1(TypedDict):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Add test case for duplicate fields within a single definition. Example:

class Bad(TypedDict):
    x: int
    x: int

Comment thread mypy/semanal.py
fields.append(name)
types.append(AnyType() if stmt.type is None else self.anal_type(stmt.type))
# ...despite possible minor failures that allow further analyzis.
if name.startswith('_'):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why not allow fields starting with underscores? Existing JSON data may use underscore prefixes, I think.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I agree this is probably an unnecessary limitation (I copied it from the functional form, and that one probably copied it from namedtuple). Maybe it is worth making a separate PR removing this limitation from both forms?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

That sounds reasonable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The no-underscore-prefix limitation allows extending the syntax of the functional form with new keywords in the future if it becomes useful.

I believe the no-underscore-prefix limitation for namedtuples used a similar rationale.

@ilevkivskyi

Copy link
Copy Markdown
Member Author

@JukkaL Thank you for review! I implemented changes in a new commit.

@JukkaL

JukkaL commented Feb 7, 2017

Copy link
Copy Markdown
Collaborator

Thank you!

@JukkaL
JukkaL merged commit 88ceec0 into python:master Feb 7, 2017
JukkaL pushed a commit that referenced this pull request Mar 6, 2017
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.

3 participants