2021-12-27 08:29:09 +00:00
|
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
|
2023-06-03 10:12:03 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-05-05 08:24:53 +00:00
|
|
|
import json
|
|
|
|
import shutil
|
|
|
|
import subprocess
|
|
|
|
|
2023-06-03 10:12:03 +00:00
|
|
|
from pathlib import Path
|
|
|
|
|
2021-05-05 08:24:53 +00:00
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
2022-08-18 08:25:00 +00:00
|
|
|
pytestmark = [
|
|
|
|
pytest.mark.skipif(
|
|
|
|
shutil.which("pyright") is None, reason="Requires pyright."
|
|
|
|
),
|
|
|
|
]
|
2021-05-05 08:24:53 +00:00
|
|
|
|
|
|
|
|
2024-07-13 10:01:09 +00:00
|
|
|
def parse_pyright_output(test_file: Path) -> set[tuple[str, str]]:
|
2023-08-20 10:03:53 +00:00
|
|
|
pyright = subprocess.run( # noqa: PLW1510
|
2021-05-05 08:24:53 +00:00
|
|
|
["pyright", "--outputjson", str(test_file)], capture_output=True
|
|
|
|
)
|
2022-08-18 08:25:00 +00:00
|
|
|
|
2021-05-05 08:24:53 +00:00
|
|
|
pyright_result = json.loads(pyright.stdout)
|
|
|
|
|
2024-07-13 10:01:09 +00:00
|
|
|
# We use tuples instead of proper classes to get nicer diffs from pytest.
|
2022-08-18 08:25:00 +00:00
|
|
|
return {
|
2024-07-13 10:01:09 +00:00
|
|
|
(d["severity"], d["message"])
|
2021-05-05 08:24:53 +00:00
|
|
|
for d in pyright_result["generalDiagnostics"]
|
2022-03-21 07:47:47 +00:00
|
|
|
}
|
2021-05-05 08:24:53 +00:00
|
|
|
|
2022-08-18 08:25:00 +00:00
|
|
|
|
|
|
|
def test_pyright_baseline():
|
|
|
|
"""
|
2023-07-06 16:41:45 +00:00
|
|
|
The typing.dataclass_transform decorator allows pyright to determine
|
|
|
|
attrs decorated class types.
|
2022-08-18 08:25:00 +00:00
|
|
|
"""
|
|
|
|
|
2023-06-03 10:12:03 +00:00
|
|
|
test_file = Path(__file__).parent / "dataclass_transform_example.py"
|
2022-08-18 08:25:00 +00:00
|
|
|
|
|
|
|
diagnostics = parse_pyright_output(test_file)
|
|
|
|
|
2021-05-05 08:24:53 +00:00
|
|
|
expected_diagnostics = {
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"information",
|
|
|
|
'Type of "Define.__init__" is "(self: Define, a: str, b: int) -> None"',
|
2021-05-05 08:24:53 +00:00
|
|
|
),
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"information",
|
|
|
|
'Type of "DefineConverter.__init__" is '
|
2023-06-14 15:03:10 +00:00
|
|
|
'"(self: DefineConverter, with_converter: str | Buffer | '
|
2023-06-03 10:12:03 +00:00
|
|
|
'SupportsInt | SupportsIndex | SupportsTrunc) -> None"',
|
2021-05-05 08:24:53 +00:00
|
|
|
),
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"error",
|
|
|
|
'Cannot assign to attribute "a" for class '
|
|
|
|
'"Frozen"\n\xa0\xa0"Frozen" is frozen\n\xa0\xa0\xa0\xa0'
|
|
|
|
'Attribute "__set__" is unknown',
|
2023-01-12 06:22:13 +00:00
|
|
|
),
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"information",
|
|
|
|
'Type of "d.a" is "Literal[\'new\']"',
|
2021-05-05 08:24:53 +00:00
|
|
|
),
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"error",
|
|
|
|
'Cannot assign to attribute "a" for class '
|
2023-11-11 10:45:04 +00:00
|
|
|
'"FrozenDefine"\n\xa0\xa0"FrozenDefine" is frozen\n\xa0\xa0\xa0\xa0'
|
2024-07-13 10:01:09 +00:00
|
|
|
'Attribute "__set__" is unknown',
|
2021-05-05 08:24:53 +00:00
|
|
|
),
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"information",
|
|
|
|
'Type of "d2.a" is "Literal[\'new\']"',
|
2021-05-05 08:24:53 +00:00
|
|
|
),
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"information",
|
|
|
|
'Type of "af.__init__" is "(_a: int) -> None"',
|
2022-11-30 15:04:57 +00:00
|
|
|
),
|
2021-05-05 08:24:53 +00:00
|
|
|
}
|
|
|
|
|
2022-11-30 15:04:57 +00:00
|
|
|
assert expected_diagnostics == diagnostics
|
2022-08-30 13:06:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_pyright_attrsinstance_compat(tmp_path):
|
|
|
|
"""
|
|
|
|
Test that `AttrsInstance` is compatible with Pyright.
|
|
|
|
"""
|
|
|
|
test_pyright_attrsinstance_compat_path = (
|
|
|
|
tmp_path / "test_pyright_attrsinstance_compat.py"
|
|
|
|
)
|
|
|
|
test_pyright_attrsinstance_compat_path.write_text(
|
|
|
|
"""\
|
|
|
|
import attrs
|
|
|
|
|
|
|
|
# We can assign any old object to `AttrsInstance`.
|
|
|
|
foo: attrs.AttrsInstance = object()
|
|
|
|
|
|
|
|
reveal_type(attrs.AttrsInstance)
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
|
|
|
|
diagnostics = parse_pyright_output(test_pyright_attrsinstance_compat_path)
|
|
|
|
expected_diagnostics = {
|
2024-07-13 10:01:09 +00:00
|
|
|
(
|
|
|
|
"information",
|
|
|
|
'Type of "attrs.AttrsInstance" is "type[AttrsInstance]"',
|
|
|
|
)
|
2022-08-30 13:06:10 +00:00
|
|
|
}
|
|
|
|
assert diagnostics == expected_diagnostics
|