From deb08a30e054eef7fb18a23ef666319c3d5a51a6 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sat, 19 Oct 2024 15:41:17 +0900 Subject: [PATCH 01/20] Pyright wants aliases everywhere --- src/trio/_core/_local.py | 4 +- src/trio/_core/_run.py | 10 +++-- src/trio/_tests/test_exports.py | 70 +++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/trio/_core/_local.py b/src/trio/_core/_local.py index 53cbfc135..141a30b52 100644 --- a/src/trio/_core/_local.py +++ b/src/trio/_core/_local.py @@ -38,8 +38,8 @@ class RunVar(Generic[T]): """ - _name: str - _default: T | type[_NoValue] = _NoValue + _name: str = attrs.field(alias="name") + _default: T | type[_NoValue] = attrs.field(default=_NoValue, alias="default") def get(self, default: T | type[_NoValue] = _NoValue) -> T: """Gets the value of this :class:`RunVar` for the current run call.""" diff --git a/src/trio/_core/_run.py b/src/trio/_core/_run.py index cba7a8dec..f141685eb 100644 --- a/src/trio/_core/_run.py +++ b/src/trio/_core/_run.py @@ -544,9 +544,13 @@ class CancelScope: cancelled_caught: bool = attrs.field(default=False, init=False) # Constructor arguments: - _relative_deadline: float = attrs.field(default=inf, kw_only=True) - _deadline: float = attrs.field(default=inf, kw_only=True) - _shield: bool = attrs.field(default=False, kw_only=True) + _relative_deadline: float = attrs.field( + default=inf, + kw_only=True, + alias="relative_deadline", + ) + _deadline: float = attrs.field(default=inf, kw_only=True, alias="deadline") + _shield: bool = attrs.field(default=False, kw_only=True, alias="shield") def __attrs_post_init__(self) -> None: if isnan(self._deadline): diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index a463b778f..036ad93cb 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -9,6 +9,7 @@ import json import socket as stdlib_socket import sys +import tokenize import types from pathlib import Path, PurePath from types import ModuleType @@ -572,3 +573,72 @@ def test_classes_are_final() -> None: continue assert class_is_final(class_) + + +def test_pyright_recognizes_init_attributes() -> None: + # Obviously, this isn't completely accurate. + # It should still be good enough. Hopefully. + # (attrs updates fields before we can access them) + files = [] + + for path in (Path(inspect.getfile(trio)) / "..").glob("**/*.py"): + with open(path, "rb") as f: + files.append(list(tokenize.tokenize(f.readline))) + + for module in PUBLIC_MODULES: + for name, class_ in module.__dict__.items(): + if not attrs.has(class_): + continue + if isinstance(class_, _util.NoPublicConstructor): + continue + + file = None + start = None + for contents in files: + last_was_class = False + for i, token in enumerate(contents): + if ( + token.type == tokenize.NAME + and token.string == name + and last_was_class + ): + assert file is None + file = contents + start = i - 1 + + if token.type == tokenize.NAME and token.string == "class": + last_was_class = True + else: + last_was_class = False + + assert file is not None + + count = -1 + # linters don't like my not using the index, go figure. + for end_offset, token in enumerate(file[start:]): # noqa: B007 + if token.type == tokenize.INDENT: + count += 1 + if token.type == tokenize.DEDENT and count: + count -= 1 + elif token.type == tokenize.DEDENT: + break + + assert token.type == tokenize.DEDENT + class_source = ( + tokenize.untokenize(file[start : start + end_offset]) + .replace("\\", "") + .strip() + ) + + attributes = list(attrs.fields(class_)) + attributes = [attr for attr in attributes if attr.name.startswith("_")] + attributes = [attr for attr in attributes if attr.init] + + attributes = [ + # could this be improved by parsing AST? yes. this is simpler though. + attr + for attr in attributes + if f'alias="{attr.alias}"' not in class_source + ] + + assert attributes == [], class_ From 1e65f6880b3a16180ace95c7e2e20bee9f003cc1 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sat, 19 Oct 2024 15:46:14 +0900 Subject: [PATCH 02/20] Changelog --- newsfragments/3114.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/3114.bugfix.rst diff --git a/newsfragments/3114.bugfix.rst b/newsfragments/3114.bugfix.rst new file mode 100644 index 000000000..2f0771219 --- /dev/null +++ b/newsfragments/3114.bugfix.rst @@ -0,0 +1 @@ +Ensure that Pyright recognizes our underscore prefixed attributes for attrs classes. From 59abcf880851138b26249e16e713ca43d132479b Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sat, 19 Oct 2024 15:49:36 +0900 Subject: [PATCH 03/20] Make backslash replacement more correct --- src/trio/_tests/test_exports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 036ad93cb..fde1943a5 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -626,7 +626,7 @@ def test_pyright_recognizes_init_attributes() -> None: assert token.type == tokenize.DEDENT class_source = ( tokenize.untokenize(file[start : start + end_offset]) - .replace("\\", "") + .replace("\\\n", "") .strip() ) From cbb08fb142563952616ebb0e05794160732760d0 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sat, 19 Oct 2024 03:14:46 -0400 Subject: [PATCH 04/20] Debug which class doesn't exist --- src/trio/_tests/test_exports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index fde1943a5..1e5541932 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -611,7 +611,7 @@ def test_pyright_recognizes_init_attributes() -> None: else: last_was_class = False - assert file is not None + assert file is not None, class_ count = -1 # linters don't like my not using the index, go figure. From 9c97bad2c0aa6cff47526540e3a1be38c7c82c9f Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sat, 19 Oct 2024 03:19:09 -0400 Subject: [PATCH 05/20] Debug a bit better --- src/trio/_tests/test_exports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 1e5541932..46f419b62 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -611,7 +611,7 @@ def test_pyright_recognizes_init_attributes() -> None: else: last_was_class = False - assert file is not None, class_ + assert file is not None, f"{name}: {class_!r}" count = -1 # linters don't like my not using the index, go figure. From 35609d403abf644d78e289e9749625037841d1d6 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sat, 19 Oct 2024 16:32:28 +0900 Subject: [PATCH 06/20] Fix weirdness around PosixPath needing to be resolved --- src/trio/_tests/test_exports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 46f419b62..446a9550c 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -581,7 +581,7 @@ def test_pyright_recognizes_init_attributes() -> None: # (attrs updates fields before we can access them) files = [] - for path in (Path(inspect.getfile(trio)) / "..").glob("**/*.py"): + for path in (Path(inspect.getfile(trio)) / "..").resolve().glob("**/*.py"): with open(path, "rb") as f: files.append(list(tokenize.tokenize(f.readline))) From 4bc3e588f9c65be7aa52043da0ab2fb845e268bc Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sat, 19 Oct 2024 16:35:29 +0900 Subject: [PATCH 07/20] Appease type checker --- src/trio/_tests/test_exports.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 446a9550c..5f6d3d59f 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -612,6 +612,7 @@ def test_pyright_recognizes_init_attributes() -> None: last_was_class = False assert file is not None, f"{name}: {class_!r}" + assert start is not None count = -1 # linters don't like my not using the index, go figure. From 37b9c38f3ec07c7eb60745967b2720d784bad815 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sun, 20 Oct 2024 19:30:55 +0900 Subject: [PATCH 08/20] Don't even consider tests in the alias test --- src/trio/_tests/test_exports.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 5f6d3d59f..a3992a8d6 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -581,7 +581,11 @@ def test_pyright_recognizes_init_attributes() -> None: # (attrs updates fields before we can access them) files = [] - for path in (Path(inspect.getfile(trio)) / "..").resolve().glob("**/*.py"): + parent = (Path(inspect.getfile(trio)) / "..").resolve() + for path in parent.glob("**/*.py"): + if "_tests" in path[len(parent) :]: + continue + with open(path, "rb") as f: files.append(list(tokenize.tokenize(f.readline))) From 3cda304e17a2593a9152f72bd9cc05bee6ca8a5d Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sun, 20 Oct 2024 19:33:56 +0900 Subject: [PATCH 09/20] Turn paths into strings before indexing --- src/trio/_tests/test_exports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index a3992a8d6..a4b2f0fab 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -583,7 +583,7 @@ def test_pyright_recognizes_init_attributes() -> None: parent = (Path(inspect.getfile(trio)) / "..").resolve() for path in parent.glob("**/*.py"): - if "_tests" in path[len(parent) :]: + if "_tests" in str(path)[len(str(parent)) :]: continue with open(path, "rb") as f: From 9eca8515be8e86b60dae42984ef2916ac5f01ca0 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sun, 20 Oct 2024 19:38:28 -0400 Subject: [PATCH 10/20] Explain the test better --- src/trio/_tests/test_exports.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index a4b2f0fab..7dad2a676 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -576,9 +576,26 @@ def test_classes_are_final() -> None: def test_pyright_recognizes_init_attributes() -> None: - # Obviously, this isn't completely accurate. - # It should still be good enough. Hopefully. - # (attrs updates fields before we can access them) + """Check whether we provide `alias` for all underscore prefixed attributes + + We cannot check this at runtime, as attrs sets the `alias` attribute on + fields, but instead we can reconstruct the source code of the class and + check that. Unfortunately, `inspect.getsourcelines` does not work so we + need to build up this source code ourself. + + The approach taken here is: + 1. read every file that could contain the classes in question + 2. tokenize them, for a couple reasons: + - tokenization unlike ast parsing can be 1-1 undone + - tokenization allows us to get the whole class block + - tokenization allows us to find ``class {name}`` without prefix + matches + 3. for every exported class: + 1. find the file + 2. isolate the class block + 3. undo tokenization + 4. find the string ``alias="{what it should be}"`` + """ files = [] parent = (Path(inspect.getfile(trio)) / "..").resolve() @@ -619,8 +636,8 @@ def test_pyright_recognizes_init_attributes() -> None: assert start is not None count = -1 - # linters don't like my not using the index, go figure. - for end_offset, token in enumerate(file[start:]): # noqa: B007 + end_offset = 0 + for end_offset, token in enumerate(file[start:]): # pragma: no branch if token.type == tokenize.INDENT: count += 1 if token.type == tokenize.DEDENT and count: From ba67f7e6df7bebb12a4da41b7a5f02d08ad2988a Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sun, 20 Oct 2024 19:42:21 -0400 Subject: [PATCH 11/20] Fixes for pre-commit --- src/trio/_tests/test_exports.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 7dad2a676..2b32b0eb7 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -577,12 +577,12 @@ def test_classes_are_final() -> None: def test_pyright_recognizes_init_attributes() -> None: """Check whether we provide `alias` for all underscore prefixed attributes - + We cannot check this at runtime, as attrs sets the `alias` attribute on fields, but instead we can reconstruct the source code of the class and check that. Unfortunately, `inspect.getsourcelines` does not work so we need to build up this source code ourself. - + The approach taken here is: 1. read every file that could contain the classes in question 2. tokenize them, for a couple reasons: @@ -637,7 +637,7 @@ def test_pyright_recognizes_init_attributes() -> None: count = -1 end_offset = 0 - for end_offset, token in enumerate(file[start:]): # pragma: no branch + for end_offset, token in enumerate(file[start:]): # pragma: no branch # noqa: B007 if token.type == tokenize.INDENT: count += 1 if token.type == tokenize.DEDENT and count: From 88cf458e6d36b0acfa7e2343b40900bb05cebf21 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sun, 20 Oct 2024 19:45:38 -0400 Subject: [PATCH 12/20] Reformat according to black --- src/trio/_tests/test_exports.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 2b32b0eb7..b777684c6 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -637,7 +637,9 @@ def test_pyright_recognizes_init_attributes() -> None: count = -1 end_offset = 0 - for end_offset, token in enumerate(file[start:]): # pragma: no branch # noqa: B007 + for end_offset, token in enumerate( # noqa: B007 + file[start:] + ): # pragma: no branch if token.type == tokenize.INDENT: count += 1 if token.type == tokenize.DEDENT and count: From 819797afaf12c5af73357ac17897a389710efed4 Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sun, 20 Oct 2024 19:46:41 -0400 Subject: [PATCH 13/20] One last pre-commit fix --- src/trio/_tests/test_exports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index b777684c6..6ed879fde 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -638,7 +638,7 @@ def test_pyright_recognizes_init_attributes() -> None: count = -1 end_offset = 0 for end_offset, token in enumerate( # noqa: B007 - file[start:] + file[start:], ): # pragma: no branch if token.type == tokenize.INDENT: count += 1 From f21cbb01567fcb36bc9e29c8be033394408cc4c9 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Tue, 22 Oct 2024 11:43:40 +1000 Subject: [PATCH 14/20] Simplify alias test by monkeypatching attrs. --- pyproject.toml | 2 +- src/_trio_check_attrs_aliases.py | 21 ++++++++ src/trio/_tests/test_exports.py | 90 ++++---------------------------- 3 files changed, 33 insertions(+), 80 deletions(-) create mode 100644 src/_trio_check_attrs_aliases.py diff --git a/pyproject.toml b/pyproject.toml index ff4aa3460..9d57d2b2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -189,7 +189,7 @@ reportUnnecessaryTypeIgnoreComment = true typeCheckingMode = "strict" [tool.pytest.ini_options] -addopts = ["--strict-markers", "--strict-config", "-p trio._tests.pytest_plugin"] +addopts = ["--strict-markers", "--strict-config", "-p _trio_check_attrs_aliases", "-p trio._tests.pytest_plugin"] faulthandler_timeout = 60 filterwarnings = [ "error", diff --git a/src/_trio_check_attrs_aliases.py b/src/_trio_check_attrs_aliases.py new file mode 100644 index 000000000..d716949d8 --- /dev/null +++ b/src/_trio_check_attrs_aliases.py @@ -0,0 +1,21 @@ +"""Conftest is executed by Pytest before test modules. + +We use this to monkeypatch attrs.field(), so that we can detect if aliases are used for test_exports. +""" + +from typing import Any + +import attrs + +orig_field = attrs.field + + +def field(**kwargs: Any) -> Any: + if "alias" in kwargs: + metadata = kwargs.setdefault("metadata", {}) + metadata["trio_test_has_alias"] = True + return orig_field(**kwargs) + + +field.trio_modded = True # type: ignore +attrs.field = field diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 6ed879fde..8c5f33505 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -9,7 +9,6 @@ import json import socket as stdlib_socket import sys -import tokenize import types from pathlib import Path, PurePath from types import ModuleType @@ -576,93 +575,26 @@ def test_classes_are_final() -> None: def test_pyright_recognizes_init_attributes() -> None: - """Check whether we provide `alias` for all underscore prefixed attributes - - We cannot check this at runtime, as attrs sets the `alias` attribute on - fields, but instead we can reconstruct the source code of the class and - check that. Unfortunately, `inspect.getsourcelines` does not work so we - need to build up this source code ourself. - - The approach taken here is: - 1. read every file that could contain the classes in question - 2. tokenize them, for a couple reasons: - - tokenization unlike ast parsing can be 1-1 undone - - tokenization allows us to get the whole class block - - tokenization allows us to find ``class {name}`` without prefix - matches - 3. for every exported class: - 1. find the file - 2. isolate the class block - 3. undo tokenization - 4. find the string ``alias="{what it should be}"`` - """ - files = [] - - parent = (Path(inspect.getfile(trio)) / "..").resolve() - for path in parent.glob("**/*.py"): - if "_tests" in str(path)[len(str(parent)) :]: - continue - - with open(path, "rb") as f: - files.append(list(tokenize.tokenize(f.readline))) + """Check whether we provide `alias` for all underscore prefixed attributes. + Attrs always sets the `alias` attribute on fields, so a pytest plugin is used + to monkeypatch `field()` to record whether an alias was defined in the metadata. + See `_trio_check_attrs_aliases`. + """ + assert hasattr(attrs.field, "trio_modded") for module in PUBLIC_MODULES: - for name, class_ in module.__dict__.items(): + for class_ in module.__dict__.values(): if not attrs.has(class_): continue if isinstance(class_, _util.NoPublicConstructor): continue - file = None - start = None - for contents in files: - last_was_class = False - for i, token in enumerate(contents): - if ( - token.type == tokenize.NAME - and token.string == name - and last_was_class - ): - assert file is None - file = contents - start = i - 1 - - if token.type == tokenize.NAME and token.string == "class": - last_was_class = True - else: - last_was_class = False - - assert file is not None, f"{name}: {class_!r}" - assert start is not None - - count = -1 - end_offset = 0 - for end_offset, token in enumerate( # noqa: B007 - file[start:], - ): # pragma: no branch - if token.type == tokenize.INDENT: - count += 1 - if token.type == tokenize.DEDENT and count: - count -= 1 - elif token.type == tokenize.DEDENT: - break - - assert token.type == tokenize.DEDENT - class_source = ( - tokenize.untokenize(file[start : start + end_offset]) - .replace("\\\n", "") - .strip() - ) - - attributes = list(attrs.fields(class_)) - attributes = [attr for attr in attributes if attr.name.startswith("_")] - attributes = [attr for attr in attributes if attr.init] - attributes = [ - # could this be improved by parsing AST? yes. this is simpler though. attr - for attr in attributes - if f'alias="{attr.alias}"' not in class_source + for attr in attrs.fields(class_) + if attr.name.startswith("_") + if attr.init + if "trio_test_has_alias" not in attr.metadata ] assert attributes == [], class_ From 30befc904928bb7210d53f54e1de339888ea8449 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Sun, 10 Nov 2024 10:02:13 +1000 Subject: [PATCH 15/20] Skip pyright init attributes test if plugin has not run --- src/_trio_check_attrs_aliases.py | 1 + src/trio/_tests/test_exports.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/_trio_check_attrs_aliases.py b/src/_trio_check_attrs_aliases.py index d716949d8..256160832 100644 --- a/src/_trio_check_attrs_aliases.py +++ b/src/_trio_check_attrs_aliases.py @@ -17,5 +17,6 @@ def field(**kwargs: Any) -> Any: return orig_field(**kwargs) +# Mark it as being ours, so the test knows it can actually run. field.trio_modded = True # type: ignore attrs.field = field diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 8c5f33505..90ece79e9 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -574,6 +574,11 @@ def test_classes_are_final() -> None: assert class_is_final(class_) +# Plugin might not be running, especially if running from an installed version. +@pytest.mark.skipif( + not hasattr(attrs.field, "trio_modded"), + reason="Pytest plugin not installed.", +) def test_pyright_recognizes_init_attributes() -> None: """Check whether we provide `alias` for all underscore prefixed attributes. @@ -581,7 +586,6 @@ def test_pyright_recognizes_init_attributes() -> None: to monkeypatch `field()` to record whether an alias was defined in the metadata. See `_trio_check_attrs_aliases`. """ - assert hasattr(attrs.field, "trio_modded") for module in PUBLIC_MODULES: for class_ in module.__dict__.values(): if not attrs.has(class_): From a23712c657cac955f391963bbce8647e16a48dcc Mon Sep 17 00:00:00 2001 From: EXPLOSION Date: Sat, 9 Nov 2024 19:59:30 -0500 Subject: [PATCH 16/20] Catch any other renaming too --- src/_trio_check_attrs_aliases.py | 6 +++--- src/trio/_tests/test_exports.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/_trio_check_attrs_aliases.py b/src/_trio_check_attrs_aliases.py index 256160832..0454c8da5 100644 --- a/src/_trio_check_attrs_aliases.py +++ b/src/_trio_check_attrs_aliases.py @@ -11,9 +11,9 @@ def field(**kwargs: Any) -> Any: - if "alias" in kwargs: - metadata = kwargs.setdefault("metadata", {}) - metadata["trio_test_has_alias"] = True + original_args = kwargs.copy() + metadata = kwargs.setdefault("metadata", {}) + metadata["original_args"] = original_args return orig_field(**kwargs) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 90ece79e9..8dc13f1fd 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -596,9 +596,8 @@ def test_pyright_recognizes_init_attributes() -> None: attributes = [ attr for attr in attrs.fields(class_) - if attr.name.startswith("_") if attr.init - if "trio_test_has_alias" not in attr.metadata + if attr.alias not in (attr.name, attr.metadata["original_args"].get("alias")) ] assert attributes == [], class_ From 74e67f16096b7675d6c06d20b6f4a4e4a7df0f91 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Nov 2024 00:59:42 +0000 Subject: [PATCH 17/20] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/trio/_tests/test_exports.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 8dc13f1fd..92b9a500a 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -597,7 +597,8 @@ def test_pyright_recognizes_init_attributes() -> None: attr for attr in attrs.fields(class_) if attr.init - if attr.alias not in (attr.name, attr.metadata["original_args"].get("alias")) + if attr.alias + not in (attr.name, attr.metadata["original_args"].get("alias")) ] assert attributes == [], class_ From 593701be3e79cd103b4269b7a1b3ab406947bf1a Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sun, 10 Nov 2024 10:39:13 +0900 Subject: [PATCH 18/20] Handle autoattribs --- src/trio/_tests/test_exports.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 92b9a500a..640db7a9e 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -598,7 +598,11 @@ def test_pyright_recognizes_init_attributes() -> None: for attr in attrs.fields(class_) if attr.init if attr.alias - not in (attr.name, attr.metadata["original_args"].get("alias")) + not in ( + attr.name, + # original_args may not be present in autoattribs + attr.metadata.get("original_args", {}).get("alias"), + ) ] assert attributes == [], class_ From ff487e2816998d38e45a03ccf9683cf058f95633 Mon Sep 17 00:00:00 2001 From: A5rocks Date: Sun, 10 Nov 2024 11:59:01 +0900 Subject: [PATCH 19/20] Disambiguate --- src/trio/_tests/test_exports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trio/_tests/test_exports.py b/src/trio/_tests/test_exports.py index 640db7a9e..d105f9918 100644 --- a/src/trio/_tests/test_exports.py +++ b/src/trio/_tests/test_exports.py @@ -600,8 +600,8 @@ def test_pyright_recognizes_init_attributes() -> None: if attr.alias not in ( attr.name, - # original_args may not be present in autoattribs - attr.metadata.get("original_args", {}).get("alias"), + # trio_original_args may not be present in autoattribs + attr.metadata.get("trio_original_args", {}).get("alias"), ) ] From a6ea1487da4a83eabddd973b4bc80e4bf34c1427 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Sun, 10 Nov 2024 15:05:42 +1000 Subject: [PATCH 20/20] Synchronise name --- src/_trio_check_attrs_aliases.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_trio_check_attrs_aliases.py b/src/_trio_check_attrs_aliases.py index 0454c8da5..3b8e518c0 100644 --- a/src/_trio_check_attrs_aliases.py +++ b/src/_trio_check_attrs_aliases.py @@ -13,7 +13,7 @@ def field(**kwargs: Any) -> Any: original_args = kwargs.copy() metadata = kwargs.setdefault("metadata", {}) - metadata["original_args"] = original_args + metadata["trio_original_args"] = original_args return orig_field(**kwargs)