8000 [PEP 747] Recognize TypeForm[T] type and values (#9773) by davidfstr · Pull Request #18690 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

[PEP 747] Recognize TypeForm[T] type and values (#9773) #18690

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
8000
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ca4c79f
[PEP 747] Recognize TypeForm[T] type and values (#9773)
davidfstr Sep 29, 2024
9dcfc23
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 16, 2025
5cb1da5
Eliminate use of Type Parameter Syntax, which only works on Python >=…
davidfstr Feb 19, 2025
3ece208
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 19, 2025
799bc48
Remove INPUTS directory
davidfstr Feb 19, 2025
6bda848
WIP: Don't declare attributes on Expression to avoid confusing mypyc
davidfstr Feb 20, 2025
9df0e6b
SQ -> WIP: Don't declare attributes on Expression to avoid confusing …
davidfstr Feb 21, 2025
a2c318b
SQ -> WIP: Don't declare attributes on Expression to avoid confusing …
davidfstr Feb 21, 2025
f398374
Recognize non-string type expressions everywhere lazily. Optimize eag…
davidfstr Feb 25, 2025
bd5911f
NOMERGE: Disable test that is already failing on master branch
davidfstr Mar 4, 2025
3801bcc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 4, 2025
c4db784
Fix mypyc errors: Replace EllipsisType with NotParsed type
davidfstr Mar 4, 2025
29fe65a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 4, 2025
4134250
mypy_primer: Enable TypeForm feature when checking effects on open so…
davidfstr Mar 5, 2025
5fb5bd8
Revert "mypy_primer: Enable TypeForm feature when checking effects on…
davidfstr Mar 8, 2025
54cd64d
NOMERGE: mypy_primer: Enable --enable-incomplete-feature=TypeForm whe…
davidfstr Mar 8, 2025
075980b
Ignore warnings like: <type_comment>:1: SyntaxWarning: invalid escape…
davidfstr Mar 14, 2025
6797cac
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 14, 2025
4162a35
Rerun CI
davidfstr Mar 17, 2025
d1aafcd
Improve warning message when string annotation used in TypeForm context
davidfstr Mar 18, 2025
1d9620d
Print error code for the MAYBE_UNRECOGNIZED_STR_TYPEFORM note
davidfstr Mar 26, 2025
76cae61
Document the [maybe-unrecognized-str-typeform] error code
davidfstr Mar 26, 2025
170a5e7
Fix doc generation warning
davidfstr Mar 26, 2025
84c06a6
Merge branch 'master' into f/typeform3
davidfstr Apr 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
  • Loading branch information
pre-commit-ci[bot] committed Mar 4, 2025
commit 3801bcc8b19a3bbecc9a1f89b567af087c920601
11 changes: 7 additions & 4 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2560,9 +2560,11 @@ def visit_class_def(self, defn: ClassDef) -> None:
for base in typ.mro[1:]:
if base.is_final:
self.fail(message_registry.CANNOT_INHERIT_FROM_FINAL.format(base.name), defn)
with self.tscope.class_scope(defn.info), \
self.enter_partial_types(is_class=True), \
self.enter_class(defn.info):
with (
self.tscope.class_scope(defn.info),
self.enter_partial_types(is_class=True),
self.enter_class(defn.info),
):
old_binder = self.binder
self.binder = ConditionalTypeBinder()
with self.binder.top_frame_context():
Expand Down Expand Up @@ -7946,6 +7948,7 @@ class TypeCheckerAsSemanticAnalyzer(SemanticAnalyzerCoreInterface):
See ExpressionChecker.try_parse_as_type_expression() to understand how this
class is used.
"""

_chk: TypeChecker
_names: dict[str, SymbolTableNode]
did_fail: bool
Expand Down Expand Up @@ -7991,7 +7994,7 @@ def note(self, msg: str, ctx: Context, *, code: ErrorCode | None = None) -> None

def incomplete_feature_enabled(self, feature: str, ctx: Context) -> bool:
if feature not in self._chk.options.enable_incomplete_feature:
self.fail('__ignored__', ctx)
self.fail("__ignored__", ctx)
return False
return True

Expand Down
35 changes: 18 additions & 17 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
freshen_all_functions_type_vars,
freshen_function_type_vars,
)
from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError
from mypy.exprtotype import TypeTranslationError, expr_to_unanalyzed_type
from mypy.infer import ArgumentInferContext, infer_function_type_arguments, infer_type_arguments
from mypy.literals import literal
from mypy.maptype import map_instance_to_supertype
Expand All @@ -47,6 +47,7 @@
LITERAL_TYPE,
REVEAL_LOCALS,
REVEAL_TYPE,
UNBOUND_IMPORTED,
ArgKind,
AssertTypeExpr,
AssignmentExpr,
Expand All @@ -67,7 +68,6 @@
FloatExpr,
FuncDef,
GeneratorExpr,
get_member_expr_fullname,
IndexExpr,
IntExpr,
LambdaExpr,
Expand Down Expand Up @@ -105,10 +105,10 @@
TypeVarExpr,
TypeVarTupleExpr,
UnaryExpr,
UNBOUND_IMPORTED,
Var,
YieldExpr,
YieldFromExpr,
get_member_expr_fullname,
)
from mypy.options import PRECISE_TUPLE_TYPES
from mypy.plugin import (
Expand All @@ -127,16 +127,20 @@
is_subtype,
non_method_protocol_members,
)
from mypy.traverser import all_name_and_member_expressions, has_await_expression, has_str_expression
from mypy.traverser import (
all_name_and_member_expressions,
has_await_expression,
has_str_expression,
)
from mypy.tvar_scope import TypeVarLikeScope
from mypy.typeanal import (
TypeAnalyser,
check_for_explicit_any,
fix_instance,
has_any_from_unimported_type,
instantiate_type_alias,
make_optional_type,
set_any_tvars,
TypeAnalyser,
validate_instance,
)
from mypy.typeops import (
Expand Down Expand Up @@ -6335,17 +6339,19 @@ def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> Type | No
# Check whether has already been parsed as a type expression
# by SemanticAnalyzer.try_parse_as_type_expression(),
# perhaps containing a string annotation
if (isinstance(maybe_type_expr, (StrExpr, IndexExpr, OpExpr))
and maybe_type_expr.as_type is not Ellipsis):
if (
isinstance(maybe_type_expr, (StrExpr, IndexExpr, OpExpr))
and maybe_type_expr.as_type is not Ellipsis
):
return maybe_type_expr.as_type

# If is potentially a type expression containing a string annotation,
# don't try to parse it because there isn't enough information
# available to the TypeChecker pass to resolve string annotations
if has_str_expression(maybe_type_expr):
self.chk.note(
'TypeForm containing a string annotation cannot be recognized here. '
'Try assigning the TypeForm to a variable and use the variable here instead.',
"TypeForm containing a string annotation cannot be recognized here. "
"Try assigning the TypeForm to a variable and use the variable here instead.",
maybe_type_expr,
)
return None
Expand All @@ -6354,13 +6360,8 @@ def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> Type | No
# to be looked up by TypeAnalyser when binding the
# UnboundTypes corresponding to those expressions.
(name_exprs, member_exprs) = all_name_and_member_expressions(maybe_type_expr)
sym_for_name = {
e.name:
SymbolTableNode(UNBOUND_IMPORTED, e.node)
for e in name_exprs
} | {
e_name:
SymbolTableNode(UNBOUND_IMPORTED, e.node)
sym_for_name = {e.name: SymbolTableNode(UNBOUND_IMPORTED, e.node) for e in name_exprs} | {
e_name: SymbolTableNode(UNBOUND_IMPORTED, e.node)
for e in member_exprs
if (e_name := get_member_expr_fullname(e)) is not None
}
Expand All @@ -6377,7 +6378,7 @@ def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> Type | No

try:
typ1 = expr_to_unanalyzed_type(
maybe_type_expr, self.chk.options, self.chk.is_typeshed_stub,
maybe_type_expr, self.chk.options, self.chk.is_typeshed_stub
)
typ2 = typ1.accept(tpan)
if chk_sem.did_fail:
Expand Down
3 changes: 2 additions & 1 deletion mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from __future__ import annotations

import builtins
import os
from abc import abstractmethod
import builtins
from collections import defaultdict
from collections.abc import Iterator, Sequence
from enum import Enum, unique
Expand All @@ -25,6 +25,7 @@
else:
EllipsisType = Any


class Context:
"""Base type for objects that are valid as error message locations."""

Expand Down
7 changes: 3 additions & 4 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@

from __future__ import annotations

import re
from collections.abc import Collection, Iterable, Iterator
from contextlib import contextmanager
from typing import Any, Callable, Final, TypeVar, cast
from typing_extensions import TypeAlias as _TypeAlias, TypeGuard
from typing_extensions import TypeAlias as _TypeAlias, TypeGuard, assert_never

from mypy import errorcodes as codes, message_registry
from mypy.constant_fold import constant_fold_expr
Expand Down Expand Up @@ -308,8 +309,6 @@
from mypy.typevars import fill_typevars
from mypy.util import correct_relative_import, is_dunder, module_prefix, unmangle, unnamed_function
from mypy.visitor import NodeVisitor
import re
from typing_extensions import assert_never

T = TypeVar("T")

Expand Down Expand Up @@ -7695,7 +7694,7 @@ def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> None:
maybe_type_expr.as_type = None
return
elif isinstance(maybe_type_expr, OpExpr):
if maybe_type_expr.op != '|':
if maybe_type_expr.op != "|":
# Binary operators other than '|' never spell a valid type
maybe_type_expr.as_type = None
return
Expand Down
Loading
0