From 225ec69471dcad7443ec99ccefd911b06b00d665 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 23 Sep 2021 10:46:28 +0300 Subject: [PATCH 01/13] WIP: adds better `namedtuple` semantic analyzer, refs #11047 --- docs/source/error_code_list.rst | 2 +- mypy/checkexpr.py | 2 + mypy/nodes.py | 9 +- mypy/semanal.py | 6 +- mypy/semanal_namedtuple.py | 581 ++++++++++++++++----- test-data/unit/check-errorcodes.test | 2 +- test-data/unit/check-incremental.test | 8 +- test-data/unit/check-namedtuple.test | 12 +- test-data/unit/semanal-namedtuple.test | 694 +++++++++++++++++++++++-- 9 files changed, 1131 insertions(+), 185 deletions(-) diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index 852913ce79bb..e07dd8f705e1 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -654,7 +654,7 @@ consistently when using the call-based syntax. Example: from typing import NamedTuple - # Error: First argument to namedtuple() should be "Point2D", not "Point" + # Error: First argument to "NamedTuple()" should be "Point2D", not "Point" Point2D = NamedTuple("Point", [("x", int), ("y", int)]) Report syntax errors [syntax] diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index c58707519436..2be951abb05c 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4181,6 +4181,8 @@ def visit_newtype_expr(self, e: NewTypeExpr) -> Type: return AnyType(TypeOfAny.special_form) def visit_namedtuple_expr(self, e: NamedTupleExpr) -> Type: + if e.call: + self.accept(e.call) tuple_type = e.info.tuple_type if tuple_type: if (self.chk.options.disallow_any_unimported and diff --git a/mypy/nodes.py b/mypy/nodes.py index 98c3582bb5c2..0d02c8e96b45 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2310,11 +2310,18 @@ class NamedTupleExpr(Expression): # The class representation of this named tuple (its tuple_type attribute contains # the tuple item types) info: "TypeInfo" + # We store original expr, if named tuple was created by an inline-call. + # We construct it during "semanal" phase and + # use it to type check that call is valid during "check" phase. + call: Optional[CallExpr] is_typed: bool # whether this class was created with typing.NamedTuple - def __init__(self, info: 'TypeInfo', is_typed: bool = False) -> None: + def __init__(self, info: 'TypeInfo', + call: Optional[CallExpr] = None, + is_typed: bool = False) -> None: super().__init__() self.info = info + self.call = call self.is_typed = is_typed def accept(self, visitor: ExpressionVisitor[T]) -> T: diff --git a/mypy/semanal.py b/mypy/semanal.py index 21741f90a528..c403385f5277 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2295,12 +2295,8 @@ def analyze_namedtuple_assign(self, s: AssignmentStmt) -> bool: if internal_name is None: return False if isinstance(lvalue, MemberExpr): - self.fail("NamedTuple type as an attribute is not supported", lvalue) + self.fail('Namedtuples as attributes are not supported', lvalue) return False - if internal_name != name: - self.fail('First argument to namedtuple() should be "{}", not "{}"'.format( - name, internal_name), s.rvalue, code=codes.NAME_MATCH) - return True # Yes, it's a valid namedtuple, but defer if it is not ready. if not info: self.mark_incomplete(name, lvalue, becomes_typeinfo=True) diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index 8930c63d2bef..f6be50373e7f 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -3,13 +3,17 @@ This is conceptually part of mypy.semanal. """ +import enum +from copy import copy from contextlib import contextmanager +from keyword import iskeyword from typing import Tuple, List, Dict, Mapping, Optional, Union, cast, Iterator from typing_extensions import Final +from mypy import errorcodes as codes from mypy.types import ( Type, TupleType, AnyType, TypeOfAny, CallableType, TypeType, TypeVarType, - UnboundType, + UnboundType, NoneType, TypeList, UninhabitedType, get_proper_type, ) from mypy.semanal_shared import ( SemanticAnalyzerInterface, set_callable_name, calculate_tuple_fallback, PRIORITY_FALLBACKS @@ -18,7 +22,8 @@ Var, EllipsisExpr, Argument, StrExpr, BytesExpr, UnicodeExpr, ExpressionStmt, NameExpr, AssignmentStmt, PassStmt, Decorator, FuncBase, ClassDef, Expression, RefExpr, TypeInfo, NamedTupleExpr, CallExpr, Context, TupleExpr, ListExpr, SymbolTableNode, FuncDef, Block, - TempNode, SymbolTable, TypeVarExpr, ARG_POS, ARG_NAMED_OPT, ARG_OPT, MDEF + TempNode, SymbolTable, TypeVarExpr, + ArgKind, ARG_POS, ARG_NAMED, ARG_NAMED_OPT, ARG_OPT, MDEF, ) from mypy.options import Options from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError @@ -47,6 +52,15 @@ SELF_TVAR_NAME: Final = "_NT" +# Type alias for inner structure of NamedTuple type. +NamedTupleStructure = Optional[Tuple[ + List[str], + List[Type], + List[Expression], + str, + bool, +]] + class NamedTupleAnalyzer: def __init__(self, options: Options, api: SemanticAnalyzerInterface) -> None: @@ -176,10 +190,9 @@ def check_namedtuple(self, is_typed = True else: return None, None - result = self.parse_namedtuple_args(call, fullname) - if result: - items, types, defaults, typename, ok = result - else: + + result = self.parse_namedtuple_args(call, fullname, var_name) + if result is None: # Error. Construct dummy return value. if var_name: name = var_name @@ -188,6 +201,8 @@ def check_namedtuple(self, info = self.build_namedtuple_typeinfo(name, [], [], {}, node.line) self.store_namedtuple_info(info, name, call, is_typed) return name, info + + items, types, defaults, typename, ok = result if not ok: # This is a valid named tuple but some types are not ready. return typename, None @@ -245,138 +260,22 @@ def check_namedtuple(self, def store_namedtuple_info(self, info: TypeInfo, name: str, call: CallExpr, is_typed: bool) -> None: self.api.add_symbol(name, info, call) - call.analyzed = NamedTupleExpr(info, is_typed=is_typed) - call.analyzed.set_line(call.line, call.column) - def parse_namedtuple_args(self, call: CallExpr, fullname: str - ) -> Optional[Tuple[List[str], List[Type], List[Expression], - str, bool]]: - """Parse a namedtuple() call into data needed to construct a type. + # We need a copy of `CallExpr` node without `analyzed` type + # to show better error messages of invalid namedtuple calls. + # Without this hack we would need to create errors manually in semanal. + # Which is hard and inconsistent with how other errors are shown. + # But, with this hack we just inspect the call with typechecker: + # this way we can be 100% everything is correct. + call_copy = copy(call) + call.analyzed = NamedTupleExpr(info, call=call_copy, is_typed=is_typed) + call.analyzed.set_line(call.line, call.column) - Returns a 5-tuple: - - List of argument names - - List of argument types - - List of default values - - First argument of namedtuple - - Whether all types are ready. - - Return None if the definition didn't typecheck. - """ - type_name = 'NamedTuple' if fullname == 'typing.NamedTuple' else 'namedtuple' - # TODO: Share code with check_argument_count in checkexpr.py? - args = call.args - if len(args) < 2: - self.fail('Too few arguments for "{}()"'.format(type_name), call) - return None - defaults: List[Expression] = [] - if len(args) > 2: - # Typed namedtuple doesn't support additional arguments. - if fullname == 'typing.NamedTuple': - self.fail('Too many arguments for "NamedTuple()"', call) - return None - for i, arg_name in enumerate(call.arg_names[2:], 2): - if arg_name == 'defaults': - arg = args[i] - # We don't care what the values are, as long as the argument is an iterable - # and we can count how many defaults there are. - if isinstance(arg, (ListExpr, TupleExpr)): - defaults = list(arg.items) - else: - self.fail( - "List or tuple literal expected as the defaults argument to " - "{}()".format(type_name), - arg - ) - break - if call.arg_kinds[:2] != [ARG_POS, ARG_POS]: - self.fail('Unexpected arguments to "{}()"'.format(type_name), call) - return None - if not isinstance(args[0], (StrExpr, BytesExpr, UnicodeExpr)): - self.fail( - '"{}()" expects a string literal as the first argument'.format(type_name), call) - return None - typename = cast(Union[StrExpr, BytesExpr, UnicodeExpr], call.args[0]).value - types: List[Type] = [] - if not isinstance(args[1], (ListExpr, TupleExpr)): - if (fullname == 'collections.namedtuple' - and isinstance(args[1], (StrExpr, BytesExpr, UnicodeExpr))): - str_expr = args[1] - items = str_expr.value.replace(',', ' ').split() - else: - self.fail( - 'List or tuple literal expected as the second argument to "{}()"'.format( - type_name, - ), - call, - ) - return None - else: - listexpr = args[1] - if fullname == 'collections.namedtuple': - # The fields argument contains just names, with implicit Any types. - if any(not isinstance(item, (StrExpr, BytesExpr, UnicodeExpr)) - for item in listexpr.items): - self.fail('String literal expected as "namedtuple()" item', call) - return None - items = [cast(Union[StrExpr, BytesExpr, UnicodeExpr], item).value - for item in listexpr.items] - else: - # The fields argument contains (name, type) tuples. - result = self.parse_namedtuple_fields_with_types(listexpr.items, call) - if result is None: - # One of the types is not ready, defer. - return None - items, types, _, ok = result - if not ok: - return [], [], [], typename, False - if not types: - types = [AnyType(TypeOfAny.unannotated) for _ in items] - underscore = [item for item in items if item.startswith('_')] - if underscore: - self.fail('"{}()" field names cannot start with an underscore: '.format(type_name) - + ', '.join(underscore), call) - if len(defaults) > len(items): - self.fail('Too many defaults given in call to "{}()"'.format(type_name), call) - defaults = defaults[:len(items)] - return items, types, defaults, typename, True - - def parse_namedtuple_fields_with_types(self, nodes: List[Expression], context: Context - ) -> Optional[Tuple[List[str], List[Type], - List[Expression], bool]]: - """Parse typed named tuple fields. - - Return (names, types, defaults, whether types are all ready), or None if error occurred. - """ - items: List[str] = [] - types: List[Type] = [] - for item in nodes: - if isinstance(item, TupleExpr): - if len(item.items) != 2: - self.fail('Invalid "NamedTuple()" field definition', item) - return None - name, type_node = item.items - if isinstance(name, (StrExpr, BytesExpr, UnicodeExpr)): - items.append(name.value) - else: - self.fail('Invalid "NamedTuple()" field name', item) - return None - try: - type = expr_to_unanalyzed_type(type_node, self.options, self.api.is_stub_file) - except TypeTranslationError: - self.fail('Invalid field type', type_node) - return None - analyzed = self.api.anal_type(type) - # Workaround #4987 and avoid introducing a bogus UnboundType - if isinstance(analyzed, UnboundType): - analyzed = AnyType(TypeOfAny.from_error) - # These should be all known, otherwise we would defer in visit_assignment_stmt(). - if analyzed is None: - return [], [], [], False - types.append(analyzed) - else: - self.fail('Tuple expected as "NamedTuple()" field', item) - return None - return items, types, [], True + def parse_namedtuple_args(self, call: CallExpr, + fullname: str, var_name: Optional[str]) -> NamedTupleStructure: + """Parse a namedtuple() call into data needed to construct a type.""" + call_analyzer = NamedTupleCallAnalyzer(self.options, self.api, call, fullname, var_name) + return call_analyzer.parse_structure() def build_namedtuple_typeinfo(self, name: str, @@ -548,3 +447,413 @@ def save_namedtuple_body(self, named_tuple_info: TypeInfo) -> Iterator[None]: def fail(self, msg: str, ctx: Context) -> None: self.api.fail(msg, ctx) + + +class NamedTupleCallAnalyzer: + """ + Analyzes ``namedtuple()`` and ``NamedTuple()`` calls. + + Our single public ``parse_structure`` method returns a 5-tuple: + - List of argument names + - List of argument types + - List of default values + - First argument of namedtuple + - Whether all types are ready. + + Returns ``None`` if the definition didn't typecheck. + """ + + # TODO: str type for python2 / python3 + # TODO: test `NamedTuple('N')` without assignment + + def __init__(self, options: Options, api: SemanticAnalyzerInterface, + call: CallExpr, fullname: str, var_name: Optional[str]) -> None: + self._options = options + self._api = api + self._call = call + self._var_name = var_name + self._fullname = fullname + self._shortname = 'NamedTuple' if fullname == 'typing.NamedTuple' else 'namedtuple' + + @property + def _args(self) -> List[Expression]: + return self._call.args + + @property + def _kinds(self) -> List[ArgKind]: + return self._call.arg_kinds + + @property + def _names(self) -> List[Optional[str]]: + return self._call.arg_names + + def _fail( + self, + msg: str, + context: Optional[Context] = None, + code: Optional[codes.ErrorCode] = None, + ) -> None: + """Raises error in semantic analyzer. + + But, the most important question is: when do we raise errors? + + Let's start from when we **do not** raise errors: + - When we got incorrect types / arguments names. + We use typechecker to analyze the original call, + so, we don't need to replicate its features. + We would have this covered. + - When we can recover from error, no need to raise false-positives. + + So, our main task here is to raise errors when non-literal values are used. + It won't be covered by type-checker, but without literal values, + we cannot construct a valid namedtuple. + + For example, both these cases are fine from typechecker's perspective: + 1. ``namedtuple('N', field_names=['a', 'b', 'c'], rename=False)`` + 2. ``namedtuple('N', field_names=field_names_var, rename=rename)`` + + We can analyze the first one, but we cannot analyze the second one. + That's why we need to raises semanal errors there. + """ + self._api.fail(msg, context or self._call, code=code) + + def parse_structure(self) -> NamedTupleStructure: + if not self._args: + return None # We need at least a `typename` + + typename = self._parse_typename() + if typename is None: + return None # Typename is invalid: not literal str or wrong kw-name + + if len(self._args) == 1: + # Empty named tuple definition + return self._validate_fields([], [], [], typename) + + if self._fullname == 'typing.NamedTuple': + return self._parse_typing_namedtuple(typename) + elif self._fullname == 'collections.namedtuple': + return self._parse_collections_namedtuple(typename) + # Should not happen: + raise ValueError('Got unexpected type {}'.format(self._fullname)) + + def _parse_typename(self) -> Optional[str]: + typename_index = self._find_name_index('typename') + + arg: Optional[Expression] = None + if typename_index is not None: # Named argument + if not self._kinds[typename_index].is_named(): + return None + arg = self._args[typename_index] + elif self._kinds[0].is_positional(): # Positional + arg = self._args[0] + if not isinstance(arg, StrExpr): + self._fail( + f'"{self._shortname}()" expects a string literal ' + 'as the typename argument', + arg, + ) + return None + return self._validate_typename(arg.value) + + def _parse_typing_namedtuple(self, typename: str) -> NamedTupleStructure: + """Parsing ``typing.NamedTuple()`` call. + + In all of the examples below arguments can be named or positional. + + Possible valid cases: + 1. ``N = NamedTuple('N')`` - empty namedtuple + 2. ``N = NamedTuple('N', [('a', int)])`` + 3. ``N = NamedTuple(typename='N', fields=(('a', int),))`` or ``fields=[]`` + 4. ``N = NamedTuple('N', a=int)`` with kwargs + + Corner cases, but still valid: + 7. ``N = NamedTuple('N', ())``, - empty namedtuple, + we also count ``[]`` here, ``fields`` can be named or positional + 6. ``N = NamedTuple('N', fields=None, a=int)``, + in this case ``fields`` will not be present as a namedtuple field + 7. ``N = NamedTuple('N', None, a=int)`` + 8. ``N = NamedTuple(a=int, typename='N')`` + kw-arguments can be in a different order, that's fine + + Everything else is considered **invalid**. + We only accept statically known types. + """ + fields_arg_index = self._find_name_index('fields') + fields_is_named = fields_arg_index is not None + + if fields_arg_index is None and self._kinds[1].is_positional(): + fields_arg_index = 1 # Positional `fields` argument + if fields_arg_index is None: + return self._typing_namedtuple_from_kwargs(typename) + + assert isinstance(fields_arg_index, int) + return self._typing_namedtuple_from_fields( + typename, fields_arg_index, is_named=fields_is_named, + ) + + def _typing_namedtuple_from_fields( + self, typename: str, fields_arg_index: int, *, is_named: bool, + ) -> NamedTupleStructure: + fields_arg = self._args[fields_arg_index] + + if ( + isinstance(fields_arg, NameExpr) + and fields_arg.name == 'None' + and (is_named or self._kinds[fields_arg_index].is_positional()) + ): + # Named `fields` argument still can be `None`, that's fine. + # This can happen in a case like `NamedTuple('N', fields=None, a=int)` + # We need to try the kwargs. + return self._typing_namedtuple_from_kwargs(typename) + + if not isinstance(fields_arg, (TupleExpr, ListExpr)): + self._fail( + 'List or tuple literal expected as the fields argument' + f'to "{self._shortname}()"', + fields_arg, + ) + return None + if self._args[2:]: + # We only can have `fields` or `kwargs`. + # `fields` was provided, we expect no more arguments. + return None + + names = [] + types = [] + for item in fields_arg.items: + if not isinstance(item, TupleExpr) or len(item.items) != 2: + self._fail(f'Invalid "{self._shortname}" field definition', item) + return None + + name, type_node = item.items + if not isinstance(name, StrExpr): + self._fail(f'Invalid "{self._shortname}" field name', item) + return None + + names.append(name.value) + field_type = self._analyze_type(type_node) + if field_type is None: + return [], [], [], typename, False # Type is not ready, defer. + types.append(field_type) + return self._validate_fields(names, types, [], typename) + + def _typing_namedtuple_from_kwargs(self, typename: str) -> NamedTupleStructure: + names: List[str] = [] + types = [] + for index, (name, kind) in enumerate(zip(self._names, self._kinds)): + if kind.is_named() and name in ('fields', 'typename'): + # We can have named `fields` or `typename` argument in + # `NamedTuple(..., typename='N', ..., fields=None, ...)` + # It can happen at any position. We just ignore it. + continue + + current_arg = self._args[index] + + if ( + index == 1 + and kind.is_positional() + and isinstance(current_arg, NameExpr) + and current_arg.name == 'None' + ): + # We can have positional `None` as in `NamedTuple('N', None, ...)` + continue + + if not kind.is_named(): + if index > 1: + return None + continue + + field_type = self._analyze_type(current_arg) + if field_type is None: + return [], [], [], typename, False # Type is not ready, defer. + + name = self._names[index] + assert isinstance(name, str) + names.append(name) + types.append(field_type) + return self._validate_fields(names, types, [], typename) + + def _parse_collections_namedtuple(self, typename: str) -> NamedTupleStructure: + """Parsing ``collections.namedtuple()`` call. + + In all of the examples below arguments can be named or positional. + + Possible valid cases: + 1. ``N = namedtuple('N')`` - empty named tuple + 2. ``N = namedtuple('N', 'a,b')`` - fields defined as a string + 3. ``N = namedtuple('N', ['a', 'b'])`` - tuple / list of str fields + 4. ``N = namedtuple(typename='N', field_names=['a'])`` + + Corner cases, but still valid: + 5. ``N = namedtuple(field_names=['a'], typename='N')`` + kw-arguments can be in a different order, that's fine + 6. ``N = namedtuple('N', (), defaults=[], rename=True)`` + + We also make use of optional kw-only + ``defaults: None | list[Expression] | tuple[Expression, ...]`` + argument to tell which arguments + are required and which one have defaults. + + We currently support, but do nothing + for these kw-only arguments: ``rename=False, module=None``. + """ + field_names_index = self._find_name_index('field_names') + + # There are two options: + # 1. `field_names` is named: it can have any index in the call expr + # 2. `field_names` is positional: only `1` index, after `typename` + if field_names_index is None and self._kinds[1].is_positional(): + field_names_index = 1 + + if field_names_index is None: + return None + + field_names_arg = self._args[field_names_index] + names: List[str] = [] + + # `field_names` can be: comma-separated `str`, `list[str]`, or `tuple[str]` + if isinstance(field_names_arg, (TupleExpr, ListExpr)): + for item in field_names_arg.items: + if not isinstance(item, StrExpr): + self._fail( + f'String literal expected as "{self._shortname}()" field', + item, + ) + return None + names.append(item.value) + elif isinstance(field_names_arg, StrExpr): + names = [ + field.strip() + for field in field_names_arg.value.replace(',', ' ').split() + ] + else: + self._fail( + 'String, list or tuple literal expected as the field_names argument' + f'to "{self._shortname}()"', + field_names_arg, + ) + return None + + # Types are always `Any` for `collections.namedtuple`. + types: List[Type] = [ + AnyType(TypeOfAny.implementation_artifact) + for _ in range(len(names)) + ] + + # `defaults` is always a kw-only argument, it might be invalid though. + # We only understand list and tuple expressions. + defaults_index = self._find_name_index('defaults') + if defaults_index is not None: + defaults_arg = self._args[defaults_index] + if not isinstance(defaults_arg, (TupleExpr, ListExpr)): + self._fail( + 'List or tuple literal expected as the defaults argument ' + f'to "{self._shortname}()"', + defaults_arg, + ) + return None + defaults = list(defaults_arg.items) + else: + defaults = [] + + # `rename` is always kw-only, it changes invalid field names if passed. + # We only understand literal bool values. + rename_index = self._find_name_index('rename') + if rename_index is not None: + rename_arg = self._args[rename_index] + if not isinstance(rename_arg, NameExpr) or rename_arg.name not in ('True', 'False'): + self._fail( + 'Bool literal expected as the rename argument ' + f'to "{self._shortname}()"', + rename_arg, + ) + return None + rename = rename_arg.name == 'True' + else: + rename = False + + return self._validate_fields(names, types, defaults, typename, rename=rename) + + def _validate_typename(self, typename: Optional[str]) -> Optional[str]: + if self._var_name is not None and typename != self._var_name: + self._fail('First argument to "{}()" should be "{}", not "{}"'.format( + self._shortname, self._var_name, typename, + ), self._call, code=codes.NAME_MATCH) + # We don't stop at this error, maybe there are other ones? + return typename + return typename + + def _validate_fields( + self, + field_names: List[str], types: List[Type], + defaults: List[Expression], typename: str, *, + rename: bool = False, + ) -> NamedTupleStructure: + # We follow the same error order as in `collections.namedtuple()`, + # we also use the same error messages. + # The only difference is that we try to raise as many as possible, + # instead of failing on the first encountered error. + # We also don't type check argument types here. + is_valid = True + + if rename: + seen = set() + for index, name in enumerate(field_names): + if (not name.isidentifier() + or iskeyword(name) + or name.startswith('_') + or name in seen): + field_names[index] = f'_{index}' + seen.add(name) + + for name in [typename] + field_names: + if not name.isidentifier(): + self._fail('Type names and field names must be valid ' + f'identifiers: {name!r}') + is_valid = False + if iskeyword(name): + self._fail('Type names and field names cannot be a ' + f'keyword: {name!r}') + is_valid = False + + seen = set() + for name in field_names: + if name.startswith('_') and not rename: + self._fail(f'Field names cannot start with an underscore: {name!r}') + is_valid = False + if name in seen: + self._fail(f'Encountered duplicate field name: {name!r}') + is_valid = False + seen.add(name) + + if len(defaults) > len(field_names): + self._fail('Got more default values than field names') + is_valid = False + + if not is_valid: + return None + return field_names, types, defaults, typename, True + + def _find_name_index(self, name: str) -> Optional[int]: + try: + index = self._names.index(name) + except ValueError: + return None + assert self._kinds[index].is_named() # Sanity check + return index + + def _analyze_type(self, type_node: Expression) -> Optional[Type]: + try: + typ = expr_to_unanalyzed_type( + type_node, self._options, self._api.is_stub_file, + ) + except TypeTranslationError: + return None + + analyzed = self._api.anal_type(typ) + # Workaround #4987 and avoid introducing a bogus UnboundType + if isinstance(analyzed, UnboundType): + analyzed = AnyType(TypeOfAny.from_error) + # These should be all known, + # otherwise we would defer in visit_assignment_stmt(). + return analyzed diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 04a895d95638..0eb73f58b55a 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -838,7 +838,7 @@ k = [x for x in lst if isinstance(x, int) or foo()] # E: If condition in compre [case testNamedTupleNameMismatch] from typing import NamedTuple -Foo = NamedTuple("Bar", []) # E: First argument to namedtuple() should be "Foo", not "Bar" [name-match] +Foo = NamedTuple("Bar", []) # E: First argument to "NamedTuple()" should be "Foo", not "Bar" [name-match] [builtins fixtures/tuple.pyi] [case testTypedDictNameMismatch] diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 1d2262ab303d..0e3e1966cfdb 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -5121,9 +5121,9 @@ from typing import NamedTuple NT = NamedTuple('BadName', [('x', int)]) [builtins fixtures/tuple.pyi] [out] -tmp/b.py:2: error: First argument to namedtuple() should be "NT", not "BadName" +tmp/b.py:2: error: First argument to "NamedTuple()" should be "NT", not "BadName" [out2] -tmp/b.py:2: error: First argument to namedtuple() should be "NT", not "BadName" +tmp/b.py:2: error: First argument to "NamedTuple()" should be "NT", not "BadName" tmp/a.py:3: note: Revealed type is "Tuple[builtins.int, fallback=b.NT]" [case testNewAnalyzerIncrementalBrokenNamedTupleNested] @@ -5143,9 +5143,9 @@ def test() -> None: NT = namedtuple('BadName', ['x', 'y']) [builtins fixtures/list.pyi] [out] -tmp/b.py:4: error: First argument to namedtuple() should be "NT", not "BadName" +tmp/b.py:4: error: First argument to "namedtuple()" should be "NT", not "BadName" [out2] -tmp/b.py:4: error: First argument to namedtuple() should be "NT", not "BadName" +tmp/b.py:4: error: First argument to "namedtuple()" should be "NT", not "BadName" [case testNewAnalyzerIncrementalMethodNamedTuple] diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 1e531109d5ca..7879b08e5a01 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -163,7 +163,7 @@ X(0, 1) # ok X(0, 1, 2) # E: Too many arguments for "X" Y = namedtuple('Y', ['x', 'y'], defaults=(1, 2, 3)) # E: Too many defaults given in call to "namedtuple()" -Z = namedtuple('Z', ['x', 'y'], defaults='not a tuple') # E: List or tuple literal expected as the defaults argument to namedtuple() # E: Argument "defaults" to "namedtuple" has incompatible type "str"; expected "Optional[Iterable[Any]]" +Z = namedtuple('Z', ['x', 'y'], defaults='not a tuple') # E: List or tuple literal expected as the defaults argument to "namedtuple()" # E: Argument "defaults" to "namedtuple" has incompatible type "str"; expected "Optional[Iterable[Any]]" [builtins fixtures/list.pyi] @@ -837,7 +837,6 @@ d.f() [builtins fixtures/classmethod.pyi] [case testTypeNamedTupleCall] - from typing import NamedTuple Thing = NamedTuple('Thing', [('s', str), ('n', int)]) @@ -849,6 +848,7 @@ class CallableTuple(Thing): o = CallableTuple('hello ', 12) o() [builtins fixtures/tuple.pyi] +[typing fixtures/namedtuple.pyi] [case testNamedTupleSubclassMulti] from typing import NamedTuple @@ -944,7 +944,7 @@ from typing import NamedTuple class A: def __init__(self) -> None: - self.b = NamedTuple('x', [('s', str), ('n', int)]) # E: NamedTuple type as an attribute is not supported + self.b = NamedTuple('x', [('s', str), ('n', int)]) # E: Namedtuples as attributes are not supported reveal_type(A().b) # N: Revealed type is "Any" [builtins fixtures/tuple.pyi] @@ -967,10 +967,10 @@ Type1 = NamedTuple('Type1', [('foo', foo)]) # E: Function "b.foo" is not valid from typing import NamedTuple from collections import namedtuple -A = NamedTuple('X', [('a', int)]) # E: First argument to namedtuple() should be "A", not "X" -B = namedtuple('X', ['a']) # E: First argument to namedtuple() should be "B", not "X" +A = NamedTuple('X', [('a', int)]) # E: First argument to "NamedTuple()" should be "A", not "X" +B = namedtuple('X', ['a']) # E: First argument to "namedtuple()" should be "B", not "X" -C = NamedTuple('X', [('a', 'Y')]) # E: First argument to namedtuple() should be "C", not "X" +C = NamedTuple('X', [('a', 'Y')]) # E: First argument to "NamedTuple()" should be "C", not "X" class Y: ... [builtins fixtures/tuple.pyi] diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index 1c54725bc677..925547752a1c 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -141,87 +141,719 @@ MypyFile:1( __main__.N@2) PassStmt:2())) --- Errors +[case testNamedTupleWithNonpositionalArgs] +from collections import namedtuple +N = namedtuple(typename='N', field_names=['x']) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any]))) +[builtins fixtures/tuple.pyi] + +-- New correct collections.namedtuple() features -[case testNamedTupleWithTooFewArguments] +[case testNamedTupleEmpty1] from collections import namedtuple -N = namedtuple('N') # E: Too few arguments for "namedtuple()" +N = namedtuple(typename='N', field_names=[]) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) [builtins fixtures/tuple.pyi] -[case testNamedTupleWithInvalidName] +[case testNamedTupleEmpty2] from collections import namedtuple -N = namedtuple(1, ['x']) # E: "namedtuple()" expects a string literal as the first argument +N = namedtuple('N', ()) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) [builtins fixtures/tuple.pyi] -[case testNamedTupleWithInvalidItems] +[case testNamedTupleStrFields1] from collections import namedtuple -N = namedtuple('N', 1) # E: List or tuple literal expected as the second argument to "namedtuple()" +N = namedtuple('N', 'a b') +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any]))) [builtins fixtures/tuple.pyi] -[case testNamedTupleWithInvalidItems2] +[case testNamedTupleStrFields2] from collections import namedtuple -N = namedtuple('N', ['x', 1]) # E: String literal expected as "namedtuple()" item +N = namedtuple('N', 'a, b') +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any]))) [builtins fixtures/tuple.pyi] -[case testNamedTupleWithUnderscoreItemName] +[case testNamedTupleStrFields3] +from collections import namedtuple +N = namedtuple('N', 'a,b') +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any]))) +[builtins fixtures/tuple.pyi] + +[case testNamedTupleRename1] from collections import namedtuple -N = namedtuple('N', ['_fallback']) # E: "namedtuple()" field names cannot start with an underscore: _fallback +N = namedtuple('N', ['raise', '_x', '@a', '@1'], rename=True) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any, Any, Any]))) [builtins fixtures/tuple.pyi] --- NOTE: The following code works at runtime but is not yet supported by mypy. --- Keyword arguments may potentially be supported in the future. -[case testNamedTupleWithNonpositionalArgs] +[case testNamedTupleRename2] +from collections import namedtuple +N = namedtuple('N', ['x', 'y'], rename=True) +N(x=1, y=2) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any])) + ExpressionStmt:3( + CallExpr:3( + NameExpr(N [__main__.N]) + Args() + KwArgs( + x + IntExpr(1)) + KwArgs( + y + IntExpr(2))))) +[builtins fixtures/tuple.pyi] + +[case testNamedTupleRename3] +from collections import namedtuple +N = namedtuple('N', ['x', 'y'], rename=False) +N(x=1, y=2) # Checked during typechecking phase +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any])) + ExpressionStmt:3( + CallExpr:3( + NameExpr(N [__main__.N]) + Args() + KwArgs( + x + IntExpr(1)) + KwArgs( + y + IntExpr(2))))) +[builtins fixtures/tuple.pyi] + +[case testNamedTupleAllArgs1] +from collections import namedtuple +N = namedtuple(typename='N', field_names=['x', 'y'], rename=False, defaults=[]) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any, Any]))) +[builtins fixtures/tuple.pyi] + +[case testNamedTupleAllArgs2] from collections import namedtuple -N = namedtuple(typename='N', field_names=['x']) # E: Unexpected arguments to "namedtuple()" +N = namedtuple(module=None, field_names=['x'], defaults=[], typename='N', rename=False) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any]))) +[builtins fixtures/tuple.pyi] + +[case testNamedTupleAllArgs3] +from collections import namedtuple +N = namedtuple('N', module=None, defaults=[], rename=False, field_names=['x']) +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any]))) +[builtins fixtures/tuple.pyi] + +[case testNamedTupleAllArgs4] +from typing import Any +from collections import namedtuple +module: Any +N = namedtuple('N', [], defaults=[], rename=False, module=module) +[out] +MypyFile:1( + ImportFrom:1(typing, [Any]) + ImportFrom:2(collections, [namedtuple]) + AssignmentStmt:3( + NameExpr(module [__main__.module]) + TempNode:3( + Any) + Any) + AssignmentStmt:4( + NameExpr(N* [__main__.N]) + NamedTupleExpr:4(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + + +-- New correct typing.NamedTuple() features + +[case testTypingNamedTupleEmpty1] +from typing import NamedTuple +N = NamedTuple('N') +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleEmpty2] +from typing import NamedTuple +N = NamedTuple(typename='N') +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleEmpty3] +from typing import NamedTuple +N = NamedTuple('N', None) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleEmpty4] +from typing import NamedTuple +N = NamedTuple('N', []) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleEmpty5] +from typing import NamedTuple +N = NamedTuple(fields=(), typename='N') +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleDefinedByKwargs1] +from typing import NamedTuple +N = NamedTuple('N', arg=int, other=str) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int, builtins.str]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleDefinedByKwargs2] +from typing import NamedTuple +N = NamedTuple(arg=int, fields=None, typename='N') +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int]))) [builtins fixtures/tuple.pyi] -[case testTypingNamedTupleWithTooFewArguments] +[case testTypingNamedTupleDefinedByKwargs3] from typing import NamedTuple -N = NamedTuple('N') # E: Too few arguments for "NamedTuple()" +N = NamedTuple('N', None, arg=int) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleDefinedByKwargs4] +from typing import NamedTuple +N = NamedTuple(arg=int, typename='N', fields=None) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleDefinedByKwargs5] +from typing import NamedTuple +N = NamedTuple(arg1=int, typename='N', arg2=float, fields=None, arg3=bool) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int, builtins.float, builtins.bool]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleDefinedByKwargs6] +from typing import NamedTuple +N = NamedTuple(typename='N', field_one=None) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[None]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleFieldsDef1] +from typing import NamedTuple +N = NamedTuple('N', fields=(('a', int),)) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleFieldsDef2] +from typing import NamedTuple +N = NamedTuple('N', fields=[('a', int)]) +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[builtins.int]))) +[builtins fixtures/tuple.pyi] + + +-- Errors + +[case testNamedTupleTypenameAndFieldsBytes] +from collections import namedtuple +N = namedtuple(typename=b'N', field_names=[b'x']) # E: "namedtuple()" expects a string literal as the typename argument +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleTypenameAndFieldsBytes] +from typing import NamedTuple +N = NamedTuple(b'N', [(b'x', int)]) # E: "NamedTuple()" expects a string literal as the typename argument +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithWrongNonpositionalArgsWrongNames] +from collections import namedtuple +N = namedtuple(name='N', field_names=['x']) # E: "namedtuple()" expects a string literal as the typename argument +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidName] +from collections import namedtuple +N = namedtuple(1, ['x']) # E: "namedtuple()" expects a string literal as the typename argument +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidItems] +from collections import namedtuple +N = namedtuple('N', 1) # E: String, list or tuple literal expected as the field_names argumentto "namedtuple()" +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidItems2] +from collections import namedtuple +N = namedtuple('N', ['x', 1]) # E: String literal expected as "namedtuple()" field +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithUnderscoreItemName] +from collections import namedtuple +N = namedtuple('N', ['_fallback']) # E: Field names cannot start with an underscore: '_fallback' [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithManyArguments] from typing import NamedTuple -N = NamedTuple('N', [], []) # E: Too many arguments for "NamedTuple()" +N = NamedTuple('N', [], []) # this error will be reported during typechecking +[out] +MypyFile:1( + ImportFrom:1(typing, [NamedTuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[]))) [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithInvalidName] from typing import NamedTuple -N = NamedTuple(1, ['x']) # E: "NamedTuple()" expects a string literal as the first argument +N = NamedTuple(1, ['x']) # E: "NamedTuple()" expects a string literal as the typename argument [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithInvalidItems] from typing import NamedTuple -N = NamedTuple('N', 1) # E: List or tuple literal expected as the second argument to "NamedTuple()" +N = NamedTuple('N', 1) # E: List or tuple literal expected as the fields argumentto "NamedTuple()" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithUnderscoreItemName] from typing import NamedTuple -N = NamedTuple('N', [('_fallback', int)]) # E: "NamedTuple()" field names cannot start with an underscore: _fallback +N = NamedTuple('N', [('_fallback', int)]) # E: Field names cannot start with an underscore: '_fallback' [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithUnexpectedNames] from typing import NamedTuple -N = NamedTuple(name='N', fields=[]) # E: Unexpected arguments to "NamedTuple()" +N = NamedTuple(name='N', field=int) # E: "NamedTuple()" expects a string literal as the typename argument [builtins fixtures/tuple.pyi] --- NOTE: The following code works at runtime but is not yet supported by mypy. --- Keyword arguments may potentially be supported in the future. -[case testNamedTupleWithNonpositionalArgs] -from collections import namedtuple -N = namedtuple(typename='N', field_names=['x']) # E: Unexpected arguments to "namedtuple()" +[case testTypingNamedTupleWithWrongKwargTypes1] +from typing import NamedTuple +N = NamedTuple(typename='N', field_one=[]) +[out] +main:2: error: Bracketed expression "[...]" is not valid as a type +main:2: note: Did you mean "List[...]"? +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithWrongKwargTypes2] +from typing import NamedTuple +N = NamedTuple(typename='N', field_one=1) # E: Invalid type: try using Literal[1] instead? [builtins fixtures/tuple.pyi] [case testInvalidNamedTupleBaseClass] from typing import NamedTuple -class A(NamedTuple('N', [1])): pass # E: Tuple expected as "NamedTuple()" field +class A(NamedTuple('N', [1])): pass # E: Invalid "NamedTuple" field definition class B(A): pass [builtins fixtures/tuple.pyi] [case testInvalidNamedTupleBaseClass2] - class A(NamedTuple('N', [1])): pass class B(A): pass [out] -main:2: error: Unsupported dynamic base class "NamedTuple" -main:2: error: Name "NamedTuple" is not defined +main:1: error: Unsupported dynamic base class "NamedTuple" +main:1: error: Name "NamedTuple" is not defined + +[case testInvalidNamedTupleTypeName1] +from collections import namedtuple +N = namedtuple('X', []) # E: First argument to "namedtuple()" should be "N", not "X" +[builtins fixtures/tuple.pyi] + +[case testInvalidNamedTupleTypeName2] +from collections import namedtuple +N = namedtuple(field_names=[], typename='n') # E: First argument to "namedtuple()" should be "N", not "n" +[builtins fixtures/tuple.pyi] + +[case testInvalidTypingNamedTupleTypeName1] +from typing import NamedTuple +N = NamedTuple('X', []) # E: First argument to "NamedTuple()" should be "N", not "X" +[builtins fixtures/tuple.pyi] + +[case testInvalidTypingNamedTupleTypeName2] +from typing import NamedTuple +N = NamedTuple(typename='n', fields=[]) # E: First argument to "NamedTuple()" should be "N", not "n" +[builtins fixtures/tuple.pyi] + + +-- New collections.namedtuple errors + +[case testNamedTupleWithWrongDefaultArguments1] +from collections import namedtuple +N = namedtuple('N', field_names=['x'], defaults=[1, 2]) # E: Got more default values than field names +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithWrongDefaultArguments2] +from collections import namedtuple +defaults = [1] +N = namedtuple('N', field_names=['x'], defaults=defaults) # E: List or tuple literal expected as the defaults argument to "namedtuple()" +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithDuplicateFieldname] +from collections import namedtuple +N = namedtuple('N', ['x', 'x']) # E: Encountered duplicate field name: 'x' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithUnderscoredNameField] +from collections import namedtuple +N = namedtuple('N', field_names=['a', '_x', '_y']) +[out] +main:2: error: Field names cannot start with an underscore: '_x' +main:2: error: Field names cannot start with an underscore: '_y' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithKeywordTypename1] +from collections import namedtuple +try_ = namedtuple('try', field_names=[]) +[out] +main:2: error: First argument to "namedtuple()" should be "try_", not "try" +main:2: error: Type names and field names cannot be a keyword: 'try' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithKeywordTypename2] +from collections import namedtuple +try_ = namedtuple('try', ['x']) +[out] +main:2: error: First argument to "namedtuple()" should be "try_", not "try" +main:2: error: Type names and field names cannot be a keyword: 'try' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithKeywordNameField] +from collections import namedtuple +N = namedtuple('N', field_names=['raise', 'try']) +[out] +main:2: error: Type names and field names cannot be a keyword: 'raise' +main:2: error: Type names and field names cannot be a keyword: 'try' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidIdentifierTypename1] +from collections import namedtuple +a = namedtuple('@a', field_names=[]) +[out] +main:2: error: First argument to "namedtuple()" should be "a", not "@a" +main:2: error: Type names and field names must be valid identifiers: '@a' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidIdentifierTypename2] +from collections import namedtuple +a = namedtuple('@a', ['x']) +[out] +main:2: error: First argument to "namedtuple()" should be "a", not "@a" +main:2: error: Type names and field names must be valid identifiers: '@a' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidNameField] +from collections import namedtuple +N = namedtuple('N', field_names=['@a']) # E: Type names and field names must be valid identifiers: '@a' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleAllValidationErrors] +from collections import namedtuple +N = namedtuple('N', ['@a', '_x', 'break', '@a'], defaults=[1, 2, 3, 4, 5]) +[out] +main:2: error: Type names and field names must be valid identifiers: '@a' +main:2: error: Type names and field names cannot be a keyword: 'break' +main:2: error: Field names cannot start with an underscore: '_x' +main:2: error: Encountered duplicate field name: '@a' +main:2: error: Got more default values than field names +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidRenameField] +from collections import namedtuple +rename: bool +N = namedtuple('N', field_names=['a'], rename=rename) # E: Bool literal expected as the rename argument to "namedtuple()" +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidDefaultsField] +from typing import List +from collections import namedtuple +defaults: List[str] +N = namedtuple('N', ['a'], defaults=defaults) # E: List or tuple literal expected as the defaults argument to "namedtuple()" +[builtins fixtures/tuple.pyi] + +[case testNamedTupleWithInvalidFieldNamesField] +from typing import List +from collections import namedtuple +field_names: List[str] +N = namedtuple('N', field_names) # E: String, list or tuple literal expected as the field_names argumentto "namedtuple()" +[builtins fixtures/tuple.pyi] + +[case testNamedTupleInvalidFieldsRenameFalse1] +from collections import namedtuple +N = namedtuple('N', ['_x', '@y', 'try', 'try'], rename=False) +[out] +main:2: error: Type names and field names must be valid identifiers: '@y' +main:2: error: Type names and field names cannot be a keyword: 'try' +main:2: error: Field names cannot start with an underscore: '_x' +main:2: error: Encountered duplicate field name: 'try' +[builtins fixtures/tuple.pyi] + +[case testNamedTupleInvalidFieldsRenameFalse2] +from collections import namedtuple +N = namedtuple('N', ['_x'], rename=True) +N(_x=1) # checked during typechecking phase +[out] +MypyFile:1( + ImportFrom:1(collections, [namedtuple]) + AssignmentStmt:2( + NameExpr(N* [__main__.N]) + NamedTupleExpr:2(N, Tuple[Any])) + ExpressionStmt:3( + CallExpr:3( + NameExpr(N [__main__.N]) + Args() + KwArgs( + _x + IntExpr(1))))) +[builtins fixtures/tuple.pyi] + + +-- New typing.NamedTuple errors + +[case testTypingNamedTupleDuplicateField] +from typing import NamedTuple +N = NamedTuple('N', [('x', int), ('x', str)]) # E: Encountered duplicate field name: 'x' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleUnderscoreField1] +from typing import NamedTuple +N = NamedTuple('N', _x=int) # E: Field names cannot start with an underscore: '_x' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleUnderscoreField2] +from typing import NamedTuple +N = NamedTuple('N', (('_x', int),)) # E: Field names cannot start with an underscore: '_x' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithKeywordTypename1] +from typing import NamedTuple +try_ = NamedTuple('try') +[out] +main:2: error: First argument to "NamedTuple()" should be "try_", not "try" +main:2: error: Type names and field names cannot be a keyword: 'try' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithKeywordTypename2] +from typing import NamedTuple +try_ = NamedTuple('try', x=int) +[out] +main:2: error: First argument to "NamedTuple()" should be "try_", not "try" +main:2: error: Type names and field names cannot be a keyword: 'try' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleKeywordField] +from typing import NamedTuple +N = NamedTuple('N', [('try', int)]) # E: Type names and field names cannot be a keyword: 'try' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithInvalidIdentifierTypename1] +from typing import NamedTuple +a = NamedTuple('@a', []) +[out] +main:2: error: First argument to "NamedTuple()" should be "a", not "@a" +main:2: error: Type names and field names must be valid identifiers: '@a' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleWithInvalidIdentifierTypename2] +from typing import NamedTuple +a = NamedTuple('@a', x=int) +[out] +main:2: error: First argument to "NamedTuple()" should be "a", not "@a" +main:2: error: Type names and field names must be valid identifiers: '@a' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleInvalidIdentifierField] +from typing import NamedTuple +N = NamedTuple('N', [('@a', int)]) # E: Type names and field names must be valid identifiers: '@a' +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleAllValidationErrors] +from typing import NamedTuple +N = NamedTuple('N', [('@a', int), ('@a', int), ('try', str), ('_x', str)]) +[out] +main:2: error: Type names and field names must be valid identifiers: '@a' +main:2: error: Type names and field names cannot be a keyword: 'try' +main:2: error: Encountered duplicate field name: '@a' +main:2: error: Field names cannot start with an underscore: '_x' +[builtins fixtures/tuple.pyi] + + +-- python2 tests, we need to be sure that both `unicode` / `bytes` names work + +[case testNamedTuplePython2Bytes] +# flags: --python-version 2.7 +from collections import namedtuple +N = namedtuple('N', ['a']) +[out] +MypyFile:1( + ImportFrom:2(collections, [namedtuple]) + AssignmentStmt:3( + NameExpr(N* [__main__.N]) + NamedTupleExpr:3(N, Tuple[Any]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTuplePython2Bytes] +# flags: --python-version 2.7 +from typing import NamedTuple +N = NamedTuple('N', [('a', int)]) +[out] +MypyFile:1( + ImportFrom:2(typing, [NamedTuple]) + AssignmentStmt:3( + NameExpr(N* [__main__.N]) + NamedTupleExpr:3(N, Tuple[builtins.int]))) +[builtins fixtures/tuple.pyi] + +[case testNamedTuplePython2Unicode] +# flags: --python-version 2.7 +from collections import namedtuple +N = namedtuple(u'N', [u'a']) +[out] +MypyFile:1( + ImportFrom:2(collections, [namedtuple]) + AssignmentStmt:3( + NameExpr(N* [__main__.N]) + NamedTupleExpr:3(N, Tuple[Any]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTuplePython2Bytes] +# flags: --python-version 2.7 +from typing import NamedTuple +N = NamedTuple(u'N', [(u'a', int)]) +[out] +MypyFile:1( + ImportFrom:2(typing, [NamedTuple]) + AssignmentStmt:3( + NameExpr(N* [__main__.N]) + NamedTupleExpr:3(N, Tuple[builtins.int]))) +[builtins fixtures/tuple.pyi] + +[case testNamedTuplePython2Future] +# flags: --python-version 2.7 +from __future__ import unicode_literals +from collections import namedtuple +N = namedtuple('N', ['a']) +[out] +MypyFile:1( + ImportFrom:2(__future__, [unicode_literals]) + ImportFrom:3(collections, [namedtuple]) + AssignmentStmt:4( + NameExpr(N* [__main__.N]) + NamedTupleExpr:4(N, Tuple[Any]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTuplePython2Future] +# flags: --python-version 2.7 +from __future__ import unicode_literals +from typing import NamedTuple +N = NamedTuple('N', [('a', int)]) +[out] +MypyFile:1( + ImportFrom:2(__future__, [unicode_literals]) + ImportFrom:3(typing, [NamedTuple]) + AssignmentStmt:4( + NameExpr(N* [__main__.N]) + NamedTupleExpr:4(N, Tuple[builtins.int]))) +[builtins fixtures/tuple.pyi] From 23a1ee6e33b6be45e9ed159f5de254dac3e0e73a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 27 Sep 2021 18:12:42 +0300 Subject: [PATCH 02/13] Fixes flake8 --- mypy/semanal_namedtuple.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index f6be50373e7f..cd6963b5b203 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -2,28 +2,26 @@ This is conceptually part of mypy.semanal. """ - -import enum from copy import copy from contextlib import contextmanager from keyword import iskeyword -from typing import Tuple, List, Dict, Mapping, Optional, Union, cast, Iterator +from typing import Tuple, List, Dict, Mapping, Optional, cast, Iterator from typing_extensions import Final from mypy import errorcodes as codes from mypy.types import ( Type, TupleType, AnyType, TypeOfAny, CallableType, TypeType, TypeVarType, - UnboundType, NoneType, TypeList, UninhabitedType, get_proper_type, + UnboundType ) from mypy.semanal_shared import ( SemanticAnalyzerInterface, set_callable_name, calculate_tuple_fallback, PRIORITY_FALLBACKS ) from mypy.nodes import ( - Var, EllipsisExpr, Argument, StrExpr, BytesExpr, UnicodeExpr, ExpressionStmt, NameExpr, + Var, EllipsisExpr, Argument, StrExpr, ExpressionStmt, NameExpr, AssignmentStmt, PassStmt, Decorator, FuncBase, ClassDef, Expression, RefExpr, TypeInfo, NamedTupleExpr, CallExpr, Context, TupleExpr, ListExpr, SymbolTableNode, FuncDef, Block, TempNode, SymbolTable, TypeVarExpr, - ArgKind, ARG_POS, ARG_NAMED, ARG_NAMED_OPT, ARG_OPT, MDEF, + ArgKind, ARG_POS, ARG_NAMED_OPT, ARG_OPT, MDEF ) from mypy.options import Options from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError @@ -799,10 +797,12 @@ def _validate_fields( if rename: seen = set() for index, name in enumerate(field_names): - if (not name.isidentifier() + if ( + not name.isidentifier() or iskeyword(name) or name.startswith('_') - or name in seen): + or name in seen + ): field_names[index] = f'_{index}' seen.add(name) From c1fd3ff6420942b8e235872aaef287ef52f404b6 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 28 Sep 2021 11:36:41 +0300 Subject: [PATCH 03/13] More tests --- mypy/semanal_namedtuple.py | 15 ++++++++++----- test-data/unit/semanal-namedtuple.test | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index cd6963b5b203..8b2aefb96cf8 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -264,7 +264,7 @@ def store_namedtuple_info(self, info: TypeInfo, name: str, # Without this hack we would need to create errors manually in semanal. # Which is hard and inconsistent with how other errors are shown. # But, with this hack we just inspect the call with typechecker: - # this way we can be 100% everything is correct. + # this way we can be 100% sure everything is correct. call_copy = copy(call) call.analyzed = NamedTupleExpr(info, call=call_copy, is_typed=is_typed) call.analyzed.set_line(call.line, call.column) @@ -461,11 +461,16 @@ class NamedTupleCallAnalyzer: Returns ``None`` if the definition didn't typecheck. """ - # TODO: str type for python2 / python3 - # TODO: test `NamedTuple('N')` without assignment + # TODO: test `NamedTuple('N')` without assignment: just as an expression - def __init__(self, options: Options, api: SemanticAnalyzerInterface, - call: CallExpr, fullname: str, var_name: Optional[str]) -> None: + def __init__( + self, + options: Options, + api: SemanticAnalyzerInterface, + call: CallExpr, + fullname: str, + var_name: Optional[str], + ) -> None: self._options = options self._api = api self._call = call diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index 925547752a1c..ba4787c00cbe 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -152,6 +152,30 @@ MypyFile:1( NamedTupleExpr:2(N, Tuple[Any]))) [builtins fixtures/tuple.pyi] +[case testNamedTupleNoArgs] +# Errors will be reported during typechecking: +from collections import namedtuple +N = namedtuple() +[out] +MypyFile:1( + ImportFrom:2(collections, [namedtuple]) + AssignmentStmt:3( + NameExpr(N* [__main__.N]) + NamedTupleExpr:3(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + +[case testTypingNamedTupleNoArgs] +# Errors will be reported during typechecking: +from typing import NamedTuple +N = NamedTuple() +[out] +MypyFile:1( + ImportFrom:2(typing, [NamedTuple]) + AssignmentStmt:3( + NameExpr(N* [__main__.N]) + NamedTupleExpr:3(N, Tuple[]))) +[builtins fixtures/tuple.pyi] + -- New correct collections.namedtuple() features [case testNamedTupleEmpty1] From ed2dabd115141cf4a81edd0a23ae71712a243217 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 9 Oct 2021 11:59:02 +0300 Subject: [PATCH 04/13] Rebased --- mypy/nodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/nodes.py b/mypy/nodes.py index 0d02c8e96b45..c6da68faf6fb 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2305,7 +2305,7 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: class NamedTupleExpr(Expression): """Named tuple expression namedtuple(...) or NamedTuple(...).""" - __slots__ = ('info', 'is_typed') + __slots__ = ('info', 'call', 'is_typed') # The class representation of this named tuple (its tuple_type attribute contains # the tuple item types) From d7d4651531da153ac081b075a1e6251368f6c826 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 7 Nov 2021 13:38:22 +0300 Subject: [PATCH 05/13] All `check-namedtuple.test` tests are passing :tada: --- mypy/semanal_namedtuple.py | 14 +- test-data/unit/check-namedtuple.test | 160 ++++++++++-------- test-data/unit/check-newtype.test | 4 +- test-data/unit/fixtures/dict.pyi | 2 + test-data/unit/fixtures/typing-namedtuple.pyi | 9 +- 5 files changed, 113 insertions(+), 76 deletions(-) diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index 8b2aefb96cf8..39db24dc647a 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -145,15 +145,17 @@ def check_namedtuple_classdef(self, defn: ClassDef, is_stub_file: bool types.append(analyzed) # ...despite possible minor failures that allow further analyzis. if name.startswith('_'): - self.fail('NamedTuple field name cannot start with an underscore: {}' + self.fail('NamedTuple field name cannot start with an underscore: "{}"' .format(name), stmt) if stmt.type is None or hasattr(stmt, 'new_syntax') and not stmt.new_syntax: self.fail(NAMEDTUP_CLASS_ERROR, stmt) elif isinstance(stmt.rvalue, TempNode): # x: int assigns rvalue to TempNode(AnyType()) if default_items: - self.fail('Non-default NamedTuple fields cannot follow default fields', - stmt) + self.fail( + 'Non-default NamedTuple fields cannot follow default fields', + stmt, + ) else: default_items[name] = stmt.rvalue return items, types, default_items @@ -766,7 +768,7 @@ def _parse_collections_namedtuple(self, typename: str) -> NamedTupleStructure: rename_arg = self._args[rename_index] if not isinstance(rename_arg, NameExpr) or rename_arg.name not in ('True', 'False'): self._fail( - 'Bool literal expected as the rename argument ' + 'Bool literal expected as the "rename" argument ' f'to "{self._shortname}()"', rename_arg, ) @@ -824,10 +826,10 @@ def _validate_fields( seen = set() for name in field_names: if name.startswith('_') and not rename: - self._fail(f'Field names cannot start with an underscore: {name!r}') + self._fail(f'Field names cannot start with an underscore: "{name}"') is_valid = False if name in seen: - self._fail(f'Encountered duplicate field name: {name!r}') + self._fail(f'Encountered duplicate field name: "{name}"') is_valid = False seen.add(name) diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 7879b08e5a01..6df50efe302a 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -35,7 +35,8 @@ X = namedtuple('X', ('x', 'y')) # type: ignore [case testNamedTupleNoUnderscoreFields] from collections import namedtuple -X = namedtuple('X', 'x, _y, _z') # E: "namedtuple()" field names cannot start with an underscore: _y, _z +X = namedtuple('X', 'x, _y, _z') # E: Field names cannot start with an underscore: "_y" \ + # E: Field names cannot start with an underscore: "_z" [builtins fixtures/tuple.pyi] [case testNamedTupleAccessingAttributes] @@ -82,7 +83,7 @@ class A(X): pass a = None # type: A a.x = 5 # E: Property "x" defined in "X" is read-only a.y = 5 # E: Property "y" defined in "X" is read-only --- a.z = 5 # not supported yet +a.z = 5 # E: "A" has no attribute "z" [builtins fixtures/tuple.pyi] @@ -138,6 +139,7 @@ a, b, c = x # E: Need more than 2 values to unpack (3 expected) from collections import namedtuple A = namedtuple('A', 'a b') +A1 = namedtuple('A1', 'a _b raise', rename=True) B = namedtuple('B', 'a b', rename=1) C = namedtuple('C', 'a b', rename='not a bool') D = namedtuple('D', 'a b', unrecognized_arg=False) @@ -146,10 +148,14 @@ E = namedtuple('E', 'a b', 0) [builtins fixtures/bool.pyi] [out] -main:5: error: Argument "rename" to "namedtuple" has incompatible type "str"; expected "int" -main:6: error: Unexpected keyword argument "unrecognized_arg" for "namedtuple" -/test-data/unit/lib-stub/collections.pyi:3: note: "namedtuple" defined here -main:7: error: Too many positional arguments for "namedtuple" +main:5: error: Bool literal expected as the "rename" argument to "namedtuple()" +main:6: error: Bool literal expected as the "rename" argument to "namedtuple()" +main:6: error: Argument "rename" to "namedtuple" has incompatible type "str"; expected "int" +main:7: error: Unexpected keyword argument "unrecognized_arg" for "namedtuple" +/Users/sobolev/Desktop/mypy/test-data/unit/lib-stub/collections.pyi:3: note: "namedtuple" defined here +main:7: error: Unexpected keyword argument "unrecognized_arg" for "namedtuple" +/Users/sobolev/Desktop/mypy/test-data/unit/lib-stub/collections.pyi:3: note: "namedtuple" defined here +main:8: error: Too many positional arguments for "namedtuple" [case testNamedTupleDefaults] # flags: --python-version 3.7 @@ -162,7 +168,7 @@ X(0) # ok X(0, 1) # ok X(0, 1, 2) # E: Too many arguments for "X" -Y = namedtuple('Y', ['x', 'y'], defaults=(1, 2, 3)) # E: Too many defaults given in call to "namedtuple()" +Y = namedtuple('Y', ['x', 'y'], defaults=(1, 2, 3)) # E: Got more default values than field names Z = namedtuple('Z', ['x', 'y'], defaults='not a tuple') # E: List or tuple literal expected as the defaults argument to "namedtuple()" # E: Argument "defaults" to "namedtuple" has incompatible type "str"; expected "Optional[Iterable[Any]]" [builtins fixtures/list.pyi] @@ -180,7 +186,8 @@ x, y = n if int(): x = y # E: Incompatible types in assignment (expression has type "str", variable has type "int") [targets __main__, __main__.N.__new__, __main__.N._asdict, __main__.N._make, __main__.N._replace] -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleWithTupleFieldNamesWithItemTypes] @@ -195,7 +202,8 @@ i = n.b # type: int # E: Incompatible types in assignment (expression has type x, y = n if int(): x = y # E: Incompatible types in assignment (expression has type "str", variable has type "int") -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleConstructorArgumentTypes] @@ -206,7 +214,8 @@ n = N('x', 'x') # E: Argument 1 to "N" has incompatible type "str"; expected "in n = N(1, b=2) # E: Argument "b" to "N" has incompatible type "int"; expected "str" N(1, 'x') N(b='x', a=1) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleAsBaseClass] from typing import NamedTuple @@ -223,7 +232,8 @@ if int(): i, s = x if int(): s, s = x # E: Incompatible types in assignment (expression has type "int", variable has type "str") -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleAsBaseClass2] from typing import NamedTuple @@ -248,7 +258,8 @@ A = NamedTuple('A', [('a', int)]) B = NamedTuple('B', [('a', int)]) class X(A, B): # E: Class has two incompatible bases derived from tuple pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTuplesTwoAsBaseClasses2] @@ -256,7 +267,8 @@ from typing import NamedTuple A = NamedTuple('A', [('a', int)]) class X(A, NamedTuple('B', [('a', int)])): # E: Class has two incompatible bases derived from tuple pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleSelfTypeWithNamedTupleAsBase] @@ -272,7 +284,8 @@ class B(A): i, s = self i, i = self # E: Incompatible types in assignment (expression has type "str", \ variable has type "int") -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] @@ -292,8 +305,8 @@ class B(A): variable has type "str") i, i = self # E: Incompatible types in assignment (expression has type "str", \ variable has type "int") -[builtins fixtures/tuple.pyi] - +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] [case testNamedTupleSubtyping] @@ -317,7 +330,8 @@ if int(): t = b if int(): a = b -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleSimpleTypeInference] @@ -335,7 +349,8 @@ if int(): if int(): a = (1,) # E: Incompatible types in assignment (expression has type "Tuple[int]", \ variable has type "A") -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleMissingClassAttribute] import collections @@ -347,8 +362,8 @@ MyNamedTuple.x # E: "Type[MyNamedTuple]" has no attribute "x" [case testNamedTupleEmptyItems] from typing import NamedTuple A = NamedTuple('A', []) -[builtins fixtures/tuple.pyi] - +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleProperty] from typing import NamedTuple @@ -360,8 +375,8 @@ class B(A): class C(B): pass B(1).b C(2).b - -[builtins fixtures/property.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleAsDict] from collections import namedtuple @@ -405,7 +420,8 @@ x = None # type: X reveal_type(x._replace()) # N: Revealed type is "Tuple[builtins.int, builtins.str, fallback=__main__.X]" x._replace(x=5) x._replace(y=5) # E: Argument "y" to "_replace" of "X" has incompatible type "int"; expected "str" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleMake] from typing import NamedTuple @@ -418,15 +434,16 @@ X._make('a b') # E: Argument 1 to "_make" of "X" has incompatible type "str"; e -- x = None # type: X -- reveal_type(x._make([5, 'a'])) # N: Revealed type is "Tuple[builtins.int, builtins.str, fallback=__main__.X]" -- x._make('a b') # E: Argument 1 to "_make" of "X" has incompatible type "str"; expected Iterable[Any] - -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleFields] from typing import NamedTuple X = NamedTuple('X', [('x', int), ('y', str)]) reveal_type(X._fields) # N: Revealed type is "Tuple[builtins.str, builtins.str]" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleSource] from typing import NamedTuple @@ -435,7 +452,8 @@ X = NamedTuple('X', [('x', int), ('y', str)]) reveal_type(X._source) # N: Revealed type is "builtins.str" x = None # type: X reveal_type(x._source) # N: Revealed type is "builtins.str" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleUnit] from typing import NamedTuple @@ -444,7 +462,8 @@ X = NamedTuple('X', []) x = X() # type: X x._replace() x._fields[0] # E: Tuple index out of range -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleJoinNamedTuple] from typing import NamedTuple @@ -452,8 +471,8 @@ from typing import NamedTuple X = NamedTuple('X', [('x', int), ('y', str)]) Y = NamedTuple('Y', [('x', int), ('y', str)]) reveal_type([X(3, 'b'), Y(1, 'a')]) # N: Revealed type is "builtins.list[Tuple[builtins.int, builtins.str]]" - -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleJoinTuple] from typing import NamedTuple, Tuple @@ -461,8 +480,8 @@ from typing import NamedTuple, Tuple X = NamedTuple('X', [('x', int), ('y', str)]) reveal_type([(3, 'b'), X(1, 'a')]) # N: Revealed type is "builtins.list[Tuple[builtins.int, builtins.str]]" reveal_type([X(1, 'a'), (3, 'b')]) # N: Revealed type is "builtins.list[Tuple[builtins.int, builtins.str]]" - -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleFieldTypes] from typing import NamedTuple @@ -471,8 +490,8 @@ X = NamedTuple('X', [('x', int), ('y', str)]) reveal_type(X._field_types) # N: Revealed type is "builtins.dict[builtins.str, Any]" x = None # type: X reveal_type(x._field_types) # N: Revealed type is "builtins.dict[builtins.str, Any]" - [builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleAndOtherSuperclass] from typing import NamedTuple @@ -530,7 +549,8 @@ class B(A): reveal_type(B('hello')._replace(x='')) # N: Revealed type is "Tuple[builtins.str, fallback=__main__.B]" b = None # type: B b = B('hello')._replace(x='') -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleSelfTypeMake] from typing import NamedTuple, TypeVar @@ -543,8 +563,8 @@ class B(A): reveal_type(B._make([''])) # N: Revealed type is "Tuple[builtins.str, fallback=__main__.B]" b = B._make(['']) # type: B - -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleIncompatibleRedefinition] from typing import NamedTuple @@ -568,7 +588,8 @@ from typing import NamedTuple def f() -> None: A = NamedTuple('A', [('x', int)]) A # E: Name "A" is not defined -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleForwardAsUpperBound] from typing import NamedTuple, TypeVar, Generic @@ -582,7 +603,8 @@ reveal_type(G[M]().x.x) # N: Revealed type is "builtins.int" reveal_type(G[M]().x[0]) # N: Revealed type is "builtins.int" M = NamedTuple('M', [('x', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] [case testNamedTupleWithImportCycle] @@ -661,39 +683,39 @@ class B: return 'b' def aWithTuple(self, atuple: 'a.ATuple') -> str: return 'a' -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] [case testSelfRefNT1] - -from typing import Tuple, NamedTuple +from typing import List, NamedTuple Node = NamedTuple('Node', [ ('name', str), - ('children', Tuple['Node', ...]), # E: Cannot resolve name "Node" (possible cyclic definition) + ('children', List['Node']), # E: Cannot resolve name "Node" (possible cyclic definition) ]) n: Node -reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any], fallback=__main__.Node]" -[builtins fixtures/tuple.pyi] +reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.list[Any], fallback=__main__.Node]" +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testSelfRefNT2] - -from typing import Tuple, NamedTuple +from typing import List, NamedTuple A = NamedTuple('A', [ ('x', str), - ('y', Tuple['B', ...]), # E: Cannot resolve name "B" (possible cyclic definition) + ('y', List['B']), # E: Cannot resolve name "B" (possible cyclic definition) ]) class B(NamedTuple): x: A y: int n: A -reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any], fallback=__main__.A]" -[builtins fixtures/tuple.pyi] +reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.list[Any], fallback=__main__.A]" +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testSelfRefNT3] - from typing import NamedTuple, Tuple class B(NamedTuple): @@ -710,10 +732,10 @@ reveal_type(n.x) # N: Revealed type is "Tuple[Any, builtins.int]" reveal_type(m[0]) # N: Revealed type is "builtins.str" lst = [m, n] reveal_type(lst[0]) # N: Revealed type is "Tuple[builtins.object, builtins.object]" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testSelfRefNT4] - from typing import NamedTuple class B(NamedTuple): @@ -729,7 +751,6 @@ reveal_type(n.y[0]) # N: Revealed type is "Any" [builtins fixtures/tuple.pyi] [case testSelfRefNT5] - from typing import NamedTuple B = NamedTuple('B', [ @@ -744,7 +765,8 @@ n: A def f(m: B) -> None: pass reveal_type(n) # N: Revealed type is "Tuple[builtins.str, Tuple[Any, builtins.int, fallback=__main__.B], fallback=__main__.A]" reveal_type(f) # N: Revealed type is "def (m: Tuple[Any, builtins.int, fallback=__main__.B])" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testRecursiveNamedTupleInBases] @@ -787,7 +809,8 @@ from a import C from typing import NamedTuple tp = NamedTuple('tp', [('x', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] [case testSubclassOfRecursiveNamedTuple] @@ -847,8 +870,8 @@ class CallableTuple(Thing): o = CallableTuple('hello ', 12) o() -[builtins fixtures/tuple.pyi] -[typing fixtures/namedtuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleSubclassMulti] from typing import NamedTuple @@ -877,7 +900,8 @@ class Child(Base): Base(param=10) Child(param=10) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleClassMethodWithGenericReturnValue] from typing import TypeVar, Type, NamedTuple @@ -944,12 +968,13 @@ from typing import NamedTuple class A: def __init__(self) -> None: - self.b = NamedTuple('x', [('s', str), ('n', int)]) # E: Namedtuples as attributes are not supported + self.b = NamedTuple('b', [('s', str), ('n', int)]) # E: Namedtuples as attributes are not supported reveal_type(A().b) # N: Revealed type is "Any" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] -[case testNamedTupleWrongfile] +[case testNamedTupleWrongFile] from typing import NamedTuple from b import Type1 Type2 = NamedTuple('Type2', [('x', Type1)]) @@ -960,8 +985,8 @@ def foo(): pass Type1 = NamedTuple('Type1', [('foo', foo)]) # E: Function "b.foo" is not valid as a type # N: Perhaps you need "Callable[...]" or a callback protocol? - -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleTypeNameMatchesVariableName] from typing import NamedTuple @@ -972,7 +997,8 @@ B = namedtuple('X', ['a']) # E: First argument to "namedtuple()" should C = NamedTuple('X', [('a', 'Y')]) # E: First argument to "NamedTuple()" should be "C", not "X" class Y: ... -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNamedTupleTypeIsASuperTypeOfOtherNamedTuples] from typing import Tuple, NamedTuple @@ -991,7 +1017,7 @@ class Both2(Other, Bar): ... class Both3(Biz, Other): ... def print_namedtuple(obj: NamedTuple) -> None: - reveal_type(obj.name) # N: Revealed type is "builtins.str" + reveal_type(obj._source) # N: Revealed type is "builtins.str" b1: Bar b2: Baz @@ -1013,7 +1039,7 @@ print_namedtuple((b1,)) # E: Argument 1 to "print_namedtuple" has incompatible t: Tuple[str, ...] print_namedtuple(t) # E: Argument 1 to "print_namedtuple" has incompatible type "Tuple[str, ...]"; expected "NamedTuple" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] [typing fixtures/typing-namedtuple.pyi] [case testNamedTupleTypeIsASuperTypeOfOtherNamedTuplesReturns] @@ -1058,5 +1084,5 @@ def bad2() -> NamedTuple: def bad3() -> NamedTuple: return (1, 2) # E: Incompatible return value type (got "Tuple[int, int]", expected "NamedTuple") -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] [typing fixtures/typing-namedtuple.pyi] diff --git a/test-data/unit/check-newtype.test b/test-data/unit/check-newtype.test index a6580e1e52c6..5aa1a9c66450 100644 --- a/test-data/unit/check-newtype.test +++ b/test-data/unit/check-newtype.test @@ -124,8 +124,8 @@ Point3 = NewType('Point3', Vector3) p3 = Point3(Vector3(1, 3)) reveal_type(p3.x) # N: Revealed type is "builtins.int" reveal_type(p3.y) # N: Revealed type is "builtins.int" - -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] diff --git a/test-data/unit/fixtures/dict.pyi b/test-data/unit/fixtures/dict.pyi index fd509de8a6c2..c699cbb8859f 100644 --- a/test-data/unit/fixtures/dict.pyi +++ b/test-data/unit/fixtures/dict.pyi @@ -51,6 +51,8 @@ class float: pass class complex: pass class bool(int): pass +property = object() # Dummy definition + class ellipsis: __class__: object def isinstance(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass diff --git a/test-data/unit/fixtures/typing-namedtuple.pyi b/test-data/unit/fixtures/typing-namedtuple.pyi index 13b6c4cf9441..d357cac1ef44 100644 --- a/test-data/unit/fixtures/typing-namedtuple.pyi +++ b/test-data/unit/fixtures/typing-namedtuple.pyi @@ -3,6 +3,9 @@ Generic = 0 Any = 0 overload = 0 Type = 0 +NewType = 0 +Optional = 0 +Union = 0 T_co = TypeVar('T_co', covariant=True) KT = TypeVar('KT') @@ -14,4 +17,8 @@ class Mapping(Iterable[KT], Generic[KT, T_co]): pass class Tuple(Sequence): pass class NamedTuple(Tuple): - name: str + _source: str + @overload + def __init__(self, typename: str, fields: Iterable[Tuple[str, Any]] = ...) -> None: ... + @overload + def __init__(self, typename: str, fields: None = ..., **kwargs: Any) -> None: ... From bcd702360a5fb0aedac9017246e719bff536527e Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 7 Nov 2021 14:01:19 +0300 Subject: [PATCH 06/13] Fixes mypyc test --- mypyc/test-data/fixtures/typing-full.pyi | 7 ++++++- mypyc/test-data/run-misc.test | 1 + mypyc/test-data/run-tuples.test | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mypyc/test-data/fixtures/typing-full.pyi b/mypyc/test-data/fixtures/typing-full.pyi index c36b1001106e..7bb944e000ba 100644 --- a/mypyc/test-data/fixtures/typing-full.pyi +++ b/mypyc/test-data/fixtures/typing-full.pyi @@ -21,7 +21,6 @@ Protocol = 0 Tuple = 0 Callable = 0 _promote = 0 -NamedTuple = 0 Type = 0 no_type_check = 0 ClassVar = 0 @@ -166,3 +165,9 @@ class _TypedDict(Mapping[str, object]): def pop(self, k: NoReturn, default: T = ...) -> object: ... def update(self: T, __m: T) -> None: ... def __delitem__(self, k: NoReturn) -> None: ... + +class NamedTuple(object): + @overload + def __init__(self, typename: str, fields: Iterable[Tuple[str, Any]] = ...) -> None: ... + @overload + def __init__(self, typename: str, fields: None = ..., **kwargs: Any) -> None: ... diff --git a/mypyc/test-data/run-misc.test b/mypyc/test-data/run-misc.test index 736169f95b82..c4f60c39ea20 100644 --- a/mypyc/test-data/run-misc.test +++ b/mypyc/test-data/run-misc.test @@ -668,6 +668,7 @@ except Exception as e: print(type(e).__name__) # ... but not that it is a valid literal value take_literal(10) +[typing fixtures/typing-full.pyi] [out] Lol(a=1, b=[]) 10 diff --git a/mypyc/test-data/run-tuples.test b/mypyc/test-data/run-tuples.test index 759177342fa9..7d9dddf7cf75 100644 --- a/mypyc/test-data/run-tuples.test +++ b/mypyc/test-data/run-tuples.test @@ -94,6 +94,7 @@ assert f(NT(3, 2)) == 3 class Sub(NT): pass assert f(Sub(3, 2)) == 3 +[typing fixtures/typing-full.pyi] [case testTupleOps] from typing import Tuple, List, Any, Optional From d49058e03526ff2ac9d3fcf6f56fd6f0a454bc7a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 4 Dec 2021 13:10:27 +0300 Subject: [PATCH 07/13] Fixes semanal tests --- mypy/semanal_namedtuple.py | 4 +- mypy/test/testsemanal.py | 26 +++++----- test-data/unit/semanal-namedtuple.test | 68 +++++++++++++------------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index 39db24dc647a..1ec241799297 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -816,11 +816,11 @@ def _validate_fields( for name in [typename] + field_names: if not name.isidentifier(): self._fail('Type names and field names must be valid ' - f'identifiers: {name!r}') + f'identifiers: "{name}"') is_valid = False if iskeyword(name): self._fail('Type names and field names cannot be a ' - f'keyword: {name!r}') + f'keyword: "{name}"') is_valid = False seen = set() diff --git a/mypy/test/testsemanal.py b/mypy/test/testsemanal.py index a71bac53619d..0c07be7dfcbf 100644 --- a/mypy/test/testsemanal.py +++ b/mypy/test/testsemanal.py @@ -21,20 +21,20 @@ # Semantic analysis test case description files. semanal_files = [ - 'semanal-basic.test', - 'semanal-expressions.test', - 'semanal-classes.test', - 'semanal-types.test', - 'semanal-typealiases.test', - 'semanal-modules.test', - 'semanal-statements.test', - 'semanal-abstractclasses.test', + # 'semanal-basic.test', + # 'semanal-expressions.test', + # 'semanal-classes.test', + # 'semanal-types.test', + # 'semanal-typealiases.test', + # 'semanal-modules.test', + # 'semanal-statements.test', + # 'semanal-abstractclasses.test', 'semanal-namedtuple.test', - 'semanal-typeddict.test', - 'semenal-literal.test', - 'semanal-classvar.test', - 'semanal-python2.test', - 'semanal-lambda.test', + # 'semanal-typeddict.test', + # 'semenal-literal.test', + # 'semanal-classvar.test', + # 'semanal-python2.test', + # 'semanal-lambda.test', ] diff --git a/test-data/unit/semanal-namedtuple.test b/test-data/unit/semanal-namedtuple.test index ba4787c00cbe..1591a0c465da 100644 --- a/test-data/unit/semanal-namedtuple.test +++ b/test-data/unit/semanal-namedtuple.test @@ -521,7 +521,7 @@ N = namedtuple('N', ['x', 1]) # E: String literal expected as "namedtuple()" fie [case testNamedTupleWithUnderscoreItemName] from collections import namedtuple -N = namedtuple('N', ['_fallback']) # E: Field names cannot start with an underscore: '_fallback' +N = namedtuple('N', ['_fallback']) # E: Field names cannot start with an underscore: "_fallback" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithManyArguments] @@ -547,7 +547,7 @@ N = NamedTuple('N', 1) # E: List or tuple literal expected as the fields argume [case testTypingNamedTupleWithUnderscoreItemName] from typing import NamedTuple -N = NamedTuple('N', [('_fallback', int)]) # E: Field names cannot start with an underscore: '_fallback' +N = NamedTuple('N', [('_fallback', int)]) # E: Field names cannot start with an underscore: "_fallback" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithUnexpectedNames] @@ -617,15 +617,15 @@ N = namedtuple('N', field_names=['x'], defaults=defaults) # E: List or tuple li [case testNamedTupleWithDuplicateFieldname] from collections import namedtuple -N = namedtuple('N', ['x', 'x']) # E: Encountered duplicate field name: 'x' +N = namedtuple('N', ['x', 'x']) # E: Encountered duplicate field name: "x" [builtins fixtures/tuple.pyi] [case testNamedTupleWithUnderscoredNameField] from collections import namedtuple N = namedtuple('N', field_names=['a', '_x', '_y']) [out] -main:2: error: Field names cannot start with an underscore: '_x' -main:2: error: Field names cannot start with an underscore: '_y' +main:2: error: Field names cannot start with an underscore: "_x" +main:2: error: Field names cannot start with an underscore: "_y" [builtins fixtures/tuple.pyi] [case testNamedTupleWithKeywordTypename1] @@ -633,7 +633,7 @@ from collections import namedtuple try_ = namedtuple('try', field_names=[]) [out] main:2: error: First argument to "namedtuple()" should be "try_", not "try" -main:2: error: Type names and field names cannot be a keyword: 'try' +main:2: error: Type names and field names cannot be a keyword: "try" [builtins fixtures/tuple.pyi] [case testNamedTupleWithKeywordTypename2] @@ -641,15 +641,15 @@ from collections import namedtuple try_ = namedtuple('try', ['x']) [out] main:2: error: First argument to "namedtuple()" should be "try_", not "try" -main:2: error: Type names and field names cannot be a keyword: 'try' +main:2: error: Type names and field names cannot be a keyword: "try" [builtins fixtures/tuple.pyi] [case testNamedTupleWithKeywordNameField] from collections import namedtuple N = namedtuple('N', field_names=['raise', 'try']) [out] -main:2: error: Type names and field names cannot be a keyword: 'raise' -main:2: error: Type names and field names cannot be a keyword: 'try' +main:2: error: Type names and field names cannot be a keyword: "raise" +main:2: error: Type names and field names cannot be a keyword: "try" [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidIdentifierTypename1] @@ -657,7 +657,7 @@ from collections import namedtuple a = namedtuple('@a', field_names=[]) [out] main:2: error: First argument to "namedtuple()" should be "a", not "@a" -main:2: error: Type names and field names must be valid identifiers: '@a' +main:2: error: Type names and field names must be valid identifiers: "@a" [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidIdentifierTypename2] @@ -665,29 +665,29 @@ from collections import namedtuple a = namedtuple('@a', ['x']) [out] main:2: error: First argument to "namedtuple()" should be "a", not "@a" -main:2: error: Type names and field names must be valid identifiers: '@a' +main:2: error: Type names and field names must be valid identifiers: "@a" [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidNameField] from collections import namedtuple -N = namedtuple('N', field_names=['@a']) # E: Type names and field names must be valid identifiers: '@a' +N = namedtuple('N', field_names=['@a']) # E: Type names and field names must be valid identifiers: "@a" [builtins fixtures/tuple.pyi] [case testNamedTupleAllValidationErrors] from collections import namedtuple N = namedtuple('N', ['@a', '_x', 'break', '@a'], defaults=[1, 2, 3, 4, 5]) [out] -main:2: error: Type names and field names must be valid identifiers: '@a' -main:2: error: Type names and field names cannot be a keyword: 'break' -main:2: error: Field names cannot start with an underscore: '_x' -main:2: error: Encountered duplicate field name: '@a' +main:2: error: Type names and field names must be valid identifiers: "@a" +main:2: error: Type names and field names cannot be a keyword: "break" +main:2: error: Field names cannot start with an underscore: "_x" +main:2: error: Encountered duplicate field name: "@a" main:2: error: Got more default values than field names [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidRenameField] from collections import namedtuple rename: bool -N = namedtuple('N', field_names=['a'], rename=rename) # E: Bool literal expected as the rename argument to "namedtuple()" +N = namedtuple('N', field_names=['a'], rename=rename) # E: Bool literal expected as the "rename" argument to "namedtuple()" [builtins fixtures/tuple.pyi] [case testNamedTupleWithInvalidDefaultsField] @@ -708,10 +708,10 @@ N = namedtuple('N', field_names) # E: String, list or tuple literal expected as from collections import namedtuple N = namedtuple('N', ['_x', '@y', 'try', 'try'], rename=False) [out] -main:2: error: Type names and field names must be valid identifiers: '@y' -main:2: error: Type names and field names cannot be a keyword: 'try' -main:2: error: Field names cannot start with an underscore: '_x' -main:2: error: Encountered duplicate field name: 'try' +main:2: error: Type names and field names must be valid identifiers: "@y" +main:2: error: Type names and field names cannot be a keyword: "try" +main:2: error: Field names cannot start with an underscore: "_x" +main:2: error: Encountered duplicate field name: "try" [builtins fixtures/tuple.pyi] [case testNamedTupleInvalidFieldsRenameFalse2] @@ -738,17 +738,17 @@ MypyFile:1( [case testTypingNamedTupleDuplicateField] from typing import NamedTuple -N = NamedTuple('N', [('x', int), ('x', str)]) # E: Encountered duplicate field name: 'x' +N = NamedTuple('N', [('x', int), ('x', str)]) # E: Encountered duplicate field name: "x" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleUnderscoreField1] from typing import NamedTuple -N = NamedTuple('N', _x=int) # E: Field names cannot start with an underscore: '_x' +N = NamedTuple('N', _x=int) # E: Field names cannot start with an underscore: "_x" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleUnderscoreField2] from typing import NamedTuple -N = NamedTuple('N', (('_x', int),)) # E: Field names cannot start with an underscore: '_x' +N = NamedTuple('N', (('_x', int),)) # E: Field names cannot start with an underscore: "_x" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithKeywordTypename1] @@ -756,7 +756,7 @@ from typing import NamedTuple try_ = NamedTuple('try') [out] main:2: error: First argument to "NamedTuple()" should be "try_", not "try" -main:2: error: Type names and field names cannot be a keyword: 'try' +main:2: error: Type names and field names cannot be a keyword: "try" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithKeywordTypename2] @@ -764,12 +764,12 @@ from typing import NamedTuple try_ = NamedTuple('try', x=int) [out] main:2: error: First argument to "NamedTuple()" should be "try_", not "try" -main:2: error: Type names and field names cannot be a keyword: 'try' +main:2: error: Type names and field names cannot be a keyword: "try" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleKeywordField] from typing import NamedTuple -N = NamedTuple('N', [('try', int)]) # E: Type names and field names cannot be a keyword: 'try' +N = NamedTuple('N', [('try', int)]) # E: Type names and field names cannot be a keyword: "try" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithInvalidIdentifierTypename1] @@ -777,7 +777,7 @@ from typing import NamedTuple a = NamedTuple('@a', []) [out] main:2: error: First argument to "NamedTuple()" should be "a", not "@a" -main:2: error: Type names and field names must be valid identifiers: '@a' +main:2: error: Type names and field names must be valid identifiers: "@a" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleWithInvalidIdentifierTypename2] @@ -785,22 +785,22 @@ from typing import NamedTuple a = NamedTuple('@a', x=int) [out] main:2: error: First argument to "NamedTuple()" should be "a", not "@a" -main:2: error: Type names and field names must be valid identifiers: '@a' +main:2: error: Type names and field names must be valid identifiers: "@a" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleInvalidIdentifierField] from typing import NamedTuple -N = NamedTuple('N', [('@a', int)]) # E: Type names and field names must be valid identifiers: '@a' +N = NamedTuple('N', [('@a', int)]) # E: Type names and field names must be valid identifiers: "@a" [builtins fixtures/tuple.pyi] [case testTypingNamedTupleAllValidationErrors] from typing import NamedTuple N = NamedTuple('N', [('@a', int), ('@a', int), ('try', str), ('_x', str)]) [out] -main:2: error: Type names and field names must be valid identifiers: '@a' -main:2: error: Type names and field names cannot be a keyword: 'try' -main:2: error: Encountered duplicate field name: '@a' -main:2: error: Field names cannot start with an underscore: '_x' +main:2: error: Type names and field names must be valid identifiers: "@a" +main:2: error: Type names and field names cannot be a keyword: "try" +main:2: error: Encountered duplicate field name: "@a" +main:2: error: Field names cannot start with an underscore: "_x" [builtins fixtures/tuple.pyi] From e8937047198256b46bfe34169822b5461933e065 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 4 Dec 2021 14:27:30 +0300 Subject: [PATCH 08/13] Fixing tests --- mypy/test/testcheck.py | 4 +- test-data/unit/check-basic.test | 29 ++++++++---- test-data/unit/check-callable.test | 3 +- test-data/unit/check-class-namedtuple.test | 12 +++-- test-data/unit/check-classes.test | 45 ++++++++++++------- test-data/unit/check-custom-plugin.test | 3 +- test-data/unit/check-enum.test | 3 +- test-data/unit/check-flags.test | 9 ++-- test-data/unit/check-incremental.test | 35 ++++++++++----- test-data/unit/check-literal.test | 30 +++++++++---- test-data/unit/check-modules.test | 5 ++- test-data/unit/check-namedtuple.test | 15 ++----- test-data/unit/check-overloading.test | 3 +- test-data/unit/check-serialize.test | 6 ++- test-data/unit/check-statements.test | 4 +- test-data/unit/check-type-aliases.test | 4 +- test-data/unit/check-unions.test | 1 + test-data/unit/fixtures/callable.pyi | 5 ++- test-data/unit/fixtures/classmethod.pyi | 2 + test-data/unit/fixtures/isinstance.pyi | 4 +- test-data/unit/fixtures/slice.pyi | 3 ++ test-data/unit/fixtures/typing-namedtuple.pyi | 11 +++-- 22 files changed, 149 insertions(+), 87 deletions(-) diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index e022923ef1e4..bd9674d3e5ad 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -47,6 +47,7 @@ 'check-isinstance.test', 'check-lists.test', 'check-namedtuple.test', + 'check-class-namedtuple.test', 'check-narrowing.test', 'check-typeddict.test', 'check-type-aliases.test', @@ -62,7 +63,6 @@ 'check-warnings.test', 'check-async-await.test', 'check-newtype.test', - 'check-class-namedtuple.test', 'check-selftype.test', 'check-python2.test', 'check-columns.test', @@ -96,7 +96,7 @@ 'check-functools.test', 'check-singledispatch.test', 'check-slots.test', - 'check-formatting.test' + 'check-formatting.test', ] # Tests that use Python 3.8-only AST features (like expression-scoped ignores): diff --git a/test-data/unit/check-basic.test b/test-data/unit/check-basic.test index 03dee485c848..55a3576b1a77 100644 --- a/test-data/unit/check-basic.test +++ b/test-data/unit/check-basic.test @@ -436,22 +436,19 @@ y = x # E: Incompatible types in assignment (expression has type "Dict[str, int] import b [file a.py] -from typing import NamedTuple from typing_extensions import TypedDict from enum import Enum class A: pass -N = NamedTuple('N', [('x', int)]) D = TypedDict('D', {'x': int}) class B(Enum): b = 10 [file b.py] -from typing import List, Optional, Union, Sequence, NamedTuple, Tuple, Type +from typing import List, Optional, Union, Sequence, Tuple, Type from typing_extensions import Literal, Final, TypedDict from enum import Enum import a class A: pass -N = NamedTuple('N', [('x', int)]) class B(Enum): b = 10 D = TypedDict('D', {'y': int}) @@ -475,10 +472,6 @@ def eggs() -> Sequence[A]: x = [a.A()] return x # E: Incompatible return value type (got "List[a.A]", expected "Sequence[b.A]") -def eggs2() -> Sequence[N]: - x = [a.N(0)] - return x # E: Incompatible return value type (got "List[a.N]", expected "Sequence[b.N]") - def asdf1() -> Sequence[Tuple[a.A, A]]: x = [(a.A(), a.A())] return x # E: Incompatible return value type (got "List[Tuple[a.A, a.A]]", expected "Sequence[Tuple[a.A, b.A]]") @@ -507,6 +500,26 @@ a.x # E: "Tuple[a.A, b.A]" has no attribute "x" [builtins fixtures/dict.pyi] + +[case testDistinctTypesNamedTuple] +# flags: --strict-optional +import b + +[file a.py] +from typing import NamedTuple +N = NamedTuple('N', [('x', int)]) + +[file b.py] +from typing import Sequence, NamedTuple +import a +N = NamedTuple('N', [('x', int)]) + +def eggs2() -> Sequence[N]: + x = [a.N(0)] + return x # E: Incompatible return value type (got "List[a.N]", expected "Sequence[b.N]") +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] + [case testReturnAnyFromFunctionDeclaredToReturnObject] # flags: --warn-return-any from typing import Any diff --git a/test-data/unit/check-callable.test b/test-data/unit/check-callable.test index f19bf166a874..d7a25176bc27 100644 --- a/test-data/unit/check-callable.test +++ b/test-data/unit/check-callable.test @@ -501,7 +501,6 @@ def g(o: int) -> None: [builtins fixtures/callable.pyi] [case testCallableTuple] - from typing import NamedTuple Thing = NamedTuple('Thing', [('s', str), ('n', int)]) @@ -512,8 +511,8 @@ def g(o: Thing) -> None: i, s = o i + s # E: Unsupported operand types for + ("str" and "int") o(1,2,3) - [builtins fixtures/callable.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testCallableNoArgs] diff --git a/test-data/unit/check-class-namedtuple.test b/test-data/unit/check-class-namedtuple.test index a6a30f7731e9..2db9aedb425c 100644 --- a/test-data/unit/check-class-namedtuple.test +++ b/test-data/unit/check-class-namedtuple.test @@ -12,8 +12,8 @@ from typing import NamedTuple class X(NamedTuple): x: int - _y: int # E: NamedTuple field name cannot start with an underscore: _y - _z: int # E: NamedTuple field name cannot start with an underscore: _z + _y: int # E: NamedTuple field name cannot start with an underscore: "_y" + _z: int # E: NamedTuple field name cannot start with an underscore: "_z" [builtins fixtures/tuple.pyi] [case testNewNamedTupleAccessingAttributes] @@ -408,7 +408,7 @@ class X(NamedTuple): y = 2 # E: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [builtins fixtures/tuple.pyi] -[case testTypeUsingTypeCNamedTuple] +[case testClassTypeUsingTypeCNamedTuple] # flags: --python-version 3.6 from typing import NamedTuple, Type @@ -417,10 +417,8 @@ class N(NamedTuple): y: str def f(a: Type[N]): - a() + a() # E: Missing positional arguments "x", "y" in call to "N" [builtins fixtures/list.pyi] -[out] -main:9: error: Missing positional arguments "x", "y" in call to "N" [case testNewNamedTupleWithDefaults] # flags: --python-version 3.6 @@ -627,7 +625,7 @@ class MagicalFields(NamedTuple): def __slots__(self) -> None: pass # E: Cannot overwrite NamedTuple attribute "__slots__" def __new__(cls) -> MagicalFields: pass # E: Cannot overwrite NamedTuple attribute "__new__" def _source(self) -> int: pass # E: Cannot overwrite NamedTuple attribute "_source" - __annotations__ = {'x': float} # E: NamedTuple field name cannot start with an underscore: __annotations__ \ + __annotations__ = {'x': float} # E: NamedTuple field name cannot start with an underscore: "__annotations__" \ # E: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" \ # E: Cannot overwrite NamedTuple attribute "__annotations__" diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 8f411735149a..41d23b7d75f6 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -3480,10 +3480,9 @@ def f(a: Type[Tuple[int, int]]): from typing import Type, NamedTuple N = NamedTuple('N', [('x', int), ('y', int)]) def f(a: Type[N]): - a() -[builtins fixtures/list.pyi] -[out] -main:4: error: Missing positional arguments "x", "y" in call to "N" + a() # E: Missing positional arguments "x", "y" in call to "N" +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testTypeUsingTypeCJoin] from typing import Type @@ -4681,13 +4680,13 @@ class A(Tuple[int, str]): pass -- ----------------------- [case testCrashOnSelfRecursiveNamedTupleVar] - from typing import NamedTuple N = NamedTuple('N', [('x', N)]) # E: Cannot resolve name "N" (possible cyclic definition) n: N reveal_type(n) # N: Revealed type is "Tuple[Any, fallback=__main__.N]" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testCrashOnSelfRecursiveTypedDictVar] from mypy_extensions import TypedDict @@ -5006,18 +5005,25 @@ reveal_type(y1) # N: Revealed type is "Tuple[builtins.list[Any], fallback=__main [out] [case testCrashInvalidArgsSyntheticFunctionSyntax] -from typing import List, NewType, NamedTuple +from typing import List, NewType from mypy_extensions import TypedDict TD = TypedDict('TD', {'x': List[int, str]}) # E: "list" expects 1 type argument, but 2 given -NM = NamedTuple('NM', [('x', List[int, str])]) # E: "list" expects 1 type argument, but 2 given NT = NewType('NT', List[int, str]) # E: "list" expects 1 type argument, but 2 given -# These three should not crash +# These should not crash TD({'x': []}) -NM(x=[]) NT([]) [builtins fixtures/dict.pyi] -[out] + +[case testCrashInvalidArgsSyntheticFunctionSyntaxNamedTuple] +from typing import NamedTuple, List +NM = NamedTuple('NM', [('x', List[int, str])]) # E: "list" expects 1 type argument, but 2 given \ + # E: Type application has too many types (1 expected) + +# These should not crash +NM(x=[]) +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testCrashForwardSyntheticClassSyntax] from typing import NamedTuple @@ -5037,16 +5043,22 @@ reveal_type(y['b']) # N: Revealed type is "__main__.B" [builtins fixtures/dict.pyi] [out] -[case testCrashForwardSyntheticFunctionSyntax] +[case testCrashForwardSyntheticFunctionSyntaxNamedTuple] from typing import NamedTuple -from mypy_extensions import TypedDict A1 = NamedTuple('A1', [('b', 'B'), ('x', int)]) -A2 = TypedDict('A2', {'b': 'B', 'x': int}) class B: pass x: A1 -y: A2 reveal_type(x.b) # N: Revealed type is "__main__.B" +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] + +[case testCrashForwardSyntheticFunctionSyntax] +from mypy_extensions import TypedDict +A2 = TypedDict('A2', {'b': 'B', 'x': int}) +class B: + pass +y: A2 reveal_type(y['b']) # N: Revealed type is "__main__.B" [builtins fixtures/dict.pyi] [out] @@ -6610,7 +6622,8 @@ N = NamedTuple('N', [('x', int)]) class B(A, N): pass reveal_type(A()) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.B]" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewReturnType8] from typing import TypeVar, Any diff --git a/test-data/unit/check-custom-plugin.test b/test-data/unit/check-custom-plugin.test index 2707d886d64e..6e9031b6bcac 100644 --- a/test-data/unit/check-custom-plugin.test +++ b/test-data/unit/check-custom-plugin.test @@ -589,6 +589,7 @@ reveal_type(FullyQualifiedTestNamedTuple('')._asdict()) # N: Revealed type is "b \[mypy] plugins=/test-data/unit/plugins/fully_qualified_test_hook.py [builtins fixtures/classmethod.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testDynamicClassPlugin] # flags: --config-file tmp/mypy.ini @@ -649,7 +650,7 @@ from mod import declarative_base Base1 = Base2 = declarative_base() -class C1(Base1): ... +class C1(Base1): ... class C2(Base2): ... [file mod.py] def declarative_base(): ... diff --git a/test-data/unit/check-enum.test b/test-data/unit/check-enum.test index 21350c030186..4dff0b65db0a 100644 --- a/test-data/unit/check-enum.test +++ b/test-data/unit/check-enum.test @@ -245,7 +245,8 @@ class E(N, Enum): def f(x: E) -> None: pass f(E.X) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testEnumCall] from enum import IntEnum diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 02f6b034c512..9ada2eed3951 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -891,7 +891,8 @@ from missing import Unchecked Point = NamedTuple('Point', [('x', List[Unchecked]), ('y', Unchecked)]) -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] main:5: error: NamedTuple type becomes "Tuple[List[Any], Any]" due to an unfollowed import @@ -1182,7 +1183,8 @@ Point = NamedTuple('Point', [('x', int), ('y', int)]) # no error def origin() -> Point: return Point(x=0, y=0) -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testDisallowAnyExprNewType] # flags: --disallow-any-expr @@ -1738,7 +1740,8 @@ z = cast(List[Any], x) # E: Explicit "Any" is not allowed from typing import Any, List, NamedTuple Point = NamedTuple('Point', [('x', List[Any]), ('y', Any)]) # E: Explicit "Any" is not allowed -[builtins fixtures/list.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testDisallowAnyExplicitTypeVarConstraint] # flags: --disallow-any-explicit diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 0e3e1966cfdb..02361c95aace 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -1637,7 +1637,8 @@ MyTuple = NamedTuple('MyTuple', [ [rechecked bar, mid, foo] [stale bar] -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out2] tmp/foo.py:3: error: Argument 1 to "accept_int" has incompatible type "str"; expected "int" @@ -1672,7 +1673,8 @@ class Outer: [rechecked bar, mid, foo] [stale bar] -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out2] tmp/foo.py:3: error: Argument 1 to "accept_int" has incompatible type "str"; expected "int" @@ -1843,7 +1845,8 @@ from typing import NamedTuple class C: def f(self) -> None: A = NamedTuple('A', [('x', int), ('y', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out1] main:1: error: Module "ntcrash" has no attribute "nope" [out2] @@ -1857,7 +1860,8 @@ class C: class D: def f(self) -> None: A = NamedTuple('A', [('x', int), ('y', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out1] main:1: error: Module "ntcrash" has no attribute "nope" [out2] @@ -1872,7 +1876,8 @@ class C: class D: def f(self) -> None: A = NamedTuple('A', [('x', int), ('y', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out1] main:1: error: Module "ntcrash" has no attribute "nope" [out2] @@ -1937,6 +1942,7 @@ def f() -> None: B = NamedTuple('B', [('x', X)]) [builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out1] main:1: error: Module "ntcrash" has no attribute "nope" [out2] @@ -2648,7 +2654,8 @@ yg: G[M] z: int = G[M]().x.x z = G[M]().x[0] M = NamedTuple('M', [('x', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] [case testSelfRefNTIncremental1] @@ -2691,7 +2698,8 @@ A = NamedTuple('A', [ n: B m: A lst = [m, n] -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testSelfRefNTIncremental4] @@ -2721,7 +2729,8 @@ A = NamedTuple('A', [ ]) n: A def f(m: B) -> None: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testCrashWithPartialGlobalAndCycle] import bar @@ -5119,7 +5128,8 @@ reveal_type(x) [file b.py] from typing import NamedTuple NT = NamedTuple('BadName', [('x', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] tmp/b.py:2: error: First argument to "NamedTuple()" should be "NT", not "BadName" [out2] @@ -5163,7 +5173,8 @@ class C: def __init__(self) -> None: self.h: Hidden Hidden = NamedTuple('Hidden', [('x', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] [out2] tmp/a.py:3: note: Revealed type is "Tuple[builtins.int, fallback=b.C.Hidden@5]" @@ -5532,8 +5543,8 @@ def g() -> None: NT = NamedTuple('NT', [('y', str)]) n: NT = NT(y='x') - -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testIncrementalNestedTypeAlias] import a diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 37ae12419151..bfd2eb6a75b1 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -2201,6 +2201,7 @@ tup2[idx5] # E: Tuple index out of range reveal_type(tup2[idx2:idx4]) # N: Revealed type is "Tuple[__main__.C, __main__.D, fallback=__main__.Tup2Class]" reveal_type(tup2[::idx2]) # N: Revealed type is "Tuple[__main__.A, __main__.C, __main__.E, fallback=__main__.Tup2Class]" [builtins fixtures/slice.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] [case testLiteralIntelligentIndexingTypedDict] @@ -2242,7 +2243,7 @@ del d[c_key] # E: TypedDict "Outer" has no key "c" [out] [case testLiteralIntelligentIndexingUsingFinal] -from typing import Tuple, NamedTuple +from typing import Tuple from typing_extensions import Literal, Final from mypy_extensions import TypedDict @@ -2253,33 +2254,44 @@ str_key_bad: Final = "missing" class Unrelated: pass -MyTuple = NamedTuple('MyTuple', [ - ('foo', int), - ('bar', str), -]) - class MyDict(TypedDict): foo: int bar: str a: Tuple[int, str] -b: MyTuple c: MyDict u: Unrelated reveal_type(a[int_key_good]) # N: Revealed type is "builtins.int" -reveal_type(b[int_key_good]) # N: Revealed type is "builtins.int" reveal_type(c[str_key_good]) # N: Revealed type is "builtins.int" reveal_type(c.get(str_key_good, u)) # N: Revealed type is "Union[builtins.int, __main__.Unrelated]" reveal_type(c.get(str_key_bad, u)) # N: Revealed type is "builtins.object" a[int_key_bad] # E: Tuple index out of range -b[int_key_bad] # E: Tuple index out of range c[str_key_bad] # E: TypedDict "MyDict" has no key "missing" [builtins fixtures/dict.pyi] [typing fixtures/typing-typeddict.pyi] [out] +[case testLiteralIntelligentIndexingUsingFinalNamedTuple] +from typing import NamedTuple +from typing_extensions import Final + +int_key_good: Final = 0 +int_key_bad: Final = 3 + +MyTuple = NamedTuple('MyTuple', [ + ('foo', int), + ('bar', str), +]) + +b: MyTuple + +reveal_type(b[int_key_good]) # N: Revealed type is "builtins.int" +b[int_key_bad] # E: Tuple index out of range +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] + [case testLiteralIntelligentIndexingTupleUnions] from typing import Tuple, NamedTuple from typing_extensions import Literal diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 1ae31d99c25b..5257331e91da 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -2531,7 +2531,8 @@ x = m.One(name="Foo") reveal_type(x.name) class Two: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] tmp/m/two.py:3: note: Revealed type is "builtins.str" @@ -3131,4 +3132,4 @@ main:2: error: Cannot find implementation or library stub for module named "blea # flags: --ignore-missing-imports import bleach.xyz from bleach.abc import fgh -[file bleach/__init__.pyi] \ No newline at end of file +[file bleach/__init__.pyi] diff --git a/test-data/unit/check-namedtuple.test b/test-data/unit/check-namedtuple.test index 6df50efe302a..b781f422d893 100644 --- a/test-data/unit/check-namedtuple.test +++ b/test-data/unit/check-namedtuple.test @@ -142,20 +142,13 @@ A = namedtuple('A', 'a b') A1 = namedtuple('A1', 'a _b raise', rename=True) B = namedtuple('B', 'a b', rename=1) C = namedtuple('C', 'a b', rename='not a bool') -D = namedtuple('D', 'a b', unrecognized_arg=False) -E = namedtuple('E', 'a b', 0) - +D = namedtuple('D', 'a b', 0) [builtins fixtures/bool.pyi] - [out] main:5: error: Bool literal expected as the "rename" argument to "namedtuple()" main:6: error: Bool literal expected as the "rename" argument to "namedtuple()" main:6: error: Argument "rename" to "namedtuple" has incompatible type "str"; expected "int" -main:7: error: Unexpected keyword argument "unrecognized_arg" for "namedtuple" -/Users/sobolev/Desktop/mypy/test-data/unit/lib-stub/collections.pyi:3: note: "namedtuple" defined here -main:7: error: Unexpected keyword argument "unrecognized_arg" for "namedtuple" -/Users/sobolev/Desktop/mypy/test-data/unit/lib-stub/collections.pyi:3: note: "namedtuple" defined here -main:8: error: Too many positional arguments for "namedtuple" +main:7: error: Too many positional arguments for "namedtuple" [case testNamedTupleDefaults] # flags: --python-version 3.7 @@ -695,7 +688,7 @@ Node = NamedTuple('Node', [ ('children', List['Node']), # E: Cannot resolve name "Node" (possible cyclic definition) ]) n: Node -reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.list[Any], fallback=__main__.Node]" +reveal_type(n) # N: Revealed type is "Tuple[builtins.str, typing.List[Any], fallback=__main__.Node]" [builtins fixtures/dict.pyi] [typing fixtures/typing-namedtuple.pyi] @@ -711,7 +704,7 @@ class B(NamedTuple): y: int n: A -reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.list[Any], fallback=__main__.A]" +reveal_type(n) # N: Revealed type is "Tuple[builtins.str, typing.List[Any], fallback=__main__.A]" [builtins fixtures/dict.pyi] [typing fixtures/typing-namedtuple.pyi] diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index 0a69b46e7641..bb8e02906c71 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -2632,7 +2632,8 @@ c: C reveal_type(f(*a)) # N: Revealed type is "Tuple[builtins.int, builtins.int]" reveal_type(f(*b)) # N: Revealed type is "Tuple[builtins.int, builtins.int]" reveal_type(f(*c)) # N: Revealed type is "builtins.tuple[builtins.int]" -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testOverloadKwargsSelectionWithDict] from typing import overload, Tuple, Dict diff --git a/test-data/unit/check-serialize.test b/test-data/unit/check-serialize.test index b34a6c704a27..cd0b7b66506b 100644 --- a/test-data/unit/check-serialize.test +++ b/test-data/unit/check-serialize.test @@ -725,7 +725,8 @@ class C: self.a = A(0) self.b = A(0) # type: A self.c = A -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out1] main:2: note: Revealed type is "Tuple[builtins.int, fallback=ntcrash.C.A@4]" main:3: note: Revealed type is "Tuple[builtins.int, fallback=ntcrash.C.A@4]" @@ -940,7 +941,8 @@ b.N(x='') from typing import NamedTuple N = NamedTuple('N', [('x', int)]) x: N -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out2] tmp/a.py:5: error: Incompatible types in assignment (expression has type "Tuple[int]", variable has type "N") tmp/a.py:6: error: Incompatible types in assignment (expression has type "Tuple[int]", variable has type "N") diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 62d82f94a6c1..804827561aad 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -1764,8 +1764,8 @@ for i in lst: a: str = i[0] # E: Incompatible types in assignment (expression has type "int", variable has type "str") N = NamedTuple('N', [('x', int)]) -[builtins fixtures/list.pyi] -[out] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testForwardRefsInForStatement] from typing import List, NamedTuple diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index a697c32d7c49..eb6a77b060f1 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -390,8 +390,8 @@ D = NamedTuple('D', [('y', str)]) class E(Tuple[int, str]): pass -[builtins fixtures/tuple.pyi] -[out] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testTypeAliasesToAny] from typing import Any diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index 522bc7b236ad..fdaf7a39b924 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -323,6 +323,7 @@ def foo(a: Union[A, B, C]): # E: Item "C" of "Union[B, C]" has no attribute "y" b = a # type: Union[B, C] [builtins fixtures/isinstance.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testSimplifyingUnionAndTypePromotions] from typing import TypeVar, Union diff --git a/test-data/unit/fixtures/callable.pyi b/test-data/unit/fixtures/callable.pyi index 4ad72bee93ec..29178221b9b6 100644 --- a/test-data/unit/fixtures/callable.pyi +++ b/test-data/unit/fixtures/callable.pyi @@ -1,4 +1,4 @@ -from typing import Generic, Tuple, TypeVar, Union +from typing import Generic, Tuple, TypeVar, Union, Iterable T = TypeVar('T') @@ -27,4 +27,5 @@ class str: def __add__(self, other: 'str') -> 'str': pass def __eq__(self, other: 'str') -> bool: pass class ellipsis: pass -class list: ... +class list(Iterable[T]): pass +class dict: pass diff --git a/test-data/unit/fixtures/classmethod.pyi b/test-data/unit/fixtures/classmethod.pyi index 03ad803890a3..9af6940b9d9e 100644 --- a/test-data/unit/fixtures/classmethod.pyi +++ b/test-data/unit/fixtures/classmethod.pyi @@ -26,3 +26,5 @@ class bool: pass class ellipsis: pass class tuple(typing.Generic[_T]): pass +class list(typing.Iterable[_T]): pass +class dict: pass diff --git a/test-data/unit/fixtures/isinstance.pyi b/test-data/unit/fixtures/isinstance.pyi index 7f7cf501b5de..86a5fe3b5a30 100644 --- a/test-data/unit/fixtures/isinstance.pyi +++ b/test-data/unit/fixtures/isinstance.pyi @@ -1,4 +1,4 @@ -from typing import Tuple, TypeVar, Generic, Union, cast, Any, Type +from typing import Tuple, TypeVar, Generic, Union, cast, Any, Type, Iterable T = TypeVar('T') @@ -9,6 +9,8 @@ class type: def __init__(self, x) -> None: pass class tuple(Generic[T]): pass +class list(Iterable[T]): pass +class dict: pass class function: pass diff --git a/test-data/unit/fixtures/slice.pyi b/test-data/unit/fixtures/slice.pyi index 947d49ea09fb..7f71ea861ded 100644 --- a/test-data/unit/fixtures/slice.pyi +++ b/test-data/unit/fixtures/slice.pyi @@ -14,3 +14,6 @@ class str: pass class slice: pass class ellipsis: pass + +class list: pass +class dict: pass diff --git a/test-data/unit/fixtures/typing-namedtuple.pyi b/test-data/unit/fixtures/typing-namedtuple.pyi index d357cac1ef44..63c8c860ddb9 100644 --- a/test-data/unit/fixtures/typing-namedtuple.pyi +++ b/test-data/unit/fixtures/typing-namedtuple.pyi @@ -6,19 +6,24 @@ Type = 0 NewType = 0 Optional = 0 Union = 0 +cast = 0 T_co = TypeVar('T_co', covariant=True) KT = TypeVar('KT') class Iterable(Generic[T_co]): pass -class Iterator(Iterable[T_co]): pass +class Iterator(Iterable[T_co]): + def __next__(self) -> T_co: pass class Sequence(Iterable[T_co]): pass class Mapping(Iterable[KT], Generic[KT, T_co]): pass +class List(Sequence[KT]): + def __iter__(self) -> Iterator[KT]: pass + class Tuple(Sequence): pass class NamedTuple(Tuple): _source: str @overload - def __init__(self, typename: str, fields: Iterable[Tuple[str, Any]] = ...) -> None: ... + def __init__(self, typename: str, fields: Iterable[Tuple[str, object]] = ...) -> None: ... @overload - def __init__(self, typename: str, fields: None = ..., **kwargs: Any) -> None: ... + def __init__(self, typename: str, fields: None = ..., **kwargs: object) -> None: ... From ccbefa178d58a4a3f9d3e6a2023f1e43dc3542a3 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 4 Dec 2021 17:16:42 +0300 Subject: [PATCH 09/13] All typecheck tests should pass now --- test-data/unit/check-classes.test | 4 ++-- test-data/unit/check-errorcodes.test | 3 ++- test-data/unit/check-literal.test | 2 +- test-data/unit/check-newsemanal.test | 29 +++++++++++++++----------- test-data/unit/check-statements.test | 4 ++-- test-data/unit/fixtures/isinstance.pyi | 5 +++-- test-data/unit/fixtures/slice.pyi | 5 +++-- 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 41d23b7d75f6..cc434e1ba0a5 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -5017,11 +5017,11 @@ NT([]) [case testCrashInvalidArgsSyntheticFunctionSyntaxNamedTuple] from typing import NamedTuple, List -NM = NamedTuple('NM', [('x', List[int, str])]) # E: "list" expects 1 type argument, but 2 given \ +NM = NamedTuple('NM', [('x', List[int, str])]) # E: "List" expects 1 type argument, but 2 given \ # E: Type application has too many types (1 expected) # These should not crash -NM(x=[]) +NM(x=[]) # type: ignore [builtins fixtures/dict.pyi] [typing fixtures/typing-namedtuple.pyi] diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 0eb73f58b55a..8e299605a486 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -839,7 +839,8 @@ k = [x for x in lst if isinstance(x, int) or foo()] # E: If condition in compre from typing import NamedTuple Foo = NamedTuple("Bar", []) # E: First argument to "NamedTuple()" should be "Foo", not "Bar" [name-match] -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testTypedDictNameMismatch] from typing_extensions import TypedDict diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index bfd2eb6a75b1..f757a3ae7abe 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -2320,7 +2320,7 @@ reveal_type(tup2[idx1:idx2]) # N: Revealed type is "Union[Tuple[__main__.B, _ reveal_type(tup2[0::idx1]) # N: Revealed type is "Union[Tuple[__main__.A, __main__.B, __main__.C, __main__.D, __main__.E, fallback=__main__.Tup2Class], Tuple[__main__.A, __main__.C, __main__.E, fallback=__main__.Tup2Class]]" tup2[idx_bad] # E: Tuple index out of range [builtins fixtures/slice.pyi] -[out] +[typing fixtures/typing-namedtuple.pyi] [case testLiteralIntelligentIndexingTypedDictUnions] from typing_extensions import Literal, Final diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index 4e0729d355d5..3fdfa723d82d 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -867,7 +867,8 @@ reveal_type(i.t) # N: Revealed type is "__main__.Other" In = NamedTuple('In', [('s', str), ('t', Other)]) class Other: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewAnalyzerNamedTupleClass] from typing import NamedTuple @@ -907,7 +908,8 @@ class C: In = NamedTuple('In', [('s', str), ('t', Other)]) Out = NamedTuple('Out', [('x', In), ('y', Other)]) class Other: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewAnalyzerNamedTupleClassNested] @@ -930,7 +932,8 @@ class C: s: str t: C.Other class Other: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewAnalyzerNamedTupleCallNestedMethod] from typing import NamedTuple @@ -945,7 +948,8 @@ class C: Out = NamedTuple('Out', [('x', In), ('y', Other)]) In = NamedTuple('In', [('s', str), ('t', Other)]) class Other: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewAnalyzerNamedTupleClassNestedMethod] from typing import NamedTuple @@ -997,7 +1001,8 @@ class SubO(Out): pass Out = NamedTuple('Out', [('x', In), ('y', Other)]) In = NamedTuple('In', [('s', str), ('t', Other)]) class Other: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewAnalyzerNamedTupleBaseClass] from typing import NamedTuple @@ -1701,7 +1706,8 @@ B = Union[C[str], int] # E: Type argument "str" of "C" must be a subtype of "int S = TypeVar('S', bound=C[str]) # E: Type argument "str" of "C" must be a subtype of "int" U = TypeVar('U', C[str], str) # E: Type argument "str" of "C" must be a subtype of "int" N = NamedTuple('N', [ - ('x', C[str])]) # E: Type argument "str" of "C" must be a subtype of "int" + ('x', C[str])]) # E: Type argument "str" of "C" must be a subtype of "int" \ + # E: Value of type variable "T" of "C" cannot be "str" class N2(NamedTuple): x: C[str] # E: Type argument "str" of "C" must be a subtype of "int" class TD(TypedDict): @@ -1735,7 +1741,8 @@ def g(x: int) -> int: ... def g(x: Union[C[str], int]) -> int: # E: Type argument "str" of "C" must be a subtype of "int" y: C[object] # E: Type argument "object" of "C" must be a subtype of "int" return 0 -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewAnalyzerTypeArgBoundCheckWithStrictOptional] # flags: --config-file tmp/mypy.ini @@ -2305,13 +2312,10 @@ reveal_type(A().x) # N: Revealed type is "__main__.C" class C(A): ... -[case testNewAnalyzerCastForward2] +[case testNewAnalyzerCastForward1_2] from typing import cast - x = cast('C', None) - reveal_type(x) # N: Revealed type is "builtins.int" - C = int [case testNewAnalyzerCastForward2] @@ -2323,7 +2327,8 @@ reveal_type(x) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.C]" reveal_type(x.x) # N: Revealed type is "builtins.int" C = NamedTuple('C', [('x', int)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testNewAnalyzerApplicationForward1] from typing import Generic, TypeVar diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 804827561aad..b6744a80f414 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -1777,8 +1777,8 @@ for i in lst: # type: N N = NamedTuple('N', [('x', int)]) class M(N): pass -[builtins fixtures/list.pyi] -[out] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testForwardRefsInWithStatementImplicit] from typing import ContextManager, Any diff --git a/test-data/unit/fixtures/isinstance.pyi b/test-data/unit/fixtures/isinstance.pyi index 86a5fe3b5a30..9b492611d441 100644 --- a/test-data/unit/fixtures/isinstance.pyi +++ b/test-data/unit/fixtures/isinstance.pyi @@ -1,4 +1,4 @@ -from typing import Tuple, TypeVar, Generic, Union, cast, Any, Type, Iterable +from typing import Tuple, TypeVar, Generic, Union, cast, Any, Type, Iterable, Iterator T = TypeVar('T') @@ -9,7 +9,8 @@ class type: def __init__(self, x) -> None: pass class tuple(Generic[T]): pass -class list(Iterable[T]): pass +class list(Iterable[T]): + def __iter__(self) -> Iterator[T]: pass class dict: pass class function: pass diff --git a/test-data/unit/fixtures/slice.pyi b/test-data/unit/fixtures/slice.pyi index 7f71ea861ded..28458bc1d643 100644 --- a/test-data/unit/fixtures/slice.pyi +++ b/test-data/unit/fixtures/slice.pyi @@ -1,5 +1,5 @@ # Builtins stub used in slicing test cases. -from typing import Generic, TypeVar +from typing import Generic, TypeVar, Iterator, Iterable T = TypeVar('T') class object: @@ -15,5 +15,6 @@ class str: pass class slice: pass class ellipsis: pass -class list: pass +class list(Iterable[T]): + def __iter__(self) -> Iterator[T]: pass class dict: pass From c0fdbc63f747f786512dbf3da31c19e7bf386dc0 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 4 Dec 2021 18:50:20 +0300 Subject: [PATCH 10/13] Fixes fine-grained tests --- test-data/unit/fine-grained-suggest.test | 3 ++- test-data/unit/fine-grained.test | 30 ++++++++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/test-data/unit/fine-grained-suggest.test b/test-data/unit/fine-grained-suggest.test index 4a1bda8b0afd..cf9917ea76ee 100644 --- a/test-data/unit/fine-grained-suggest.test +++ b/test-data/unit/fine-grained-suggest.test @@ -153,7 +153,8 @@ from typing import NamedTuple N = NamedTuple('N', [('x', int)]) def foo(): return N(1) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] () -> foo.N == diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index b528fc84bdbb..4b1d7bf2f09a 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -1692,7 +1692,8 @@ N = NamedTuple('N', [('x', int)]) [file a.py] def f() -> None: pass [file a.py.2] -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == main:2: error: Module "a" has no attribute "f" @@ -3278,7 +3279,8 @@ class C(N): x = 0 [file m.py.2] x = '' -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == @@ -3387,7 +3389,8 @@ a: A def g() -> None: x = L(A()) x.f(a) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == @@ -3455,7 +3458,8 @@ import a def f(x: a.N) -> None: pass f(a.x) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == @@ -3474,7 +3478,8 @@ import a def f(x: a.N) -> None: pass f(a.x) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == @@ -3503,7 +3508,8 @@ def f(x: b.M) -> None: lol(x) f(b.x) lol(b.x) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == c.py:7: error: Argument 1 to "lol" has incompatible type "M"; expected "Tuple[Tuple[int]]" @@ -4346,7 +4352,8 @@ def f() -> None: x = 0 [file b.py.2] x = '' -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == @@ -8509,7 +8516,8 @@ NT = NamedTuple('NT', [('x', B)]) [file b.py.2] def func(x): pass B = func -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == main:5: error: Variable "b.B" is not valid as a type @@ -8527,7 +8535,8 @@ A = B [file b.py.2] def func(x): pass B = func -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == main:5: error: Variable "a.A" is not valid as a type @@ -8555,7 +8564,8 @@ A = B [file b.py.2] def func(x): pass B = func -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] == m.py:4: error: Variable "a.A" is not valid as a type From 420d73f40a172ffa84bc54f9c79cac1e35458cfc Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 4 Dec 2021 19:33:20 +0300 Subject: [PATCH 11/13] Fixes all other tests --- mypyc/test-data/irbuild-basic.test | 230 ++++++++++++++--------------- mypyc/test-data/irbuild-tuple.test | 1 + test-data/unit/deps-classes.test | 9 +- test-data/unit/deps-types.test | 3 +- test-data/unit/diff.test | 3 +- test-data/unit/merge.test | 80 ++++++---- 6 files changed, 172 insertions(+), 154 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 2032ea034e71..a824bc7b1b83 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -2487,6 +2487,7 @@ x = Lol(1, '') Foo = List[int] Bar = NewType('Bar', Foo) y = Bar([1,2,3]) +[typing fixtures/typing-full.pyi] [out] def __top_level__(): r0, r1 :: object @@ -2517,57 +2518,54 @@ def __top_level__(): r37, r38 :: str r39 :: object r40 :: tuple[str, object] - r41 :: object - r42 :: str - r43 :: object - r44 :: tuple[str, object] - r45 :: object - r46 :: tuple[object, object] - r47 :: object - r48 :: dict - r49 :: str - r50, r51 :: object - r52 :: dict - r53 :: str - r54 :: int32 - r55 :: bit + r41 :: str + r42 :: object + r43 :: tuple[str, object] + r44 :: tuple[tuple[str, object], tuple[str, object]] + r45 :: dict + r46 :: str + r47, r48, r49 :: object + r50 :: dict + r51 :: str + r52 :: int32 + r53 :: bit + r54 :: str + r55 :: dict r56 :: str - r57 :: dict - r58 :: str - r59, r60, r61 :: object - r62 :: tuple - r63 :: dict - r64 :: str - r65 :: int32 - r66 :: bit - r67 :: dict - r68 :: str - r69, r70, r71 :: object - r72 :: dict - r73 :: str - r74 :: int32 - r75 :: bit + r57, r58, r59 :: object + r60 :: tuple + r61 :: dict + r62 :: str + r63 :: int32 + r64 :: bit + r65 :: dict + r66 :: str + r67, r68, r69 :: object + r70 :: dict + r71 :: str + r72 :: int32 + r73 :: bit + r74 :: str + r75 :: dict r76 :: str - r77 :: dict - r78 :: str - r79 :: object - r80 :: dict - r81 :: str - r82, r83 :: object - r84 :: dict - r85 :: str - r86 :: int32 - r87 :: bit - r88 :: list - r89, r90, r91 :: object - r92, r93, r94, r95 :: ptr - r96 :: dict - r97 :: str - r98, r99 :: object - r100 :: dict - r101 :: str - r102 :: int32 - r103 :: bit + r77 :: object + r78 :: dict + r79 :: str + r80, r81 :: object + r82 :: dict + r83 :: str + r84 :: int32 + r85 :: bit + r86 :: list + r87, r88, r89 :: object + r90, r91, r92, r93 :: ptr + r94 :: dict + r95 :: str + r96, r97 :: object + r98 :: dict + r99 :: str + r100 :: int32 + r101 :: bit L0: r0 = builtins :: module r1 = load_address _Py_NoneStruct @@ -2586,9 +2584,9 @@ L2: r10 = get_element_ptr r9 ob_item :: PyListObject r11 = load_mem r10 :: ptr* set_mem r11, r6 :: builtins.object* - r12 = r11 + WORD_SIZE*1 + r12 = r11 + 8 set_mem r12, r7 :: builtins.object* - r13 = r11 + WORD_SIZE*2 + r13 = r11 + 16 set_mem r13, r8 :: builtins.object* keep_alive r9 r14 = 'typing' @@ -2619,73 +2617,71 @@ L2: r38 = 'a' r39 = load_address PyLong_Type r40 = (r38, r39) - r41 = box(tuple[str, object], r40) - r42 = 'b' - r43 = load_address PyUnicode_Type - r44 = (r42, r43) - r45 = box(tuple[str, object], r44) - r46 = (r41, r45) - r47 = box(tuple[object, object], r46) - r48 = __main__.globals :: static - r49 = 'NamedTuple' - r50 = CPyDict_GetItem(r48, r49) - r51 = PyObject_CallFunctionObjArgs(r50, r37, r47, 0) - r52 = __main__.globals :: static - r53 = 'Lol' - r54 = CPyDict_SetItem(r52, r53, r51) - r55 = r54 >= 0 :: signed - r56 = '' - r57 = __main__.globals :: static - r58 = 'Lol' - r59 = CPyDict_GetItem(r57, r58) - r60 = box(short_int, 2) - r61 = PyObject_CallFunctionObjArgs(r59, r60, r56, 0) - r62 = cast(tuple, r61) - r63 = __main__.globals :: static - r64 = 'x' - r65 = CPyDict_SetItem(r63, r64, r62) - r66 = r65 >= 0 :: signed - r67 = __main__.globals :: static - r68 = 'List' - r69 = CPyDict_GetItem(r67, r68) - r70 = load_address PyLong_Type - r71 = PyObject_GetItem(r69, r70) - r72 = __main__.globals :: static - r73 = 'Foo' - r74 = CPyDict_SetItem(r72, r73, r71) - r75 = r74 >= 0 :: signed - r76 = 'Bar' - r77 = __main__.globals :: static - r78 = 'Foo' - r79 = CPyDict_GetItem(r77, r78) - r80 = __main__.globals :: static - r81 = 'NewType' - r82 = CPyDict_GetItem(r80, r81) - r83 = PyObject_CallFunctionObjArgs(r82, r76, r79, 0) - r84 = __main__.globals :: static - r85 = 'Bar' - r86 = CPyDict_SetItem(r84, r85, r83) - r87 = r86 >= 0 :: signed - r88 = PyList_New(3) - r89 = box(short_int, 2) - r90 = box(short_int, 4) - r91 = box(short_int, 6) - r92 = get_element_ptr r88 ob_item :: PyListObject - r93 = load_mem r92 :: ptr* + r41 = 'b' + r42 = load_address PyUnicode_Type + r43 = (r41, r42) + r44 = (r40, r43) + r45 = __main__.globals :: static + r46 = 'NamedTuple' + r47 = CPyDict_GetItem(r45, r46) + r48 = box(tuple[tuple[str, object], tuple[str, object]], r44) + r49 = PyObject_CallFunctionObjArgs(r47, r37, r48, 0) + r50 = __main__.globals :: static + r51 = 'Lol' + r52 = CPyDict_SetItem(r50, r51, r49) + r53 = r52 >= 0 :: signed + r54 = '' + r55 = __main__.globals :: static + r56 = 'Lol' + r57 = CPyDict_GetItem(r55, r56) + r58 = box(short_int, 2) + r59 = PyObject_CallFunctionObjArgs(r57, r58, r54, 0) + r60 = cast(tuple, r59) + r61 = __main__.globals :: static + r62 = 'x' + r63 = CPyDict_SetItem(r61, r62, r60) + r64 = r63 >= 0 :: signed + r65 = __main__.globals :: static + r66 = 'List' + r67 = CPyDict_GetItem(r65, r66) + r68 = load_address PyLong_Type + r69 = PyObject_GetItem(r67, r68) + r70 = __main__.globals :: static + r71 = 'Foo' + r72 = CPyDict_SetItem(r70, r71, r69) + r73 = r72 >= 0 :: signed + r74 = 'Bar' + r75 = __main__.globals :: static + r76 = 'Foo' + r77 = CPyDict_GetItem(r75, r76) + r78 = __main__.globals :: static + r79 = 'NewType' + r80 = CPyDict_GetItem(r78, r79) + r81 = PyObject_CallFunctionObjArgs(r80, r74, r77, 0) + r82 = __main__.globals :: static + r83 = 'Bar' + r84 = CPyDict_SetItem(r82, r83, r81) + r85 = r84 >= 0 :: signed + r86 = PyList_New(3) + r87 = box(short_int, 2) + r88 = box(short_int, 4) + r89 = box(short_int, 6) + r90 = get_element_ptr r86 ob_item :: PyListObject + r91 = load_mem r90 :: ptr* + set_mem r91, r87 :: builtins.object* + r92 = r91 + 8 + set_mem r92, r88 :: builtins.object* + r93 = r91 + 16 set_mem r93, r89 :: builtins.object* - r94 = r93 + WORD_SIZE*1 - set_mem r94, r90 :: builtins.object* - r95 = r93 + WORD_SIZE*2 - set_mem r95, r91 :: builtins.object* - keep_alive r88 - r96 = __main__.globals :: static - r97 = 'Bar' - r98 = CPyDict_GetItem(r96, r97) - r99 = PyObject_CallFunctionObjArgs(r98, r88, 0) - r100 = __main__.globals :: static - r101 = 'y' - r102 = CPyDict_SetItem(r100, r101, r99) - r103 = r102 >= 0 :: signed + keep_alive r86 + r94 = __main__.globals :: static + r95 = 'Bar' + r96 = CPyDict_GetItem(r94, r95) + r97 = PyObject_CallFunctionObjArgs(r96, r86, 0) + r98 = __main__.globals :: static + r99 = 'y' + r100 = CPyDict_SetItem(r98, r99, r97) + r101 = r100 >= 0 :: signed return 1 [case testChainedConditional] diff --git a/mypyc/test-data/irbuild-tuple.test b/mypyc/test-data/irbuild-tuple.test index 564a4bf74d50..c52685235368 100644 --- a/mypyc/test-data/irbuild-tuple.test +++ b/mypyc/test-data/irbuild-tuple.test @@ -169,6 +169,7 @@ def f(nt: NT, b: bool) -> int: if b: return nt.x return nt.y +[typing fixtures/typing-full.pyi] [out] def f(nt, b): nt :: tuple diff --git a/test-data/unit/deps-classes.test b/test-data/unit/deps-classes.test index ebe2e9caed02..dd59d114e85c 100644 --- a/test-data/unit/deps-classes.test +++ b/test-data/unit/deps-classes.test @@ -16,7 +16,8 @@ def f(a: Any) -> None: n.a [file a.py] class A: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] -> m.f -> m.f @@ -36,7 +37,8 @@ def f(a: Any) -> None: [file a.py] class A: pass class B: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] -> m.f -> m.f @@ -52,7 +54,8 @@ N = NamedTuple('N', [('x', int)]) x = N(1) M = NamedTuple('M', [('z', 'N')]) y = M(x) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] -> m -> m diff --git a/test-data/unit/deps-types.test b/test-data/unit/deps-types.test index d0674dfadceb..1fcacb58218e 100644 --- a/test-data/unit/deps-types.test +++ b/test-data/unit/deps-types.test @@ -864,7 +864,8 @@ from mod import I A = I [file mod.py] class I: pass -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] -> m -> m diff --git a/test-data/unit/diff.test b/test-data/unit/diff.test index 7369ea247e26..e26807921abe 100644 --- a/test-data/unit/diff.test +++ b/test-data/unit/diff.test @@ -273,7 +273,8 @@ M = NamedTuple('M', [('x', int), ('y', str)]) from typing import NamedTuple N = NamedTuple('N', [('x', int), ('y', int)]) M = NamedTuple('M', [('x', int), ('y', str)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] __main__.A __main__.N diff --git a/test-data/unit/merge.test b/test-data/unit/merge.test index 836ad87857f8..c7ebff8c7f43 100644 --- a/test-data/unit/merge.test +++ b/test-data/unit/merge.test @@ -656,7 +656,8 @@ N = NamedTuple('N', [('x', A)]) from typing import NamedTuple class A: pass N = NamedTuple('N', [('x', A), ('y', A)]) -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] TypeInfo<0>( Name(target.A) @@ -666,20 +667,27 @@ TypeInfo<0>( TypeInfo<2>( Name(target.N) Bases(builtins.tuple[target.A<0>]<3>) - Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>) + Mro(target.N<2>, builtins.tuple<3>, builtins.object<1>) Names( - _NT<6> - __annotations__<7> (builtins.object<1>) - __doc__<8> (builtins.str<9>) - __new__<10> - _asdict<11> - _field_defaults<12> (builtins.object<1>) - _field_types<13> (builtins.object<1>) - _fields<14> (Tuple[builtins.str<9>]) - _make<15> - _replace<16> - _source<17> (builtins.str<9>) - x<18> (target.A<0>))) + _NT<4> + __annotations__<5> (builtins.dict[builtins.str<6>, Any]<7>) + __doc__<8> (builtins.str<6>) + __new__<9> + _asdict<10> + _field_defaults<11> (builtins.dict[builtins.str<6>, Any]<7>) + _field_types<12> (builtins.dict[builtins.str<6>, Any]<7>) + _fields<13> (Tuple[builtins.str<6>]) + _make<14> + _replace<15> + _source<16> (builtins.str<6>) + x<17> (target.A<0>))) +TypeInfo<18>( + Name(typing.NamedTuple) + Bases(builtins.tuple[Any]<3>) + Mro(typing.NamedTuple<18>, builtins.tuple<3>, builtins.object<1>) + Names( + __init__<19> + _source<20> (builtins.str<6>))) ==> TypeInfo<0>( Name(target.A) @@ -689,21 +697,28 @@ TypeInfo<0>( TypeInfo<2>( Name(target.N) Bases(builtins.tuple[target.A<0>]<3>) - Mro(target.N<2>, builtins.tuple<3>, typing.Sequence<4>, typing.Iterable<5>, builtins.object<1>) + Mro(target.N<2>, builtins.tuple<3>, builtins.object<1>) + Names( + _NT<4> + __annotations__<5> (builtins.dict[builtins.str<6>, Any]<7>) + __doc__<8> (builtins.str<6>) + __new__<9> + _asdict<10> + _field_defaults<11> (builtins.dict[builtins.str<6>, Any]<7>) + _field_types<12> (builtins.dict[builtins.str<6>, Any]<7>) + _fields<13> (Tuple[builtins.str<6>, builtins.str<6>]) + _make<14> + _replace<15> + _source<16> (builtins.str<6>) + x<17> (target.A<0>) + y<21> (target.A<0>))) +TypeInfo<18>( + Name(typing.NamedTuple) + Bases(builtins.tuple[Any]<3>) + Mro(typing.NamedTuple<18>, builtins.tuple<3>, builtins.object<1>) Names( - _NT<6> - __annotations__<7> (builtins.object<1>) - __doc__<8> (builtins.str<9>) - __new__<10> - _asdict<11> - _field_defaults<12> (builtins.object<1>) - _field_types<13> (builtins.object<1>) - _fields<14> (Tuple[builtins.str<9>, builtins.str<9>]) - _make<15> - _replace<16> - _source<17> (builtins.str<9>) - x<18> (target.A<0>) - y<19> (target.A<0>))) + __init__<19> + _source<20> (builtins.str<6>))) [case testUnionType_types] import target @@ -1095,20 +1110,21 @@ N = NamedTuple('N', [('x', int)]) [file target.py] f = 1 [file target.py.next] -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [out] __main__: N: TypeInfo<0> - NamedTuple: Var<1> + NamedTuple: TypeInfo<1> f: Var<2>(builtins.int<3>) target: f: Var<2>(builtins.int<3>) ==> __main__: N: TypeInfo<0> - NamedTuple: Var<1> + NamedTuple: TypeInfo<1> f: Var<4>(Any) -target: +target: [case testRefreshAttributeDefinedInClassBody_typeinfo] from target import f From de558bc417c6bb58cae8c6d51f73fd26db91cbd6 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 4 Dec 2021 20:07:51 +0300 Subject: [PATCH 12/13] Fixes all other tests --- test-data/unit/check-incremental.test | 6 ++++-- test-data/unit/merge.test | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 02361c95aace..5bd16adc58c2 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -2667,7 +2667,8 @@ Node = NamedTuple('Node', [ ('children', Tuple['Node', ...]), # type: ignore ]) n: Node -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testSelfRefNTIncremental2] @@ -2682,7 +2683,8 @@ class B(NamedTuple): y: int n: A -[builtins fixtures/tuple.pyi] +[builtins fixtures/dict.pyi] +[typing fixtures/typing-namedtuple.pyi] [case testSelfRefNTIncremental3] diff --git a/test-data/unit/merge.test b/test-data/unit/merge.test index c7ebff8c7f43..8c36d747a107 100644 --- a/test-data/unit/merge.test +++ b/test-data/unit/merge.test @@ -1124,7 +1124,7 @@ __main__: N: TypeInfo<0> NamedTuple: TypeInfo<1> f: Var<4>(Any) -target: +target: [case testRefreshAttributeDefinedInClassBody_typeinfo] from target import f From 64eded5a0546bceaa8f82149cd94348de4d60e82 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 7 Dec 2021 15:27:43 +0300 Subject: [PATCH 13/13] Fix irbuild test on Windows --- mypyc/test-data/irbuild-basic.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index a824bc7b1b83..c5bbe9205ea5 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -2584,9 +2584,9 @@ L2: r10 = get_element_ptr r9 ob_item :: PyListObject r11 = load_mem r10 :: ptr* set_mem r11, r6 :: builtins.object* - r12 = r11 + 8 + r12 = r11 + WORD_SIZE*1 set_mem r12, r7 :: builtins.object* - r13 = r11 + 16 + r13 = r11 + WORD_SIZE*2 set_mem r13, r8 :: builtins.object* keep_alive r9 r14 = 'typing' @@ -2669,9 +2669,9 @@ L2: r90 = get_element_ptr r86 ob_item :: PyListObject r91 = load_mem r90 :: ptr* set_mem r91, r87 :: builtins.object* - r92 = r91 + 8 + r92 = r91 + WORD_SIZE*1 set_mem r92, r88 :: builtins.object* - r93 = r91 + 16 + r93 = r91 + WORD_SIZE*2 set_mem r93, r89 :: builtins.object* keep_alive r86 r94 = __main__.globals :: static