Skip to content

Commit e2fb319

Browse files
committed
feat: add type hints to rdflib.plugins.sparql.{algebra,operators}
More or less complete type hints for `rdflib.plugins.sparql.algebra` and `rdflib.plugins.sparql.operators`. This does not change runtime behaviour. Other changes: - Fixed line endings of `test/test_issues/test_issue1043.py` and `test/test_issues/test_issue910.py`. - Removed a type hint comment that was present in rdflib/plugins/sparql/algebra.py Related issues: - Closes <#2029>.
1 parent a70a9c8 commit e2fb319

File tree

6 files changed

+346
-237
lines changed

6 files changed

+346
-237
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,11 @@ and will be removed for release.
166166
<!-- -->
167167

168168
- Added type hints.
169-
[PR #2057](https://github.com/RDFLib/rdflib/pull/2057).
170169
- `rdflib.store` and builtin stores have mostly complete type hints.
170+
[PR #2057](https://github.com/RDFLib/rdflib/pull/2057).
171+
- `rdflib.plugins.sparql.algebra` amd `rdflib.plugins.sparql.operators` have
172+
mostly complete type hints.
173+
[PR #2094](https://github.com/RDFLib/rdflib/pull/2094).
171174

172175
<!-- -->
173176
<!-- -->

Taskfile.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,17 @@ tasks:
131131
desc: Run tests
132132
cmds:
133133
- '{{.TEST_HARNESS}}{{print .VENV_BINPREFIX "pytest" | shellQuote}} {{if (mustFromJson .WITH_COVERAGE)}}--cov --cov-report={{end}} {{.CLI_ARGS}}'
134-
135134
flake8:
136135
desc: Run flake8
137136
cmds:
138-
- "{{._PYTHON | shellQuote}} -m flakeheaven lint {{.CLI_ARGS}}"
139-
137+
- |
138+
if {{._PYTHON | shellQuote}} -c 'import importlib; exit(0 if importlib.util.find_spec("flakeheaven") is not None else 1)'
139+
then
140+
1>&2 echo "running flakeheaven"
141+
{{._PYTHON | shellQuote}} -m flakeheaven lint {{.CLI_ARGS}}
142+
else
143+
1>&2 echo "skipping flakeheaven as it is not installed, likely because python version is older than 3.8"
144+
fi
140145
black:
141146
desc: Run black
142147
cmds:

rdflib/plugins/sparql/algebra.py

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
"""
24
Converting the 'parse-tree' output of pyparsing to a SPARQL Algebra expression
35
@@ -48,9 +50,7 @@ def OrderBy(p: CompValue, expr: List[CompValue]) -> CompValue:
4850
return CompValue("OrderBy", p=p, expr=expr)
4951

5052

51-
def ToMultiSet(
52-
p: typing.Union[List[Dict[Variable, Identifier]], CompValue]
53-
) -> CompValue:
53+
def ToMultiSet(p: typing.Union[List[Dict[Variable, str]], CompValue]) -> CompValue:
5454
return CompValue("ToMultiSet", p=p)
5555

5656

@@ -66,31 +66,35 @@ def Minus(p1: CompValue, p2: CompValue) -> CompValue:
6666
return CompValue("Minus", p1=p1, p2=p2)
6767

6868

69-
def Graph(term, graph) -> CompValue:
69+
def Graph(term: Identifier, graph: CompValue) -> CompValue:
7070
return CompValue("Graph", term=term, p=graph)
7171

7272

73-
def BGP(triples=None) -> CompValue:
73+
def BGP(
74+
triples: Optional[List[Tuple[Identifier, Identifier, Identifier]]] = None
75+
) -> CompValue:
7476
return CompValue("BGP", triples=triples or [])
7577

7678

7779
def LeftJoin(p1: CompValue, p2: CompValue, expr) -> CompValue:
7880
return CompValue("LeftJoin", p1=p1, p2=p2, expr=expr)
7981

8082

81-
def Filter(expr, p: CompValue) -> CompValue:
83+
def Filter(expr: Expr, p: CompValue) -> CompValue:
8284
return CompValue("Filter", expr=expr, p=p)
8385

8486

85-
def Extend(p: CompValue, expr, var) -> CompValue:
87+
def Extend(
88+
p: CompValue, expr: typing.Union[Identifier, Expr], var: Variable
89+
) -> CompValue:
8690
return CompValue("Extend", p=p, expr=expr, var=var)
8791

8892

89-
def Values(res) -> CompValue:
93+
def Values(res: List[Dict[Variable, str]]) -> CompValue:
9094
return CompValue("values", res=res)
9195

9296

93-
def Project(p: CompValue, PV) -> CompValue:
97+
def Project(p: CompValue, PV: List[Variable]) -> CompValue:
9498
return CompValue("Project", p=p, PV=PV)
9599

96100

@@ -102,7 +106,7 @@ def _knownTerms(
102106
triple: Tuple[Identifier, Identifier, Identifier],
103107
varsknown: Set[typing.Union[BNode, Variable]],
104108
varscount: Dict[Identifier, int],
105-
):
109+
) -> Tuple[int, int, bool]:
106110
return (
107111
len(
108112
[
@@ -124,7 +128,7 @@ def reorderTriples(
124128
ones with most bindings first
125129
"""
126130

127-
def _addvar(term, varsknown):
131+
def _addvar(term: str, varsknown: Set[typing.Union[Variable, BNode]]):
128132
if isinstance(term, (Variable, BNode)):
129133
varsknown.add(term)
130134

@@ -180,20 +184,25 @@ def triples(
180184
return reorderTriples((l[x], l[x + 1], l[x + 2]) for x in range(0, len(l), 3)) # type: ignore[misc]
181185

182186

183-
def translatePName(p: typing.Union[CompValue, str], prologue: Prologue):
187+
# type error: Missing return statement
188+
def translatePName( # type: ignore[return]
189+
p: typing.Union[CompValue, str], prologue: Prologue
190+
) -> Optional[Identifier]:
184191
"""
185192
Expand prefixed/relative URIs
186193
"""
187194
if isinstance(p, CompValue):
188195
if p.name == "pname":
189-
return prologue.absolutize(p)
196+
# type error: Incompatible return value type (got "Union[CompValue, str, None]", expected "Optional[Identifier]")
197+
return prologue.absolutize(p) # type: ignore[return-value]
190198
if p.name == "literal":
191199
# type error: Argument "datatype" to "Literal" has incompatible type "Union[CompValue, str, None]"; expected "Optional[str]"
192200
return Literal(
193201
p.string, lang=p.lang, datatype=prologue.absolutize(p.datatype) # type: ignore[arg-type]
194202
)
195203
elif isinstance(p, URIRef):
196-
return prologue.absolutize(p)
204+
# type error: Incompatible return value type (got "Union[CompValue, str, None]", expected "Optional[Identifier]")
205+
return prologue.absolutize(p) # type: ignore[return-value]
197206

198207

199208
@overload
@@ -253,8 +262,8 @@ def translatePath(p: typing.Union[CompValue, URIRef]) -> Optional["Path"]: # ty
253262

254263

255264
def translateExists(
256-
e: typing.Union[Expr, Literal, Variable]
257-
) -> typing.Union[Expr, Literal, Variable]:
265+
e: typing.Union[Expr, Literal, Variable, URIRef]
266+
) -> typing.Union[Expr, Literal, Variable, URIRef]:
258267
"""
259268
Translate the graph pattern used by EXISTS and NOT EXISTS
260269
http://www.w3.org/TR/sparql11-query/#sparqlCollectFilters
@@ -273,7 +282,7 @@ def _c(n):
273282
return e
274283

275284

276-
def collectAndRemoveFilters(parts):
285+
def collectAndRemoveFilters(parts: List[CompValue]) -> Optional[Expr]:
277286
"""
278287
279288
FILTER expressions apply to the whole group graph pattern in which
@@ -294,7 +303,8 @@ def collectAndRemoveFilters(parts):
294303
i += 1
295304

296305
if filters:
297-
return and_(*filters)
306+
# type error: Argument 1 to "and_" has incompatible type "*List[Union[Expr, Literal, Variable]]"; expected "Expr"
307+
return and_(*filters) # type: ignore[arg-type]
298308

299309
return None
300310

@@ -380,7 +390,7 @@ def translateGroupGraphPattern(graphPattern: CompValue) -> CompValue:
380390

381391

382392
class StopTraversal(Exception): # noqa: N818
383-
def __init__(self, rv):
393+
def __init__(self, rv: bool):
384394
self.rv = rv
385395

386396

@@ -444,7 +454,7 @@ def traverse(
444454
visitPre: Callable[[Any], Any] = lambda n: None,
445455
visitPost: Callable[[Any], Any] = lambda n: None,
446456
complete: Optional[bool] = None,
447-
):
457+
) -> Any:
448458
"""
449459
Traverse tree, visit each node with visit function
450460
visit function may raise StopTraversal to stop traversal
@@ -504,7 +514,7 @@ def _findVars(x, res: Set[Variable]) -> Optional[CompValue]: # type: ignore[ret
504514
return x
505515

506516

507-
def _addVars(x, children) -> Set[Variable]:
517+
def _addVars(x, children: List[Set[Variable]]) -> Set[Variable]:
508518
"""
509519
find which variables may be bound by this part of the query
510520
"""
@@ -549,7 +559,7 @@ def _sample(e: typing.Union[CompValue, List[Expr], Expr, List[str], Variable], v
549559
return CompValue("Aggregate_Sample", vars=e)
550560

551561

552-
def _simplifyFilters(e):
562+
def _simplifyFilters(e: Any) -> Any:
553563
if isinstance(e, Expr):
554564
return simplifyFilters(e)
555565

@@ -592,11 +602,11 @@ def translateAggregates(
592602

593603
def translateValues(
594604
v: CompValue,
595-
) -> typing.Union[List[Dict[Variable, Identifier]], CompValue]:
605+
) -> typing.Union[List[Dict[Variable, str]], CompValue]:
596606
# if len(v.var)!=len(v.value):
597607
# raise Exception("Unmatched vars and values in ValueClause: "+str(v))
598608

599-
res: List[Dict[Variable, Identifier]] = []
609+
res: List[Dict[Variable, str]] = []
600610
if not v.var:
601611
return res
602612
if not v.value:
@@ -722,7 +732,7 @@ def translate(q: CompValue) -> Tuple[CompValue, List[Variable]]:
722732

723733

724734
# type error: Missing return statement
725-
def simplify(n) -> Optional[CompValue]: # type: ignore[return]
735+
def simplify(n: Any) -> Optional[CompValue]: # type: ignore[return]
726736
"""Remove joins to empty BGPs"""
727737
if isinstance(n, CompValue):
728738
if n.name == "Join":
@@ -735,7 +745,7 @@ def simplify(n) -> Optional[CompValue]: # type: ignore[return]
735745
return n
736746

737747

738-
def analyse(n, children):
748+
def analyse(n: Any, children: Any) -> bool:
739749
"""
740750
Some things can be lazily joined.
741751
This propegates whether they can up the tree
@@ -757,7 +767,7 @@ def analyse(n, children):
757767
def translatePrologue(
758768
p: ParseResults,
759769
base: Optional[str],
760-
initNs: Optional[Mapping[str, str]] = None,
770+
initNs: Optional[Mapping[str, Any]] = None,
761771
prologue: Optional[Prologue] = None,
762772
) -> Prologue:
763773

@@ -780,7 +790,12 @@ def translatePrologue(
780790
return prologue
781791

782792

783-
def translateQuads(quads: CompValue):
793+
def translateQuads(
794+
quads: CompValue,
795+
) -> Tuple[
796+
List[Tuple[Identifier, Identifier, Identifier]],
797+
DefaultDict[str, List[Tuple[Identifier, Identifier, Identifier]]],
798+
]:
784799
if quads.triples:
785800
alltriples = triples(quads.triples)
786801
else:
@@ -825,7 +840,7 @@ def translateUpdate1(u: CompValue, prologue: Prologue) -> CompValue:
825840
def translateUpdate(
826841
q: CompValue,
827842
base: Optional[str] = None,
828-
initNs: Optional[Mapping[str, str]] = None,
843+
initNs: Optional[Mapping[str, Any]] = None,
829844
) -> Update:
830845
"""
831846
Returns a list of SPARQL Update Algebra expressions
@@ -854,7 +869,7 @@ def translateUpdate(
854869
def translateQuery(
855870
q: ParseResults,
856871
base: Optional[str] = None,
857-
initNs: Optional[Mapping[str, str]] = None,
872+
initNs: Optional[Mapping[str, Any]] = None,
858873
) -> Query:
859874
"""
860875
Translate a query-parsetree to a SPARQL Algebra Expression
@@ -901,7 +916,7 @@ def translateAlgebra(query_algebra: Query) -> str:
901916
"""
902917
import os
903918

904-
def overwrite(text):
919+
def overwrite(text: str):
905920
file = open("query.txt", "w+")
906921
file.write(text)
907922
file.close()
@@ -938,19 +953,26 @@ def find_nth(haystack, needle, n):
938953
with open("query.txt", "w") as file:
939954
file.write(filedata)
940955

941-
aggr_vars = collections.defaultdict(list) # type: dict
956+
aggr_vars: DefaultDict[Identifier, List[Identifier]] = collections.defaultdict(list)
942957

943-
def convert_node_arg(node_arg):
958+
def convert_node_arg(
959+
node_arg: typing.Union[Identifier, CompValue, Expr, str]
960+
) -> str:
944961
if isinstance(node_arg, Identifier):
945962
if node_arg in aggr_vars.keys():
946-
grp_var = aggr_vars[node_arg].pop(0).n3()
963+
# type error: "Identifier" has no attribute "n3"
964+
grp_var = aggr_vars[node_arg].pop(0).n3() # type: ignore[attr-defined]
947965
return grp_var
948966
else:
949-
return node_arg.n3()
967+
# type error: "Identifier" has no attribute "n3"
968+
return node_arg.n3() # type: ignore[attr-defined]
950969
elif isinstance(node_arg, CompValue):
951970
return "{" + node_arg.name + "}"
952-
elif isinstance(node_arg, Expr):
953-
return "{" + node_arg.name + "}"
971+
# type error notes: this is because Expr is a subclass of CompValue
972+
# type error: Subclass of "str" and "Expr" cannot exist: would have incompatible method signatures
973+
elif isinstance(node_arg, Expr): # type: ignore[unreachable]
974+
# type error: Statement is unreachable
975+
return "{" + node_arg.name + "}" # type: ignore[unreachable]
954976
elif isinstance(node_arg, str):
955977
return node_arg
956978
else:
@@ -1529,7 +1551,7 @@ def sparql_query_text(node):
15291551
return query_from_algebra
15301552

15311553

1532-
def pprintAlgebra(q):
1554+
def pprintAlgebra(q) -> None:
15331555
def pp(p, ind=" "):
15341556
# if isinstance(p, list):
15351557
# print "[ "

0 commit comments

Comments
 (0)