iolanta 2.1.11__py3-none-any.whl → 2.1.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. iolanta/cli/main.py +200 -80
  2. iolanta/facets/facet.py +15 -9
  3. iolanta/facets/mermaid_roadmap/__init__.py +0 -0
  4. iolanta/facets/mermaid_roadmap/facet.py +133 -0
  5. iolanta/facets/mermaid_roadmap/inference/blocks.sparql +13 -0
  6. iolanta/facets/mermaid_roadmap/inference/has-task-default-type.sparql +16 -0
  7. iolanta/facets/mermaid_roadmap/inference/task.sparql +26 -0
  8. iolanta/facets/mermaid_roadmap/inference/unblocked.sparql +21 -0
  9. iolanta/facets/mermaid_roadmap/mermaid_roadmap.yamlld +59 -0
  10. iolanta/facets/mermaid_roadmap/sparql/edges.sparql +25 -0
  11. iolanta/facets/mermaid_roadmap/sparql/nodes.sparql +17 -0
  12. iolanta/facets/query/__init__.py +0 -0
  13. iolanta/facets/query/ask_result_csv.py +23 -0
  14. iolanta/facets/query/ask_result_json.py +24 -0
  15. iolanta/facets/query/ask_result_table.py +23 -0
  16. iolanta/facets/query/construct_result_csv.py +34 -0
  17. iolanta/facets/query/construct_result_json.py +32 -0
  18. iolanta/facets/query/construct_result_table.py +55 -0
  19. iolanta/facets/query/data/query_result.yamlld +102 -0
  20. iolanta/facets/query/select_result_csv.py +36 -0
  21. iolanta/facets/query/select_result_json.py +24 -0
  22. iolanta/facets/query/select_result_table.py +48 -0
  23. iolanta/iolanta.py +146 -55
  24. iolanta/mcp/cli.py +16 -3
  25. iolanta/mermaid/models.py +74 -40
  26. iolanta/sparqlspace/processor.py +232 -179
  27. {iolanta-2.1.11.dist-info → iolanta-2.1.13.dist-info}/METADATA +2 -2
  28. {iolanta-2.1.11.dist-info → iolanta-2.1.13.dist-info}/RECORD +30 -10
  29. {iolanta-2.1.11.dist-info → iolanta-2.1.13.dist-info}/WHEEL +1 -1
  30. {iolanta-2.1.11.dist-info → iolanta-2.1.13.dist-info}/entry_points.txt +10 -0
@@ -0,0 +1,25 @@
1
+ PREFIX roadmap: <https://iolanta.tech/roadmap/>
2
+
3
+ SELECT DISTINCT ?source ?target WHERE {
4
+ # Find roadmap:blocks relationships across all graphs (including inferred)
5
+ ?source roadmap:blocks ?target .
6
+
7
+ # Only include edges where both source and target are Task/Event/Bug nodes
8
+ # (they will be filtered by the nodes query, but this ensures we only show
9
+ # relevant edges)
10
+ {
11
+ ?source a roadmap:Task .
12
+ } UNION {
13
+ ?source a roadmap:Event .
14
+ } UNION {
15
+ ?source a roadmap:Bug .
16
+ }
17
+
18
+ {
19
+ ?target a roadmap:Task .
20
+ } UNION {
21
+ ?target a roadmap:Event .
22
+ } UNION {
23
+ ?target a roadmap:Bug .
24
+ }
25
+ }
@@ -0,0 +1,17 @@
1
+ PREFIX roadmap: <https://iolanta.tech/roadmap/>
2
+ PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
3
+
4
+ SELECT DISTINCT ?node ?is_unblocked WHERE {
5
+ # Search across all graphs (including inference graphs)
6
+ # This finds both original types and inferred types
7
+ {
8
+ ?node rdf:type roadmap:Task .
9
+ } UNION {
10
+ ?node rdf:type roadmap:Event .
11
+ } UNION {
12
+ ?node rdf:type roadmap:Bug .
13
+ }
14
+
15
+ # Check if node is unblocked (has roadmap:Unblocked type)
16
+ BIND(EXISTS { ?node rdf:type roadmap:Unblocked } AS ?is_unblocked)
17
+ }
File without changes
@@ -0,0 +1,23 @@
1
+ from pathlib import Path
2
+
3
+ from rdflib import Literal
4
+
5
+ from iolanta.facets.cli.base import Renderable, RichFacet
6
+ from iolanta.facets.errors import NotALiteral
7
+
8
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
9
+
10
+
11
+ class AskResultCsvFacet(RichFacet):
12
+ """Render ASK query results as CSV."""
13
+
14
+ META = META
15
+
16
+ def show(self) -> Renderable:
17
+ """Render bool (ASK result) as CSV."""
18
+ if not isinstance(self.this, Literal):
19
+ raise NotALiteral(node=self.this)
20
+
21
+ query_result = self.this.value
22
+
23
+ return "result\n" + str(query_result).lower()
@@ -0,0 +1,24 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ from rdflib import Literal
5
+
6
+ from iolanta.facets.cli.base import Renderable, RichFacet
7
+ from iolanta.facets.errors import NotALiteral
8
+
9
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
10
+
11
+
12
+ class AskResultJsonFacet(RichFacet):
13
+ """Render ASK query results as JSON."""
14
+
15
+ META = META
16
+
17
+ def show(self) -> Renderable:
18
+ """Render bool (ASK result) as JSON."""
19
+ if not isinstance(self.this, Literal):
20
+ raise NotALiteral(node=self.this)
21
+
22
+ query_result = self.this.value
23
+
24
+ return json.dumps(query_result)
@@ -0,0 +1,23 @@
1
+ from pathlib import Path
2
+
3
+ from rdflib import Literal
4
+
5
+ from iolanta.facets.cli.base import Renderable, RichFacet
6
+ from iolanta.facets.errors import NotALiteral
7
+
8
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
9
+
10
+
11
+ class AskResultTableFacet(RichFacet):
12
+ """Render ASK query results as table/text."""
13
+
14
+ META = META
15
+
16
+ def show(self) -> Renderable:
17
+ """Render bool (ASK result) as text."""
18
+ if not isinstance(self.this, Literal):
19
+ raise NotALiteral(node=self.this)
20
+
21
+ query_result = self.this.value
22
+
23
+ return "✅ `True`" if query_result else "❌ `False`"
@@ -0,0 +1,34 @@
1
+ import csv
2
+ import io
3
+ from pathlib import Path
4
+ from typing import cast
5
+
6
+ from rdflib import Graph, Literal
7
+
8
+ from iolanta.facets.cli.base import Renderable, RichFacet
9
+ from iolanta.facets.errors import NotALiteral
10
+
11
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
12
+
13
+
14
+ class ConstructResultCsvFacet(RichFacet):
15
+ """Render CONSTRUCT query results as CSV."""
16
+
17
+ META = META
18
+
19
+ def show(self) -> Renderable:
20
+ """Render Graph (CONSTRUCT result) as CSV."""
21
+ if not isinstance(self.this, Literal):
22
+ raise NotALiteral(node=self.this)
23
+
24
+ graph = cast(Graph, self.this.value)
25
+
26
+ if not graph:
27
+ return ""
28
+
29
+ output = io.StringIO()
30
+ writer = csv.writer(output)
31
+ writer.writerow(('subject', 'predicate', 'object'))
32
+ writer.writerows(graph)
33
+
34
+ return output.getvalue()
@@ -0,0 +1,32 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import cast
4
+
5
+ from rdflib import Graph, Literal
6
+
7
+ from iolanta.facets.cli.base import Renderable, RichFacet
8
+ from iolanta.facets.errors import NotALiteral
9
+
10
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
11
+
12
+
13
+ class ConstructResultJsonFacet(RichFacet):
14
+ """Render CONSTRUCT query results as JSON."""
15
+
16
+ META = META
17
+
18
+ def show(self) -> Renderable:
19
+ """Render Graph (CONSTRUCT result) as JSON."""
20
+ if not isinstance(self.this, Literal):
21
+ raise NotALiteral(node=self.this)
22
+
23
+ graph = cast(Graph, self.this.value)
24
+ fieldnames = ('subject', 'predicate', 'object')
25
+ return json.dumps(
26
+ [
27
+ dict(zip(fieldnames, triple))
28
+ for triple in graph
29
+ ],
30
+ indent=2,
31
+ default=str,
32
+ )
@@ -0,0 +1,55 @@
1
+ from pathlib import Path
2
+ from typing import cast
3
+
4
+ from more_itertools import consume
5
+ from rdflib import Graph, Literal
6
+ from rich.table import Table
7
+
8
+ from iolanta.cli.formatters.pretty import pretty_print_value
9
+ from iolanta.facets.cli.base import Renderable, RichFacet
10
+ from iolanta.facets.errors import NotALiteral
11
+
12
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
13
+
14
+
15
+ class ConstructResultTableFacet(RichFacet):
16
+ """Render CONSTRUCT query results as table."""
17
+
18
+ META = META
19
+
20
+ def show(self) -> Renderable:
21
+ """Render Graph (CONSTRUCT result) as table."""
22
+ if not isinstance(self.this, Literal):
23
+ raise NotALiteral(node=self.this)
24
+
25
+ graph = cast(Graph, self.this.value)
26
+
27
+ if not graph:
28
+ table = Table(
29
+ 'Subject',
30
+ 'Predicate',
31
+ 'Object',
32
+ show_header=True,
33
+ header_style="bold magenta",
34
+ )
35
+ return table
36
+
37
+ table = Table(
38
+ 'Subject',
39
+ 'Predicate',
40
+ 'Object',
41
+ show_header=True,
42
+ header_style="bold magenta",
43
+ )
44
+
45
+ consume(
46
+ table.add_row(
47
+ *[
48
+ str(pretty_print_value(value))
49
+ for value in triple
50
+ ],
51
+ )
52
+ for triple in graph
53
+ )
54
+
55
+ return table
@@ -0,0 +1,102 @@
1
+ "@context":
2
+ "@import": https://json-ld.org/contexts/dollar-convenience.jsonld
3
+ iolanta: https://iolanta.tech/
4
+ rdfs: "http://www.w3.org/2000/01/rdf-schema#"
5
+ rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
6
+ owl: http://www.w3.org/2002/07/owl#
7
+
8
+ $: rdfs:label
9
+ →:
10
+ "@type": "@id"
11
+ "@id": iolanta:outputs
12
+ ⊆:
13
+ "@type": "@id"
14
+ "@id": rdfs:subClassOf
15
+ iolanta:hasDatatypeFacet:
16
+ "@type": "@id"
17
+
18
+ $included:
19
+ # Define the three SPARQL result datatypes
20
+ - $id: https://iolanta.tech/datatypes/sparql-select-result
21
+ $type: owl:Class
22
+ ⊆: rdfs:Datatype
23
+ $: SPARQL SELECT Result
24
+ rdfs:comment: Datatype for SPARQL SELECT query results (variable bindings)
25
+
26
+ - $id: https://iolanta.tech/datatypes/sparql-construct-result
27
+ $type: owl:Class
28
+ ⊆: rdfs:Datatype
29
+ $: SPARQL CONSTRUCT Result
30
+ rdfs:comment: Datatype for SPARQL CONSTRUCT query results (RDF graph)
31
+
32
+ - $id: https://iolanta.tech/datatypes/sparql-ask-result
33
+ $type: owl:Class
34
+ ⊆: rdfs:Datatype
35
+ $: SPARQL ASK Result
36
+ rdfs:comment: Datatype for SPARQL ASK query results (boolean)
37
+
38
+ # Register SelectResult facets for each output format
39
+ - $id: pkg:pypi/iolanta#select-result-table-facet
40
+ $type: iolanta:Facet
41
+ $: SPARQL SELECT Result Table Facet
42
+ →: https://iolanta.tech/datatypes/table
43
+
44
+ - $id: pkg:pypi/iolanta#select-result-json-facet
45
+ $type: iolanta:Facet
46
+ $: SPARQL SELECT Result JSON Facet
47
+ →: https://iolanta.tech/datatypes/json
48
+
49
+ - $id: pkg:pypi/iolanta#select-result-csv-facet
50
+ $type: iolanta:Facet
51
+ $: SPARQL SELECT Result CSV Facet
52
+ →: https://iolanta.tech/datatypes/csv
53
+
54
+ - $id: https://iolanta.tech/datatypes/sparql-select-result
55
+ iolanta:hasDatatypeFacet:
56
+ - pkg:pypi/iolanta#select-result-table-facet
57
+ - pkg:pypi/iolanta#select-result-json-facet
58
+ - pkg:pypi/iolanta#select-result-csv-facet
59
+
60
+ # Register ConstructResult facets for each output format
61
+ - $id: pkg:pypi/iolanta#construct-result-table-facet
62
+ $type: iolanta:Facet
63
+ $: SPARQL CONSTRUCT Result Table Facet
64
+ →: https://iolanta.tech/datatypes/table
65
+
66
+ - $id: pkg:pypi/iolanta#construct-result-json-facet
67
+ $type: iolanta:Facet
68
+ $: SPARQL CONSTRUCT Result JSON Facet
69
+ →: https://iolanta.tech/datatypes/json
70
+
71
+ - $id: pkg:pypi/iolanta#construct-result-csv-facet
72
+ $type: iolanta:Facet
73
+ $: SPARQL CONSTRUCT Result CSV Facet
74
+ →: https://iolanta.tech/datatypes/csv
75
+
76
+ - $id: https://iolanta.tech/datatypes/sparql-construct-result
77
+ iolanta:hasDatatypeFacet:
78
+ - pkg:pypi/iolanta#construct-result-table-facet
79
+ - pkg:pypi/iolanta#construct-result-json-facet
80
+ - pkg:pypi/iolanta#construct-result-csv-facet
81
+
82
+ # Register AskResult facets for each output format
83
+ - $id: pkg:pypi/iolanta#ask-result-table-facet
84
+ $type: iolanta:Facet
85
+ $: SPARQL ASK Result Table Facet
86
+ →: https://iolanta.tech/datatypes/table
87
+
88
+ - $id: pkg:pypi/iolanta#ask-result-json-facet
89
+ $type: iolanta:Facet
90
+ $: SPARQL ASK Result JSON Facet
91
+ →: https://iolanta.tech/datatypes/json
92
+
93
+ - $id: pkg:pypi/iolanta#ask-result-csv-facet
94
+ $type: iolanta:Facet
95
+ $: SPARQL ASK Result CSV Facet
96
+ →: https://iolanta.tech/datatypes/csv
97
+
98
+ - $id: https://iolanta.tech/datatypes/sparql-ask-result
99
+ iolanta:hasDatatypeFacet:
100
+ - pkg:pypi/iolanta#ask-result-table-facet
101
+ - pkg:pypi/iolanta#ask-result-json-facet
102
+ - pkg:pypi/iolanta#ask-result-csv-facet
@@ -0,0 +1,36 @@
1
+ import csv
2
+ import io
3
+ from pathlib import Path
4
+
5
+ from rdflib import Literal
6
+
7
+ from iolanta.facets.cli.base import Renderable, RichFacet
8
+ from iolanta.facets.errors import NotALiteral
9
+
10
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
11
+
12
+
13
+ class SelectResultCsvFacet(RichFacet):
14
+ """Render SELECT query results as CSV."""
15
+
16
+ META = META
17
+
18
+ def show(self) -> Renderable:
19
+ """Render SelectResult as CSV."""
20
+ if not isinstance(self.this, Literal):
21
+ raise NotALiteral(node=self.this)
22
+
23
+ query_result = self.this.value
24
+
25
+ if not query_result:
26
+ return ""
27
+
28
+ output = io.StringIO()
29
+ first_row = query_result[0]
30
+ fieldnames = first_row.keys()
31
+
32
+ writer = csv.DictWriter(output, fieldnames=fieldnames)
33
+ writer.writeheader()
34
+ writer.writerows(query_result)
35
+
36
+ return output.getvalue()
@@ -0,0 +1,24 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ from rdflib import Literal
5
+
6
+ from iolanta.facets.cli.base import Renderable, RichFacet
7
+ from iolanta.facets.errors import NotALiteral
8
+
9
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
10
+
11
+
12
+ class SelectResultJsonFacet(RichFacet):
13
+ """Render SELECT query results as JSON."""
14
+
15
+ META = META
16
+
17
+ def show(self) -> Renderable:
18
+ """Render SelectResult as JSON."""
19
+ if not isinstance(self.this, Literal):
20
+ raise NotALiteral(node=self.this)
21
+
22
+ query_result = self.this.value
23
+
24
+ return json.dumps(query_result, indent=2, default=str)
@@ -0,0 +1,48 @@
1
+ from pathlib import Path
2
+
3
+ from more_itertools import consume, first
4
+ from rdflib import Literal
5
+ from rich.table import Table
6
+
7
+ from iolanta.cli.formatters.pretty import pretty_print_value
8
+ from iolanta.facets.cli.base import Renderable, RichFacet
9
+ from iolanta.facets.errors import NotALiteral
10
+
11
+ META = Path(__file__).parent / 'data' / 'query_result.yamlld'
12
+
13
+
14
+ class SelectResultTableFacet(RichFacet):
15
+ """Render SELECT query results as table."""
16
+
17
+ META = META
18
+
19
+ def show(self) -> Renderable:
20
+ """Render SelectResult as table."""
21
+ if not isinstance(self.this, Literal):
22
+ raise NotALiteral(node=self.this)
23
+
24
+ query_result = self.this.value
25
+
26
+ if not query_result:
27
+ table = Table(show_header=True, header_style="bold magenta")
28
+ return table
29
+
30
+ columns = first(query_result).keys()
31
+
32
+ table = Table(
33
+ *columns,
34
+ show_header=True,
35
+ header_style="bold magenta",
36
+ )
37
+
38
+ consume(
39
+ table.add_row(
40
+ *[
41
+ str(pretty_print_value(value))
42
+ for value in row.values()
43
+ ],
44
+ )
45
+ for row in query_result
46
+ )
47
+
48
+ return table