diff --git a/rdflib/compare.py b/rdflib/compare.py index 32f3e2fac..592836d6e 100644 --- a/rdflib/compare.py +++ b/rdflib/compare.py @@ -104,7 +104,7 @@ Union, ) -from rdflib.graph import ConjunctiveGraph, Graph, ReadOnlyGraphAggregate +from rdflib.graph import ConjunctiveGraph, Graph, ReadOnlyGraphAggregate, _TripleType from rdflib.term import BNode, IdentifiedNode, Node, URIRef if TYPE_CHECKING: @@ -281,7 +281,6 @@ def copy(self): ) -_TripleT = List[Node] _HashT = Callable[[], "HASH"] @@ -326,7 +325,9 @@ def _initial_color(self) -> List[Color]: self._neighbors[p].add(p) if len(bnodes) > 0: return [Color(list(bnodes), self.hashfunc, hash_cache=self._hash_cache)] + [ - Color([x], self.hashfunc, x, hash_cache=self._hash_cache) + # type error: List item 0 has incompatible type "Union[IdentifiedNode, Literal]"; expected "IdentifiedNode" + # type error: Argument 3 to "Color" has incompatible type "Union[IdentifiedNode, Literal]"; expected "Tuple[Tuple[Union[int, str], URIRef, Union[int, str]], ...]" + Color([x], self.hashfunc, x, hash_cache=self._hash_cache) # type: ignore[list-item, arg-type] for x in others ] else: @@ -521,7 +522,7 @@ def canonical_triples(self, stats: Optional[Stats] = None): def _canonicalize_bnodes( self, - triple: Tuple[IdentifiedNode, IdentifiedNode, Node], + triple: "_TripleType", labels: Dict[Node, str], ): for term in triple: @@ -531,7 +532,7 @@ def _canonicalize_bnodes( yield term -def to_isomorphic(graph): +def to_isomorphic(graph: Graph) -> IsomorphicGraph: if isinstance(graph, IsomorphicGraph): return graph result = IsomorphicGraph() @@ -541,7 +542,7 @@ def to_isomorphic(graph): return result -def isomorphic(graph1, graph2): +def isomorphic(graph1: Graph, graph2: Graph) -> bool: """Compare graph for equality. Uses an algorithm to compute unique hashes which takes bnodes into account. @@ -577,7 +578,9 @@ def isomorphic(graph1, graph2): return gd1 == gd2 -def to_canonical_graph(g1, stats=None): +def to_canonical_graph( + g1: Graph, stats: Optional[Stats] = None +) -> ReadOnlyGraphAggregate: """Creates a canonical, read-only graph. Creates a canonical, read-only graph where all bnode id:s are based on @@ -588,7 +591,7 @@ def to_canonical_graph(g1, stats=None): return ReadOnlyGraphAggregate([graph]) -def graph_diff(g1, g2): +def graph_diff(g1: Graph, g2: Graph) -> Tuple[Graph, Graph, Graph]: """Returns three sets of triples: "in both", "in first" and "in second".""" # bnodes have deterministic values in canonical graphs: cg1 = to_canonical_graph(g1) @@ -602,7 +605,7 @@ def graph_diff(g1, g2): _MOCK_BNODE = BNode() -def similar(g1, g2): +def similar(g1: Graph, g2: Graph): """Checks if the two graphs are "similar". Checks if the two graphs are "similar", by comparing sorted triples where @@ -615,12 +618,12 @@ def similar(g1, g2): return all(t1 == t2 for (t1, t2) in _squashed_graphs_triples(g1, g2)) -def _squashed_graphs_triples(g1, g2): +def _squashed_graphs_triples(g1: Graph, g2: Graph): for (t1, t2) in zip(sorted(_squash_graph(g1)), sorted(_squash_graph(g2))): yield t1, t2 -def _squash_graph(graph): +def _squash_graph(graph: Graph): return (_squash_bnodes(triple) for triple in graph) diff --git a/rdflib/graph.py b/rdflib/graph.py index 79ea0d769..97b029bf9 100644 --- a/rdflib/graph.py +++ b/rdflib/graph.py @@ -16,6 +16,7 @@ TextIO, Tuple, Type, + TypeVar, Union, cast, overload, @@ -38,6 +39,29 @@ from rdflib.store import Store from rdflib.term import BNode, Genid, IdentifiedNode, Literal, Node, RDFLibGenid, URIRef +_SubjectType = Node +_PredicateType = Node +_ObjectType = Node + +_TripleType = Tuple["_SubjectType", "_PredicateType", "_ObjectType"] +_QuadType = Tuple["_SubjectType", "_PredicateType", "_ObjectType", "Graph"] +_OptionalQuadType = Tuple[ + "_SubjectType", "_PredicateType", "_ObjectType", Optional["Graph"] +] +_OptionalIdentifiedQuadType = Tuple[ + "_SubjectType", "_PredicateType", "_ObjectType", Optional["Node"] +] +_TriplePatternType = Tuple[ + Optional["_SubjectType"], Optional["_PredicateType"], Optional["_ObjectType"] +] +_QuadPatternType = Tuple[ + Optional["_SubjectType"], + Optional["_PredicateType"], + Optional["_ObjectType"], + Optional["Graph"], +] +_GraphT = TypeVar("_GraphT", bound="Graph") + assert Literal # avoid warning assert Namespace # avoid warning @@ -356,15 +380,15 @@ def __init__( self.default_union = False @property - def store(self): + def store(self) -> Store: return self.__store @property - def identifier(self): + def identifier(self) -> Node: return self.__identifier @property - def namespace_manager(self): + def namespace_manager(self) -> NamespaceManager: """ this graph's namespace-manager """ @@ -373,7 +397,7 @@ def namespace_manager(self): return self.__namespace_manager @namespace_manager.setter - def namespace_manager(self, nm): + def namespace_manager(self, nm: NamespaceManager): self.__namespace_manager = nm def __repr__(self): @@ -424,7 +448,7 @@ def close(self, commit_pending_transaction=False): """ return self.__store.close(commit_pending_transaction=commit_pending_transaction) - def add(self, triple: Tuple[Node, Node, Node]): + def add(self, triple: "_TripleType"): """Add a triple with self as context""" s, p, o = triple assert isinstance(s, Node), "Subject %s must be an rdflib term" % (s,) @@ -433,7 +457,7 @@ def add(self, triple: Tuple[Node, Node, Node]): self.__store.add((s, p, o), self, quoted=False) return self - def addN(self, quads: Iterable[Tuple[Node, Node, Node, Any]]): # noqa: N802 + def addN(self, quads: Iterable["_QuadType"]): # noqa: N802 """Add a sequence of triple with context""" self.__store.addN( @@ -457,34 +481,40 @@ def remove(self, triple): @overload def triples( self, - triple: Tuple[ - Optional[IdentifiedNode], Optional[IdentifiedNode], Optional[Node] - ], - ) -> Iterable[Tuple[IdentifiedNode, IdentifiedNode, Node]]: + triple: "_TriplePatternType", + ) -> Generator["_TripleType", None, None]: ... @overload def triples( self, - triple: Tuple[Optional[IdentifiedNode], Path, Optional[Node]], - ) -> Iterable[Tuple[IdentifiedNode, Path, Node]]: + triple: Tuple[Optional["_SubjectType"], Path, Optional["_ObjectType"]], + ) -> Generator[Tuple["_SubjectType", Path, "_ObjectType"], None, None]: ... @overload def triples( self, triple: Tuple[ - Optional[IdentifiedNode], Union[None, Path, IdentifiedNode], Optional[Node] + Optional["_SubjectType"], + Union[None, Path, "_PredicateType"], + Optional["_ObjectType"], ], - ) -> Iterable[Tuple[IdentifiedNode, Union[IdentifiedNode, Path], Node]]: + ) -> Generator[ + Tuple["_SubjectType", Union["_PredicateType", Path], "_ObjectType"], None, None + ]: ... def triples( self, triple: Tuple[ - Optional[IdentifiedNode], Union[None, Path, IdentifiedNode], Optional[Node] + Optional["_SubjectType"], + Union[None, Path, "_PredicateType"], + Optional["_ObjectType"], ], - ) -> Iterable[Tuple[IdentifiedNode, Union[IdentifiedNode, Path], Node]]: + ) -> Generator[ + Tuple["_SubjectType", Union["_PredicateType", Path], "_ObjectType"], None, None + ]: """Generator over the triple store Returns triples that match the given triple pattern. If triple pattern @@ -495,7 +525,9 @@ def triples( for _s, _o in p.eval(self, s, o): yield _s, p, _o else: - for (_s, _p, _o), cg in self.__store.triples((s, p, o), context=self): + # type error: Argument 1 to "triples" of "Store" has incompatible type "Tuple[Optional[Node], Optional[Node], Optional[Node]]"; expected "Tuple[Optional[IdentifiedNode], Optional[IdentifiedNode], Optional[Node]]" + # NOTE on type error: This is because the store typing is too narrow, willbe fixed in subsequent PR. + for (_s, _p, _o), cg in self.__store.triples((s, p, o), context=self): # type: ignore [arg-type] yield _s, _p, _o def __getitem__(self, item): @@ -578,7 +610,7 @@ def __len__(self): """ return self.__store.__len__(context=self) - def __iter__(self): + def __iter__(self) -> Generator["_TripleType", None, None]: """Iterates over all triples in the store""" return self.triples((None, None, None)) @@ -623,20 +655,20 @@ def __gt__(self, other): def __ge__(self, other): return self > other or self == other - def __iadd__(self, other): + def __iadd__(self: "_GraphT", other: Iterable["_TripleType"]) -> "_GraphT": """Add all triples in Graph other to Graph. BNode IDs are not changed.""" self.addN((s, p, o, self) for s, p, o in other) return self - def __isub__(self, other): + def __isub__(self: "_GraphT", other: Iterable["_TripleType"]) -> "_GraphT": """Subtract all triples in Graph other from Graph. BNode IDs are not changed.""" for triple in other: self.remove(triple) return self - def __add__(self, other): + def __add__(self, other: "Graph") -> "Graph": """Set-theoretic union BNode IDs are not changed.""" try: @@ -651,7 +683,7 @@ def __add__(self, other): retval.add(y) return retval - def __mul__(self, other): + def __mul__(self, other: "Graph") -> "Graph": """Set-theoretic intersection. BNode IDs are not changed.""" try: @@ -663,7 +695,7 @@ def __mul__(self, other): retval.add(x) return retval - def __sub__(self, other): + def __sub__(self, other: "Graph") -> "Graph": """Set-theoretic difference. BNode IDs are not changed.""" try: @@ -704,10 +736,10 @@ def set(self, triple): def subjects( self, - predicate: Union[None, Path, IdentifiedNode] = None, - object: Optional[Node] = None, + predicate: Union[None, Path, "_PredicateType"] = None, + object: Optional["_ObjectType"] = None, unique: bool = False, - ) -> Iterable[IdentifiedNode]: + ) -> Generator["_SubjectType", None, None]: """A generator of (optionally unique) subjects with the given predicate and object""" if not unique: @@ -728,10 +760,10 @@ def subjects( def predicates( self, - subject: Optional[IdentifiedNode] = None, - object: Optional[Node] = None, + subject: Optional["_SubjectType"] = None, + object: Optional["_ObjectType"] = None, unique: bool = False, - ) -> Iterable[IdentifiedNode]: + ) -> Generator["_PredicateType", None, None]: """A generator of (optionally unique) predicates with the given subject and object""" if not unique: @@ -752,10 +784,10 @@ def predicates( def objects( self, - subject: Optional[IdentifiedNode] = None, - predicate: Union[None, Path, IdentifiedNode] = None, + subject: Optional["_SubjectType"] = None, + predicate: Union[None, Path, "_PredicateType"] = None, unique: bool = False, - ) -> Iterable[Node]: + ) -> Generator["_ObjectType", None, None]: """A generator of (optionally unique) objects with the given subject and predicate""" if not unique: @@ -775,8 +807,8 @@ def objects( raise def subject_predicates( - self, object: Optional[Node] = None, unique: bool = False - ) -> Generator[Tuple[IdentifiedNode, IdentifiedNode], None, None]: + self, object: Optional["_ObjectType"] = None, unique: bool = False + ) -> Generator[Tuple["_SubjectType", "_PredicateType"], None, None]: """A generator of (optionally unique) (subject, predicate) tuples for the given object""" if not unique: @@ -796,8 +828,10 @@ def subject_predicates( raise def subject_objects( - self, predicate: Union[None, Path, IdentifiedNode] = None, unique: bool = False - ) -> Generator[Tuple[IdentifiedNode, Node], None, None]: + self, + predicate: Union[None, Path, "_PredicateType"] = None, + unique: bool = False, + ) -> Generator[Tuple["_SubjectType", "_ObjectType"], None, None]: """A generator of (optionally unique) (subject, object) tuples for the given predicate""" if not unique: @@ -817,8 +851,8 @@ def subject_objects( raise def predicate_objects( - self, subject: Optional[IdentifiedNode] = None, unique: bool = False - ) -> Generator[Tuple[IdentifiedNode, Node], None, None]: + self, subject: Optional["_SubjectType"] = None, unique: bool = False + ) -> Generator[Tuple["_PredicateType", "_ObjectType"], None, None]: """A generator of (optionally unique) (predicate, object) tuples for the given subject""" if not unique: @@ -1641,10 +1675,21 @@ def __str__(self): def _spoc( self, triple_or_quad: Union[ - Tuple[Node, Node, Node, Optional[Any]], Tuple[Node, Node, Node] + Tuple[ + Optional["_SubjectType"], + Optional["_PredicateType"], + Optional["_ObjectType"], + Optional[Any], + ], + "_TriplePatternType", ], default: bool = False, - ) -> Tuple[Node, Node, Node, Optional[Graph]]: + ) -> Tuple[ + Optional["_SubjectType"], + Optional["_PredicateType"], + Optional["_ObjectType"], + Optional[Graph], + ]: ... @overload @@ -1658,10 +1703,23 @@ def _spoc( def _spoc( self, triple_or_quad: Optional[ - Union[Tuple[Node, Node, Node, Optional[Any]], Tuple[Node, Node, Node]] + Union[ + Tuple[ + Optional["_SubjectType"], + Optional["_PredicateType"], + Optional["_ObjectType"], + Optional[Any], + ], + "_TriplePatternType", + ] ], default: bool = False, - ) -> Tuple[Optional[Node], Optional[Node], Optional[Node], Optional[Graph]]: + ) -> Tuple[ + Optional["_SubjectType"], + Optional["_PredicateType"], + Optional["_ObjectType"], + Optional[Graph], + ]: """ helper method for having methods that support either triples or quads @@ -1686,7 +1744,8 @@ def __contains__(self, triple_or_quad): def add( self, triple_or_quad: Union[ - Tuple[Node, Node, Node, Optional[Any]], Tuple[Node, Node, Node] + Tuple["_SubjectType", "_PredicateType", "_ObjectType", Optional[Any]], + "_TripleType", ], ) -> "ConjunctiveGraph": """ @@ -1699,7 +1758,8 @@ def add( _assertnode(s, p, o) - self.store.add((s, p, o), context=c, quoted=False) + # type error: Argument "context" to "add" of "Store" has incompatible type "Optional[Graph]"; expected "Graph" + self.store.add((s, p, o), context=c, quoted=False) # type: ignore[arg-type] return self @overload @@ -1718,7 +1778,7 @@ def _graph(self, c: Optional[Union[Graph, Node, str]]) -> Optional[Graph]: else: return c - def addN(self, quads: Iterable[Tuple[Node, Node, Node, Any]]): # noqa: N802 + def addN(self, quads: Iterable["_QuadType"]): # noqa: N802 """Add a sequence of triples with context""" self.store.addN( @@ -1769,14 +1829,24 @@ def triples(self, triple_or_quad, context=None): for (s, p, o), cg in self.store.triples((s, p, o), context=context): yield s, p, o - def quads(self, triple_or_quad=None): + def quads( + self, + triple_or_quad: Union[ + "_TriplePatternType", + "_QuadPatternType", + None, + ] = None, + ) -> Generator[_OptionalQuadType, None, None]: """Iterate over all the quads in the entire conjunctive graph""" s, p, o, c = self._spoc(triple_or_quad) - for (s, p, o), cg in self.store.triples((s, p, o), context=c): + # type error: Argument 1 to "triples" of "Store" has incompatible type "Tuple[Optional[Node], Optional[Node], Optional[Node]]"; expected "Tuple[Optional[IdentifiedNode], Optional[IdentifiedNode], Optional[Node]]" + # NOTE on type error: This is because the store typing is too narrow, willbe fixed in subsequent PR. + for (s, p, o), cg in self.store.triples((s, p, o), context=c): # type: ignore[arg-type] for ctx in cg: - yield s, p, o, ctx + # type error: Incompatible types in "yield" (actual type "Tuple[Optional[Node], Optional[Node], Optional[Node], Any]", expected type "Tuple[Node, Node, Node, Optional[Graph]]") + yield s, p, o, ctx # type: ignore[misc] def triples_choices(self, triple, context=None): """Iterate over all the triples in the entire conjunctive graph""" @@ -1794,7 +1864,9 @@ def __len__(self): """Number of triples in the entire conjunctive graph""" return self.store.__len__() - def contexts(self, triple=None): + def contexts( + self, triple: Optional["_TripleType"] = None + ) -> Generator[Graph, None, None]: """Iterate over all contexts in the graph If triple is specified, iterate over all contexts the triple is in. @@ -1831,7 +1903,7 @@ def remove_context(self, context): """Removes the given context from the graph""" self.store.remove((None, None, None), context) - def context_id(self, uri, context_id=None): + def context_id(self, uri: str, context_id: Optional[str] = None) -> URIRef: """URI#context""" uri = uri.split("#", 1)[0] if context_id is None: @@ -2104,16 +2176,27 @@ def contexts(self, triple=None): graphs = contexts - def quads(self, quad): + # type error: Return type "Generator[Tuple[Node, Node, Node, Optional[Node]], None, None]" of "quads" incompatible with return type "Generator[Tuple[Node, Node, Node, Optional[Graph]], None, None]" in supertype "ConjunctiveGraph" + def quads( # type: ignore[override] + self, + quad: Union[ + "_TriplePatternType", + "_QuadPatternType", + None, + ] = None, + ) -> Generator[_OptionalIdentifiedQuadType, None, None]: for s, p, o, c in super(Dataset, self).quads(quad): - if c.identifier == self.default_context: + # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" + if c.identifier == self.default_context: # type: ignore[union-attr] yield s, p, o, None else: - yield s, p, o, c.identifier + # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" [union-attr] + yield s, p, o, c.identifier # type: ignore[union-attr] - def __iter__( + # type error: Return type "Generator[Tuple[Node, URIRef, Node, Optional[IdentifiedNode]], None, None]" of "__iter__" incompatible with return type "Generator[Tuple[IdentifiedNode, IdentifiedNode, Union[IdentifiedNode, Literal]], None, None]" in supertype "Graph" + def __iter__( # type: ignore[override] self, - ) -> Generator[Tuple[Node, URIRef, Node, Optional[IdentifiedNode]], None, None]: + ) -> Generator[_OptionalIdentifiedQuadType, None, None]: """Iterates over all quads in the store""" return self.quads((None, None, None, None)) @@ -2129,7 +2212,7 @@ class QuotedGraph(Graph): def __init__(self, store, identifier): super(QuotedGraph, self).__init__(store, identifier) - def add(self, triple: Tuple[Node, Node, Node]): + def add(self, triple: "_TripleType"): """Add a triple with self as context""" s, p, o = triple assert isinstance(s, Node), "Subject %s must be an rdflib term" % (s,) @@ -2139,7 +2222,7 @@ def add(self, triple: Tuple[Node, Node, Node]): self.store.add((s, p, o), self, quoted=True) return self - def addN(self, quads: Tuple[Node, Node, Node, Any]) -> "QuotedGraph": # type: ignore[override] # noqa: N802 + def addN(self, quads: Iterable["_QuadType"]) -> "QuotedGraph": # noqa: N802 """Add a sequence of triple with context""" self.store.addN( @@ -2348,10 +2431,10 @@ def __cmp__(self, other): else: return -1 - def __iadd__(self, other): + def __iadd__(self: "_GraphT", other: Iterable["_TripleType"]) -> "_GraphT": raise ModificationException() - def __isub__(self, other): + def __isub__(self: "_GraphT", other: Iterable["_TripleType"]) -> "_GraphT": raise ModificationException() # Conv. methods @@ -2442,7 +2525,10 @@ def reset(self): def add( self, - triple_or_quad: Union[Tuple[Node, Node, Node], Tuple[Node, Node, Node, Any]], + triple_or_quad: Union[ + "_TripleType", + "_QuadType", + ], ) -> "BatchAddGraph": """ Add a triple to the buffer @@ -2459,7 +2545,7 @@ def add( self.batch.append(triple_or_quad) return self - def addN(self, quads: Iterable[Tuple[Node, Node, Node, Any]]): # noqa: N802 + def addN(self, quads: Iterable["_QuadType"]): # noqa: N802 if self.__batch_addn: for q in quads: self.add(q) diff --git a/rdflib/paths.py b/rdflib/paths.py index 8e2c60f19..0aabd19c8 100644 --- a/rdflib/paths.py +++ b/rdflib/paths.py @@ -184,10 +184,10 @@ from functools import total_ordering from typing import TYPE_CHECKING, Callable, Iterator, Optional, Tuple, Union -from rdflib.term import IdentifiedNode, Node, URIRef +from rdflib.term import Node, URIRef if TYPE_CHECKING: - from rdflib import Graph + from rdflib.graph import Graph, _ObjectType, _SubjectType # property paths @@ -209,9 +209,9 @@ class Path(object): def eval( self, graph: "Graph", - subj: Optional[IdentifiedNode] = None, - obj: Optional[Node] = None, - ) -> Iterator[Tuple[IdentifiedNode, Node]]: + subj: Optional["_SubjectType"] = None, + obj: Optional["_ObjectType"] = None, + ) -> Iterator[Tuple["_SubjectType", "_ObjectType"]]: raise NotImplementedError() def __lt__(self, other): diff --git a/rdflib/plugins/parsers/ntriples.py b/rdflib/plugins/parsers/ntriples.py index 42b4940e0..2a199f637 100644 --- a/rdflib/plugins/parsers/ntriples.py +++ b/rdflib/plugins/parsers/ntriples.py @@ -15,11 +15,11 @@ from rdflib.exceptions import ParserError as ParseError from rdflib.parser import InputSource, Parser from rdflib.term import BNode as bNode -from rdflib.term import Literal, Node +from rdflib.term import Literal from rdflib.term import URIRef as URI if TYPE_CHECKING: - from rdflib.graph import Graph + from rdflib.graph import Graph, _ObjectType, _PredicateType, _SubjectType __all__ = ["unquote", "uriquote", "W3CNTriplesParser", "NTGraphSink", "NTParser"] @@ -306,7 +306,7 @@ class NTGraphSink(object): def __init__(self, graph: "Graph"): self.g = graph - def triple(self, s: Node, p: Node, o: Node): + def triple(self, s: "_SubjectType", p: "_PredicateType", o: "_ObjectType"): self.g.add((s, p, o)) diff --git a/rdflib/plugins/serializers/rdfxml.py b/rdflib/plugins/serializers/rdfxml.py index 587f1f164..0308b5164 100644 --- a/rdflib/plugins/serializers/rdfxml.py +++ b/rdflib/plugins/serializers/rdfxml.py @@ -190,7 +190,8 @@ def serialize( ) for predicate in possible: - prefix, namespace, local = nm.compute_qname_strict(predicate) + # type error: Argument 1 to "compute_qname_strict" of "NamespaceManager" has incompatible type "Node"; expected "str" + prefix, namespace, local = nm.compute_qname_strict(predicate) # type: ignore[arg-type] namespaces[prefix] = namespace namespaces["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" @@ -206,7 +207,8 @@ def serialize( subject: IdentifiedNode # Write out subjects that can not be inline - for subject in store.subjects(): + # type error: Incompatible types in assignment (expression has type "Node", variable has type "IdentifiedNode") + for subject in store.subjects(): # type: ignore[assignment] if (None, None, subject) in store: if (subject, None, subject) in store: self.subject(subject, 1) @@ -217,7 +219,8 @@ def serialize( # write out BNodes last (to ensure they can be inlined where possible) bnodes = set() - for subject in store.subjects(): + # type error: Incompatible types in assignment (expression has type "Node", variable has type "IdentifiedNode") + for subject in store.subjects(): # type: ignore[assignment] if isinstance(subject, BNode): bnodes.add(subject) continue diff --git a/rdflib/util.py b/rdflib/util.py index 328a87430..c3d04065c 100644 --- a/rdflib/util.py +++ b/rdflib/util.py @@ -29,7 +29,7 @@ TYPE_CHECKING, Any, Callable, - Iterable, + Iterator, List, Optional, Set, @@ -41,7 +41,7 @@ import rdflib.graph # avoid circular dependency from rdflib.compat import sign from rdflib.namespace import XSD, Namespace, NamespaceManager -from rdflib.term import BNode, IdentifiedNode, Literal, Node, URIRef +from rdflib.term import BNode, Literal, Node, URIRef if TYPE_CHECKING: from rdflib.graph import Graph @@ -409,13 +409,13 @@ def find_roots( def get_tree( graph: "Graph", - root: "IdentifiedNode", + root: "Node", prop: "URIRef", - mapper: Callable[["IdentifiedNode"], "IdentifiedNode"] = lambda x: x, + mapper: Callable[["Node"], "Node"] = lambda x: x, sortkey: Optional[Callable[[Any], Any]] = None, - done: Optional[Set["IdentifiedNode"]] = None, + done: Optional[Set["Node"]] = None, dir: str = "down", -) -> Optional[Tuple[IdentifiedNode, List[Any]]]: +) -> Optional[Tuple[Node, List[Any]]]: """ Return a nested list/tuple structure representing the tree built by the transitive property given, starting from the root given @@ -442,12 +442,11 @@ def get_tree( done.add(root) tree = [] - branches: Iterable[IdentifiedNode] + branches: Iterator[Node] if dir == "down": branches = graph.subjects(prop, root) else: - # type error: Incompatible types in assignment (expression has type "Iterable[Node]", variable has type "Iterable[IdentifiedNode]") - branches = graph.objects(root, prop) # type: ignore[assignment] + branches = graph.objects(root, prop) for branch in branches: t = get_tree(graph, branch, prop, mapper, sortkey, done, dir) diff --git a/test/plugins/parser/example/rdflib/plugin/parser/__init__.py b/test/plugins/parser/example/rdflib/plugin/parser/__init__.py index 6aae60256..a6aefa291 100644 --- a/test/plugins/parser/example/rdflib/plugin/parser/__init__.py +++ b/test/plugins/parser/example/rdflib/plugin/parser/__init__.py @@ -6,7 +6,7 @@ from rdflib.graph import Graph from rdflib.namespace import Namespace from rdflib.parser import InputSource - from rdflib.term import Identifier + from rdflib.term import URIRef class ExampleParser(Parser): @@ -22,7 +22,9 @@ def namespace(cls) -> "Namespace": return Namespace("example:rdflib:plugin:parser:") @classmethod - def constant_output(cls) -> Set[Tuple["Identifier", "Identifier", "Identifier"]]: + def constant_output( + cls, + ) -> Set[Tuple["URIRef", "URIRef", "URIRef"]]: return {(cls.namespace().subj, cls.namespace().pred, cls.namespace().obj)} diff --git a/test/test_graph/test_canonicalization.py b/test/test_graph/test_canonicalization.py index 0c69d202b..88410fe0a 100644 --- a/test/test_graph/test_canonicalization.py +++ b/test/test_graph/test_canonicalization.py @@ -2,7 +2,7 @@ from collections import Counter from io import StringIO from test.utils import GraphHelper -from typing import Set, Tuple +from typing import TYPE_CHECKING, Set import pytest @@ -11,7 +11,9 @@ from rdflib.compare import to_canonical_graph, to_isomorphic from rdflib.namespace import FOAF from rdflib.plugins.stores.memory import Memory -from rdflib.term import Node + +if TYPE_CHECKING: + from rdflib.graph import _TripleType def get_digest_value(rdf, mimetype): @@ -516,8 +518,7 @@ def test_issue725_collapsing_bnodes_2(): ), "canonicalization changed node position counts" -_Triple = Tuple[Node, Node, Node] -_TripleSet = Set[_Triple] +_TripleSet = Set["_TripleType"] class TestConsistency(unittest.TestCase): diff --git a/test/test_graph/test_diff.py b/test/test_graph/test_diff.py index a6e22f0bc..4839fcb4b 100644 --- a/test/test_graph/test_diff.py +++ b/test/test_graph/test_diff.py @@ -1,19 +1,21 @@ import unittest from test.utils import GraphHelper -from typing import Set, Tuple +from typing import TYPE_CHECKING, Set from unittest.case import expectedFailure import rdflib from rdflib import Graph from rdflib.compare import graph_diff from rdflib.namespace import FOAF, RDF -from rdflib.term import BNode, Literal, Node +from rdflib.term import BNode, Literal + +if TYPE_CHECKING: + from rdflib.graph import _TripleType """Test for graph_diff - much more extensive testing would certainly be possible""" -_TripleT = Tuple[Node, Node, Node] -_TripleSetT = Set[_TripleT] +_TripleSetT = Set["_TripleType"] class TestDiff(unittest.TestCase): diff --git a/test/test_namespace/test_namespace.py b/test/test_namespace/test_namespace.py index 9c680876a..45c9a0693 100644 --- a/test/test_namespace/test_namespace.py +++ b/test/test_namespace/test_namespace.py @@ -279,7 +279,7 @@ def test_expand_curie_exception_messages(self) -> None: assert str(e.value) == "Argument must be a string, not BNode." with pytest.raises(TypeError) as e: - assert g.namespace_manager.expand_curie(Graph()) is None + assert g.namespace_manager.expand_curie(Graph()) is None # type: ignore[arg-type] assert str(e.value) == "Argument must be a string, not Graph." @pytest.mark.parametrize( diff --git a/test/test_roundtrip.py b/test/test_roundtrip.py index 6a3f492e2..632b3add1 100644 --- a/test/test_roundtrip.py +++ b/test/test_roundtrip.py @@ -268,10 +268,12 @@ def roundtrip( # # So we have to scrub the literals' string datatype declarations... for c in g2.contexts(): - for s, p, o in c.triples((None, None, None)): + # type error: Incompatible types in assignment (expression has type "Node", variable has type "str") + for s, p, o in c.triples((None, None, None)): # type: ignore[assignment] if type(o) == rdflib.Literal and o.datatype == XSD.string: c.remove((s, p, o)) - c.add((s, p, rdflib.Literal(str(o)))) + # type error: Argument 1 to "add" of "Graph" has incompatible type "Tuple[str, Node, Literal]"; expected "Tuple[Node, Node, Node]" + c.add((s, p, rdflib.Literal(str(o)))) # type: ignore[arg-type] if logger.isEnabledFor(logging.DEBUG): both, first, second = rdflib.compare.graph_diff(g1, g2) diff --git a/test/test_typing.py b/test/test_typing.py index 3fd58a3a3..2ee06d2a4 100644 --- a/test/test_typing.py +++ b/test/test_typing.py @@ -22,9 +22,12 @@ from typing import Set, Tuple +import rdflib + # TODO Bug - rdflib.plugins.sparql.prepareQuery() will run fine if this # test is run, but mypy can't tell the symbol is exposed. import rdflib.plugins.sparql.processor +from rdflib.term import Node def test_rdflib_query_exercise() -> None: @@ -56,8 +59,8 @@ def test_rdflib_query_exercise() -> None: graph.add((kb_https_uriref, predicate_q, literal_two)) graph.add((kb_bnode, predicate_p, literal_one)) - expected_nodes_using_predicate_q: Set[rdflib.IdentifiedNode] = {kb_https_uriref} - computed_nodes_using_predicate_q: Set[rdflib.IdentifiedNode] = set() + expected_nodes_using_predicate_q: Set[Node] = {kb_https_uriref} + computed_nodes_using_predicate_q: Set[Node] = set() for triple in graph.triples((None, predicate_q, None)): computed_nodes_using_predicate_q.add(triple[0]) assert expected_nodes_using_predicate_q == computed_nodes_using_predicate_q diff --git a/test/utils/__init__.py b/test/utils/__init__.py index 47270f765..56af5e5ff 100644 --- a/test/utils/__init__.py +++ b/test/utils/__init__.py @@ -169,12 +169,15 @@ def quad_set( """ result: GHQuadSet = set() for sn, pn, on, gn in graph.quads((None, None, None, None)): + gn_id: Identifier if isinstance(graph, Dataset): - assert isinstance(gn, Identifier) - gn_id = gn + # type error: Subclass of "Graph" and "Identifier" cannot exist: would have incompatible method signatures + assert isinstance(gn, Identifier) # type: ignore[unreachable] + gn_id = gn # type: ignore[unreachable] elif isinstance(graph, ConjunctiveGraph): assert isinstance(gn, Graph) - gn_id = gn.identifier + # type error: Incompatible types in assignment (expression has type "Node", variable has type "Identifier") + gn_id = gn.identifier # type: ignore[assignment] else: raise ValueError(f"invalid graph type {type(graph)}: {graph!r}") s, p, o = cls.nodes((sn, pn, on), exclude_blanks) diff --git a/test/utils/earl.py b/test/utils/earl.py index dd8b75388..d8a5d92a3 100644 --- a/test/utils/earl.py +++ b/test/utils/earl.py @@ -13,7 +13,7 @@ from rdflib import RDF, BNode, Graph, Literal, URIRef from rdflib.namespace import DC, DOAP, FOAF -from rdflib.term import Node +from rdflib.term import IdentifiedNode, Node if TYPE_CHECKING: from _pytest.main import Session @@ -40,8 +40,8 @@ def __init__( graph.bind("doap", DOAP) graph.bind("dc", DC) - self.asserter: Node - asserter: Node + self.asserter: IdentifiedNode + asserter: IdentifiedNode if asserter_uri is not None or asserter_homepage is not None: # cast to remove Optional because mypy is not smart enough to # figure out that it won't be optional.