8000 Add support for namedtuple methods (issue #1076) by elazarg · Pull Request #1810 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Add support for namedtuple methods (issue #1076) #1810

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 85 commits into from
Sep 2, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
ecca142
namedtuple: add (shaky) support for _replace, _asdict + naive test
elazarg Jul 6, 2016
8ef445f
namedtuple: add tests and refine types
elazarg Jul 6, 2016
5e429cd
minor cleanup
elazarg Jul 6, 2016
0214e3c
minor cleanup
elazarg Jul 6, 2016
fbb75c3
flake8-ing
elazarg Jul 6, 2016
17d7f8b
fix type errors
elazarg Jul 6, 2016
6dd370c
fix type errors
elazarg Jul 6, 2016
1370fbf
Merge branch 'namedtuple' of https://github.com/elazarg/mypy into nam…
elazarg Jul 6, 2016
560eb3e
_fields will not be supported
elazarg Jul 6, 2016
2627511
slight refactoring
elazarg Jul 6, 2016
46475d4
restore tests for _replace and _asdict
elazarg Jul 6, 2016
c1dc1c7
NamedTupleTypeInfo
elazarg Jul 9, 2016
763e0c0
run both Replace and AsTuple
elazarg Jul 10, 2016
4b10a35
fix most of the tests
elazarg Jul 10, 2016
ee047f8
complete support for _replace
elazarg Jul 10, 2016
725d53c
flake8-ing
elazarg Jul 10, 2016
044e640
Add partial support for calling '_replace' statically
elazarg Jul 12, 2016
eb6534e
fix method name
elazarg Aug 11, 2016
aa0d5da
namedtuple tests pass. list has problems
elazarg Aug 14, 2016
e12bd01
tests pass. OrderedDict unsupported. cleanup still required
elazarg Aug 14, 2016
dc9d8da
fix line endings
elazarg Aug 14, 2016
158b068
flake8-ing
elazarg Aug 14, 2016
90ffb08
s/self_type/with_fallback. Fix visitor type
elazarg Aug 14, 2016
9a6e6cd
uniform copy_with. typechecks.
elazarg Aug 14, 2016
76d709e
uniform copy_with. typechecks.
elazarg Aug 14, 2016
20bf222
rename tests to startwith NamedTuple
elazarg Aug 15, 2016
a2696c2
Read-only attributes. Can't set new attributes in subclasses yet
elazarg Aug 15, 2016
9e1b866
update semantic namedtuple repr name
elazarg Aug 15, 2016
f7b531f
support _fields
elazarg Aug 15, 2016
67bdafe
support _source. test for unit namedtuple
elazarg Aug 15, 2016
39bce74
support _asdict()->OrderedDict as an UnboundType
elazarg Aug 15, 2016
a2db6a0
minor cleanup
elazarg Aug 15, 2016
8784ce0
support _make and _field_types
elazarg Aug 16, 2016
191de7c
namedtuple: add (shaky) support for _replace, _asdict + naive test
elazarg Jul 6, 2016
6d2d6d1
namedtuple: add tests and refine types
elazarg Jul 6, 2016
8819af9
minor cleanup
elazarg Jul 6, 2016
9fb5137
flake8-ing
elazarg Jul 6, 2016
35c30a2
fix type errors
elazarg Jul 6, 2016
a642a7f
_fields will not be supported
elazarg Jul 6, 2016
c505cbc
slight refactoring
elazarg Jul 6, 2016
9f96ca7
restore tests for _replace and _asdict
elazarg Jul 6, 2016
5c2d3ac
NamedTupleTypeInfo
elazarg Jul 9, 2016
41ed075
run both Replace and AsTuple
elazarg Jul 10, 2016
6dd568f
fix most of the tests
elazarg Jul 10, 2016
b18fc25
complete support for _replace
elazarg Jul 10, 2016
d7dbd3f
flake8-ing
elazarg Jul 10, 2016
2b67380
Add partial support for calling '_replace' statically
elazarg Jul 12, 2016
525c081
fix method name
elazarg Aug 11, 2016
15acfe0
namedtuple tests pass. list has problems
elazarg Aug 14, 2016
fb9ba7f
tests pass. OrderedDict unsupported. cleanup still required
elazarg Aug 14, 2016
99635c5
fix line endings
elazarg Aug 14, 2016
8f61c13
flake8-ing
elazarg Aug 14, 2016
ff21b0c
s/self_type/with_fallback. Fix visitor type
elazarg Aug 14, 2016
4c1bfe4
uniform copy_with. typechecks.
elazarg Aug 14, 2016
b0d78ba
uniform copy_with. typechecks.
elazarg Aug 14, 2016
87c804c
rename tests to startwith NamedTuple
elazarg Aug 15, 2016
6adc2f9
Read-only attributes. Can't set new attributes in subclasses yet
elazarg Aug 15, 2016
7ed7b0e
update semantic namedtuple repr name
elazarg Aug 15, 2016
c7dc9a7
support _fields
elazarg Aug 15, 2016
b39925b
support _source. test for unit namedtuple
elazarg Aug 15, 2016
030307e
support _asdict()->OrderedDict as an UnboundType
elazarg Aug 15, 2016
12d3407
minor cleanup
elazarg Aug 15, 2016
1f944fc
support _make and _field_types
elazarg Aug 16, 2016
7825f79
Merge branch 'namedtuple'
elazarg Aug 16, 2016
8a0ce40
merge upstream
elazarg Aug 16, 2016
7978357
merge fix except Awaitable lookup
elazarg Aug 16, 2016
badc3f9
merge fix
elazarg Aug 16, 2016
c051f3f
Merge remote
elazarg Aug 17, 2016
44c124b
Merge branch 'master' into namedtuple
elazarg Aug 17, 2016
d067c9e
fix syntax error
elazarg Aug 17, 2016
42342de
Merge branch 'master' into namedtuple
elazarg Aug 18, 2016
a5ccc50
join/meet namedtuples as namedtuple only if attrs are equal
elazarg Aug 20, 2016
eaf4b99
join/meet namedtuples as namedtuple only if attrs are equal. add tests.
elazarg Aug 20, 2016
9829b25
Fix conflicts:
elazarg Aug 21, 2016
b1988f8
Merge branch 'master' into namedtuple
elazarg Aug 28, 2016
8ced59e
Merge remote-tracking branch 'upstream/master' into namedtuple
elazarg Aug 28, 2016
053ee56
remove NamedTupleType
elazarg Aug 30, 2016
94bb8d0
Merge remote-tracking branch 'upstream/master' into namedtuple
elazarg Aug 30, 2016
71f0d78
restore semanal test
elazarg Aug 30, 2016
66a77fb
fix signatures
elazarg Sep 1, 2016
922dd91
_asdict() -> Dict
elazarg Sep 1, 2016
6460839
_asdict() -> OrderedDict
elazarg Sep 1, 2016
cd5b933
use buitlins.dict; rearrange build_namedtuple_typeinfo
elazarg Sep 1, 2016
4b93761
Merge remote-tracking branch 'upstream/master' into namedtuple
elazarg Sep 1, 2016
500a847
remove unneeded 'class dict' from proprty.pyi
elazarg Sep 1, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix signatures
  • Loading branch information
elazarg committed Sep 1, 2016
commit 66a77fba8602494c0117928047040a5f99a2bf13
5 changes: 3 additions & 2 deletions mypy/join.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,9 @@ def visit_tuple_type(self, t: TupleType) -> Type:
items = [] # type: List[Type]
for i in range(t.length()):
items.append(self.join(t.items[i], self.s.items[i]))
# TODO: What if the fallback types are different?
return TupleType(items, t.fallback)
# join fallback types if they are different
from typing import cast
return TupleType(items, cast(Instance, join_instances(self.s.fallback, t.fallback)))
else:
return self.default(self.s)

Expand Down
4 changes: 2 additions & 2 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2027,8 +2027,8 @@ def deserialize(cls, data: JsonDict) -> 'TypeInfo':
return ti


def namedtuple_type_info(tup: 'mypy.types.TupleType', *args) -> TypeInfo:
info = TypeInfo(*args)
def namedtuple_type_info(tup: 'mypy.types.TupleType', names: 'SymbolTable', defn: ClassDef) -> TypeInfo:
info = TypeInfo(names, defn)
info.tuple_type = tup
info.bases = [tup.fallback]
info.is_named_tuple = True
Expand Down
76 changes: 39 additions & 37 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@
traverse the entire AST.
"""

from functools import partial

import sys
from typing import (
List, Dict, Set, Tuple, cast, Any, TypeVar, Union, Optional, Callable
)
Expand All @@ -62,7 +59,7 @@
SymbolTableNode, BOUND_TVAR, UNBOUND_TVAR, ListComprehension, GeneratorExpr,
FuncExpr, MDEF, FuncBase, Decorator, SetExpr, TypeVarExpr, NewTypeExpr,
StrExpr, BytesExpr, PrintStmt, ConditionalExpr, PromoteExpr,
ComparisonExpr, StarExpr, ARG_POS, ARG_NAMED, ARG_OPT, MroError, type_aliases,
ComparisonExpr, StarExpr, ARG_POS, ARG_NAMED, MroError, type_aliases,
YieldFromExpr, NamedTupleExpr, NonlocalDecl,
SetComprehension, DictionaryComprehension, TYPE_ALIAS, TypeAliasExpr,
YieldExpr, ExecStmt, Argument, BackquoteExpr, ImportBase, AwaitExpr,
Expand All @@ -75,9 +72,8 @@
from mypy.errors import Errors, report_internal_error
from mypy.types import (
NoneTyp, CallableType, Overloaded, Instance, Type, TypeVarType, AnyType,
FunctionLike, UnboundType, TypeList, TypeVarDef, Void,
replace_leading_arg_type, TupleType, UnionType, StarType, EllipsisType
)
FunctionLike, UnboundType, TypeList, TypeVarDef,
replace_leading_arg_type, TupleType, UnionType, StarType, EllipsisType, TypeType)
from mypy.nodes import function_type, implicit_module_attrs
from mypy.typeanal import TypeAnalyser, TypeAnalyserPass3, analyze_type_alias
from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError
Expand Down Expand Up @@ -319,9 +315,8 @@ def visit_func_def(self, defn: FuncDef) -> None:
# A coroutine defined as `async def foo(...) -> T: ...`
# has external return type `Awaitable[T]`.
defn.type = defn.type.copy_modified(
ret_type=Instance(
self.named_type_or_none('typing.Awaitable').type,
[defn.type.ret_type]))
ret_type=self.external_instance('typing.Awaitable',
[defn.type.ret_type]))
self.errors.pop_function()

def prepare_method_signature(self, func: FuncDef) -> None:
Expand Down Expand Up @@ -874,6 +869,9 @@ def named_type_or_none(self, qualified_name: str) -> Instance:
return None
return Instance(cast(TypeInfo, sym.node), [])

def external_instance(self, qualified_name: str, args: List[Type] = None) -> Instance:
return Instance(self.named_type_or_none(qualified_name).type, args or None)
Copy link
Collaborator

Choose a reason for hiding this comment

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

The second argument shouldn't be None -- it should be an empty list if there are no arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops.


def is_instance_type(self, t: Type) -> bool:
return isinstance(t, Instance)

Expand Down Expand Up @@ -1642,7 +1640,7 @@ def parse_namedtuple_args(self, call: CallExpr,
if (fullname == 'collections.namedtuple'
and isinstance(args[1], (StrExpr, BytesExpr, UnicodeExpr))):
str_expr = cast(StrExpr, args[1])
items = str_expr.value.split()
items = str_expr.value.replace(',', ' ').split()
else:
return self.fail_namedtuple_arg(
"List literal expected as the second argument to namedtuple()", call)
Expand Down Expand Up @@ -1696,51 +1694,53 @@ def build_namedtuple_typeinfo(self, name: str, items: List[str],
tup = TupleType(types, self.named_type('__builtins__.tuple', types))
class_def = ClassDef(name, Block([]))
class_def.fullname = self.qualified_name(name)

info = namedtuple_type_info(tup, symbols, class_def)

vars = [Var(item, typ) for item, typ in zip(items, types)]
this_type = self_type(info)
add_field = partial(self.add_namedtuple_field, symbols, info)
strtype = self.named_type('__builtins__.str')
strtype = self.named_type('__builtins__.str') # type: Type

def add_field(var: Var, is_initialized_in_class: bool = False,
is_property: bool = False) -> None:
var.info = info
var.is_initialized_in_class = is_initialized_in_class
var.is_property = is_property
symbols[var.name()] = SymbolTableNode(MDEF, var)

for var in vars:
add_field(var, is_property=True)

tuple_of_strings = TupleType([strtype for _ in items],
self.named_type('__builtins__.tuple', [AnyType()]))
add_field(Var('_fields', tuple_of_strings),
is_initialized_in_class=True)
add_field(Var('_field_types', UnboundType('Dict', [strtype, AnyType()])),
is_initialized_in_class=True)
add_field(Var('_source', strtype),
is_initialized_in_class=True)

add_method = partial(self.add_namedtuple_method, symbols, info, this_type)
# TODO: refine type of values
dictype = self.external_instance('typing.Dict', [strtype, AnyType()])
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should probably be builtins.dict. Internally the type is defined in builtins and typing only has an alias.

add_field(Var('_fields', tuple_of_strings), is_initialized_in_class=True)
add_field(Var('_field_types', dictype), is_initialized_in_class=True)
add_field(Var('_source', strtype), is_initialized_in_class=True)

def add_method(funcname: str, ret: Type, args: List[Argument], name=None,
is_classmethod=False) -> None:
self.add_namedtuple_method(symbols, info, this_type,
funcname, ret, args, name, is_classmethod)

add_method('_replace', ret=this_type,
args=self.factory_args(vars, ARG_NAMED, initializer=EllipsisExpr()))
add_method('__init__', ret=NoneTyp(),
args=self.factory_args(vars, ARG_POS), name=info.name())
# TODO: refine to OrderedDict[str, Union[types]]
add_method('_asdict', ret=UnboundType('collections.OrderedDict', is_ret_type=True),
args=[])

# TODO: refine signature
union = UnboundType('Iterable', [UnionType(types)])
# actual signature should return OrderedDict[str, Union[types]]
dictype = self.external_instance('typing.OrderedDict', [strtype, AnyType()])
add_method('_asdict', args=[], ret=dictype)

# note: actual signature should accept an invariant version of Iterable[UnionType[types]].
# but it can't be expressed
# 'new' and 'len' as function types.
iterable_type = self.external_instance('typing.Iterable', [AnyType()])
add_method('_make', ret=this_type, is_classmethod=True,
args=[Argument(Var('iterable', union), union, None, ARG_POS),
args=[Argument(Var('iterable', iterable_type), iterable_type, None, ARG_POS),
Argument(Var('new'), AnyType(), EllipsisExpr(), ARG_NAMED),
Argument(Var('len'), AnyType(), EllipsisExpr(), ARG_NAMED)])
return info

def add_namedtuple_field(self, symbols: SymbolTable, info: TypeInfo, var: Var,
is_initialized_in_class: bool = False,
is_property: bool = False) -> None:
var.info = info
var.is_initialized_in_class = is_initialized_in_class
var.is_property = is_property
symbols[var.name()] = SymbolTableNode(MDEF, var)

def factory_args(self, vars: List[Var], kind: int,
initializer: Expression = None) -> List[Argument]:
return [Argument(var, var.type, initializer, kind) for var in vars]
Expand Down Expand Up @@ -2511,6 +2511,8 @@ def fail(self, msg: str, ctx: Context, serious: bool = False, *,
self.function_stack and
self.function_stack[-1].is_dynamic()):
return
# In case it's a bug and we don't really have context
assert ctx is not None, msg
self.errors.report(ctx.get_line(), msg, blocker=blocker)

def fail_blocker(self, msg: str, ctx: Context) -> None:
Expand Down
Loading
0