iolanta 2.0.1__py3-none-any.whl → 2.0.5__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.
- iolanta/data/context.yaml +15 -0
- iolanta/data/graph-triples.yamlld +6 -0
- iolanta/data/textual-browser.yaml +68 -50
- iolanta/facets/facet.py +5 -0
- iolanta/facets/locator.py +32 -1
- iolanta/facets/textual_class/facets.py +35 -46
- iolanta/facets/textual_class/sparql/instances.sparql +1 -1
- iolanta/facets/textual_property_pairs_table.py +133 -0
- iolanta/iolanta.py +3 -3
- iolanta/parse_quads.py +0 -7
- iolanta/sparqlspace/cli.py +64 -0
- iolanta/{cyberspace → sparqlspace}/processor.py +113 -72
- iolanta/sparqlspace/sparqlspace.py +32 -0
- {iolanta-2.0.1.dist-info → iolanta-2.0.5.dist-info}/METADATA +1 -1
- {iolanta-2.0.1.dist-info → iolanta-2.0.5.dist-info}/RECORD +20 -16
- {iolanta-2.0.1.dist-info → iolanta-2.0.5.dist-info}/entry_points.txt +2 -1
- /iolanta/{cyberspace → sparqlspace}/__init__.py +0 -0
- /iolanta/{cyberspace → sparqlspace}/inference/wikibase-claim.sparql +0 -0
- /iolanta/{cyberspace → sparqlspace}/inference/wikibase-statement-property.sparql +0 -0
- {iolanta-2.0.1.dist-info → iolanta-2.0.5.dist-info}/WHEEL +0 -0
iolanta/data/context.yaml
CHANGED
|
@@ -59,3 +59,18 @@
|
|
|
59
59
|
|
|
60
60
|
rdf:type:
|
|
61
61
|
"@type": "@id"
|
|
62
|
+
|
|
63
|
+
$: rdfs:label
|
|
64
|
+
→:
|
|
65
|
+
"@type": "@id"
|
|
66
|
+
"@id": iolanta:outputs
|
|
67
|
+
|
|
68
|
+
⊆:
|
|
69
|
+
"@type": "@id"
|
|
70
|
+
"@id": rdfs:subClassOf
|
|
71
|
+
|
|
72
|
+
⪯:
|
|
73
|
+
"@type": "@id"
|
|
74
|
+
"@id": iolanta:is-preferred-over
|
|
75
|
+
|
|
76
|
+
↦: iolanta:matches
|
|
@@ -10,55 +10,75 @@
|
|
|
10
10
|
dcterms: https://purl.org/dc/terms/
|
|
11
11
|
xsd: https://www.w3.org/2001/XMLSchema#
|
|
12
12
|
|
|
13
|
+
iolanta:outputs:
|
|
14
|
+
"@type": "@id"
|
|
15
|
+
|
|
16
|
+
$: rdfs:label
|
|
17
|
+
→:
|
|
18
|
+
"@type": "@id"
|
|
19
|
+
"@id": iolanta:outputs
|
|
20
|
+
|
|
21
|
+
⊆:
|
|
22
|
+
"@type": "@id"
|
|
23
|
+
"@id": rdfs:subClassOf
|
|
24
|
+
|
|
25
|
+
⪯:
|
|
26
|
+
"@type": "@id"
|
|
27
|
+
"@id": iolanta:is-preferred-over
|
|
28
|
+
|
|
29
|
+
↦: iolanta:matches
|
|
30
|
+
|
|
13
31
|
"@included":
|
|
14
32
|
- $id: iolanta:icon
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
$id: xsd:string
|
|
33
|
+
$: Icon
|
|
34
|
+
⊆: xsd:string
|
|
18
35
|
|
|
19
36
|
- $id: dcterms:creator
|
|
20
37
|
iolanta:icon: ©️
|
|
21
38
|
|
|
22
39
|
- $id: https://iolanta.tech/datatypes/icon
|
|
23
|
-
|
|
40
|
+
$: Icon
|
|
24
41
|
iolanta:hasDefaultFacet:
|
|
25
42
|
$id: python://iolanta.facets.icon.IconFacet
|
|
26
|
-
iolanta
|
|
27
|
-
$id: https://iolanta.tech/datatypes/icon
|
|
43
|
+
→: https://iolanta.tech/datatypes/icon
|
|
28
44
|
|
|
29
45
|
- $id: np:Nanopublication
|
|
30
|
-
|
|
46
|
+
$: Nanopublication
|
|
31
47
|
iolanta:hasInstanceFacet:
|
|
32
48
|
$id: python://iolanta.facets.textual_nanopublication.NanopublicationFacet
|
|
33
|
-
|
|
34
|
-
iolanta
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
$: Nanopublication
|
|
50
|
+
→: https://iolanta.tech/cli/textual
|
|
51
|
+
⪯:
|
|
52
|
+
- python://iolanta.facets.textual_default.TextualDefaultFacet
|
|
53
|
+
- python://iolanta.facets.textual_graph.GraphFacet
|
|
38
54
|
|
|
39
55
|
- $id: https://iolanta.tech/cli/interactive
|
|
40
56
|
iolanta:hasDefaultFacet:
|
|
41
57
|
$id: python://iolanta.facets.textual_browser.TextualBrowserFacet
|
|
42
58
|
|
|
43
|
-
- $id:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
59
|
+
- $id: python://iolanta.facets.textual_default.TextualDefaultFacet
|
|
60
|
+
$: Properties
|
|
61
|
+
⪯: python://iolanta.facets.textual_default.InverseProperties
|
|
62
|
+
→: https://iolanta.tech/cli/textual
|
|
63
|
+
↦: |
|
|
64
|
+
ASK WHERE {
|
|
65
|
+
GRAPH ?graph { $this ?property ?value }
|
|
66
|
+
FILTER (?graph != <iolanta://_meta>)
|
|
67
|
+
}
|
|
49
68
|
|
|
50
|
-
- $id:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
$
|
|
69
|
+
- $id: python://iolanta.facets.textual_default.InverseProperties
|
|
70
|
+
$: Inverse Properties
|
|
71
|
+
→: https://iolanta.tech/cli/textual
|
|
72
|
+
↦: |
|
|
73
|
+
ASK WHERE {
|
|
74
|
+
GRAPH ?graph { ?something ?property $this }
|
|
75
|
+
FILTER (?graph != <iolanta://_meta>)
|
|
76
|
+
}
|
|
56
77
|
|
|
57
78
|
- $id: "urn:"
|
|
58
79
|
iolanta:hasFacetByPrefix:
|
|
59
80
|
$id: python://iolanta.facets.textual_provenance.TextualProvenanceFacet
|
|
60
|
-
iolanta
|
|
61
|
-
$id: https://iolanta.tech/cli/textual
|
|
81
|
+
→: https://iolanta.tech/cli/textual
|
|
62
82
|
|
|
63
83
|
- $id: https://iolanta.tech/cli/link
|
|
64
84
|
iolanta:hasDefaultFacet:
|
|
@@ -67,43 +87,41 @@
|
|
|
67
87
|
- $id: https://wikiba.se/ontology#Statement
|
|
68
88
|
iolanta:hasInstanceFacet:
|
|
69
89
|
$id: python://iolanta.facets.wikibase_statement_title.WikibaseStatementTitle
|
|
70
|
-
|
|
71
|
-
iolanta
|
|
72
|
-
$id: https://iolanta.tech/datatypes/title
|
|
90
|
+
$: Title
|
|
91
|
+
→: https://iolanta.tech/datatypes/title
|
|
73
92
|
|
|
74
93
|
- $id: rdfs:Class
|
|
75
94
|
iolanta:hasInstanceFacet:
|
|
76
95
|
$id: python://iolanta.facets.textual_class.Class
|
|
77
|
-
|
|
78
|
-
iolanta
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
- $id: python://iolanta.facets.textual_default.InverseProperties
|
|
96
|
+
$: Instances
|
|
97
|
+
→: https://iolanta.tech/cli/textual
|
|
98
|
+
⪯:
|
|
99
|
+
- python://iolanta.facets.textual_browser.TextualBrowserFacet
|
|
100
|
+
- python://iolanta.facets.textual_default.InverseProperties
|
|
83
101
|
|
|
84
102
|
- $id: owl:Ontology
|
|
85
103
|
iolanta:hasInstanceFacet:
|
|
86
104
|
$id: python://iolanta.facets.textual_ontology.OntologyFacet
|
|
87
|
-
|
|
88
|
-
iolanta
|
|
89
|
-
|
|
90
|
-
iolanta:is-preferred-over:
|
|
91
|
-
- $id: python://iolanta.facets.textual_default.TextualDefaultFacet
|
|
92
|
-
|
|
93
|
-
- $id: iolanta:Graph
|
|
94
|
-
iolanta:hasInstanceFacet:
|
|
95
|
-
$id: python://iolanta.facets.textual_graph.GraphFacet
|
|
96
|
-
rdfs:label: Graph Triples
|
|
97
|
-
iolanta:outputs:
|
|
98
|
-
$id: https://iolanta.tech/cli/textual
|
|
105
|
+
$: Ontology
|
|
106
|
+
→: https://iolanta.tech/cli/textual
|
|
107
|
+
⪯: python://iolanta.facets.textual_default.TextualDefaultFacet
|
|
99
108
|
|
|
100
109
|
- $id: https://iolanta.tech/datatypes/textual-graph-triples
|
|
101
|
-
|
|
110
|
+
$: Graph Triples
|
|
102
111
|
iolanta:hasDefaultFacet:
|
|
103
112
|
$id: python://iolanta.facets.textual_graph_triples.GraphTriplesFacet
|
|
104
|
-
iolanta
|
|
105
|
-
$id: https://iolanta.tech/datatypes/textual-graph-triples
|
|
113
|
+
→: https://iolanta.tech/datatypes/textual-graph-triples
|
|
106
114
|
|
|
107
115
|
- $id: https://iolanta.tech/qname
|
|
108
116
|
iolanta:hasDefaultFacet:
|
|
109
117
|
$id: python://iolanta.facets.qname.QNameFacet
|
|
118
|
+
|
|
119
|
+
- $id: python://iolanta.facets.textual_property_pairs_table.TextualPropertyPairsTableFacet
|
|
120
|
+
$: Subjects → Objects
|
|
121
|
+
→: https://iolanta.tech/cli/textual
|
|
122
|
+
↦: ASK WHERE { ?subject $this ?object }
|
|
123
|
+
|
|
124
|
+
- $id: python://iolanta.facets.textual_class.Class
|
|
125
|
+
↦:
|
|
126
|
+
- ASK WHERE { ?instance a $this }
|
|
127
|
+
- ASK WHERE { $this rdfs:subClassOf ?superclass }
|
iolanta/facets/facet.py
CHANGED
|
@@ -20,6 +20,11 @@ class Facet(Generic[FacetOutput]):
|
|
|
20
20
|
iolanta: 'iolanta.Iolanta' = field(repr=False)
|
|
21
21
|
as_datatype: Optional[NotLiteralNode] = None
|
|
22
22
|
|
|
23
|
+
@property
|
|
24
|
+
def this(self) -> NotLiteralNode:
|
|
25
|
+
"""This node."""
|
|
26
|
+
return self.iri
|
|
27
|
+
|
|
23
28
|
@property
|
|
24
29
|
def stored_queries_path(self) -> Path:
|
|
25
30
|
"""Construct directory for stored queries for this facet."""
|
iolanta/facets/locator.py
CHANGED
|
@@ -15,7 +15,16 @@ class FoundRow(TypedDict):
|
|
|
15
15
|
"""Facet and datatype to render an IRI."""
|
|
16
16
|
|
|
17
17
|
facet: NotLiteralNode
|
|
18
|
-
|
|
18
|
+
output_datatype: NotLiteralNode
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
GET_QUERY_TO_FACET = """
|
|
22
|
+
SELECT ?facet ?match WHERE {
|
|
23
|
+
?facet
|
|
24
|
+
iolanta:matches ?match ;
|
|
25
|
+
iolanta:outputs $as_datatype .
|
|
26
|
+
}
|
|
27
|
+
"""
|
|
19
28
|
|
|
20
29
|
|
|
21
30
|
def reorder_rows_by_facet_preferences( # noqa: WPS214, WPS210
|
|
@@ -103,6 +112,27 @@ class FacetFinder: # noqa: WPS214
|
|
|
103
112
|
key=self.row_sorter_by_output_datatype,
|
|
104
113
|
)
|
|
105
114
|
|
|
115
|
+
def by_sparql(self) -> Iterable[FoundRow]:
|
|
116
|
+
"""Determine facet by SHACL shape of the data."""
|
|
117
|
+
if not isinstance(self.node, URIRef):
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
rows = self.iolanta.query(
|
|
121
|
+
GET_QUERY_TO_FACET,
|
|
122
|
+
as_datatype=self.as_datatype,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
query_to_facet = {
|
|
126
|
+
row['match']: row['facet']
|
|
127
|
+
for row in rows
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for query, facet in query_to_facet.items():
|
|
131
|
+
# TODO: Verify that `query` is an ASK query
|
|
132
|
+
is_matching = self.iolanta.query(query, this=self.node)
|
|
133
|
+
if is_matching:
|
|
134
|
+
yield FoundRow(facet=facet, output_datatype=self.as_datatype)
|
|
135
|
+
|
|
106
136
|
def by_prefix(self) -> Iterable[FoundRow]:
|
|
107
137
|
"""Determine facet by URL prefix.
|
|
108
138
|
|
|
@@ -254,6 +284,7 @@ class FacetFinder: # noqa: WPS214
|
|
|
254
284
|
|
|
255
285
|
def _found_facets(self) -> Iterable[FoundRow]:
|
|
256
286
|
"""Compose a stream of all possible facet choices."""
|
|
287
|
+
yield from self.by_sparql()
|
|
257
288
|
yield from self.by_prefix()
|
|
258
289
|
yield from self.by_datatype()
|
|
259
290
|
yield from self.by_facet()
|
|
@@ -6,7 +6,7 @@ import funcy
|
|
|
6
6
|
from rich.console import RenderResult
|
|
7
7
|
from rich.text import Text
|
|
8
8
|
from textual.binding import Binding, BindingType
|
|
9
|
-
from textual.containers import Vertical
|
|
9
|
+
from textual.containers import Vertical # removed unused VerticalScroll (F401)
|
|
10
10
|
from textual.reactive import Reactive
|
|
11
11
|
from textual.widget import Widget
|
|
12
12
|
from textual.widgets import Label, ListItem, ListView
|
|
@@ -70,10 +70,8 @@ class InstancesList(ListView): # noqa: WPS214
|
|
|
70
70
|
|
|
71
71
|
DEFAULT_CSS = """
|
|
72
72
|
InstancesList {
|
|
73
|
-
height:
|
|
74
|
-
|
|
73
|
+
height: 1fr;
|
|
75
74
|
layout: vertical;
|
|
76
|
-
overflow-x: hidden;
|
|
77
75
|
overflow-y: auto;
|
|
78
76
|
}
|
|
79
77
|
"""
|
|
@@ -121,31 +119,6 @@ class InstancesList(ListView): # noqa: WPS214
|
|
|
121
119
|
parent_class=self.parent_class,
|
|
122
120
|
)
|
|
123
121
|
|
|
124
|
-
def on_list_view_highlighted(self):
|
|
125
|
-
"""
|
|
126
|
-
Find out whether the last item of the list is highlighted.
|
|
127
|
-
|
|
128
|
-
If yes then add more elements.
|
|
129
|
-
"""
|
|
130
|
-
if not self._nodes or (self.index >= len(self._nodes) - 1):
|
|
131
|
-
new_instance_items = list(self.stream_instance_items_chunk())
|
|
132
|
-
self.run_worker(
|
|
133
|
-
functools.partial(
|
|
134
|
-
self.render_newly_added_instances,
|
|
135
|
-
new_instance_items,
|
|
136
|
-
),
|
|
137
|
-
thread=True,
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
# #126 `extend()` here will lead to freeze in some situations
|
|
141
|
-
for new_item in new_instance_items:
|
|
142
|
-
self.append(new_item)
|
|
143
|
-
|
|
144
|
-
def on_list_item__child_clicked(self) -> None: # noqa: WPS116
|
|
145
|
-
"""Navigate on click."""
|
|
146
|
-
# FIXME if we call `action_goto()` here we'll navigate to the item that
|
|
147
|
-
# was selected _prior_ to this click.
|
|
148
|
-
|
|
149
122
|
def action_goto(self):
|
|
150
123
|
"""Navigate."""
|
|
151
124
|
self.app.action_goto(self.highlighted_child.node)
|
|
@@ -160,6 +133,32 @@ class InstancesList(ListView): # noqa: WPS214
|
|
|
160
133
|
),
|
|
161
134
|
)
|
|
162
135
|
|
|
136
|
+
def compose(self):
|
|
137
|
+
"""Fill in the instances."""
|
|
138
|
+
for instance in self.instances: # noqa: WPS526
|
|
139
|
+
yield InstanceItem(
|
|
140
|
+
node=instance,
|
|
141
|
+
parent_class=self.parent_class,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def render_instances(self):
|
|
145
|
+
"""Render all instances."""
|
|
146
|
+
for instance_item in self.children:
|
|
147
|
+
self.app.call_from_thread(
|
|
148
|
+
instance_item.update,
|
|
149
|
+
self.app.iolanta.render(
|
|
150
|
+
instance_item.node,
|
|
151
|
+
as_datatype=DATATYPES.title,
|
|
152
|
+
),
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def on_mount(self):
|
|
156
|
+
"""Render the first chunk of instances."""
|
|
157
|
+
self.run_worker(
|
|
158
|
+
self.render_instances,
|
|
159
|
+
thread=True,
|
|
160
|
+
)
|
|
161
|
+
|
|
163
162
|
|
|
164
163
|
class Bottom(Label):
|
|
165
164
|
"""Label below the instances list."""
|
|
@@ -198,29 +197,19 @@ class Class(Facet[Widget]):
|
|
|
198
197
|
We have to stop if a subsequent attempt returns no results. That's why
|
|
199
198
|
we can't use `funcy.distinct()` or something similar.
|
|
200
199
|
"""
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
),
|
|
208
|
-
).difference(known_instances)
|
|
209
|
-
|
|
210
|
-
if not instances:
|
|
211
|
-
return
|
|
212
|
-
|
|
213
|
-
yield from instances
|
|
214
|
-
|
|
215
|
-
known_instances.update(instances)
|
|
200
|
+
return set(
|
|
201
|
+
funcy.pluck(
|
|
202
|
+
'instance',
|
|
203
|
+
self.stored_query('instances.sparql', iri=self.iri),
|
|
204
|
+
),
|
|
205
|
+
)
|
|
216
206
|
|
|
217
207
|
def show(self) -> Widget:
|
|
218
208
|
"""Render the instances list."""
|
|
219
209
|
return InstancesBody(
|
|
220
210
|
PageTitle(self.iri),
|
|
221
211
|
InstancesList(
|
|
222
|
-
instances=self.stream_instances(),
|
|
212
|
+
instances=list(self.stream_instances()),
|
|
223
213
|
parent_class=self.iri,
|
|
224
214
|
),
|
|
225
|
-
Bottom('Select the last element to try loading more instances.'),
|
|
226
215
|
)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
from typing import Iterable
|
|
3
|
+
|
|
4
|
+
import funcy
|
|
5
|
+
from rdflib import Literal, Node
|
|
6
|
+
from rich.style import Style
|
|
7
|
+
from rich.text import Text
|
|
8
|
+
from textual.containers import Vertical
|
|
9
|
+
from textual.coordinate import Coordinate
|
|
10
|
+
from textual.widgets import DataTable
|
|
11
|
+
|
|
12
|
+
from iolanta import Facet
|
|
13
|
+
from iolanta.facets.page_title import PageTitle
|
|
14
|
+
from iolanta.models import NotLiteralNode
|
|
15
|
+
from iolanta.namespaces import DATATYPES
|
|
16
|
+
from iolanta.widgets.mixin import IolantaWidgetMixin
|
|
17
|
+
|
|
18
|
+
PAIRS_QUERY = """
|
|
19
|
+
SELECT ?subject ?object WHERE {
|
|
20
|
+
?subject $this ?object .
|
|
21
|
+
} ORDER BY ?subject ?object
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PairsTable(IolantaWidgetMixin, DataTable):
|
|
26
|
+
"""Render subject → object properties as a table with two columns."""
|
|
27
|
+
|
|
28
|
+
BINDINGS = [
|
|
29
|
+
('enter', 'goto', 'Goto'),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
def __init__(self, pairs: Iterable[tuple[NotLiteralNode, Node]]):
|
|
33
|
+
"""Construct."""
|
|
34
|
+
super().__init__(show_header=False, cell_padding=1)
|
|
35
|
+
self.pairs = list(pairs)
|
|
36
|
+
|
|
37
|
+
def render_human_readable_cells(self):
|
|
38
|
+
"""Replace the cells with their human readable titles."""
|
|
39
|
+
terms_and_coordinates = sorted(
|
|
40
|
+
self.node_to_coordinates.items(),
|
|
41
|
+
key=lambda node_and_coordinates_pair: len(
|
|
42
|
+
node_and_coordinates_pair[1],
|
|
43
|
+
),
|
|
44
|
+
reverse=True,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
for term, coordinates in terms_and_coordinates:
|
|
48
|
+
title = self.iolanta.render(term, as_datatype=DATATYPES.title)
|
|
49
|
+
for coordinate in coordinates:
|
|
50
|
+
self.app.call_from_thread(
|
|
51
|
+
self.update_cell_at,
|
|
52
|
+
coordinate,
|
|
53
|
+
value=Text(title, no_wrap=False),
|
|
54
|
+
update_width=False,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@funcy.cached_property
|
|
58
|
+
@funcy.post_processing(dict)
|
|
59
|
+
def coordinate_to_node(self):
|
|
60
|
+
"""Return a mapping of coordinates to their corresponding nodes."""
|
|
61
|
+
for row_number, (subject, object_term) in enumerate(self.pairs):
|
|
62
|
+
yield Coordinate(row_number, 0), subject
|
|
63
|
+
yield Coordinate(row_number, 1), object_term
|
|
64
|
+
|
|
65
|
+
@funcy.cached_property
|
|
66
|
+
def node_to_coordinates(self) -> defaultdict[Node, list[Coordinate]]:
|
|
67
|
+
"""Map node to coordinates where it appears."""
|
|
68
|
+
node_to_coordinate = [
|
|
69
|
+
(node, coordinate)
|
|
70
|
+
for coordinate, node in self.coordinate_to_node.items()
|
|
71
|
+
]
|
|
72
|
+
return funcy.group_values(node_to_coordinate)
|
|
73
|
+
|
|
74
|
+
def format_as_loading(self, node: Node) -> Text:
|
|
75
|
+
"""Intermediate version of a value while it is loading."""
|
|
76
|
+
if isinstance(node, Literal):
|
|
77
|
+
node_text = f'⌛ {node}'
|
|
78
|
+
else:
|
|
79
|
+
node_text = self.iolanta.node_as_qname(node)
|
|
80
|
+
node_text = f'⌛ {node_text}'
|
|
81
|
+
|
|
82
|
+
return Text(
|
|
83
|
+
node_text,
|
|
84
|
+
style=Style(dim=True),
|
|
85
|
+
no_wrap=False,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def on_mount(self):
|
|
89
|
+
"""Fill the table and start rendering."""
|
|
90
|
+
self.add_columns('Subject', 'Object')
|
|
91
|
+
self.cell_padding = 1
|
|
92
|
+
|
|
93
|
+
for subject, object_term in self.pairs:
|
|
94
|
+
self.add_row(
|
|
95
|
+
self.format_as_loading(subject),
|
|
96
|
+
self.format_as_loading(object_term),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
self.run_worker(
|
|
100
|
+
self.render_human_readable_cells,
|
|
101
|
+
thread=True,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def action_goto(self):
|
|
105
|
+
"""Navigate to the selected node."""
|
|
106
|
+
if self.cursor_coordinate:
|
|
107
|
+
node = self.coordinate_to_node.get(self.cursor_coordinate)
|
|
108
|
+
if node is not None:
|
|
109
|
+
self.app.action_goto(node)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class TextualPropertyPairsTableFacet(Facet):
|
|
113
|
+
"""Render a table of subject → object pairs for a property."""
|
|
114
|
+
|
|
115
|
+
def show(self):
|
|
116
|
+
"""Construct the table."""
|
|
117
|
+
rows = self.query(
|
|
118
|
+
PAIRS_QUERY,
|
|
119
|
+
this=self.this,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return Vertical(
|
|
123
|
+
PageTitle(
|
|
124
|
+
self.this,
|
|
125
|
+
extra='— Subjects & Objects connected by this property',
|
|
126
|
+
),
|
|
127
|
+
PairsTable(
|
|
128
|
+
[
|
|
129
|
+
(row['subject'], row['object'])
|
|
130
|
+
for row in rows
|
|
131
|
+
],
|
|
132
|
+
),
|
|
133
|
+
)
|
iolanta/iolanta.py
CHANGED
|
@@ -28,7 +28,6 @@ from yaml_ld.errors import YAMLLDError
|
|
|
28
28
|
|
|
29
29
|
from iolanta import entry_points, namespaces
|
|
30
30
|
from iolanta.conversions import path_to_iri
|
|
31
|
-
from iolanta.cyberspace.processor import normalize_term
|
|
32
31
|
from iolanta.errors import UnresolvedIRI
|
|
33
32
|
from iolanta.facets.errors import FacetError
|
|
34
33
|
from iolanta.facets.facet import Facet
|
|
@@ -53,6 +52,7 @@ from iolanta.query_result import (
|
|
|
53
52
|
format_query_bindings,
|
|
54
53
|
)
|
|
55
54
|
from iolanta.resolvers.python_import import PythonImportResolver
|
|
55
|
+
from iolanta.sparqlspace.processor import normalize_term
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
class LoggerProtocol(Protocol):
|
|
@@ -161,7 +161,7 @@ class Iolanta: # noqa: WPS214
|
|
|
161
161
|
try:
|
|
162
162
|
sparql_result: SPARQLResult = self.graph.query(
|
|
163
163
|
query_text,
|
|
164
|
-
processor='
|
|
164
|
+
processor='sparqlspace',
|
|
165
165
|
initBindings=kwargs,
|
|
166
166
|
)
|
|
167
167
|
except ParseException as err:
|
|
@@ -259,7 +259,7 @@ class Iolanta: # noqa: WPS214
|
|
|
259
259
|
)
|
|
260
260
|
|
|
261
261
|
if not quads:
|
|
262
|
-
self.logger.
|
|
262
|
+
self.logger.info(f'{source_file} | No data found')
|
|
263
263
|
continue
|
|
264
264
|
|
|
265
265
|
quad_tuples = [
|
iolanta/parse_quads.py
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
|
|
4
|
+
import rich
|
|
5
|
+
from rdflib import Node
|
|
6
|
+
from rdflib.query import Result
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
from typer import Option, Typer
|
|
9
|
+
|
|
10
|
+
from iolanta.sparqlspace.sparqlspace import SPARQLSpace
|
|
11
|
+
|
|
12
|
+
app = Typer()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class OutputFormat(StrEnum):
|
|
16
|
+
"""Output formats for the query command."""
|
|
17
|
+
|
|
18
|
+
CSV = 'csv' # noqa: WPS115
|
|
19
|
+
JSON = 'json' # noqa: WPS115
|
|
20
|
+
TABLE = 'table' # noqa: WPS115
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _format_node(node: Node):
|
|
24
|
+
return node
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _format_result(query_result: Result, output_format: OutputFormat):
|
|
28
|
+
match output_format:
|
|
29
|
+
case OutputFormat.CSV:
|
|
30
|
+
return query_result.serialize(format='csv').decode()
|
|
31
|
+
|
|
32
|
+
case OutputFormat.JSON:
|
|
33
|
+
return query_result.serialize(format='json').decode()
|
|
34
|
+
|
|
35
|
+
case OutputFormat.TABLE:
|
|
36
|
+
table = Table(*query_result.vars)
|
|
37
|
+
for row in query_result:
|
|
38
|
+
table.add_row(
|
|
39
|
+
*[
|
|
40
|
+
_format_node(node)
|
|
41
|
+
for node in row
|
|
42
|
+
],
|
|
43
|
+
)
|
|
44
|
+
return table
|
|
45
|
+
|
|
46
|
+
raise NotImplementedError(f'Output format {output_format} not implemented.')
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@app.command(name='query')
|
|
50
|
+
def query_command(
|
|
51
|
+
query: str,
|
|
52
|
+
output_format: Annotated[
|
|
53
|
+
OutputFormat,
|
|
54
|
+
Option(help='Output format.'),
|
|
55
|
+
] = OutputFormat.TABLE,
|
|
56
|
+
):
|
|
57
|
+
"""Execute a SPARQL query."""
|
|
58
|
+
query_result = SPARQLSpace().query(query)
|
|
59
|
+
rich.print(
|
|
60
|
+
_format_result(
|
|
61
|
+
query_result=query_result,
|
|
62
|
+
output_format=output_format,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import datetime
|
|
3
|
-
import itertools
|
|
4
3
|
import re
|
|
5
4
|
import time
|
|
6
5
|
from pathlib import Path
|
|
@@ -13,9 +12,11 @@ import funcy
|
|
|
13
12
|
import loguru
|
|
14
13
|
import platformdirs
|
|
15
14
|
import reasonable
|
|
15
|
+
import requests
|
|
16
16
|
import yaml_ld
|
|
17
17
|
from nanopub import NanopubClient
|
|
18
|
-
from rdflib import ConjunctiveGraph, Namespace, URIRef, Variable
|
|
18
|
+
from rdflib import ConjunctiveGraph, Dataset, Namespace, URIRef, Variable
|
|
19
|
+
from rdflib.namespace import RDF as original_RDF
|
|
19
20
|
from rdflib.plugins.sparql.algebra import translateQuery
|
|
20
21
|
from rdflib.plugins.sparql.evaluate import evalQuery
|
|
21
22
|
from rdflib.plugins.sparql.parser import parseQuery
|
|
@@ -23,6 +24,7 @@ from rdflib.plugins.sparql.parserutils import CompValue
|
|
|
23
24
|
from rdflib.plugins.sparql.sparql import Query
|
|
24
25
|
from rdflib.query import Processor
|
|
25
26
|
from rdflib.term import BNode, Literal, Node
|
|
27
|
+
from requests import HTTPError
|
|
26
28
|
from requests.exceptions import ConnectionError
|
|
27
29
|
from yaml_ld.document_loaders.content_types import ParserNotFound
|
|
28
30
|
from yaml_ld.errors import NotFound, YAMLLDError
|
|
@@ -97,13 +99,16 @@ def find_retractions_for(nanopublication: URIRef) -> set[URIRef]:
|
|
|
97
99
|
)
|
|
98
100
|
client.grlc_urls = [use_server]
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
'http://',
|
|
104
|
-
),
|
|
102
|
+
http_url = str(nanopublication).replace(
|
|
103
|
+
'https://',
|
|
104
|
+
'http://',
|
|
105
105
|
)
|
|
106
106
|
|
|
107
|
+
try:
|
|
108
|
+
retractions = client.find_retractions_of(http_url)
|
|
109
|
+
except HTTPError:
|
|
110
|
+
return set()
|
|
111
|
+
|
|
107
112
|
return {URIRef(retraction) for retraction in retractions}
|
|
108
113
|
|
|
109
114
|
|
|
@@ -111,7 +116,7 @@ def _extract_from_mapping( # noqa: WPS213
|
|
|
111
116
|
algebra: Mapping[str, Any],
|
|
112
117
|
) -> Iterable[URIRef | Variable]:
|
|
113
118
|
match algebra.name:
|
|
114
|
-
case 'SelectQuery' | 'Project' | 'Distinct':
|
|
119
|
+
case 'SelectQuery' | 'AskQuery' | 'Project' | 'Distinct':
|
|
115
120
|
yield from extract_mentioned_urls(algebra['p'])
|
|
116
121
|
|
|
117
122
|
case 'BGP':
|
|
@@ -260,7 +265,7 @@ def _extract_nanopublication_uris(
|
|
|
260
265
|
) -> Iterable[URIRef]:
|
|
261
266
|
"""Extract nanopublications to get retracting information for."""
|
|
262
267
|
match algebra.name:
|
|
263
|
-
case 'SelectQuery' | 'Project' | 'Distinct' | 'Graph':
|
|
268
|
+
case 'SelectQuery' | 'AskQuery' | 'Project' | 'Distinct' | 'Graph':
|
|
264
269
|
yield from _extract_nanopublication_uris(algebra['p'])
|
|
265
270
|
|
|
266
271
|
case 'BGP':
|
|
@@ -293,6 +298,79 @@ def apply_redirect(source: URIRef) -> URIRef:
|
|
|
293
298
|
return source
|
|
294
299
|
|
|
295
300
|
|
|
301
|
+
def extract_triples(algebra: CompValue) -> Iterable[tuple[Node, Node, Node]]:
|
|
302
|
+
"""Extract triples from a SPARQL query algebra instance."""
|
|
303
|
+
if isinstance(algebra, CompValue):
|
|
304
|
+
for key, value in algebra.items(): # noqa: WPS110
|
|
305
|
+
if key == 'triples':
|
|
306
|
+
yield from value
|
|
307
|
+
|
|
308
|
+
else:
|
|
309
|
+
yield from extract_triples(value)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
@dataclasses.dataclass(frozen=True)
|
|
313
|
+
class NanopubQueryPlugin:
|
|
314
|
+
"""Import additional information from Nanopublications Registry."""
|
|
315
|
+
|
|
316
|
+
graph: Dataset
|
|
317
|
+
|
|
318
|
+
def __call__(self, query: Query, bindings: dict[str, Any]):
|
|
319
|
+
"""Get stuff from Nanopub Registry, if it makes sense."""
|
|
320
|
+
class_uris = resolve_variables(
|
|
321
|
+
set(self._find_classes(query.algebra)),
|
|
322
|
+
bindings,
|
|
323
|
+
)
|
|
324
|
+
for class_uri in class_uris:
|
|
325
|
+
if self._is_from_nanopubs(class_uri):
|
|
326
|
+
self._load_instances(class_uri)
|
|
327
|
+
|
|
328
|
+
def _find_classes(self, algebra: CompValue) -> Iterable[URIRef]:
|
|
329
|
+
triples = extract_triples(algebra)
|
|
330
|
+
for _subject, potential_type, potential_class in triples:
|
|
331
|
+
if potential_type == original_RDF.type:
|
|
332
|
+
yield potential_class
|
|
333
|
+
|
|
334
|
+
@funcy.retry(errors=HTTPError, tries=3, timeout=3)
|
|
335
|
+
def _load_instances(self, class_uri: URIRef):
|
|
336
|
+
"""
|
|
337
|
+
Load instances from Nanopub Registry.
|
|
338
|
+
|
|
339
|
+
FIXME: Can we cache this?
|
|
340
|
+
"""
|
|
341
|
+
response = requests.post( # noqa: S113
|
|
342
|
+
'https://query.knowledgepixels.com/repo/full',
|
|
343
|
+
data={
|
|
344
|
+
'query': 'CONSTRUCT WHERE { ?instance a <%s> }' % class_uri,
|
|
345
|
+
},
|
|
346
|
+
headers={
|
|
347
|
+
'Accept': 'application/ld+json',
|
|
348
|
+
},
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
response.raise_for_status()
|
|
352
|
+
|
|
353
|
+
self.graph.get_context(BNode()).parse(
|
|
354
|
+
data=response.text,
|
|
355
|
+
format='json-ld',
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
def _is_from_nanopubs(self, class_uri: URIRef) -> bool:
|
|
359
|
+
if not isinstance(class_uri, URIRef):
|
|
360
|
+
raise ValueError(f'Not a URIRef: {class_uri}')
|
|
361
|
+
|
|
362
|
+
return self.graph.query( # noqa: WPS462
|
|
363
|
+
"""
|
|
364
|
+
ASK WHERE {
|
|
365
|
+
?_whatever <https://purl.org/nanopub/x/introduces> $class
|
|
366
|
+
}
|
|
367
|
+
""",
|
|
368
|
+
initBindings={
|
|
369
|
+
'class': class_uri,
|
|
370
|
+
},
|
|
371
|
+
).askAnswer
|
|
372
|
+
|
|
373
|
+
|
|
296
374
|
@dataclasses.dataclass(frozen=True)
|
|
297
375
|
class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
298
376
|
"""
|
|
@@ -401,25 +479,27 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
401
479
|
parse_tree = parseQuery(strOrQuery)
|
|
402
480
|
query = translateQuery(parse_tree, base, initNs)
|
|
403
481
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
482
|
+
self.load_retracting_nanopublications_by_query(
|
|
483
|
+
query=query,
|
|
484
|
+
bindings=initBindings,
|
|
485
|
+
base=base,
|
|
486
|
+
namespaces=initNs,
|
|
487
|
+
)
|
|
410
488
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
489
|
+
query, urls = extract_mentioned_urls_from_query(
|
|
490
|
+
query=query,
|
|
491
|
+
bindings=initBindings,
|
|
492
|
+
base=base,
|
|
493
|
+
namespaces=initNs,
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
for url in urls:
|
|
497
|
+
try:
|
|
498
|
+
self.load(url)
|
|
499
|
+
except Exception as err:
|
|
500
|
+
self.logger.error(f'Failed to load {url}: {err}', url, err)
|
|
417
501
|
|
|
418
|
-
|
|
419
|
-
try:
|
|
420
|
-
self.load(url)
|
|
421
|
-
except Exception as err:
|
|
422
|
-
self.logger.error(f'Failed to load {url}: {err}', url, err)
|
|
502
|
+
NanopubQueryPlugin(graph=self.graph)(query, bindings=initBindings)
|
|
423
503
|
|
|
424
504
|
self.maybe_apply_inference()
|
|
425
505
|
|
|
@@ -429,7 +509,12 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
429
509
|
|
|
430
510
|
query_result = evalQuery(self.graph, query, initBindings, base)
|
|
431
511
|
|
|
432
|
-
|
|
512
|
+
try:
|
|
513
|
+
bindings = list(query_result['bindings'])
|
|
514
|
+
except KeyError:
|
|
515
|
+
# This was probably an ASK query
|
|
516
|
+
return query_result
|
|
517
|
+
|
|
433
518
|
for row in bindings:
|
|
434
519
|
for _, maybe_iri in row.items():
|
|
435
520
|
if (
|
|
@@ -537,12 +622,6 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
537
622
|
path=not_found.path,
|
|
538
623
|
)
|
|
539
624
|
|
|
540
|
-
self.graph.add((
|
|
541
|
-
source_uri,
|
|
542
|
-
RDF.type,
|
|
543
|
-
IOLANTA.Graph,
|
|
544
|
-
))
|
|
545
|
-
|
|
546
625
|
self.graph.add((
|
|
547
626
|
source_uri,
|
|
548
627
|
RDF.type,
|
|
@@ -550,38 +629,18 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
550
629
|
source_uri,
|
|
551
630
|
))
|
|
552
631
|
|
|
553
|
-
self.graph.add((
|
|
554
|
-
IOLANTA.Graph,
|
|
555
|
-
RDF.type,
|
|
556
|
-
RDFS.Class,
|
|
557
|
-
))
|
|
558
|
-
|
|
559
632
|
self._mark_as_loaded(source_uri)
|
|
560
633
|
|
|
561
634
|
return Loaded()
|
|
562
635
|
|
|
563
636
|
except Exception as err:
|
|
564
637
|
self.logger.info(f'{source} | Failed: {err}')
|
|
565
|
-
|
|
566
|
-
self.graph.add((
|
|
567
|
-
source_uri,
|
|
568
|
-
RDF.type,
|
|
569
|
-
IOLANTA.Graph,
|
|
570
|
-
))
|
|
571
|
-
|
|
572
638
|
self.graph.add((
|
|
573
639
|
URIRef(source),
|
|
574
640
|
RDF.type,
|
|
575
641
|
IOLANTA['failed'],
|
|
576
642
|
source_uri,
|
|
577
643
|
))
|
|
578
|
-
|
|
579
|
-
self.graph.add((
|
|
580
|
-
IOLANTA.Graph,
|
|
581
|
-
RDF.type,
|
|
582
|
-
RDFS.Class,
|
|
583
|
-
))
|
|
584
|
-
|
|
585
644
|
self._mark_as_loaded(source_uri)
|
|
586
645
|
|
|
587
646
|
return Loaded()
|
|
@@ -596,18 +655,6 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
596
655
|
))
|
|
597
656
|
source = _resolved_source
|
|
598
657
|
|
|
599
|
-
self.graph.add((
|
|
600
|
-
source_uri,
|
|
601
|
-
RDF.type,
|
|
602
|
-
IOLANTA.Graph,
|
|
603
|
-
))
|
|
604
|
-
|
|
605
|
-
self.graph.add((
|
|
606
|
-
IOLANTA.Graph,
|
|
607
|
-
RDF.type,
|
|
608
|
-
RDFS.Class,
|
|
609
|
-
))
|
|
610
|
-
|
|
611
658
|
self._mark_as_loaded(source_uri)
|
|
612
659
|
|
|
613
660
|
try: # noqa: WPS225
|
|
@@ -642,13 +689,7 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
642
689
|
)
|
|
643
690
|
|
|
644
691
|
if not quads:
|
|
645
|
-
self.logger.
|
|
646
|
-
self.graph.addN([(
|
|
647
|
-
source_uri,
|
|
648
|
-
RDF.type,
|
|
649
|
-
IOLANTA.Graph,
|
|
650
|
-
source_uri,
|
|
651
|
-
)])
|
|
692
|
+
self.logger.info('{source} | No data found', source=source)
|
|
652
693
|
return Loaded()
|
|
653
694
|
|
|
654
695
|
quad_tuples = [
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
import rdflib
|
|
7
|
+
from rdflib.plugins.sparql.sparql import Query
|
|
8
|
+
from rdflib.query import Result
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class SPARQLSpace:
|
|
13
|
+
"""SPARQL interface to the Web of Data."""
|
|
14
|
+
|
|
15
|
+
graph: rdflib.Dataset = field(
|
|
16
|
+
default_factory=functools.partial(
|
|
17
|
+
rdflib.Dataset,
|
|
18
|
+
default_union=True,
|
|
19
|
+
),
|
|
20
|
+
)
|
|
21
|
+
path: Annotated[
|
|
22
|
+
Path | None,
|
|
23
|
+
'Local directory to load into the graph.',
|
|
24
|
+
] = None
|
|
25
|
+
|
|
26
|
+
def query(self, query: str | Query, **bindings) -> Result:
|
|
27
|
+
"""Execute a SPARQL query."""
|
|
28
|
+
return self.graph.query(
|
|
29
|
+
query_object=query,
|
|
30
|
+
processor='sparqlspace',
|
|
31
|
+
initBindings=bindings,
|
|
32
|
+
)
|
|
@@ -11,15 +11,12 @@ iolanta/cli/models.py,sha256=cjbpowdzI4wAP0DUk3qoVHyimk6AZwlXi9CGmusZTuM,159
|
|
|
11
11
|
iolanta/cli/pretty_print.py,sha256=M6E3TmhzA6JY5GeUVmDZLmOh5u70-393PVit4voFKDI,977
|
|
12
12
|
iolanta/context.py,sha256=bZR-tbZIrDQ-Vby01PMDZ6ifxM-0YMK68RJvAsyqCTs,507
|
|
13
13
|
iolanta/conversions.py,sha256=hbLwRF1bAbOxy17eMWLHhYksbdCWN-v4-0y0wn3XSSg,1185
|
|
14
|
-
iolanta/cyberspace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
iolanta/cyberspace/inference/wikibase-claim.sparql,sha256=JSawj3VTc9ZPoU9mvh1w1AMYb3cWyZ3x1rEYWUsKZ6A,209
|
|
16
|
-
iolanta/cyberspace/inference/wikibase-statement-property.sparql,sha256=SkSHZZlxWVDwBM3aLo0Q7hLuOj9BsIQnXtcuAuwaxqU,240
|
|
17
|
-
iolanta/cyberspace/processor.py,sha256=rxO5MaZEoXD2Kzknq7eRH3yuv8kQ5UILy8qkJxramMY,21828
|
|
18
14
|
iolanta/data/cli.yaml,sha256=TsnldYXoY5GIzoNuPDvwBKGw8eAEForZW1FCKqKI0Kg,1029
|
|
19
|
-
iolanta/data/context.yaml,sha256=
|
|
15
|
+
iolanta/data/context.yaml,sha256=LUBasiBKgQeGAYjYV_T5XvgPlrdzACeKaZwY_rKzjtI,1636
|
|
16
|
+
iolanta/data/graph-triples.yamlld,sha256=oACKRwqWcMp6TBobXMG6gbbnaauyd6wlK-gH2vVkPps,241
|
|
20
17
|
iolanta/data/html.yaml,sha256=hVFdLWLy8FMY8xpOrJMYc-tE3S0Nq83xuxVkjRW_7rI,517
|
|
21
18
|
iolanta/data/iolanta.yaml,sha256=xubIFBNU02lmFXhgOSuyQwUcZD3xCqVfeVAZMvOxKbI,1433
|
|
22
|
-
iolanta/data/textual-browser.yaml,sha256=
|
|
19
|
+
iolanta/data/textual-browser.yaml,sha256=hWN-EtLCoA8FCuihZWIAvLktara6O6BB7_E_bNukEhk,3947
|
|
23
20
|
iolanta/ensure_is_context.py,sha256=9aok8asyEx7KPesOR28VBDb3Ch9kfc3eoCpQSJwj07U,717
|
|
24
21
|
iolanta/entry_points.py,sha256=DZbf-udlEwELFGqeWENj0M2BOUPOWlmGJdqyaEtnot0,504
|
|
25
22
|
iolanta/errors.py,sha256=t_RltahnoEvcytVa1BOq2MADgHps3JNd_h5-SFu7_wM,1250
|
|
@@ -31,7 +28,7 @@ iolanta/facets/cli/record.py,sha256=lBsECxLkwVSXC-yHmUwfosxAdLBI-0UoqHe8GOCablY,
|
|
|
31
28
|
iolanta/facets/cli/sparql/link.sparql,sha256=WtWEfLAvdGc2gP0IhZil6Vglkydc3VO24vk4GwRnR5I,163
|
|
32
29
|
iolanta/facets/cli/sparql/record.sparql,sha256=GBWkmNelvaSDbvl7v0-LsJHdjFPbsSAW49kNFOUeoGQ,63
|
|
33
30
|
iolanta/facets/errors.py,sha256=sEBmnzhFcRIgOT18hfNwyMMjry0waa6IB-jC2NVTA50,4124
|
|
34
|
-
iolanta/facets/facet.py,sha256=
|
|
31
|
+
iolanta/facets/facet.py,sha256=QByUVrvt_XVBoVhfuyk6lKO--pauhMEN79GWmgejdIo,2822
|
|
35
32
|
iolanta/facets/foaf_person_title/__init__.py,sha256=oj4MNVQvv8Dysb27xiWjtZCii8-nT7-WFa3WMWUwbtU,67
|
|
36
33
|
iolanta/facets/foaf_person_title/facet.py,sha256=Q9TajjGp1v729quDzAM_Lfzawls3yujp1Z_6jXrG3gY,632
|
|
37
34
|
iolanta/facets/foaf_person_title/sparql/names.sparql,sha256=p_2hHZXhEaJ8IwGlvLoN0vb0vhGqo44uAVRpDyTzflU,107
|
|
@@ -45,7 +42,7 @@ iolanta/facets/html/base.py,sha256=JcpK7YM_QQE9vwH5w5F_EgPkPv-XRzOrcZlVSy4LhIs,1
|
|
|
45
42
|
iolanta/facets/html/code_literal.py,sha256=qCddzBrg6Y5XMIKohFQ52Tf9GPOcU7bj83tfAU1FLLU,394
|
|
46
43
|
iolanta/facets/html/default.py,sha256=Dmf_kYiL2M954iigyYsiWrMstwZ1nvxKetuR6aW3xYY,647
|
|
47
44
|
iolanta/facets/icon.py,sha256=ddZcolx1Q5_wo3w0jqiCzcc5Lsru6-jA7s7oAd1T8Og,494
|
|
48
|
-
iolanta/facets/locator.py,sha256=
|
|
45
|
+
iolanta/facets/locator.py,sha256=oiktgFGOkhVNDh4KzFY1Os--9-MSY32NYlGr-OXXxqY,8561
|
|
49
46
|
iolanta/facets/page_title.py,sha256=TwgZK2g_e5UoWYjKNgDzzkmq1EI3cY58680iC8N9kZI,1407
|
|
50
47
|
iolanta/facets/qname.py,sha256=ztyBbjjcW8dNZzuiNMqhcWfAUxk-gSjbseVGrQE7kVY,531
|
|
51
48
|
iolanta/facets/textual_browser/__init__.py,sha256=sKgDvXOwib9n9d63kdtKCEv26-FoL0VN6zxDmfcheZ8,104
|
|
@@ -58,8 +55,8 @@ iolanta/facets/textual_browser/models.py,sha256=DqTBjhkkTt5mNwqr4DzNbPSqzV-QtNqf
|
|
|
58
55
|
iolanta/facets/textual_browser/page.py,sha256=NkcQ5rSKZRbp63C8ozgsR_iVhcKHGv_SytUCQyGa7ss,786
|
|
59
56
|
iolanta/facets/textual_browser/page_switcher.py,sha256=WOsFY9hSFEnuf3za1eCUhPaQ6uTaeBuMPIAHjHhnvDY,9950
|
|
60
57
|
iolanta/facets/textual_class/__init__.py,sha256=tiL0p-3JspGcBRj4qa3rmoBFAuadk71l2ja2lJN6CEs,75
|
|
61
|
-
iolanta/facets/textual_class/facets.py,sha256=
|
|
62
|
-
iolanta/facets/textual_class/sparql/instances.sparql,sha256=
|
|
58
|
+
iolanta/facets/textual_class/facets.py,sha256=tascZiue3tbYfpIsnP8yY2dgXQIQzoQ_HPzU7DbVbao,5999
|
|
59
|
+
iolanta/facets/textual_class/sparql/instances.sparql,sha256=EW4BmuNxiRDA8djuEtvZpLLJlNSIshvId4ExlaYPcZE,106
|
|
63
60
|
iolanta/facets/textual_default/__init__.py,sha256=snxA0FEY9qfAxNv3MlZLrJsXugD4dvs5hLStZWV7soM,158
|
|
64
61
|
iolanta/facets/textual_default/facets.py,sha256=Pf5GttQ7EG0ZodjwwVXzYMffHus3MAZdJUIcbddcYtw,4738
|
|
65
62
|
iolanta/facets/textual_default/sparql/inverse-properties.sparql,sha256=daHNdhmh92Q77CSf7ULbhxg57CuYsRFfMnXQz4VYEug,64
|
|
@@ -86,6 +83,7 @@ iolanta/facets/textual_ontology/__init__.py,sha256=3H6bfYaEbXFr90C6ZpGWC4O-24uaO
|
|
|
86
83
|
iolanta/facets/textual_ontology/facets.py,sha256=60g8ANmePb9_i_-d4ui-FdtNwg9aktrOKXHkTQtLp1w,3338
|
|
87
84
|
iolanta/facets/textual_ontology/sparql/terms.sparql,sha256=oVLxN452nqog_95qRaTWnvar6rxPNxPrRonSo7oFFTg,324
|
|
88
85
|
iolanta/facets/textual_ontology/sparql/visualization-vocab.sparql,sha256=q9TmU15deL0da28mpo_8W8fgMSEcENfYeqLyM0zVbTg,65
|
|
86
|
+
iolanta/facets/textual_property_pairs_table.py,sha256=Drqc_G_6QhzNmrrfDU170eKTGrVmvQ6JMYu4ir--iUk,4176
|
|
89
87
|
iolanta/facets/textual_provenance/__init__.py,sha256=k5-_iK8Lrdwr5ZEJaDxq-UhGYe4G_adXVqGfOA5DAP8,114
|
|
90
88
|
iolanta/facets/textual_provenance/facets.py,sha256=vv3UQsI2duB36DW5Zkw3sqgAXBPmK_xAo7cU0O7jF8g,3767
|
|
91
89
|
iolanta/facets/textual_provenance/sparql/graphs.sparql,sha256=B45uKFd-1vrBuMDSbTURjUUEjHt51vAbqdL4tUcgMvk,103
|
|
@@ -96,7 +94,7 @@ iolanta/facets/title/sparql/title.sparql,sha256=4rz47tjwX2OJavWMzftaYKil1-ZHB76Z
|
|
|
96
94
|
iolanta/facets/wikibase_statement_title/__init__.py,sha256=_yk1akxgSJOiUBJIc8QGrD2vovvmx_iw_vJDuv1rD7M,91
|
|
97
95
|
iolanta/facets/wikibase_statement_title/facets.py,sha256=mUH7twlAgoeX7DgLQuRBQv4ORT6GWbN-0eJ1aliSfiQ,724
|
|
98
96
|
iolanta/facets/wikibase_statement_title/sparql/statement-title.sparql,sha256=n07DQWxKqB5c3CA4kacq2HSN0R0dLgnMnLP1AxMo5YA,320
|
|
99
|
-
iolanta/iolanta.py,sha256=
|
|
97
|
+
iolanta/iolanta.py,sha256=wCt_7aUz9TOvZTJvpJQ-qVWkOpmM531uyxIk9l3n-lk,14229
|
|
100
98
|
iolanta/loaders/__init__.py,sha256=QTiKCsQc1BTS-IlY2CQsN9iVpEIPqYFvI9ERMYVZCbU,99
|
|
101
99
|
iolanta/loaders/base.py,sha256=-DxYwqG1bfDXB2p_S-mKpkc_3Sh14OHhePbe65Iq3-s,3381
|
|
102
100
|
iolanta/loaders/data_type_choice.py,sha256=zRUXBIzjvuW28P_dhMDVevE9C8EFEIx2_X39WydWrtM,1982
|
|
@@ -109,7 +107,7 @@ iolanta/loaders/scheme_choice.py,sha256=GHA4JAD-Qq3uNdej4vs_bCrN1WMRshVRvOMxaYyP
|
|
|
109
107
|
iolanta/models.py,sha256=L0iFaga4-PCaWP18WmT03NLK_oT7q49V0WMTQskoffI,2824
|
|
110
108
|
iolanta/namespaces.py,sha256=fyWDCGPwU8Cs8d-Vmci4H0-fuIe7BMSevvEKFvG7Gf4,1153
|
|
111
109
|
iolanta/node_to_qname.py,sha256=a82_qpgT87cbekY_76tTkl4Z-6Rz6am4UGIQChUf9Y0,794
|
|
112
|
-
iolanta/parse_quads.py,sha256=
|
|
110
|
+
iolanta/parse_quads.py,sha256=2UydATeDassOrpjWfjwWnMjnSS5RZw5KBFIeKHGJ36M,2660
|
|
113
111
|
iolanta/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
114
112
|
iolanta/parsers/base.py,sha256=ZFjj0BLzW4985BdC6PwbngenhMuSYW5mNLpprZRWjhA,1048
|
|
115
113
|
iolanta/parsers/dict_parser.py,sha256=t_OK2meUh49DqSaOYkSgEwxMKUNNgjJY8rZAyL4NQKI,4546
|
|
@@ -124,9 +122,15 @@ iolanta/resolvers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
124
122
|
iolanta/resolvers/base.py,sha256=cc9bcrVZ0wTwn85I-IYCwcIRU5Lwaph8D00C0dwSOm8,302
|
|
125
123
|
iolanta/resolvers/python_import.py,sha256=kDOhApBDFfxnrDgK9M7ztMkqXfcny81Zo86FgPFb-LI,1301
|
|
126
124
|
iolanta/shortcuts.py,sha256=j8b0E_yeoas8GumsPOfxO2v2jO0noqpmKJ6LFxFfsu4,1892
|
|
125
|
+
iolanta/sparqlspace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
126
|
+
iolanta/sparqlspace/cli.py,sha256=pb6q03lzrU8OaZ4A3QAQEmaFYcQ_-sHUrPhRs6GE88w,1590
|
|
127
|
+
iolanta/sparqlspace/inference/wikibase-claim.sparql,sha256=JSawj3VTc9ZPoU9mvh1w1AMYb3cWyZ3x1rEYWUsKZ6A,209
|
|
128
|
+
iolanta/sparqlspace/inference/wikibase-statement-property.sparql,sha256=SkSHZZlxWVDwBM3aLo0Q7hLuOj9BsIQnXtcuAuwaxqU,240
|
|
129
|
+
iolanta/sparqlspace/processor.py,sha256=CXxdi7ORpddXxPh0UlnRG7oqNT9q-WdSPMxqB4CgOis,23570
|
|
130
|
+
iolanta/sparqlspace/sparqlspace.py,sha256=Y8_ZPXwuGEXbEes6XQjaQWA2Zv9y8SWxMPDFdqVBGFo,796
|
|
127
131
|
iolanta/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
128
132
|
iolanta/widgets/mixin.py,sha256=nDRCOc-gizCf1a5DAcYs4hW8eZEd6pHBPFsfm0ncv7E,251
|
|
129
|
-
iolanta-2.0.
|
|
130
|
-
iolanta-2.0.
|
|
131
|
-
iolanta-2.0.
|
|
132
|
-
iolanta-2.0.
|
|
133
|
+
iolanta-2.0.5.dist-info/METADATA,sha256=YSkBOGK0TGD_gdzzJKXxbm52W-4qtlVFpAumPPweabE,2230
|
|
134
|
+
iolanta-2.0.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
135
|
+
iolanta-2.0.5.dist-info/entry_points.txt,sha256=z9RPLmGuz3tYGPV7Qf4nNjuSJYdTUS9enC4595poe-M,221
|
|
136
|
+
iolanta-2.0.5.dist-info/RECORD,,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
[console_scripts]
|
|
2
2
|
iolanta=iolanta.cli:app
|
|
3
|
+
sparqlspace=iolanta.sparqlspace.cli:app
|
|
3
4
|
|
|
4
5
|
[iolanta.plugins]
|
|
5
6
|
base=iolanta:IolantaBase
|
|
6
7
|
|
|
7
8
|
[rdf.plugins.queryprocessor]
|
|
8
|
-
|
|
9
|
+
sparqlspace=iolanta.sparqlspace.processor:GlobalSPARQLProcessor
|
|
9
10
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|