mirror of
https://github.com/davidhalter/typeshed.git
synced 2026-01-21 18:42:07 +08:00
Use modern syntax in test-case files where possible (#9261)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
# pyright: reportUnnecessaryTypeIgnoreComment=true
|
||||
from __future__ import annotations
|
||||
|
||||
from invoke import Context, task
|
||||
|
||||
|
||||
@@ -79,20 +79,26 @@ is because the purpose of this folder is to test the implications of typeshed
|
||||
changes for end users, who will mainly be using `.py` files rather than `.pyi`
|
||||
files.
|
||||
|
||||
Another difference to the rest of typeshed is that the test cases in this
|
||||
directory cannot always use modern syntax for type hints.
|
||||
Another difference to the rest of typeshed
|
||||
(which stems from the fact that the test-case files are all `.py` files
|
||||
rather than `.pyi` files)
|
||||
is that the test cases cannot always use modern syntax for type hints.
|
||||
While we can use `from __future__ import annotations` to enable the use of
|
||||
modern typing syntax wherever possible,
|
||||
type checkers may (correctly) emit errors if PEP 604 syntax or PEP 585 syntax
|
||||
is used in a runtime context on lower versions of Python. For example:
|
||||
|
||||
For example, PEP 604
|
||||
syntax (unions with a pipe `|` operator) is new in Python 3.10. While this
|
||||
syntax can be used on older Python versions in a `.pyi` file, code using this
|
||||
syntax will fail at runtime on Python <=3.9. Since the test cases all use `.py`
|
||||
extensions, and since the tests need to pass on all Python versions >=3.7, PEP
|
||||
604 syntax cannot be used in a test case. Use `typing.Union` and
|
||||
`typing.Optional` instead.
|
||||
```python
|
||||
from __future__ import annotations
|
||||
|
||||
PEP 585 syntax can also not be used in the `test_cases` directory. Use
|
||||
`typing.Tuple` instead of `tuple`, `typing.Callable` instead of
|
||||
`collections.abc.Callable`, and `typing.Match` instead of `re.Match` (etc.).
|
||||
from typing_extensions import assert_type
|
||||
|
||||
x: str | int # PEP 604 syntax: okay on Python >=3.7, due to __future__ annotations
|
||||
assert_type(x, str | int) # Will fail at runtime on Python <3.10 (use typing.Union instead)
|
||||
|
||||
y: dict[str, int] # PEP 585 syntax: okay on Python >= 3.7, due to __future__ annotations
|
||||
assert_type(y, dict[str, int]) # Will fail at runtime on Python <3.9 (use typing.Dict instead)
|
||||
```
|
||||
|
||||
### Version-dependent tests
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from asyncio import iscoroutinefunction
|
||||
from collections.abc import Awaitable, Callable, Coroutine
|
||||
from typing import Any, Union
|
||||
from typing import Any
|
||||
from typing_extensions import assert_type
|
||||
|
||||
|
||||
def test_iscoroutinefunction(
|
||||
x: Callable[[str, int], Coroutine[str, int, bytes]],
|
||||
y: Callable[[str, int], Awaitable[bytes]],
|
||||
z: Callable[[str, int], Union[str, Awaitable[bytes]]],
|
||||
z: Callable[[str, int], str | Awaitable[bytes]],
|
||||
xx: object,
|
||||
) -> None:
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Any, Awaitable, List, Tuple, Union
|
||||
from typing_extensions import assert_type
|
||||
@@ -21,7 +23,7 @@ async def test_gather(awaitable1: Awaitable[int], awaitable2: Awaitable[str]) ->
|
||||
c = await asyncio.gather(awaitable1, awaitable2, awaitable1, awaitable1, awaitable1, awaitable1)
|
||||
assert_type(c, List[Any])
|
||||
|
||||
awaitables_list: List[Awaitable[int]] = [awaitable1]
|
||||
awaitables_list: list[Awaitable[int]] = [awaitable1]
|
||||
d = await asyncio.gather(*awaitables_list)
|
||||
assert_type(d, List[Any])
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from typing import Dict, Generic, Iterable, Tuple, TypeVar
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, Generic, Iterable, TypeVar
|
||||
from typing_extensions import assert_type
|
||||
|
||||
# These do follow `__init__` overloads order:
|
||||
@@ -6,7 +8,7 @@ from typing_extensions import assert_type
|
||||
# mypy raises: 'Need type annotation for "bad"'
|
||||
# pyright is fine with it.
|
||||
# bad = dict()
|
||||
good: Dict[str, str] = dict()
|
||||
good: dict[str, str] = dict()
|
||||
assert_type(good, Dict[str, str])
|
||||
|
||||
assert_type(dict(arg=1), Dict[str, int])
|
||||
@@ -16,7 +18,7 @@ _VT = TypeVar("_VT")
|
||||
|
||||
|
||||
class KeysAndGetItem(Generic[_KT, _VT]):
|
||||
data: Dict[_KT, _VT]
|
||||
data: dict[_KT, _VT]
|
||||
|
||||
def keys(self) -> Iterable[_KT]:
|
||||
return self.data.keys()
|
||||
@@ -33,15 +35,15 @@ kt2: KeysAndGetItem[str, int] = KeysAndGetItem()
|
||||
assert_type(dict(kt2, arg=1), Dict[str, int])
|
||||
|
||||
|
||||
def test_iterable_tuple_overload(x: Iterable[Tuple[int, str]]) -> Dict[int, str]:
|
||||
def test_iterable_tuple_overload(x: Iterable[tuple[int, str]]) -> dict[int, str]:
|
||||
return dict(x)
|
||||
|
||||
|
||||
i1: Iterable[Tuple[int, str]] = [(1, "a"), (2, "b")]
|
||||
i1: Iterable[tuple[int, str]] = [(1, "a"), (2, "b")]
|
||||
test_iterable_tuple_overload(i1)
|
||||
dict(i1, arg="a") # type: ignore
|
||||
|
||||
i2: Iterable[Tuple[str, int]] = [("a", 1), ("b", 2)]
|
||||
i2: Iterable[tuple[str, int]] = [("a", 1), ("b", 2)]
|
||||
assert_type(dict(i2, arg=1), Dict[str, int])
|
||||
|
||||
i3: Iterable[str] = ["a.b"]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterator
|
||||
from typing_extensions import assert_type
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List, Union
|
||||
from typing_extensions import assert_type
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from typing import Any, Tuple, Union
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
# The following should pass without error (see #6661):
|
||||
class Diagnostic:
|
||||
def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
|
||||
def __reduce__(self) -> str | tuple[Any, ...]:
|
||||
res = super().__reduce__()
|
||||
if isinstance(res, tuple) and len(res) >= 3:
|
||||
res[2]["_info"] = 42
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from fractions import Fraction
|
||||
from typing import Any
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, List, Union
|
||||
from typing_extensions import Literal, assert_type
|
||||
|
||||
|
||||
class Foo:
|
||||
def __add__(self, other: Any) -> "Foo":
|
||||
def __add__(self, other: Any) -> Foo:
|
||||
return Foo()
|
||||
|
||||
|
||||
class Bar:
|
||||
def __radd__(self, other: Any) -> "Bar":
|
||||
def __radd__(self, other: Any) -> Bar:
|
||||
return Bar()
|
||||
|
||||
|
||||
class Baz:
|
||||
def __add__(self, other: Any) -> "Baz":
|
||||
def __add__(self, other: Any) -> Baz:
|
||||
return Baz()
|
||||
|
||||
def __radd__(self, other: Any) -> "Baz":
|
||||
def __radd__(self, other: Any) -> Baz:
|
||||
return Baz()
|
||||
|
||||
|
||||
literal_list: List[Literal[0, 1]] = [0, 1, 1]
|
||||
literal_list: list[Literal[0, 1]] = [0, 1, 1]
|
||||
|
||||
assert_type(sum([2, 4]), int)
|
||||
assert_type(sum([3, 5], 4), int)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Tuple
|
||||
from typing_extensions import assert_type
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import codecs
|
||||
from typing_extensions import assert_type
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import ExitStack
|
||||
from typing_extensions import assert_type
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import _threading_local
|
||||
import threading
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
@@ -58,14 +60,14 @@ class Eggs:
|
||||
|
||||
|
||||
class Ham:
|
||||
def __lt__(self, other: "Ham") -> bool:
|
||||
def __lt__(self, other: Ham) -> bool:
|
||||
if not isinstance(other, Ham):
|
||||
return NotImplemented
|
||||
return True
|
||||
|
||||
|
||||
class Bacon:
|
||||
def __gt__(self, other: "Bacon") -> bool:
|
||||
def __gt__(self, other: Bacon) -> bool:
|
||||
if not isinstance(other, Bacon):
|
||||
return NotImplemented
|
||||
return True
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
# pyright: reportWildcardImportFromLibrary=false
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Match, Optional, Pattern
|
||||
from typing_extensions import assert_type
|
||||
|
||||
|
||||
@@ -85,9 +85,10 @@ def check_test_cases() -> None:
|
||||
bad_test_case_filename = 'Files in a `test_cases` directory must have names starting with "check_"; got "{}"'
|
||||
for file in testcase_dir.rglob("*.py"):
|
||||
assert file.stem.startswith("check_"), bad_test_case_filename.format(file)
|
||||
with open(file, encoding="UTF-8") as f:
|
||||
lines = {line.strip() for line in f}
|
||||
assert "from __future__ import annotations" in lines, "Test-case files should use modern typing syntax where possible"
|
||||
if package_name != "stdlib":
|
||||
with open(file, encoding="UTF-8") as f:
|
||||
lines = {line.strip() for line in f}
|
||||
pyright_setting_not_enabled_msg = (
|
||||
f'Third-party test-case file "{file}" must have '
|
||||
f'"# pyright: reportUnnecessaryTypeIgnoreComment=true" '
|
||||
@@ -205,7 +206,7 @@ def check_requirements() -> None:
|
||||
precommit_requirements = get_precommit_requirements()
|
||||
no_txt_entry_msg = "All pre-commit requirements must also be listed in `requirements-tests.txt` (missing {requirement!r})"
|
||||
for requirement, specifier in precommit_requirements.items():
|
||||
assert requirement in requirements_txt_requirements, no_txt_entry_msg.format(requirement)
|
||||
assert requirement in requirements_txt_requirements, no_txt_entry_msg.format(requirement=requirement)
|
||||
specifier_mismatch = (
|
||||
f'Specifier "{specifier}" for {requirement!r} in `.pre-commit-config.yaml` '
|
||||
f'does not match specifier "{requirements_txt_requirements[requirement]}" in `requirements-tests.txt`'
|
||||
|
||||
Reference in New Issue
Block a user