diff --git a/conformance/README.md b/conformance/README.md index e0302c80..0e450e07 100644 --- a/conformance/README.md +++ b/conformance/README.md @@ -12,6 +12,7 @@ This project contains test cases for behaviors defined in the Python typing spec * [concepts](https://typing.python.org/en/latest/spec/concepts.html) * [annotations](https://typing.python.org/en/latest/spec/annotations.html) +* [typeforms](https://typing.python.org/en/latest/spec/type-forms.html) * [specialtypes](https://typing.python.org/en/latest/spec/special-types.html) * [generics](https://typing.python.org/en/latest/spec/generics.html) * [qualifiers](https://typing.python.org/en/latest/spec/qualifiers.html) diff --git a/conformance/results/mypy/typeforms_typeform.toml b/conformance/results/mypy/typeforms_typeform.toml new file mode 100644 index 00000000..f3234f33 --- /dev/null +++ b/conformance/results/mypy/typeforms_typeform.toml @@ -0,0 +1,30 @@ +conformant = "Partial" +notes = """ +Does not support assigning Union and GenericAlias objects to their runtime types. +""" +conformance_automated = "Fail" +errors_diff = """ +Line 40: Unexpected errors ['typeforms_typeform.py:40: error: Incompatible types in assignment (expression has type "UnionType | type[str]", variable has type "UnionType") [assignment]'] +Line 43: Unexpected errors ['typeforms_typeform.py:43: error: Incompatible types in assignment (expression has type "type[list[int]]", variable has type "GenericAlias") [assignment]'] +""" +output = """ +typeforms_typeform.py:23: error: Incompatible types in assignment (expression has type "TypeForm[str | int]", variable has type "TypeForm[str | None]") [assignment] +typeforms_typeform.py:24: error: Incompatible types in assignment (expression has type "TypeForm[list[str | None]]", variable has type "TypeForm[str | None]") [assignment] +typeforms_typeform.py:40: error: Incompatible types in assignment (expression has type "UnionType | type[str]", variable has type "UnionType") [assignment] +typeforms_typeform.py:43: error: Incompatible types in assignment (expression has type "type[list[int]]", variable has type "GenericAlias") [assignment] +typeforms_typeform.py:55: error: Incompatible types in assignment (expression has type "tuple[Never, ...]", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:56: error: Incompatible types in assignment (expression has type "tuple[int, int]", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:57: error: Incompatible types in assignment (expression has type "int", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:58: error: Incompatible types in assignment (expression has type "", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:59: error: Incompatible types in assignment (expression has type "", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:60: error: Incompatible types in assignment (expression has type "", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:61: error: Incompatible types in assignment (expression has type "", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:62: error: Incompatible types in assignment (expression has type "", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:63: error: Incompatible types in assignment (expression has type "", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:64: error: Incompatible types in assignment (expression has type "", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:65: error: Incompatible types in assignment (expression has type "str", variable has type "TypeForm[Any]") [assignment] +typeforms_typeform.py:76: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:78: error: TypeForm argument is not a type [misc] +typeforms_typeform.py:88: error: Incompatible types in assignment (expression has type "TypeForm[int]", variable has type "TypeForm[str]") [assignment] +typeforms_typeform.py:98: error: Incompatible types in assignment (expression has type "type[int]", variable has type "TypeForm[str]") [assignment] +""" diff --git a/conformance/results/pyrefly/typeforms_typeform.toml b/conformance/results/pyrefly/typeforms_typeform.toml new file mode 100644 index 00000000..af7f9b5d --- /dev/null +++ b/conformance/results/pyrefly/typeforms_typeform.toml @@ -0,0 +1,77 @@ +conformance = "Unsupported" +conformance_automated = "Fail" +errors_diff = """ +Line 15: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 16: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 17: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 18: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 19: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 20: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 21: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 29: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 30: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 31: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 32: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 40: Unexpected errors ['`type[str | None]` is not assignable to `UnionType` [bad-assignment]'] +Line 41: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 43: Unexpected errors ['`type[list[int]]` is not assignable to `GenericAlias` [bad-assignment]', 'Expected `v2_actual` to be a type alias, got `GenericAlias` [invalid-type-alias]'] +Line 44: Unexpected errors ['Expected a type form, got instance of `_SpecialForm` [not-a-type]'] +Line 46: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 47: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 70: Unexpected errors ['Expected a callable, got `_SpecialForm` [not-callable]'] +Line 71: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 73: Unexpected errors ['Expected a callable, got `_SpecialForm` [not-callable]'] +Line 74: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 83: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 87: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +Line 97: Unexpected errors ['Expected a type form, got instance of `object` [not-a-type]'] +""" +output = """ +ERROR typeforms_typeform.py:15:6-26: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:16:6-26: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:17:6-26: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:18:6-26: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:19:6-26: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:20:6-26: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:21:6-26: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:23:7-27: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:24:7-27: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:29:8-21: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:30:8-21: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:31:20-33: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:32:20-33: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:40:30-40: `type[str | None]` is not assignable to `UnionType` [bad-assignment] +ERROR typeforms_typeform.py:41:15-35: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:43:33-42: `type[list[int]]` is not assignable to `GenericAlias` [bad-assignment] +ERROR typeforms_typeform.py:43:33-42: Expected `v2_actual` to be a type alias, got `GenericAlias` [invalid-type-alias] +ERROR typeforms_typeform.py:44:15-23: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:46:5-24: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:47:5-23: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:55:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:56:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:57:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:58:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:58:18-22: `Self` must appear within a class [invalid-annotation] +ERROR typeforms_typeform.py:59:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:59:26-29: Expected a type form, got instance of `Literal[1]` [not-a-type] +ERROR typeforms_typeform.py:60:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:60:26-29: Invalid literal expression [invalid-literal] +ERROR typeforms_typeform.py:61:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:61:18-31: `ClassVar` is not allowed in this context [invalid-annotation] +ERROR typeforms_typeform.py:62:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:62:18-28: `Final` is not allowed in this context [invalid-annotation] +ERROR typeforms_typeform.py:63:7-15: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:64:8-16: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:65:8-16: Expected a type form, got instance of `_SpecialForm` [not-a-type] +ERROR typeforms_typeform.py:70:6-14: Expected a callable, got `_SpecialForm` [not-callable] +ERROR typeforms_typeform.py:71:17-37: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:73:6-14: Expected a callable, got `_SpecialForm` [not-callable] +ERROR typeforms_typeform.py:74:17-36: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:76:6-14: Expected a callable, got `_SpecialForm` [not-callable] +ERROR typeforms_typeform.py:78:6-14: Expected a callable, got `_SpecialForm` [not-callable] +ERROR typeforms_typeform.py:83:24-37: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:87:5-24: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:88:5-18: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:97:5-24: Expected a type form, got instance of `object` [not-a-type] +ERROR typeforms_typeform.py:98:5-18: Expected a type form, got instance of `object` [not-a-type] +""" diff --git a/conformance/results/pyright/typeforms_typeform.toml b/conformance/results/pyright/typeforms_typeform.toml new file mode 100644 index 00000000..af5388b7 --- /dev/null +++ b/conformance/results/pyright/typeforms_typeform.toml @@ -0,0 +1,78 @@ +conformance = "Unsupported" +conformance_automated = "Fail" +errors_diff = """ +Line 58: Expected 1 errors +Line 60: Expected 1 errors +Line 61: Expected 1 errors +Line 62: Expected 1 errors +Line 64: Expected 1 errors +Line 15: Unexpected errors ['typeforms_typeform.py:15:29 - error: Type "UnionType" is not assignable to declared type "TypeForm[str | None]"'] +Line 17: Unexpected errors ['typeforms_typeform.py:17:29 - error: Type "None" is not assignable to declared type "TypeForm[str | None]"'] +Line 19: Unexpected errors ['typeforms_typeform.py:19:29 - error: Type "UnionType" is not assignable to declared type "TypeForm[str | None]"'] +Line 20: Unexpected errors ['typeforms_typeform.py:20:29 - error: Type "Literal[\\'str | None\\']" is not assignable to declared type "TypeForm[str | None]"'] +Line 21: Unexpected errors ['typeforms_typeform.py:21:29 - error: Type "type[Any]" is not assignable to declared type "TypeForm[str | None]"'] +Line 29: Unexpected errors ['typeforms_typeform.py:29:24 - error: Type "UnionType" is not assignable to declared type "TypeForm[Any]"'] +Line 32: Unexpected errors ['typeforms_typeform.py:32:13 - error: "assert_type" mismatch: expected "TypeForm[str]" but received "type[str]" (reportAssertTypeFailure)'] +Line 41: Unexpected errors ['typeforms_typeform.py:41:38 - error: Type "UnionType" is not assignable to declared type "TypeForm[str | None]"'] +Line 43: Unexpected errors ['typeforms_typeform.py:43:33 - error: Type "type[list[int]]" is not assignable to declared type "GenericAlias"'] +Line 46: Unexpected errors ['typeforms_typeform.py:46:27 - error: Type "Annotated" is not assignable to declared type "TypeForm[int | str]"'] +Line 47: Unexpected errors ['typeforms_typeform.py:47:26 - error: Type "Literal[\\'set[str]\\']" is not assignable to declared type "TypeForm[set[str]]"'] +Line 71: Unexpected errors ['typeforms_typeform.py:71:13 - error: "assert_type" mismatch: expected "TypeForm[str | None]" but received "UnionType" (reportAssertTypeFailure)'] +Line 74: Unexpected errors ['typeforms_typeform.py:74:13 - error: "assert_type" mismatch: expected "TypeForm[list[int]]" but received "type[list[int]]" (reportAssertTypeFailure)'] +""" +output = """ +typeforms_typeform.py:15:29 - error: Type "UnionType" is not assignable to declared type "TypeForm[str | None]" +  "UnionType" is not assignable to "TypeForm[str | None]" (reportAssignmentType) +typeforms_typeform.py:17:29 - error: Type "None" is not assignable to declared type "TypeForm[str | None]" +  "None" is not assignable to "TypeForm[str | None]" (reportAssignmentType) +typeforms_typeform.py:19:29 - error: Type "UnionType" is not assignable to declared type "TypeForm[str | None]" +  "UnionType" is not assignable to "TypeForm[str | None]" (reportAssignmentType) +typeforms_typeform.py:20:29 - error: Type "Literal['str | None']" is not assignable to declared type "TypeForm[str | None]" +  "Literal['str | None']" is not assignable to "TypeForm[str | None]" (reportAssignmentType) +typeforms_typeform.py:21:29 - error: Type "type[Any]" is not assignable to declared type "TypeForm[str | None]" +  Type "Any" is not assignable to type "str | None" +    "Any" is not assignable to "str" +    "Any" is not assignable to "None" (reportAssignmentType) +typeforms_typeform.py:23:30 - error: Type "UnionType" is not assignable to declared type "TypeForm[str | None]" +  "UnionType" is not assignable to "TypeForm[str | None]" (reportAssignmentType) +typeforms_typeform.py:24:30 - error: Type "type[list[str | None]]" is not assignable to declared type "TypeForm[str | None]" +  Type "list[str | None]" is not assignable to type "str | None" +    "list[str | None]" is not assignable to "str" +    "list[str | None]" is not assignable to "None" (reportAssignmentType) +typeforms_typeform.py:29:24 - error: Type "UnionType" is not assignable to declared type "TypeForm[Any]" +  "UnionType" is not assignable to "TypeForm[Any]" (reportAssignmentType) +typeforms_typeform.py:32:13 - error: "assert_type" mismatch: expected "TypeForm[str]" but received "type[str]" (reportAssertTypeFailure) +typeforms_typeform.py:41:38 - error: Type "UnionType" is not assignable to declared type "TypeForm[str | None]" +  "UnionType" is not assignable to "TypeForm[str | None]" (reportAssignmentType) +typeforms_typeform.py:43:33 - error: Type "type[list[int]]" is not assignable to declared type "GenericAlias" +  Type "type[list[int]]" is not assignable to type "GenericAlias" (reportAssignmentType) +typeforms_typeform.py:46:27 - error: Type "Annotated" is not assignable to declared type "TypeForm[int | str]" +  "Annotated" is not assignable to "TypeForm[int | str]" (reportAssignmentType) +typeforms_typeform.py:47:26 - error: Type "Literal['set[str]']" is not assignable to declared type "TypeForm[set[str]]" +  "Literal['set[str]']" is not assignable to "TypeForm[set[str]]" (reportAssignmentType) +typeforms_typeform.py:55:18 - error: Type "tuple[()]" is not assignable to declared type "TypeForm[Unknown]" +  "tuple[()]" is not assignable to "TypeForm[Unknown]" (reportAssignmentType) +typeforms_typeform.py:56:18 - error: Type "tuple[Literal[1], Literal[2]]" is not assignable to declared type "TypeForm[Unknown]" +  "tuple[Literal[1], Literal[2]]" is not assignable to "TypeForm[Unknown]" (reportAssignmentType) +typeforms_typeform.py:57:18 - error: Type "Literal[1]" is not assignable to declared type "TypeForm[Unknown]" +  "Literal[1]" is not assignable to "TypeForm[Unknown]" (reportAssignmentType) +typeforms_typeform.py:59:18 - error: Type "Literal" is not assignable to declared type "TypeForm[Unknown]" +  "Literal" is not assignable to "TypeForm[Unknown]" (reportAssignmentType) +typeforms_typeform.py:63:25 - error: Type variable "Ts" has no meaning in this context (reportGeneralTypeIssues) +typeforms_typeform.py:65:19 - error: Type "Literal['int + str']" is not assignable to declared type "TypeForm[Unknown]" +  "Literal['int + str']" is not assignable to "TypeForm[Unknown]" (reportAssignmentType) +typeforms_typeform.py:71:13 - error: "assert_type" mismatch: expected "TypeForm[str | None]" but received "UnionType" (reportAssertTypeFailure) +typeforms_typeform.py:74:13 - error: "assert_type" mismatch: expected "TypeForm[list[int]]" but received "type[list[int]]" (reportAssertTypeFailure) +typeforms_typeform.py:76:16 - error: type() call should not be used in type expression +  Use type[T] instead (reportInvalidTypeForm) +typeforms_typeform.py:76:16 - error: Call expression not allowed in type expression (reportInvalidTypeForm) +typeforms_typeform.py:78:15 - error: type() call should not be used in type expression +  Use type[T] instead (reportInvalidTypeForm) +typeforms_typeform.py:78:15 - error: Call expression not allowed in type expression (reportInvalidTypeForm) +typeforms_typeform.py:88:21 - error: Type "TypeForm[int]" is not assignable to declared type "TypeForm[str]" +  "TypeForm[int]" is not assignable to "TypeForm[str]" +    Type parameter "T@TypeForm" is covariant, but "int" is not a subtype of "str" +      "int" is not assignable to "str" (reportAssignmentType) +typeforms_typeform.py:98:21 - error: Type "type[int]" is not assignable to declared type "TypeForm[str]" +  "int" is not assignable to "str" (reportAssignmentType) +""" diff --git a/conformance/results/results.html b/conformance/results/results.html index bebbce60..3279a62b 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -176,7 +176,7 @@

Python Type System Conformance Test Results

pyright 1.1.408
-
zuban 0.5.1
+
zuban 0.6.0
pyrefly 0.53.0
@@ -215,6 +215,15 @@

Python Type System Conformance Test Results

Pass +Type forms + +     typeforms_typeform +
Partial

Does not support assigning Union and GenericAlias objects to their runtime types.

+Unknown +Unknown +Unknown + + Special types in annotations      specialtypes_any diff --git a/conformance/results/zuban/typeddicts_operations.toml b/conformance/results/zuban/typeddicts_operations.toml index 1f0db30f..7a38bd85 100644 --- a/conformance/results/zuban/typeddicts_operations.toml +++ b/conformance/results/zuban/typeddicts_operations.toml @@ -9,7 +9,7 @@ typeddicts_operations.py:26: error: TypedDict "Movie" has no key "other" [typed typeddicts_operations.py:28: error: Missing key "year" for TypedDict "Movie" [typeddict-item] typeddicts_operations.py:29: error: Incompatible types (expression has type "float", TypedDict item "year" has type "int") [typeddict-item] typeddicts_operations.py:32: error: Extra key "other" for TypedDict "Movie" [typeddict-unknown-key] -typeddicts_operations.py:37: error: Expected TypedDict key to be string literal [misc] +typeddicts_operations.py:37: error: Expected TypedDict key to be string literal [literal-required] typeddicts_operations.py:47: error: "Movie" has no attribute "clear" [attr-defined] typeddicts_operations.py:49: error: Key "name" of TypedDict "Movie" cannot be deleted [misc] typeddicts_operations.py:62: error: "MovieOptional" has no attribute "clear" [attr-defined] diff --git a/conformance/results/zuban/typeforms_typeform.toml b/conformance/results/zuban/typeforms_typeform.toml new file mode 100644 index 00000000..76eb8d27 --- /dev/null +++ b/conformance/results/zuban/typeforms_typeform.toml @@ -0,0 +1,71 @@ +conformance = "Unsupported" +conformance_automated = "Fail" +errors_diff = """ +Line 15: Unexpected errors ['typeforms_typeform.py:15: error: Invalid type comment or annotation [valid-type]'] +Line 16: Unexpected errors ['typeforms_typeform.py:16: error: Invalid type comment or annotation [valid-type]'] +Line 17: Unexpected errors ['typeforms_typeform.py:17: error: Invalid type comment or annotation [valid-type]'] +Line 18: Unexpected errors ['typeforms_typeform.py:18: error: Invalid type comment or annotation [valid-type]'] +Line 19: Unexpected errors ['typeforms_typeform.py:19: error: Invalid type comment or annotation [valid-type]'] +Line 20: Unexpected errors ['typeforms_typeform.py:20: error: Invalid type comment or annotation [valid-type]'] +Line 21: Unexpected errors ['typeforms_typeform.py:21: error: Invalid type comment or annotation [valid-type]'] +Line 29: Unexpected errors ['typeforms_typeform.py:29: error: Invalid type comment or annotation [valid-type]'] +Line 30: Unexpected errors ['typeforms_typeform.py:30: error: Invalid type comment or annotation [valid-type]'] +Line 31: Unexpected errors ['typeforms_typeform.py:31: error: Cast target is not a type [misc]'] +Line 32: Unexpected errors ['typeforms_typeform.py:32: error: Cast target is not a type [misc]'] +Line 41: Unexpected errors ['typeforms_typeform.py:41: error: Invalid type comment or annotation [valid-type]'] +Line 43: Unexpected errors ['typeforms_typeform.py:43: error: Incompatible types in assignment (expression has type "type[list[int]]", variable has type "GenericAlias") [assignment]'] +Line 44: Unexpected errors ['typeforms_typeform.py:44: error: Invalid type comment or annotation [valid-type]'] +Line 46: Unexpected errors ['typeforms_typeform.py:46: error: Invalid type comment or annotation [valid-type]'] +Line 47: Unexpected errors ['typeforms_typeform.py:47: error: Invalid type comment or annotation [valid-type]'] +Line 70: Unexpected errors ['typeforms_typeform.py:70: error: "_SpecialForm" not callable [operator]'] +Line 71: Unexpected errors ['typeforms_typeform.py:71: error: Cast target is not a type [misc]'] +Line 73: Unexpected errors ['typeforms_typeform.py:73: error: "_SpecialForm" not callable [operator]'] +Line 74: Unexpected errors ['typeforms_typeform.py:74: error: Cast target is not a type [misc]'] +Line 83: Unexpected errors ['typeforms_typeform.py:83: error: Invalid type comment or annotation [valid-type]'] +Line 87: Unexpected errors ['typeforms_typeform.py:87: error: Invalid type comment or annotation [valid-type]'] +Line 97: Unexpected errors ['typeforms_typeform.py:97: error: Invalid type comment or annotation [valid-type]'] +""" +output = """ +typeforms_typeform.py:15: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:16: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:17: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:18: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:19: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:20: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:21: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:23: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:24: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:29: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:30: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:31: error: Cast target is not a type [misc] +typeforms_typeform.py:32: error: Cast target is not a type [misc] +typeforms_typeform.py:41: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:43: error: Incompatible types in assignment (expression has type "type[list[int]]", variable has type "GenericAlias") [assignment] +typeforms_typeform.py:44: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:46: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:47: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:55: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:56: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:57: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:58: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:59: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:59: error: Parameter 1 of Literal[...] is invalid [valid-type] +typeforms_typeform.py:60: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:60: error: Parameter 1 of Literal[...] is invalid [valid-type] +typeforms_typeform.py:61: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:62: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:63: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:64: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:65: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:70: error: "_SpecialForm" not callable [operator] +typeforms_typeform.py:71: error: Cast target is not a type [misc] +typeforms_typeform.py:73: error: "_SpecialForm" not callable [operator] +typeforms_typeform.py:74: error: Cast target is not a type [misc] +typeforms_typeform.py:76: error: "_SpecialForm" not callable [operator] +typeforms_typeform.py:78: error: "_SpecialForm" not callable [operator] +typeforms_typeform.py:83: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:87: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:88: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:97: error: Invalid type comment or annotation [valid-type] +typeforms_typeform.py:98: error: Invalid type comment or annotation [valid-type] +""" diff --git a/conformance/results/zuban/version.toml b/conformance/results/zuban/version.toml index f13b3187..c5293aab 100644 --- a/conformance/results/zuban/version.toml +++ b/conformance/results/zuban/version.toml @@ -1 +1 @@ -version = "zuban 0.5.1" +version = "zuban 0.6.0" diff --git a/conformance/src/test_groups.toml b/conformance/src/test_groups.toml index f6588f56..adf2b355 100644 --- a/conformance/src/test_groups.toml +++ b/conformance/src/test_groups.toml @@ -7,6 +7,10 @@ href = "https://typing.readthedocs.io/en/latest/spec/concepts.html" name = "Type annotations" href = "https://typing.readthedocs.io/en/latest/spec/annotations.html" +[typeforms] +name = "Type forms" +href = "https://typing.readthedocs.io/en/latest/spec/type-forms.html" + [specialtypes] name = "Special types in annotations" href = "https://typing.readthedocs.io/en/latest/spec/special-types.html" diff --git a/conformance/src/type_checker.py b/conformance/src/type_checker.py index 7406a8ac..605c9081 100644 --- a/conformance/src/type_checker.py +++ b/conformance/src/type_checker.py @@ -104,6 +104,7 @@ def run_tests(self, test_files: Sequence[str]) -> dict[str, str]: ".", "--enable-error-code", "deprecated", + "--enable-incomplete-feature=TypeForm", ] proc = run(command, stdout=PIPE, text=True, encoding="utf-8") lines = proc.stdout.split("\n") diff --git a/conformance/tests/typeforms_typeform.py b/conformance/tests/typeforms_typeform.py new file mode 100644 index 00000000..3e3960ef --- /dev/null +++ b/conformance/tests/typeforms_typeform.py @@ -0,0 +1,98 @@ +""" +Tests TypeForm functionality. +""" + +# Specification: https://typing.readthedocs.io/en/latest/spec/type-forms.html#typeform + +import types +from typing import Annotated, Any, ClassVar, Final, Literal, Optional, Self, TypeVarTuple, Unpack, assert_type +from typing_extensions import TypeForm + + +# > ``TypeForm[T]`` describes the set of all type form objects that represent +# > the type ``T`` or types that are assignable to ``T``. + +ok1: TypeForm[str | None] = str | None # OK +ok2: TypeForm[str | None] = str # OK +ok3: TypeForm[str | None] = None # OK +ok4: TypeForm[str | None] = Literal[None] # OK +ok5: TypeForm[str | None] = Optional[str] # OK +ok6: TypeForm[str | None] = "str | None" # OK +ok7: TypeForm[str | None] = Any # OK + +err1: TypeForm[str | None] = str | int # E +err2: TypeForm[str | None] = list[str | None] # E + + +# > ``TypeForm[Any]`` is assignable both to and from any other ``TypeForm`` type. + +v_any: TypeForm[Any] = int | str +v_str: TypeForm[str] = str +assert_type(v_any, TypeForm[Any]) +assert_type(v_str, TypeForm[str]) + +v_any = v_str # OK +v_str = v_any # OK + + +# > Valid type expressions are assignable to ``TypeForm`` through implicit TypeForm evaluation. + +v1_actual: types.UnionType = str | None # OK +v1_type_form: TypeForm[str | None] = str | None # OK + +v2_actual: types.GenericAlias = list[int] # OK +v2_type_form: TypeForm = list[int] # OK + +v3: TypeForm[int | str] = Annotated[int | str, "metadata"] # OK +v4: TypeForm[set[str]] = "set[str]" # OK + + +# > Expressions that are not valid type expressions should not evaluate to a ``TypeForm`` type. + +Ts = TypeVarTuple("Ts") +var = 1 + +bad1: TypeForm = tuple() # E +bad2: TypeForm = (1, 2) # E +bad3: TypeForm = 1 # E +bad4: TypeForm = Self # E +bad5: TypeForm = Literal[var] # E +bad6: TypeForm = Literal[f""] # E +bad7: TypeForm = ClassVar[int] # E +bad8: TypeForm = Final[int] # E +bad9: TypeForm = Unpack[Ts] # E +bad10: TypeForm = Optional # E +bad11: TypeForm = "int + str" # E + + +# > ``TypeForm`` acts as a function that can be called with a single valid type expression. + +x1 = TypeForm(str | None) +assert_type(x1, TypeForm[str | None]) + +x2 = TypeForm("list[int]") +assert_type(x2, TypeForm[list[int]]) + +x3 = TypeForm("type(1)") # E +x4 = type(1) # OK +x5 = TypeForm(type(1)) # E + + +# > ``TypeForm`` is covariant in its single type parameter. + +def get_type_form() -> TypeForm[int]: + return int + + +t1: TypeForm[int | str] = get_type_form() # OK +t2: TypeForm[str] = get_type_form() # E + + +# > ``type[T]`` is a subtype of ``TypeForm[T]``. + +def get_type() -> type[int]: + return int + + +t3: TypeForm[int | str] = get_type() # OK +t4: TypeForm[str] = get_type() # E diff --git a/docs/spec/annotations.rst b/docs/spec/annotations.rst index 9ef5bfe5..085d9277 100644 --- a/docs/spec/annotations.rst +++ b/docs/spec/annotations.rst @@ -170,6 +170,7 @@ The following grammar describes the allowed elements of type and annotation expr : (valid only in some contexts) : | '[' `type_expression` ']' : (valid only in some contexts) + : | ('[' `type_expression` ']')? : | `string_annotation` : (must evaluate to a valid `type_expression`) maybe_unpacked: `type_expression` | `unpacked` diff --git a/docs/spec/index.rst b/docs/spec/index.rst index 30210227..47d49176 100644 --- a/docs/spec/index.rst +++ b/docs/spec/index.rst @@ -9,6 +9,7 @@ Specification for the Python type system meta concepts annotations + type-forms special-types generics qualifiers diff --git a/docs/spec/type-forms.rst b/docs/spec/type-forms.rst new file mode 100644 index 00000000..4dc7c9e3 --- /dev/null +++ b/docs/spec/type-forms.rst @@ -0,0 +1,191 @@ +.. _`type-forms`: + +Type forms +========== + +.. _`typeform`: + +TypeForm +-------- + +(Originally specified in :pep:`747`.) + +When a type expression is evaluated at runtime, the resulting value is a +*type form* object. This value encodes the information supplied in the type +expression, and it represents the type described by that type expression. + +``TypeForm`` is a :term:`special form` that, when used in a type expression, +describes a set of type form objects. It accepts a single type argument, which +must be a :ref:`valid type expression `. +``TypeForm[T]`` describes the set of all type form objects that represent +the type ``T`` or types that are :term:`assignable` to ``T``. For example, +``TypeForm[str | None]`` describes the set of all type form objects that +represent a type assignable to ``str | None``:: + + from typing import Any, Literal, Optional + from typing_extensions import TypeForm + + ok1: TypeForm[str | None] = str | None # OK + ok2: TypeForm[str | None] = str # OK + ok3: TypeForm[str | None] = None # OK + ok4: TypeForm[str | None] = Literal[None] # OK + ok5: TypeForm[str | None] = Optional[str] # OK + ok6: TypeForm[str | None] = "str | None" # OK + ok7: TypeForm[str | None] = Any # OK + + err1: TypeForm[str | None] = str | int # Error + err2: TypeForm[str | None] = list[str | None] # Error + +By this same definition, ``TypeForm[object]`` describes a type form object +that represents the type ``object`` or any type that is assignable to +``object``. Since all types in the Python type system are assignable to +``object``, ``TypeForm[object]`` describes the set of all type form objects +evaluated from all valid type expressions. + +``TypeForm[Any]`` describes a ``TypeForm`` type whose type argument is not +statically known but is a valid type form object. It is assignable both +to and from any other ``TypeForm`` type (because ``Any`` is assignable both +to and from any type). + +The type expression ``TypeForm``, with no type argument provided, is +equivalent to ``TypeForm[Any]``. + +.. _`implicit-typeform-evaluation`: + +Implicit ``TypeForm`` evaluation +-------------------------------- + +When a static type checker encounters a valid type expression, the evaluated +type of this expression should be assignable to ``TypeForm[T]`` if the type it +describes is assignable to ``T``. + +For example, if a static type checker encounters the expression +``str | None``, it may normally evaluate its type as ``UnionType`` because it +produces a runtime value that is an instance of ``types.UnionType``. However, +because this expression is a valid type expression, it is also assignable to +the type ``TypeForm[str | None]``:: + + from types import GenericAlias, UnionType + from typing_extensions import TypeForm + + v1_actual: UnionType = str | None # OK + v1_type_form: TypeForm[str | None] = str | None # OK + + v2_actual: GenericAlias = list[int] # OK + v2_type_form: TypeForm = list[int] # OK + +The ``Annotated`` special form is allowed in type expressions, so it can +also appear in an expression that is assignable to ``TypeForm``. Consistent +with the general rules for ``Annotated``, a static type checker may +choose to ignore any ``Annotated`` metadata that it does not understand:: + + from typing import Annotated + from typing_extensions import TypeForm + + v3: TypeForm[int | str] = Annotated[int | str, "metadata"] # OK + +A string literal expression containing a valid type expression should likewise +be assignable to ``TypeForm``:: + + from typing_extensions import TypeForm + + v4: TypeForm[set[str]] = "set[str]" # OK + +.. _`valid-type-expressions`: + +Valid type expressions +---------------------- + +This specification defines syntactic rules for type expressions in the form of a +:ref:`formal grammar `. Semantic rules are specified as +comments along with the grammar definition. Contextual requirements are +detailed throughout the text in sections that discuss concepts that +appear within type expressions. For example, the special form ``Self`` can be +used in a type expression only within a class, and a type variable can be used +within a type expression only when it is associated with a valid scope. + +A valid type expression is an expression that follows all of the syntactic, +semantic, and contextual rules for a type expression. + +Expressions that are not valid type expressions should not evaluate to a +``TypeForm`` type:: + + from typing import ClassVar, Final, Literal, Optional, Self, TypeVarTuple, Unpack + from typing_extensions import TypeForm + + Ts = TypeVarTuple("Ts") + var = 1 + + bad1: TypeForm = tuple() # Error: call expression not allowed in type expression + bad2: TypeForm = (1, 2) # Error: tuple expression not allowed in type expression + bad3: TypeForm = 1 # Error: non-class object not allowed in type expression + bad4: TypeForm = Self # Error: Self not allowed outside of a class + bad5: TypeForm = Literal[var] # Error: variable not allowed in type expression + bad6: TypeForm = Literal[f""] # Error: f-strings not allowed in type expression + bad7: TypeForm = ClassVar[int] # Error: ClassVar not allowed in type expression + bad8: TypeForm = Final[int] # Error: Final not allowed in type expression + bad9: TypeForm = Unpack[Ts] # Error: Unpack not allowed in this context + bad10: TypeForm = Optional # Error: invalid use of Optional special form + bad11: TypeForm = "int + str" # Error: invalid quoted type expression + +.. _`explicit-typeform-evaluation`: + +Explicit ``TypeForm`` evaluation +-------------------------------- + +``TypeForm`` also acts as a function that can be called with a single +argument. Type checkers should validate that this argument is a valid type +expression:: + + from typing import assert_type + from typing_extensions import TypeForm + + x1 = TypeForm(str | None) + assert_type(x1, TypeForm[str | None]) + + x2 = TypeForm("list[int]") + assert_type(x2, TypeForm[list[int]]) + + x3 = TypeForm("type(1)") # Error: invalid type expression + +The static type of a ``TypeForm(T)`` expression is ``TypeForm[T]``. + +At runtime the ``TypeForm(...)`` callable simply returns the value passed to +it. + +This explicit syntax serves two purposes. First, it documents the developer's +intent to use the value as a type form object. Second, static type checkers +validate that all rules for type expressions are followed:: + + x4 = type(1) # No error, evaluates to "type[int]" + + x5 = TypeForm(type(1)) # Error: call not allowed in type expression + +.. _`typeform-assignability`: + +Assignability +------------- + +``TypeForm`` has a single type parameter, which is covariant. That means +``TypeForm[B]`` is assignable to ``TypeForm[A]`` if ``B`` is assignable to +``A``:: + + from typing_extensions import TypeForm + + def get_type_form() -> TypeForm[int]: ... + + t1: TypeForm[int | str] = get_type_form() # OK + t2: TypeForm[str] = get_type_form() # Error + +``type[T]`` is a subtype of ``TypeForm[T]``, which means that ``type[B]`` is +assignable to ``TypeForm[A]`` if ``B`` is assignable to ``A``:: + + from typing_extensions import TypeForm + + def get_type() -> type[int]: ... + + t3: TypeForm[int | str] = get_type() # OK + t4: TypeForm[str] = get_type() # Error + +``TypeForm`` is a subtype of ``object`` and is assumed to have all of the +attributes and methods of ``object``.