From de2dbcc1d0b86130f46498c7da803c6ff71a3e76 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Mon, 28 Oct 2024 21:18:09 +0100 Subject: [PATCH] Pass pyright 'basic' --- nutree/rdf.py | 24 ++++++++++++++++-------- nutree/tree.py | 2 +- nutree/tree_generator.py | 6 +++--- pyproject.toml | 3 ++- tests/fixture.py | 15 ++++++++------- tests/test_core.py | 2 +- tests/test_objects.py | 9 +++++---- tests/test_rdf.py | 1 + tests/test_serialize.py | 20 ++++++++++++-------- tests/test_tree_generator.py | 6 +++++- tests/test_typed_tree.py | 1 + tests/tutorial_script.py | 2 ++ tox.ini | 2 +- 13 files changed, 58 insertions(+), 35 deletions(-) diff --git a/nutree/rdf.py b/nutree/rdf.py index a730bf2..10406ea 100644 --- a/nutree/rdf.py +++ b/nutree/rdf.py @@ -4,6 +4,12 @@ Functions and declarations to implement `rdflib `_. """ +# pyright: reportOptionalCall=false +# pyright: reportInvalidTypeForm=false +# pyright: reportGeneralTypeIssues=false +# pyright: reportOptionalMemberAccess=false +# pyright: reportArgumentType=false + from __future__ import annotations from typing import TYPE_CHECKING, Callable, Union @@ -21,15 +27,17 @@ import rdflib from rdflib import Graph, IdentifiedNode, Literal, URIRef from rdflib.namespace import RDF, XSD, DefinedNamespace, Namespace -except ImportError: # pragma: no cover + +except ImportError: rdflib = None Graph = IdentifiedNode = Literal = URIRef = None RDF = XSD = DefinedNamespace = Namespace = None - # raise + RDFMapperCallbackType = Callable[[Graph, IdentifiedNode, "Node"], Union[None, bool]] -if Namespace: + +if rdflib: class NUTREE_NS(DefinedNamespace): """ @@ -39,16 +47,16 @@ class NUTREE_NS(DefinedNamespace): _fail = True # diff_meta: - index: URIRef # - has_child: URIRef # - kind: URIRef # + index: URIRef + has_child: URIRef + kind: URIRef name: URIRef # - system_root: URIRef # + system_root: URIRef _NS = Namespace("http://wwwendt.de/namespace/nutree/rdf/0.1/") else: # rdflib unavailable # pragma: no cover - NUTREE_NS = None + NUTREE_NS = None # type: ignore def _make_graph() -> Graph: diff --git a/nutree/tree.py b/nutree/tree.py index cd22291..7eda674 100644 --- a/nutree/tree.py +++ b/nutree/tree.py @@ -191,7 +191,7 @@ def __len__(self): (also makes empty trees falsy).""" return self.count - def calc_data_id(self, data) -> DataIdType: + def calc_data_id(self, data: Any) -> DataIdType: """Called internally to calculate `data_id` for a `data` object. This value is used to lookup nodes by data, identify clones, and for diff --git a/nutree/tree_generator.py b/nutree/tree_generator.py index 9938fcb..eaf3bef 100644 --- a/nutree/tree_generator.py +++ b/nutree/tree_generator.py @@ -240,7 +240,7 @@ class TextRandomizer(Randomizer): Defaults to 1.0. """ - def __init__(self, template: Union[str, list], *, probability: float = 1.0) -> None: + def __init__(self, template: str | list[str], *, probability: float = 1.0) -> None: super().__init__(probability=probability) if not fab: raise RuntimeError("Need fabulist installed to generate random text.") @@ -275,11 +275,11 @@ class BlindTextRandomizer(Randomizer): def __init__( self, *, - sentence_count: Union[int, tuple] = (2, 6), + sentence_count: int | tuple = (2, 6), dialect: str = "ipsum", entropy: int = 2, keep_first: bool = False, - words_per_sentence: Union[int, tuple] = (3, 15), + words_per_sentence: int | tuple = (3, 15), probability: float = 1.0, ) -> None: super().__init__(probability=probability) diff --git a/pyproject.toml b/pyproject.toml index 6b9706a..788e4d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,9 +35,10 @@ ignore = [ [tool.pyright] typeCheckingMode = "basic" # typeCheckingMode = "off" +reportMissingImports = "none" # include = ["nutree"] include = ["nutree", "tests"] -exclude = ["nutree/rdf.py"] +# exclude = ["**/nutree/rdf.py"] # https://github.com/microsoft/pyright/blob/main/docs/configuration.md#sample-pyprojecttoml-file reportUnnecessaryTypeIgnoreComment = true diff --git a/tests/fixture.py b/tests/fixture.py index 0e8ef37..d9fb131 100644 --- a/tests/fixture.py +++ b/tests/fixture.py @@ -12,6 +12,7 @@ import tempfile import time import timeit +import uuid from random import randint from textwrap import dedent, indent from typing import IO, List @@ -26,10 +27,10 @@ def is_running_on_ci() -> bool: class Person: - def __init__(self, name, *, age, guid=None) -> None: - self.name = name - self.age = age - self.guid = guid + def __init__(self, name: str, *, age: int, guid: str | None = None) -> None: + self.name: str = name + self.age: int = age + self.guid: str = uuid.uuid4().hex if guid is None else guid def __repr__(self) -> str: return f"Person<{self.name}, {self.age}>" @@ -44,9 +45,9 @@ def __repr__(self) -> str: class Department: - def __init__(self, name, *, guid=None) -> None: - self.name = name - self.guid = guid + def __init__(self, name: str, *, guid: str | None = None) -> None: + self.name: str = name + self.guid: str = uuid.uuid4().hex if guid is None else guid def __repr__(self) -> str: return f"Department<{self.name}>" diff --git a/tests/test_core.py b/tests/test_core.py index a0f28bc..d385f0a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1497,7 +1497,7 @@ def pred(node): tree_2 = tree.filtered(predicate=None) # type: ignore with pytest.raises(ValueError, match="Predicate is required"): - tree_2 = tree.system_root.filtered(predicate=None) # type: ignore + tree_2 = tree.system_root.filtered(predicate=None) tree_2 = tree.copy() diff --git a/tests/test_objects.py b/tests/test_objects.py index 5dd10c6..9265ceb 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -2,6 +2,7 @@ # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ # ruff: noqa: T201, T203 `print` found +# pyright: reportOptionalMemberAccess=false import pytest from nutree import Tree @@ -106,14 +107,14 @@ def test_forward_attrs_true(self): # Note caveat: `node.name` is not forwardeded, but a native property: assert let_it_be_node.name == "Item<'Let It Be', 12.34$>" with pytest.raises(AttributeError): - let_it_be_node.name = "foo" # type: ignore + let_it_be_node.name = "foo" # `node.price` is alliased to `node.data.price` assert let_it_be_node.price == 12.34 # forward-attributes are readonly with pytest.raises(AttributeError): - let_it_be_node.price = 9.99 # type: ignore + let_it_be_node.price = 9.99 class TestDictWrapper: @@ -182,7 +183,7 @@ def test_dict(self): with pytest.raises(TypeError, match="'Node' object is not subscriptable"): # should NOT support item access via indexing - _ = node["a"] # type: ignore + _ = node["a"] with pytest.raises(AttributeError): # should not support attribute access via data @@ -250,7 +251,7 @@ class FrozenItem: # Frozen dataclasses are immutable with pytest.raises(FrozenInstanceError): - item.count += 1 + item.count += 1 # type: ignore # We can also add by passing the data_id as keyword argument: _ = tree.add(item, data_id="123-456") diff --git a/tests/test_rdf.py b/tests/test_rdf.py index c89ec04..d000ab7 100644 --- a/tests/test_rdf.py +++ b/tests/test_rdf.py @@ -2,6 +2,7 @@ # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ # ruff: noqa: T201, T203 `print` found +# pyright: reportAttributeAccessIssue=false from nutree.typed_tree import TypedTree diff --git a/tests/test_serialize.py b/tests/test_serialize.py index 4e07b7e..6b5905c 100644 --- a/tests/test_serialize.py +++ b/tests/test_serialize.py @@ -2,6 +2,9 @@ # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ # ruff: noqa: T201, T203 `print` found +# pyright: reportOptionalMemberAccess=false + +from __future__ import annotations import json import pprint @@ -130,7 +133,7 @@ def _test_serialize_objects(self, *, mode: str): ╰── Node<'Person', data_id={456-456}> """ - def _calc_id(tree, data): + def _calc_id(tree: Tree, data: Any) -> str | int: # print("calc_id", data) if isinstance(data, (fixture.Person, fixture.Department)): return data.guid @@ -484,12 +487,12 @@ class MyTree(TypedTree): } DEFAULT_VALUE_MAP = {"type": ["person", "dept"]} - def calc_data_id(tree, data): + def calc_data_id(self, data): if hasattr(data, "guid"): return data.guid return hash(data) - def serialize_mapper(self, node: Node, data: dict): + def serialize_mapper(self, node: Node, data: dict) -> dict | None: if isinstance(node.data, fixture.Department): data["type"] = "dept" data["name"] = node.data.name @@ -500,17 +503,18 @@ def serialize_mapper(self, node: Node, data: dict): return data @staticmethod - def deserialize_mapper(parent: Node, data: dict): + def deserialize_mapper(parent: Node, data: dict) -> str | object | None: node_type = data["type"] print("deserialize_mapper", data) + res = data if node_type == "person": - data = fixture.Person( + res = fixture.Person( name=data["name"], age=data["age"], guid=data["data_id"] ) elif node_type == "dept": - data = fixture.Department(name=data["name"], guid=data["data_id"]) - print(f"deserialize_mapper -> {data}") - return data + res = fixture.Department(name=data["name"], guid=data["data_id"]) + print(f"deserialize_mapper -> {res}") + return res # Use a TypedTree tree = MyTree(name="MyTree") diff --git a/tests/test_tree_generator.py b/tests/test_tree_generator.py index 6488fdf..cb28321 100644 --- a/tests/test_tree_generator.py +++ b/tests/test_tree_generator.py @@ -116,7 +116,11 @@ def test_fabulist(self): "__root__": { "function": { ":count": 3, - "title": TextRandomizer(("{idx}: Provide $(Noun:plural)",)), + "title": TextRandomizer( + [ + "{idx}: Provide $(Noun:plural)", + ] + ), "details": BlindTextRandomizer(dialect="ipsum"), "expanded": True, }, diff --git a/tests/test_typed_tree.py b/tests/test_typed_tree.py index 63f2f6e..95f7a27 100644 --- a/tests/test_typed_tree.py +++ b/tests/test_typed_tree.py @@ -2,6 +2,7 @@ # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ # ruff: noqa: T201, T203 `print` found +# pyright: reportOptionalMemberAccess=false import re diff --git a/tests/tutorial_script.py b/tests/tutorial_script.py index a66743d..9c0d9bf 100644 --- a/tests/tutorial_script.py +++ b/tests/tutorial_script.py @@ -2,6 +2,8 @@ # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ # ruff: noqa: T201, T203 `print` found +# pyright: reportAttributeAccessIssue=false +# pyright: reportOptionalMemberAccess=false import json diff --git a/tox.ini b/tox.ini index 0ae4d21..a80cea3 100644 --- a/tox.ini +++ b/tox.ini @@ -92,7 +92,7 @@ deps = changedir = {toxinidir} commands = pyright nutree tests -ignore_outcome = true +; ignore_outcome = true [testenv:docs] description = Build Sphinx documentation (output directory: docs/sphinx-build)