diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 306f581fb..9e22c94b8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,8 +20,8 @@ jobs: - run: pip install $(grep tomli== requirements-tests-py3.txt) - run: ./tests/check_consistent.py - pep-604: - name: Check for PEP 604 usage + new-syntax: + name: Ensure new syntax usage runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/stdlib/imaplib.pyi b/stdlib/imaplib.pyi index 63c57a4d4..23bc7492d 100644 --- a/stdlib/imaplib.pyi +++ b/stdlib/imaplib.pyi @@ -14,6 +14,8 @@ _CommandResults = Tuple[str, List[Any]] _AnyResponseData = Union[List[None], List[Union[bytes, Tuple[bytes, bytes]]]] +_list = list # conflicts with a method named "list" + class IMAP4: error: Type[Exception] abort: Type[Exception] @@ -22,8 +24,8 @@ class IMAP4: debug: int state: str literal: str | None - tagged_commands: dict[bytes, List[bytes] | None] - untagged_responses: dict[str, List[bytes | Tuple[bytes, bytes]]] + tagged_commands: dict[bytes, _list[bytes] | None] + untagged_responses: dict[str, _list[bytes | Tuple[bytes, bytes]]] continuation_response: str is_readonly: bool tagnum: int @@ -69,23 +71,23 @@ class IMAP4: def getquota(self, root: str) -> _CommandResults: ... def getquotaroot(self, mailbox: str) -> _CommandResults: ... def list(self, directory: str = ..., pattern: str = ...) -> Tuple[str, _AnyResponseData]: ... - def login(self, user: str, password: str) -> Tuple[Literal["OK"], List[bytes]]: ... + def login(self, user: str, password: str) -> Tuple[Literal["OK"], _list[bytes]]: ... def login_cram_md5(self, user: str, password: str) -> _CommandResults: ... def logout(self) -> Tuple[str, _AnyResponseData]: ... def lsub(self, directory: str = ..., pattern: str = ...) -> _CommandResults: ... def myrights(self, mailbox: str) -> _CommandResults: ... def namespace(self) -> _CommandResults: ... - def noop(self) -> Tuple[str, List[bytes]]: ... + def noop(self) -> Tuple[str, _list[bytes]]: ... def partial(self, message_num: str, message_part: str, start: str, length: str) -> _CommandResults: ... def proxyauth(self, user: str) -> _CommandResults: ... def rename(self, oldmailbox: str, newmailbox: str) -> _CommandResults: ... def search(self, charset: str | None, *criteria: str) -> _CommandResults: ... - def select(self, mailbox: str = ..., readonly: bool = ...) -> Tuple[str, List[bytes | None]]: ... + def select(self, mailbox: str = ..., readonly: bool = ...) -> Tuple[str, _list[bytes | None]]: ... def setacl(self, mailbox: str, who: str, what: str) -> _CommandResults: ... def setannotation(self, *args: str) -> _CommandResults: ... def setquota(self, root: str, limits: str) -> _CommandResults: ... def sort(self, sort_criteria: str, charset: str, *search_criteria: str) -> _CommandResults: ... - def starttls(self, ssl_context: Any | None = ...) -> Tuple[Literal["OK"], List[None]]: ... + def starttls(self, ssl_context: Any | None = ...) -> Tuple[Literal["OK"], _list[None]]: ... def status(self, mailbox: str, names: str) -> _CommandResults: ... def store(self, message_set: str, command: str, flags: str) -> _CommandResults: ... def subscribe(self, mailbox: str) -> _CommandResults: ... diff --git a/stdlib/multiprocessing/pool.pyi b/stdlib/multiprocessing/pool.pyi index 5eaf0562b..75583aae8 100644 --- a/stdlib/multiprocessing/pool.pyi +++ b/stdlib/multiprocessing/pool.pyi @@ -38,7 +38,7 @@ class MapResult(ApplyResult[List[_T]]): pool: Pool, chunksize: int, length: int, - callback: Callable[[List[_T]], None] | None, + callback: Callable[[list[_T]], None] | None, error_callback: Callable[[BaseException], None] | None, ) -> None: ... else: @@ -47,7 +47,7 @@ class MapResult(ApplyResult[List[_T]]): cache: dict[int, ApplyResult[Any]], chunksize: int, length: int, - callback: Callable[[List[_T]], None] | None, + callback: Callable[[list[_T]], None] | None, error_callback: Callable[[BaseException], None] | None, ) -> None: ... diff --git a/stdlib/poplib.pyi b/stdlib/poplib.pyi index 8d19067f0..b2334b7b1 100644 --- a/stdlib/poplib.pyi +++ b/stdlib/poplib.pyi @@ -12,6 +12,8 @@ CR: bytes LF: bytes CRLF: bytes +_list = list # conflicts with a method named "list" + class POP3: encoding: str host: str @@ -41,7 +43,7 @@ class POP3: @overload def uidl(self, which: Any) -> bytes: ... def utf8(self) -> bytes: ... - def capa(self) -> dict[str, List[str]]: ... + def capa(self) -> dict[str, _list[str]]: ... def stls(self, context: ssl.SSLContext | None = ...) -> bytes: ... class POP3_SSL(POP3): diff --git a/stubs/dateparser/dateparser/utils/__init__.pyi b/stubs/dateparser/dateparser/utils/__init__.pyi index 8b979d0bf..1dd818985 100644 --- a/stubs/dateparser/dateparser/utils/__init__.pyi +++ b/stubs/dateparser/dateparser/utils/__init__.pyi @@ -1,11 +1,11 @@ from collections import OrderedDict -from typing import Any, List, Mapping +from typing import Any, Mapping def strip_braces(date_string: str) -> str: ... def normalize_unicode(string: str, form: str = ...) -> str: ... def combine_dicts( primary_dict: Mapping[Any, Any], supplementary_dict: Mapping[Any, Any] -) -> OrderedDict[str, str | List[Any]]: ... +) -> OrderedDict[str, str | list[Any]]: ... def find_date_separator(format) -> Any: ... def localize_timezone(date_time, tz_string): ... def apply_tzdatabase_timezone(date_time, pytz_string): ... diff --git a/tests/check_new_syntax.py b/tests/check_new_syntax.py index 278f91cb8..3ad4739d2 100755 --- a/tests/check_new_syntax.py +++ b/tests/check_new_syntax.py @@ -11,18 +11,18 @@ def check_new_syntax(tree: ast.AST, path: Path) -> list[str]: class OldSyntaxFinder(ast.NodeVisitor): def visit_Subscript(self, node: ast.Subscript) -> None: - if not isinstance(node.value, ast.Name): - return + if isinstance(node.value, ast.Name): + if node.value.id == "Union" and isinstance(node.slice, ast.Tuple): + new_syntax = " | ".join(ast.unparse(x) for x in node.slice.elts) + errors.append(f"{path}:{node.lineno}: Use PEP 604 syntax for Union, e.g. `{new_syntax}`") + if node.value.id == "Optional": + new_syntax = f"{ast.unparse(node.slice)} | None" + errors.append(f"{path}:{node.lineno}: Use PEP 604 syntax for Optional, e.g. `{new_syntax}`") + if node.value.id in {"List", "Dict"}: + new_syntax = f"{node.value.id.lower()}[{ast.unparse(node.slice)}]" + errors.append(f"{path}:{node.lineno}: Use built-in generics, e.g. `{new_syntax}`") - if node.value.id == "Union" and isinstance(node.slice, ast.Tuple): - new_syntax = " | ".join(ast.unparse(x) for x in node.slice.elts) - errors.append(f"{path}:{node.lineno}: Use PEP 604 syntax for Union, e.g. `{new_syntax}`") - if node.value.id == "Optional": - new_syntax = f"{ast.unparse(node.slice)} | None" - errors.append(f"{path}:{node.lineno}: Use PEP 604 syntax for Optional, e.g. `{new_syntax}`") - if node.value.id in {"List", "Dict"}: - new_syntax = f"{node.value.id.lower()}[{ast.unparse(node.slice)}]" - errors.append(f"{path}:{node.lineno}: Use built-in generics, e.g. `{new_syntax}`") + self.generic_visit(node) # This doesn't check type aliases (or type var bounds, etc), since those are not # currently supported