Skip to content

Commit e0e9c2e

Browse files
elazarggvanrossum
authored andcommitted
Allow using __getitem__ defined in metaclasses of non-generic classes (#2827)
Fix #1771. (Seems to be much simpler than I thought) In particular, this will allow removing some special-casing for enum (#2812). Related to #1381.
1 parent 402a608 commit e0e9c2e

File tree

5 files changed

+18
-12
lines changed

5 files changed

+18
-12
lines changed

mypy/messages.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,13 @@ def has_no_attr(self, typ: Type, member: str, context: Context) -> Type:
392392
self.format(typ)), context)
393393
elif member == '__getitem__':
394394
# Indexed get.
395-
self.fail('Value of type {} is not indexable'.format(
396-
self.format(typ)), context)
395+
# TODO: Fix this consistently in self.format
396+
if isinstance(typ, CallableType) and typ.is_type_obj():
397+
self.fail('The type {} is not generic and not indexable'.format(
398+
self.format(typ)), context)
399+
else:
400+
self.fail('Value of type {} is not indexable'.format(
401+
self.format(typ)), context)
397402
elif member == '__setitem__':
398403
# Indexed set.
399404
self.fail('Unsupported target for indexed assignment', context)

mypy/semanal.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2623,7 +2623,7 @@ def visit_index_expr(self, expr: IndexExpr) -> None:
26232623
expr.base.accept(self)
26242624
if (isinstance(expr.base, RefExpr)
26252625
and isinstance(expr.base.node, TypeInfo)
2626-
and expr.base.node.is_enum):
2626+
and not expr.base.node.is_generic()):
26272627
expr.index.accept(self)
26282628
elif isinstance(expr.base, RefExpr) and expr.base.kind == TYPE_ALIAS:
26292629
# Special form -- subscripting a generic type alias.

test-data/unit/check-classes.test

+8
Original file line numberDiff line numberDiff line change
@@ -2883,6 +2883,14 @@ class Concrete(metaclass=Meta):
28832883
reveal_type(Concrete + X()) # E: Revealed type is 'builtins.str'
28842884
Concrete + "hello" # E: Unsupported operand types for + ("Meta" and "str")
28852885

2886+
[case testMetaclassGetitem]
2887+
class M(type):
2888+
def __getitem__(self, key) -> int: return 1
2889+
2890+
class A(metaclass=M): pass
2891+
2892+
reveal_type(A[M]) # E: Revealed type is 'builtins.int'
2893+
28862894
[case testMetaclassSelftype]
28872895
from typing import TypeVar, Type
28882896

test-data/unit/check-generics.test

+2-2
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ A[int, str, int]() # E: Type application has too many types (2 expected)
449449
a = None # type: A
450450
class A: pass
451451
a[A]() # E: Value of type "A" is not indexable
452-
A[A]() # E: Type application targets a non-generic function or class
452+
A[A]() # E: The type "A" is not generic and not indexable
453453
[out]
454454

455455
[case testTypeApplicationArgTypes]
@@ -505,7 +505,7 @@ Alias[int]("a") # E: Argument 1 to "Node" has incompatible type "str"; expected
505505
[out]
506506

507507
[case testTypeApplicationCrash]
508-
type[int] # this was crashing, see #2302 (comment) # E: Type application targets a non-generic function or class
508+
type[int] # this was crashing, see #2302 (comment) # E: The type "type" is not generic and not indexable
509509
[out]
510510

511511

test-data/unit/semanal-errors.test

-7
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,6 @@ class A: pass
103103
x = cast(A[int], 1) # E: "A" expects no type arguments, but 1 given
104104
[out]
105105

106-
[case testInvalidNumberOfGenericArgsInTypeApplication]
107-
import typing
108-
class A: pass
109-
class B: pass
110-
x = A[B[int]]() # E: "B" expects no type arguments, but 1 given
111-
[out]
112-
113106
[case testInvalidNumberOfGenericArgsInNestedGenericType]
114107
from typing import TypeVar, Generic
115108
T = TypeVar('T')

0 commit comments

Comments
 (0)