Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give Pyright what it wants (alias attributes everywhere) #3114

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
deb08a3
Pyright wants aliases everywhere
A5rocks Oct 19, 2024
1e65f68
Changelog
A5rocks Oct 19, 2024
59abcf8
Make backslash replacement more correct
A5rocks Oct 19, 2024
cbb08fb
Debug which class doesn't exist
A5rocks Oct 19, 2024
9c97bad
Debug a bit better
A5rocks Oct 19, 2024
35609d4
Fix weirdness around PosixPath needing to be resolved
A5rocks Oct 19, 2024
4bc3e58
Appease type checker
A5rocks Oct 19, 2024
37b9c38
Don't even consider tests in the alias test
A5rocks Oct 20, 2024
3cda304
Turn paths into strings before indexing
A5rocks Oct 20, 2024
9eca851
Explain the test better
A5rocks Oct 20, 2024
ba67f7e
Fixes for pre-commit
A5rocks Oct 20, 2024
88cf458
Reformat according to black
A5rocks Oct 20, 2024
819797a
One last pre-commit fix
A5rocks Oct 20, 2024
f21cbb0
Simplify alias test by monkeypatching attrs.
TeamSpen210 Oct 22, 2024
30befc9
Skip pyright init attributes test if plugin has not run
TeamSpen210 Nov 10, 2024
a23712c
Catch any other renaming too
A5rocks Nov 10, 2024
74e67f1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 10, 2024
593701b
Handle autoattribs
A5rocks Nov 10, 2024
ff487e2
Disambiguate
A5rocks Nov 10, 2024
a6ea148
Synchronise name
TeamSpen210 Nov 10, 2024
637cc5f
Update import mode because it worked locally
A5rocks Nov 24, 2024
d8c0983
Check suspicions
A5rocks Nov 24, 2024
f32b8fb
Double check
A5rocks Nov 24, 2024
7ccead5
Don't rely on installing `_trio_check_attrs_aliases.py` as a module
A5rocks Nov 24, 2024
9b4c585
importlib import mode means we can use conftest again!
A5rocks Nov 24, 2024
0c1ca17
Just do something hacky instead
A5rocks Nov 24, 2024
f0294da
Debug and remove `-Wall` for later PR
A5rocks Nov 24, 2024
cb5913d
Hopefully fix some things
A5rocks Nov 24, 2024
942b371
Give into perl
A5rocks Nov 24, 2024
ce806e9
Add perl to alpine (should work now)
A5rocks Nov 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/3114.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ensure that Pyright recognizes our underscore prefixed attributes for attrs classes.
4 changes: 2 additions & 2 deletions src/trio/_core/_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
10 changes: 7 additions & 3 deletions src/trio/_core/_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
75 changes: 75 additions & 0 deletions src/trio/_tests/test_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -572,3 +573,77 @@ 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 = []

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)))

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, f"{name}: {class_!r}"
A5rocks marked this conversation as resolved.
Show resolved Hide resolved
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
A5rocks marked this conversation as resolved.
Show resolved Hide resolved
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
]

assert attributes == [], class_
Loading