diff --git a/conformance/results/mypy/directives_assert_type.toml b/conformance/results/mypy/directives_assert_type.toml index a8feed5e..61e4a8a2 100644 --- a/conformance/results/mypy/directives_assert_type.toml +++ b/conformance/results/mypy/directives_assert_type.toml @@ -1,13 +1,14 @@ conformant = "Pass" output = """ directives_assert_type.py:27: error: Expression is of type "int | str", not "int" [assert-type] -directives_assert_type.py:28: error: Expression is of type "Any", not "int" [assert-type] -directives_assert_type.py:29: error: Expression is of type "Literal[4]", not "int" [assert-type] -directives_assert_type.py:31: error: "assert_type" expects 2 arguments [misc] -directives_assert_type.py:31: error: Too few arguments for "assert_type" [call-arg] -directives_assert_type.py:32: error: Expression is of type "Literal['']", not "int" [assert-type] -directives_assert_type.py:33: error: "assert_type" expects 2 arguments [misc] -directives_assert_type.py:33: error: Too many arguments for "assert_type" [call-arg] +directives_assert_type.py:28: error: Expression is of type "int | str", not "Any" [assert-type] +directives_assert_type.py:29: error: Expression is of type "Any", not "int" [assert-type] +directives_assert_type.py:30: error: Expression is of type "Literal[4]", not "int" [assert-type] +directives_assert_type.py:32: error: "assert_type" expects 2 arguments [misc] +directives_assert_type.py:32: error: Too few arguments for "assert_type" [call-arg] +directives_assert_type.py:33: error: Expression is of type "Literal['']", not "int" [assert-type] +directives_assert_type.py:34: error: "assert_type" expects 2 arguments [misc] +directives_assert_type.py:34: error: Too many arguments for "assert_type" [call-arg] """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/mypy/version.toml b/conformance/results/mypy/version.toml index d3740879..5c2624b4 100644 --- a/conformance/results/mypy/version.toml +++ b/conformance/results/mypy/version.toml @@ -1,2 +1,2 @@ version = "mypy 1.16.1" -test_duration = 2.2 +test_duration = 2.1 diff --git a/conformance/results/pyre/directives_assert_type.toml b/conformance/results/pyre/directives_assert_type.toml index 7c81101d..bdb7b0b9 100644 --- a/conformance/results/pyre/directives_assert_type.toml +++ b/conformance/results/pyre/directives_assert_type.toml @@ -3,11 +3,13 @@ notes = """ """ output = """ directives_assert_type.py:27:4 Assert type [70]: Expected `int` but got `Union[int, str]`. -directives_assert_type.py:28:4 Assert type [70]: Expected `int` but got `typing.Any`. -directives_assert_type.py:29:4 Assert type [70]: Expected `int` but got `typing_extensions.Literal[4]`. -directives_assert_type.py:31:4 Missing argument [20]: Call `assert_type` expects argument in position 0. -directives_assert_type.py:32:4 Assert type [70]: Expected `int` but got `typing_extensions.Literal['']`. -directives_assert_type.py:33:4 Too many arguments [19]: Call `assert_type` expects 2 positional arguments, 3 were provided. +directives_assert_type.py:28:4 Assert type [70]: Expected `typing.Any` but got `Union[int, str]`. +directives_assert_type.py:29:4 Assert type [70]: Expected `int` but got `typing.Any`. +directives_assert_type.py:30:4 Assert type [70]: Expected `int` but got `typing_extensions.Literal[4]`. +directives_assert_type.py:32:4 Missing argument [20]: Call `assert_type` expects argument in position 0. +directives_assert_type.py:33:4 Assert type [70]: Expected `int` but got `typing_extensions.Literal['']`. +directives_assert_type.py:34:4 Too many arguments [19]: Call `assert_type` expects 2 positional arguments, 3 were provided. +directives_assert_type.py:41:4 Assert type [70]: Expected `Union[typing_extensions.Literal['spam'], str]` but got `str`. """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/pyre/version.toml b/conformance/results/pyre/version.toml index c759e78d..b2c2d379 100644 --- a/conformance/results/pyre/version.toml +++ b/conformance/results/pyre/version.toml @@ -1,2 +1,2 @@ version = "pyre 0.9.23" -test_duration = 10.7 +test_duration = 11.0 diff --git a/conformance/results/pyright/directives_assert_type.toml b/conformance/results/pyright/directives_assert_type.toml index 9c37b0b0..cb868983 100644 --- a/conformance/results/pyright/directives_assert_type.toml +++ b/conformance/results/pyright/directives_assert_type.toml @@ -1,11 +1,13 @@ conformant = "Pass" output = """ directives_assert_type.py:27:17 - error: "assert_type" mismatch: expected "int" but received "int | str" (reportAssertTypeFailure) -directives_assert_type.py:28:17 - error: "assert_type" mismatch: expected "int" but received "Any" (reportAssertTypeFailure) -directives_assert_type.py:29:17 - error: "assert_type" mismatch: expected "int" but received "Literal[4]" (reportAssertTypeFailure) -directives_assert_type.py:31:5 - error: "assert_type" expects two positional arguments (reportCallIssue) -directives_assert_type.py:32:17 - error: "assert_type" mismatch: expected "int" but received "Literal['']" (reportAssertTypeFailure) -directives_assert_type.py:33:5 - error: "assert_type" expects two positional arguments (reportCallIssue) +directives_assert_type.py:28:17 - error: "assert_type" mismatch: expected "Any" but received "int | str" (reportAssertTypeFailure) +directives_assert_type.py:29:17 - error: "assert_type" mismatch: expected "int" but received "Any" (reportAssertTypeFailure) +directives_assert_type.py:30:17 - error: "assert_type" mismatch: expected "int" but received "Literal[4]" (reportAssertTypeFailure) +directives_assert_type.py:32:5 - error: "assert_type" expects two positional arguments (reportCallIssue) +directives_assert_type.py:33:17 - error: "assert_type" mismatch: expected "int" but received "Literal['']" (reportAssertTypeFailure) +directives_assert_type.py:34:5 - error: "assert_type" expects two positional arguments (reportCallIssue) +directives_assert_type.py:41:17 - error: "assert_type" mismatch: expected "str | Literal['spam']" but received "str" (reportAssertTypeFailure) """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/pyright/version.toml b/conformance/results/pyright/version.toml index ca4eb79c..bee36bba 100644 --- a/conformance/results/pyright/version.toml +++ b/conformance/results/pyright/version.toml @@ -1,2 +1,2 @@ version = "pyright 1.1.402" -test_duration = 1.8 +test_duration = 2.0 diff --git a/conformance/results/results.html b/conformance/results/results.html index 4cc4ea00..4fbf5404 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -159,13 +159,13 @@

Python Type System Conformance Test Results

- + @@ -423,7 +423,7 @@

Python Type System Conformance Test Results

- + diff --git a/conformance/tests/directives_assert_type.py b/conformance/tests/directives_assert_type.py index b5a33737..900529b1 100644 --- a/conformance/tests/directives_assert_type.py +++ b/conformance/tests/directives_assert_type.py @@ -25,6 +25,7 @@ def func1( assert_type(e, Literal[4]) # OK assert_type(a, int) # E: Type mismatch + assert_type(a, Any) # E: Type mismatch assert_type(c, int) # E: Type mismatch assert_type(e, int) # E: Type mismatch @@ -33,5 +34,12 @@ def func1( assert_type(a, int | str, a) # E: too many arguments +# > If the two types are :term:`equivalent` but syntactically different, +# > the type checker may reject the ``assert_type()`` call:: + +def func2(name: str): + assert_type(name, str | Literal["spam"]) # E?: Equivalent but not identical + + class ForwardReference: pass diff --git a/docs/spec/directives.rst b/docs/spec/directives.rst index 62e1b3c4..c7da8dfe 100644 --- a/docs/spec/directives.rst +++ b/docs/spec/directives.rst @@ -9,7 +9,8 @@ Type checker directives ----------------- The function ``typing.assert_type(val, typ)`` allows users to -ask a static type checker to confirm that *val* has an inferred type of *typ*. +ask a static type checker to confirm that the inferred type of *val* +is :term:`equivalent` to *typ*. When a type checker encounters a call to ``assert_type()``, it should emit an error if the value is not of the specified type:: @@ -18,6 +19,17 @@ should emit an error if the value is not of the specified type:: assert_type(name, str) # OK, inferred type of `name` is `str` assert_type(name, int) # type checker error +If the two types are :term:`equivalent` but syntactically different, +the type checker may reject the ``assert_type()`` call:: + + from typing import assert_type, Literal + + def greet(name: str) -> None: + assert_type(name, str | Literal["spam"]) # type checker may error + +Type checkers should aim to minimize cases where they reject +``assert_type()`` calls that use equivalent types. + The second argument must be a valid :term:`type expression`. .. _`reveal-type`:
 
mypy 1.16.1
-
2.2sec
+
2.1sec
pyright 1.1.402
-
1.8sec
+
2.0sec
pyre 0.9.23
-
10.7sec
+
11.0sec
@@ -324,7 +324,7 @@

Python Type System Conformance Test Results

     generics_type_erasure
Partial

Infers Node[Never] instead of Node[Any] when argument is not provided.

False negative on instance attribute access on type(node).

Partial

Missing error regarding `type(instance).generic_attribute`.

Pass
Partial

Does not erase unspecified type variables to `Any` prior to `assert_type` handling.

False negatives on instance attribute access on the type.

Does not infer type of `DefaultDict` with explicit type parameters on constructor.

False negatives on assert_type uses.

     generics_typevartuple_args
     aliases_newtype
Partial

`NewType`s are considered classes, not functions.

Partial

`NewType`s are considered classes, not functions.

Pass
Partial

Does not reject use of NewType in `isinstance` call.

Does not reject use of NewType in class definition statement.

Does not report inconsistency between name of NewType and assigned identifier name.

Does not reject use of NewType with generic class with TypeVar.

Does not reject use of NewType with protocol class.

Does not reject use of NewType with TypedDict class.

Does not reject use of NewType with Any.

     aliases_recursive