iolanta 2.1.6__py3-none-any.whl → 2.1.8__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/cli/main.py +1 -1
- iolanta/data/context.yaml +7 -7
- iolanta/data/iolanta.yaml +2 -2
- iolanta/data/textual-browser.yaml +7 -27
- iolanta/declension/data/declension.yamlld +7 -7
- iolanta/facets/facet.py +4 -0
- iolanta/facets/mkdocs_material_insiders_markdown/__init__.py +6 -0
- iolanta/facets/mkdocs_material_insiders_markdown/data/mkdocs_material_insiders_markdown.yamlld +20 -0
- iolanta/facets/mkdocs_material_insiders_markdown/facet.py +86 -0
- iolanta/facets/mkdocs_material_insiders_markdown/templates/datatype.jinja2.md +24 -0
- iolanta/facets/textual_browser/location.py +3 -1
- iolanta/facets/textual_browser/page_switcher.py +10 -0
- iolanta/facets/textual_class/facets.py +3 -0
- iolanta/facets/textual_class/textual-class.yamlld +25 -0
- iolanta/facets/textual_default/facets.py +50 -15
- iolanta/facets/textual_default/sparql/inverse-properties.sparql +1 -1
- iolanta/facets/textual_default/sparql/properties.sparql +2 -2
- iolanta/facets/textual_default/widgets.py +14 -6
- iolanta/iolanta.py +4 -41
- iolanta/labeled_triple_set/data/labeled_triple_set.yamlld +7 -7
- iolanta/mcp/cli.py +3 -2
- iolanta/models.py +0 -3
- iolanta/namespaces.py +2 -2
- iolanta/parse_quads.py +2 -2
- iolanta/sparqlspace/inference/wikidata-prop-label.sparql +10 -0
- iolanta/sparqlspace/inference/wikidata-statement-label.sparql +27 -0
- iolanta/sparqlspace/processor.py +78 -76
- {iolanta-2.1.6.dist-info → iolanta-2.1.8.dist-info}/METADATA +4 -3
- {iolanta-2.1.6.dist-info → iolanta-2.1.8.dist-info}/RECORD +31 -26
- {iolanta-2.1.6.dist-info → iolanta-2.1.8.dist-info}/WHEEL +1 -1
- {iolanta-2.1.6.dist-info → iolanta-2.1.8.dist-info}/entry_points.txt +1 -1
- iolanta/sparqlspace/inference/wikibase-claim.sparql +0 -9
- iolanta/sparqlspace/inference/wikibase-statement-property.sparql +0 -9
iolanta/cli/main.py
CHANGED
|
@@ -11,7 +11,7 @@ from rdflib import Literal, URIRef
|
|
|
11
11
|
from rich.console import Console
|
|
12
12
|
from rich.markdown import Markdown
|
|
13
13
|
from rich.table import Table
|
|
14
|
-
from typer import Argument, Exit, Option, Typer
|
|
14
|
+
from typer import Argument, Context, Exit, Option, Typer
|
|
15
15
|
from yarl import URL
|
|
16
16
|
|
|
17
17
|
from iolanta.cli.models import LogLevel
|
iolanta/data/context.yaml
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"@context":
|
|
2
|
-
rdfs: "
|
|
3
|
-
rdf:
|
|
2
|
+
rdfs: "http://www.w3.org/2000/01/rdf-schema#"
|
|
3
|
+
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
|
|
4
4
|
iolanta: https://iolanta.tech/
|
|
5
|
-
owl:
|
|
5
|
+
owl: http://www.w3.org/2002/07/owl#
|
|
6
6
|
schema: https://schema.org/
|
|
7
|
-
xsd:
|
|
8
|
-
skos:
|
|
9
|
-
foaf:
|
|
10
|
-
vann:
|
|
7
|
+
xsd: http://www.w3.org/2001/XMLSchema#
|
|
8
|
+
skos: http://www.w3.org/2004/02/skos/core#
|
|
9
|
+
foaf: http://xmlns.com/foaf/0.1/
|
|
10
|
+
vann: http://purl.org/vocab/vann/
|
|
11
11
|
|
|
12
12
|
"@vocab": "local:"
|
|
13
13
|
"@base": "local:"
|
iolanta/data/iolanta.yaml
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
foaf: https://xmlns.com/foaf/0.1/
|
|
5
5
|
owl: https://www.w3.org/2002/07/owl#
|
|
6
6
|
iolanta: https://iolanta.tech/
|
|
7
|
-
rdfs: "
|
|
8
|
-
rdf:
|
|
7
|
+
rdfs: "http://www.w3.org/2000/01/rdf-schema#"
|
|
8
|
+
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
|
|
9
9
|
|
|
10
10
|
$included:
|
|
11
11
|
- $id: iolanta:Facet
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"@context":
|
|
2
2
|
"@import": https://json-ld.org/contexts/dollar-convenience.jsonld
|
|
3
|
-
vann:
|
|
4
|
-
foaf:
|
|
5
|
-
owl:
|
|
3
|
+
vann: http://purl.org/vocab/vann/
|
|
4
|
+
foaf: http://xmlns.com/foaf/0.1/
|
|
5
|
+
owl: http://www.w3.org/2002/07/owl#
|
|
6
6
|
iolanta: https://iolanta.tech/
|
|
7
|
-
rdfs: "
|
|
8
|
-
rdf:
|
|
7
|
+
rdfs: "http://www.w3.org/2000/01/rdf-schema#"
|
|
8
|
+
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
|
|
9
9
|
np: https://www.nanopub.org/nschema#
|
|
10
|
-
dcterms:
|
|
11
|
-
xsd:
|
|
10
|
+
dcterms: http://purl.org/dc/terms/
|
|
11
|
+
xsd: http://www.w3.org/2001/XMLSchema#
|
|
12
12
|
|
|
13
13
|
iolanta:outputs:
|
|
14
14
|
"@type": "@id"
|
|
@@ -88,21 +88,6 @@
|
|
|
88
88
|
iolanta:hasDefaultFacet:
|
|
89
89
|
$id: pkg:pypi/iolanta#textual-link
|
|
90
90
|
|
|
91
|
-
- $id: https://wikiba.se/ontology#Statement
|
|
92
|
-
iolanta:hasInstanceFacet:
|
|
93
|
-
$id: pkg:pypi/iolanta#wikibase-statement-title
|
|
94
|
-
$: Title
|
|
95
|
-
→: https://iolanta.tech/datatypes/title
|
|
96
|
-
|
|
97
|
-
- $id: rdfs:Class
|
|
98
|
-
iolanta:hasInstanceFacet:
|
|
99
|
-
$id: pkg:pypi/iolanta#textual-class
|
|
100
|
-
$: Instances
|
|
101
|
-
→: https://iolanta.tech/cli/textual
|
|
102
|
-
⪯:
|
|
103
|
-
- pkg:pypi/iolanta#textual-browser
|
|
104
|
-
- pkg:pypi/iolanta#textual-inverse-properties
|
|
105
|
-
|
|
106
91
|
- $id: owl:Ontology
|
|
107
92
|
iolanta:hasInstanceFacet:
|
|
108
93
|
$id: pkg:pypi/iolanta#textual-ontology
|
|
@@ -125,10 +110,5 @@
|
|
|
125
110
|
→: https://iolanta.tech/cli/textual
|
|
126
111
|
↦: ASK WHERE { ?subject $this ?object }
|
|
127
112
|
|
|
128
|
-
- $id: pkg:pypi/iolanta#textual-class
|
|
129
|
-
↦:
|
|
130
|
-
- ASK WHERE { ?instance a $this }
|
|
131
|
-
- ASK WHERE { $this rdfs:subClassOf ?superclass }
|
|
132
|
-
|
|
133
113
|
- $id: https://iolanta.tech/cli/textual
|
|
134
114
|
iolanta:when-no-facet-found: pkg:pypi/iolanta#textual-no-facet-found
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"@context":
|
|
2
2
|
"@import": https://json-ld.org/contexts/dollar-convenience.jsonld
|
|
3
|
-
vann:
|
|
4
|
-
foaf:
|
|
5
|
-
owl:
|
|
3
|
+
vann: http://purl.org/vocab/vann/
|
|
4
|
+
foaf: http://xmlns.com/foaf/0.1/
|
|
5
|
+
owl: http://www.w3.org/2002/07/owl#
|
|
6
6
|
iolanta: https://iolanta.tech/
|
|
7
|
-
rdfs: "
|
|
8
|
-
rdf:
|
|
9
|
-
dcterms:
|
|
10
|
-
dcam:
|
|
7
|
+
rdfs: "http://www.w3.org/2000/01/rdf-schema#"
|
|
8
|
+
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
|
|
9
|
+
dcterms: http://purl.org/dc/terms/
|
|
10
|
+
dcam: http://purl.org/dc/dcam/
|
|
11
11
|
|
|
12
12
|
iolanta:outputs:
|
|
13
13
|
"@type": "@id"
|
iolanta/facets/facet.py
CHANGED
|
@@ -20,6 +20,10 @@ class Facet(Generic[FacetOutput]):
|
|
|
20
20
|
iolanta: 'iolanta.Iolanta' = field(repr=False)
|
|
21
21
|
as_datatype: Optional[NotLiteralNode] = None
|
|
22
22
|
|
|
23
|
+
def __post_init__(self):
|
|
24
|
+
if type(self.this) == str:
|
|
25
|
+
raise ValueError(f'Facet {self.__class__.__name__} received a string as this: {self.this}')
|
|
26
|
+
|
|
23
27
|
@property
|
|
24
28
|
def stored_queries_path(self) -> Path:
|
|
25
29
|
"""Construct directory for stored queries for this facet."""
|
iolanta/facets/mkdocs_material_insiders_markdown/data/mkdocs_material_insiders_markdown.yamlld
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"@context":
|
|
2
|
+
"@import": https://json-ld.org/contexts/dollar-convenience.jsonld
|
|
3
|
+
rdfs: "http://www.w3.org/2000/01/rdf-schema#"
|
|
4
|
+
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
|
|
5
|
+
iolanta: https://iolanta.tech/
|
|
6
|
+
|
|
7
|
+
$: rdfs:label
|
|
8
|
+
|
|
9
|
+
→:
|
|
10
|
+
"@type": "@id"
|
|
11
|
+
"@id": iolanta:outputs
|
|
12
|
+
|
|
13
|
+
↦: iolanta:matches
|
|
14
|
+
|
|
15
|
+
$id: pkg:pypi/iolanta#mkdocs-material-insiders-markdown-datatype
|
|
16
|
+
$: OutputDatatype (mkdocs-material-insiders-markdown)
|
|
17
|
+
|
|
18
|
+
→: https://iolanta.tech/datatypes/mkdocs-material-insiders-markdown
|
|
19
|
+
|
|
20
|
+
↦: ASK WHERE { $this a iolanta:OutputDatatype }
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from jinja2 import Environment, FileSystemLoader
|
|
4
|
+
from rdflib import URIRef
|
|
5
|
+
|
|
6
|
+
from iolanta.facets.facet import Facet
|
|
7
|
+
from iolanta.namespaces import DATATYPES, IOLANTA, RDF, RDFS
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MkDocsMaterialInsidersMarkdownFacet(Facet[str]):
|
|
11
|
+
"""Render rdfs:Datatype nodes as mkdocs-material-insiders-markdown."""
|
|
12
|
+
|
|
13
|
+
META = Path(__file__).parent / 'data' / 'mkdocs_material_insiders_markdown.yamlld'
|
|
14
|
+
"""Render rdfs:Datatype nodes as mkdocs-material-insiders-markdown."""
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def _template_env(self) -> Environment:
|
|
18
|
+
"""Jinja2 template environment."""
|
|
19
|
+
template_path = Path(__file__).parent / 'templates'
|
|
20
|
+
return Environment(
|
|
21
|
+
loader=FileSystemLoader(str(template_path)),
|
|
22
|
+
autoescape=False,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def show(self) -> str:
|
|
26
|
+
"""Render the datatype as markdown."""
|
|
27
|
+
# Get the label using title facet
|
|
28
|
+
label = self.render(
|
|
29
|
+
self.this,
|
|
30
|
+
as_datatype=DATATYPES.title,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Get the comment/description
|
|
34
|
+
comment_rows = self.query(
|
|
35
|
+
"""
|
|
36
|
+
SELECT ?comment WHERE {
|
|
37
|
+
$this rdfs:comment ?comment .
|
|
38
|
+
}
|
|
39
|
+
LIMIT 1
|
|
40
|
+
""",
|
|
41
|
+
this=self.this,
|
|
42
|
+
)
|
|
43
|
+
comment = str(comment_rows[0]['comment']) if comment_rows else None
|
|
44
|
+
|
|
45
|
+
# Get all types (rdf:type)
|
|
46
|
+
type_rows = self.query(
|
|
47
|
+
"""
|
|
48
|
+
SELECT ?type WHERE {
|
|
49
|
+
$this rdf:type ?type .
|
|
50
|
+
}
|
|
51
|
+
""",
|
|
52
|
+
this=self.this,
|
|
53
|
+
)
|
|
54
|
+
types = [
|
|
55
|
+
{
|
|
56
|
+
'uri': row['type'],
|
|
57
|
+
'title': self.render(row['type'], as_datatype=DATATYPES.title),
|
|
58
|
+
}
|
|
59
|
+
for row in type_rows
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
# Get all superclasses (rdfs:subClassOf)
|
|
63
|
+
superclass_rows = self.query(
|
|
64
|
+
"""
|
|
65
|
+
SELECT ?superclass WHERE {
|
|
66
|
+
$this rdfs:subClassOf ?superclass .
|
|
67
|
+
}
|
|
68
|
+
""",
|
|
69
|
+
this=self.this,
|
|
70
|
+
)
|
|
71
|
+
superclasses = [
|
|
72
|
+
{
|
|
73
|
+
'uri': row['superclass'],
|
|
74
|
+
'title': self.render(row['superclass'], as_datatype=DATATYPES.title),
|
|
75
|
+
}
|
|
76
|
+
for row in superclass_rows
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
template = self._template_env.get_template('datatype.jinja2.md')
|
|
80
|
+
return template.render(
|
|
81
|
+
label=label,
|
|
82
|
+
comment=comment,
|
|
83
|
+
types=types,
|
|
84
|
+
superclasses=superclasses,
|
|
85
|
+
)
|
|
86
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# {{ label }}
|
|
2
|
+
|
|
3
|
+
<table>
|
|
4
|
+
<thead>
|
|
5
|
+
</thead>
|
|
6
|
+
<tbody>
|
|
7
|
+
{% if types %}
|
|
8
|
+
<tr>
|
|
9
|
+
<td>∈ Instance Of</td>
|
|
10
|
+
<td>{% for type in types %}<code><a href="{{ type.uri }}">{{ type.title }}</a></code>{% if not loop.last %}, {% endif %}{% endfor %}</td>
|
|
11
|
+
</tr>
|
|
12
|
+
{% endif %}
|
|
13
|
+
{% if superclasses %}
|
|
14
|
+
<tr>
|
|
15
|
+
<td>⊊ Subclass Of</td>
|
|
16
|
+
<td>{% for superclass in superclasses %}<code><a href="{{ superclass.uri }}">{{ superclass.title }}</a></code>{% if not loop.last %}, {% endif %}{% endfor %}</td>
|
|
17
|
+
</tr>
|
|
18
|
+
{% endif %}
|
|
19
|
+
</tbody>
|
|
20
|
+
</table>
|
|
21
|
+
|
|
22
|
+
{% if comment %}
|
|
23
|
+
{{ comment | safe }}
|
|
24
|
+
{% endif %}
|
|
@@ -2,11 +2,13 @@ from dataclasses import dataclass
|
|
|
2
2
|
|
|
3
3
|
from rdflib import URIRef
|
|
4
4
|
|
|
5
|
+
from iolanta.models import NotLiteralNode
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
@dataclass
|
|
7
9
|
class Location:
|
|
8
10
|
"""Unique ID and IRI associated with it."""
|
|
9
11
|
|
|
10
12
|
page_id: str
|
|
11
|
-
url:
|
|
13
|
+
url: NotLiteralNode
|
|
12
14
|
facet_iri: URIRef | None = None
|
|
@@ -217,6 +217,9 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
217
217
|
|
|
218
218
|
def action_reload(self):
|
|
219
219
|
"""Reset Iolanta graph and re-render current view."""
|
|
220
|
+
if self.history.current is None:
|
|
221
|
+
return
|
|
222
|
+
|
|
220
223
|
self.iolanta.reset()
|
|
221
224
|
|
|
222
225
|
self.run_worker(
|
|
@@ -271,6 +274,13 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
271
274
|
facet_iri: str | None = None,
|
|
272
275
|
):
|
|
273
276
|
"""Go to an IRI."""
|
|
277
|
+
# Convert string to URIRef if needed.
|
|
278
|
+
# This happens when called via Textual action strings (from keyboard bindings
|
|
279
|
+
# in page.py line 24), which serialize URIRefs to strings in f-strings.
|
|
280
|
+
# Direct calls (like line 77) pass URIRef objects directly.
|
|
281
|
+
if isinstance(this, str):
|
|
282
|
+
this = URIRef(this)
|
|
283
|
+
|
|
274
284
|
self.run_worker(
|
|
275
285
|
functools.partial(
|
|
276
286
|
self.render_iri,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import itertools
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import ClassVar, Iterable
|
|
4
5
|
|
|
5
6
|
import funcy
|
|
@@ -186,6 +187,8 @@ class InstancesBody(Vertical):
|
|
|
186
187
|
class Class(Facet[Widget]):
|
|
187
188
|
"""Render instances of a class."""
|
|
188
189
|
|
|
190
|
+
META = Path(__file__).parent / 'textual-class.yamlld'
|
|
191
|
+
|
|
189
192
|
def stream_instances(self) -> Iterable[NotLiteralNode]:
|
|
190
193
|
"""
|
|
191
194
|
Query and stream class instances lazily.
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
|
|
7
|
+
$: rdfs:label
|
|
8
|
+
→:
|
|
9
|
+
"@type": "@id"
|
|
10
|
+
"@id": iolanta:outputs
|
|
11
|
+
⪯:
|
|
12
|
+
"@type": "@id"
|
|
13
|
+
"@id": iolanta:is-preferred-over
|
|
14
|
+
↦: iolanta:matches
|
|
15
|
+
|
|
16
|
+
$id: pkg:pypi/iolanta#textual-class
|
|
17
|
+
|
|
18
|
+
$: Instances
|
|
19
|
+
→: https://iolanta.tech/cli/textual
|
|
20
|
+
|
|
21
|
+
⪯:
|
|
22
|
+
- pkg:pypi/iolanta#textual-browser
|
|
23
|
+
- pkg:pypi/iolanta#textual-inverse-properties
|
|
24
|
+
|
|
25
|
+
↦: ASK WHERE { ?instance a $this }
|
|
@@ -4,7 +4,7 @@ from xml.dom import minidom # noqa: S408
|
|
|
4
4
|
import funcy
|
|
5
5
|
from rdflib.term import Literal, Node
|
|
6
6
|
from rich.syntax import Syntax
|
|
7
|
-
from textual.containers import VerticalScroll
|
|
7
|
+
from textual.containers import Vertical, VerticalScroll
|
|
8
8
|
from textual.widget import Widget
|
|
9
9
|
from textual.widgets import Static
|
|
10
10
|
|
|
@@ -22,17 +22,28 @@ from iolanta.models import NotLiteralNode
|
|
|
22
22
|
from iolanta.namespaces import DC, RDFS, SDO
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
class Description(Static):
|
|
26
|
+
"""Static widget with padding for descriptions."""
|
|
27
|
+
|
|
28
|
+
DEFAULT_CSS = """
|
|
29
|
+
Description {
|
|
30
|
+
padding: 1;
|
|
31
|
+
}
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
|
|
25
35
|
class TextualDefaultFacet(Facet[Widget]): # noqa: WPS214
|
|
26
36
|
"""Default rendering engine."""
|
|
27
37
|
|
|
28
38
|
query_file_name = 'properties.sparql'
|
|
39
|
+
properties_on_the_right = False
|
|
29
40
|
|
|
30
41
|
@functools.cached_property
|
|
31
42
|
def grouped_properties(self) -> dict[NotLiteralNode, list[Node]]:
|
|
32
43
|
"""Properties of current node & their values."""
|
|
33
44
|
property_rows = self.stored_query(
|
|
34
45
|
self.query_file_name,
|
|
35
|
-
|
|
46
|
+
this=self.this,
|
|
36
47
|
)
|
|
37
48
|
|
|
38
49
|
property_pairs = [
|
|
@@ -75,10 +86,18 @@ class TextualDefaultFacet(Facet[Widget]): # noqa: WPS214
|
|
|
75
86
|
for property_value in property_values
|
|
76
87
|
]
|
|
77
88
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
if self.properties_on_the_right:
|
|
90
|
+
# Property name on the right (last column), values on the left (first column)
|
|
91
|
+
yield PropertyRow(
|
|
92
|
+
PropertyValues(*property_values),
|
|
93
|
+
property_name,
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
# Property name on the left (first column), values on the right (last column)
|
|
97
|
+
yield PropertyRow(
|
|
98
|
+
property_name,
|
|
99
|
+
PropertyValues(*property_values),
|
|
100
|
+
)
|
|
82
101
|
|
|
83
102
|
@functools.cached_property
|
|
84
103
|
def description(self) -> str | Syntax | None:
|
|
@@ -134,22 +153,38 @@ class TextualDefaultFacet(Facet[Widget]): # noqa: WPS214
|
|
|
134
153
|
|
|
135
154
|
def show(self) -> Widget:
|
|
136
155
|
"""Render the content."""
|
|
137
|
-
return VerticalScroll(
|
|
138
|
-
PageTitle(self.this),
|
|
139
|
-
Static(self.description or ''),
|
|
140
|
-
self.properties,
|
|
141
|
-
)
|
|
142
156
|
|
|
157
|
+
widgets = [PageTitle(self.this)]
|
|
158
|
+
|
|
159
|
+
if self.description:
|
|
160
|
+
widgets.append(Description(self.description))
|
|
161
|
+
|
|
162
|
+
widgets.append(self.properties)
|
|
163
|
+
|
|
164
|
+
return VerticalScroll(*widgets)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class PageFooter(PageTitle):
|
|
168
|
+
"""Page footer."""
|
|
169
|
+
|
|
170
|
+
DEFAULT_CSS = """
|
|
171
|
+
PageFooter {
|
|
172
|
+
dock: bottom;
|
|
173
|
+
background: darkmagenta;
|
|
174
|
+
}
|
|
175
|
+
"""
|
|
143
176
|
|
|
144
177
|
class InverseProperties(TextualDefaultFacet):
|
|
145
178
|
"""Inverse properties view."""
|
|
146
179
|
|
|
147
180
|
query_file_name = 'inverse-properties.sparql'
|
|
181
|
+
properties_on_the_right = True
|
|
148
182
|
|
|
149
183
|
def show(self) -> Widget:
|
|
150
184
|
"""Render the content."""
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
185
|
+
return Vertical(
|
|
186
|
+
VerticalScroll(
|
|
187
|
+
self.properties,
|
|
188
|
+
),
|
|
189
|
+
PageFooter(self.this, extra='[i]& its inverse RDF properties[/i]'),
|
|
155
190
|
)
|
|
@@ -25,6 +25,7 @@ class PropertyName(Widget, can_focus=True, inherit_bindings=False):
|
|
|
25
25
|
width: 15%;
|
|
26
26
|
height: auto;
|
|
27
27
|
margin-right: 1;
|
|
28
|
+
text-style: bold;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
PropertyName:hover {
|
|
@@ -60,7 +61,8 @@ class PropertyName(Widget, can_focus=True, inherit_bindings=False):
|
|
|
60
61
|
|
|
61
62
|
def render_title(self):
|
|
62
63
|
"""Render title in a separate thread."""
|
|
63
|
-
|
|
64
|
+
title = self.app.iolanta.render(self.iri, DATATYPES.title)
|
|
65
|
+
return f'⤚{title}→'
|
|
64
66
|
|
|
65
67
|
def render(self) -> RenderResult:
|
|
66
68
|
"""Render node title."""
|
|
@@ -147,6 +149,13 @@ class PropertyValue(Widget, can_focus=True, inherit_bindings=False):
|
|
|
147
149
|
"""Return the property IRI for compatibility."""
|
|
148
150
|
return self.property_value
|
|
149
151
|
|
|
152
|
+
def render_title(self):
|
|
153
|
+
"""Render title in a separate thread."""
|
|
154
|
+
return self.app.iolanta.render(
|
|
155
|
+
self.iri,
|
|
156
|
+
as_datatype=DATATYPES.title,
|
|
157
|
+
)
|
|
158
|
+
|
|
150
159
|
def on_worker_state_changed(self, event: Worker.StateChanged):
|
|
151
160
|
"""Show the title after it has been rendered."""
|
|
152
161
|
match event.state:
|
|
@@ -191,7 +200,9 @@ class PropertiesContainer(Vertical):
|
|
|
191
200
|
DEFAULT_CSS = """
|
|
192
201
|
PropertiesContainer {
|
|
193
202
|
height: auto;
|
|
194
|
-
|
|
203
|
+
padding: 1;
|
|
204
|
+
}
|
|
205
|
+
"""
|
|
195
206
|
|
|
196
207
|
def render_all_properties(self):
|
|
197
208
|
"""Render all property names & values."""
|
|
@@ -199,10 +210,7 @@ class PropertiesContainer(Vertical):
|
|
|
199
210
|
|
|
200
211
|
widget: PropertyName | PropertyValue
|
|
201
212
|
for widget in widgets:
|
|
202
|
-
widget.renderable =
|
|
203
|
-
widget.iri,
|
|
204
|
-
as_datatype=DATATYPES.title,
|
|
205
|
-
)
|
|
213
|
+
widget.renderable = widget.render_title()
|
|
206
214
|
|
|
207
215
|
def on_mount(self):
|
|
208
216
|
"""Initiate rendering in the background."""
|
iolanta/iolanta.py
CHANGED
|
@@ -119,7 +119,7 @@ class Iolanta: # noqa: WPS214
|
|
|
119
119
|
processor='sparqlspace',
|
|
120
120
|
initBindings=kwargs,
|
|
121
121
|
)
|
|
122
|
-
except
|
|
122
|
+
except SyntaxError as err:
|
|
123
123
|
raise SPARQLParseException(
|
|
124
124
|
error=err,
|
|
125
125
|
query=query_text,
|
|
@@ -171,8 +171,9 @@ class Iolanta: # noqa: WPS214
|
|
|
171
171
|
self.logger.error(f'{source} | {parser_not_found}')
|
|
172
172
|
continue
|
|
173
173
|
except YAMLLDError as yaml_ld_error:
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
# .add() only processes local files, so errors should be raised
|
|
175
|
+
self.logger.error(f'{source_file} | {yaml_ld_error}')
|
|
176
|
+
raise
|
|
176
177
|
except ValueError as value_error:
|
|
177
178
|
self.logger.error(f'{source} | {value_error}')
|
|
178
179
|
continue
|
|
@@ -307,44 +308,6 @@ class Iolanta: # noqa: WPS214
|
|
|
307
308
|
error=err,
|
|
308
309
|
) from err
|
|
309
310
|
|
|
310
|
-
def render_all(
|
|
311
|
-
self,
|
|
312
|
-
node: Node,
|
|
313
|
-
as_datatype: NotLiteralNode,
|
|
314
|
-
) -> Iterable[Any]:
|
|
315
|
-
"""Find all possible Iolanta facets for a node and render them."""
|
|
316
|
-
choices = list(
|
|
317
|
-
FacetFinder(
|
|
318
|
-
iolanta=self,
|
|
319
|
-
node=node,
|
|
320
|
-
as_datatype=as_datatype,
|
|
321
|
-
).choices(),
|
|
322
|
-
)
|
|
323
|
-
|
|
324
|
-
pairs = [
|
|
325
|
-
(self.facet_resolver[row['facet']], row['output_datatype'])
|
|
326
|
-
for row in choices
|
|
327
|
-
]
|
|
328
|
-
|
|
329
|
-
facet_instances = [
|
|
330
|
-
facet_class(
|
|
331
|
-
this=node,
|
|
332
|
-
iolanta=self,
|
|
333
|
-
as_datatype=output_datatype,
|
|
334
|
-
)
|
|
335
|
-
for facet_class, output_datatype in pairs
|
|
336
|
-
]
|
|
337
|
-
|
|
338
|
-
for facet in facet_instances:
|
|
339
|
-
try:
|
|
340
|
-
yield facet.show()
|
|
341
|
-
except Exception as err:
|
|
342
|
-
raise FacetError(
|
|
343
|
-
node=node,
|
|
344
|
-
facet_iri=None,
|
|
345
|
-
error=err,
|
|
346
|
-
) from err
|
|
347
|
-
|
|
348
311
|
def node_as_qname(self, node: Node):
|
|
349
312
|
"""Render node as a QName if possible."""
|
|
350
313
|
qname = node_to_qname(node, self.graph)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"@context":
|
|
2
2
|
"@import": https://json-ld.org/contexts/dollar-convenience.jsonld
|
|
3
|
-
vann:
|
|
4
|
-
foaf:
|
|
5
|
-
owl:
|
|
3
|
+
vann: http://purl.org/vocab/vann/
|
|
4
|
+
foaf: http://xmlns.com/foaf/0.1/
|
|
5
|
+
owl: http://www.w3.org/2002/07/owl#
|
|
6
6
|
iolanta: https://iolanta.tech/
|
|
7
|
-
rdfs: "
|
|
8
|
-
rdf:
|
|
9
|
-
dcterms:
|
|
10
|
-
dcam:
|
|
7
|
+
rdfs: "http://www.w3.org/2000/01/rdf-schema#"
|
|
8
|
+
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
|
|
9
|
+
dcterms: http://purl.org/dc/terms/
|
|
10
|
+
dcam: http://purl.org/dc/dcam/
|
|
11
11
|
|
|
12
12
|
iolanta:outputs:
|
|
13
13
|
"@type": "@id"
|
iolanta/mcp/cli.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from pathlib import Path
|
|
1
2
|
from typing import Annotated
|
|
3
|
+
|
|
2
4
|
from fastmcp import FastMCP
|
|
3
|
-
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from iolanta.cli.main import render_and_return
|
|
6
7
|
|
|
@@ -10,7 +11,7 @@ mcp = FastMCP("Iolanta MCP Server")
|
|
|
10
11
|
@mcp.tool()
|
|
11
12
|
def render_uri(
|
|
12
13
|
uri: Annotated[str, 'URL, or file system path, to render'],
|
|
13
|
-
as_format: Annotated[str, 'Format to render as. Examples: `labeled-triple-set`, `mermaid`']
|
|
14
|
+
as_format: Annotated[str, 'Format to render as. Examples: `labeled-triple-set`, `mermaid`'],
|
|
14
15
|
) -> str:
|
|
15
16
|
"""Render a URI."""
|
|
16
17
|
result = render_and_return(uri, as_format)
|
iolanta/models.py
CHANGED
iolanta/namespaces.py
CHANGED
|
@@ -20,11 +20,11 @@ class OWL(rdflib.OWL):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class RDFS(rdflib.RDFS):
|
|
23
|
-
_NS = rdflib.Namespace('
|
|
23
|
+
_NS = rdflib.Namespace('http://www.w3.org/2000/01/rdf-schema#')
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class RDF(rdflib.RDF):
|
|
27
|
-
_NS = rdflib.Namespace('
|
|
27
|
+
_NS = rdflib.Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class DCTERMS(rdflib.DCTERMS):
|
iolanta/parse_quads.py
CHANGED
|
@@ -13,8 +13,8 @@ from iolanta.models import Quad
|
|
|
13
13
|
from iolanta.namespaces import IOLANTA, META
|
|
14
14
|
|
|
15
15
|
NORMALIZE_TERMS_MAP = MappingProxyType({
|
|
16
|
-
URIRef(_url := '
|
|
17
|
-
URIRef(_url := '
|
|
16
|
+
URIRef(_url := 'http://www.w3.org/2002/07/owl'): URIRef(f'{_url}#'),
|
|
17
|
+
URIRef(_url := 'http://www.w3.org/2000/01/rdf-schema'): URIRef(f'{_url}#'),
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
PREFIX wikibase: <http://wikiba.se/ontology#>
|
|
2
|
+
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
|
3
|
+
PREFIX prov: <http://www.w3.org/ns/prov#>
|
|
4
|
+
|
|
5
|
+
CONSTRUCT {
|
|
6
|
+
?statement rdfs:label ?label .
|
|
7
|
+
}
|
|
8
|
+
WHERE {
|
|
9
|
+
?statement a wikibase:Statement .
|
|
10
|
+
|
|
11
|
+
# Find predicates from statement to values (excluding metadata predicates)
|
|
12
|
+
?statement ?statementProp ?value .
|
|
13
|
+
|
|
14
|
+
FILTER(?statementProp != wikibase:rank)
|
|
15
|
+
FILTER(?statementProp != rdf:type)
|
|
16
|
+
FILTER(?statementProp != prov:wasDerivedFrom)
|
|
17
|
+
FILTER(?statementProp != iolanta:last-loaded-time)
|
|
18
|
+
|
|
19
|
+
# Handle entity values: get their label
|
|
20
|
+
{
|
|
21
|
+
?value rdfs:label ?label .
|
|
22
|
+
} UNION {
|
|
23
|
+
# Handle literal values: use the literal directly
|
|
24
|
+
?statement ?statementProp ?label .
|
|
25
|
+
FILTER(isLiteral(?label))
|
|
26
|
+
}
|
|
27
|
+
}
|
iolanta/sparqlspace/processor.py
CHANGED
|
@@ -35,6 +35,7 @@ from iolanta.namespaces import ( # noqa: WPS235
|
|
|
35
35
|
DCTERMS,
|
|
36
36
|
FOAF,
|
|
37
37
|
IOLANTA,
|
|
38
|
+
LOCAL,
|
|
38
39
|
META,
|
|
39
40
|
OWL,
|
|
40
41
|
PROV,
|
|
@@ -46,6 +47,8 @@ from iolanta.parse_quads import NORMALIZE_TERMS_MAP, parse_quads
|
|
|
46
47
|
|
|
47
48
|
REASONING_ENABLED = True
|
|
48
49
|
OWL_REASONING_ENABLED = False
|
|
50
|
+
|
|
51
|
+
INFERENCE_DIR = Path(__file__).parent / 'inference'
|
|
49
52
|
INDICES = [
|
|
50
53
|
URIRef('https://iolanta.tech/visualizations/index.yaml'),
|
|
51
54
|
]
|
|
@@ -112,7 +115,7 @@ def _extract_from_mapping( # noqa: WPS213
|
|
|
112
115
|
algebra: Mapping[str, Any],
|
|
113
116
|
) -> Iterable[URIRef | Variable]:
|
|
114
117
|
match algebra.name:
|
|
115
|
-
case 'SelectQuery' | 'AskQuery' | 'Project' | 'Distinct':
|
|
118
|
+
case 'SelectQuery' | 'AskQuery' | 'Project' | 'Distinct' | 'Slice':
|
|
116
119
|
yield from extract_mentioned_urls(algebra['p'])
|
|
117
120
|
|
|
118
121
|
case 'BGP':
|
|
@@ -203,9 +206,6 @@ def normalize_term(term: Node) -> Node:
|
|
|
203
206
|
* A dirty hack;
|
|
204
207
|
* Based on hard code.
|
|
205
208
|
"""
|
|
206
|
-
if isinstance(term, URIRef) and term.startswith('http://'):
|
|
207
|
-
term = URIRef(re.sub('^http', 'https', term))
|
|
208
|
-
|
|
209
209
|
return NORMALIZE_TERMS_MAP.get(term, term)
|
|
210
210
|
|
|
211
211
|
|
|
@@ -263,6 +263,12 @@ def _extract_nanopublication_uris(
|
|
|
263
263
|
match algebra.name:
|
|
264
264
|
case 'SelectQuery' | 'AskQuery' | 'Project' | 'Distinct' | 'Graph':
|
|
265
265
|
yield from _extract_nanopublication_uris(algebra['p'])
|
|
266
|
+
case 'ConstructQuery':
|
|
267
|
+
# CONSTRUCT queries don't have nanopublication URIs in bindings
|
|
268
|
+
return
|
|
269
|
+
|
|
270
|
+
case 'Slice':
|
|
271
|
+
yield from _extract_nanopublication_uris(algebra['p'])
|
|
266
272
|
|
|
267
273
|
case 'BGP':
|
|
268
274
|
for retractor, retracts, retractee in algebra['triples']:
|
|
@@ -404,64 +410,6 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
404
410
|
self.graph.last_not_inferred_source = None
|
|
405
411
|
self.graph._indices_loaded = False
|
|
406
412
|
|
|
407
|
-
def _infer_with_sparql(self):
|
|
408
|
-
"""
|
|
409
|
-
Infer triples with SPARQL rules.
|
|
410
|
-
|
|
411
|
-
FIXME:
|
|
412
|
-
* Code these rules into SHACL or some other RDF based syntax;
|
|
413
|
-
* Make them available at iolanta.tech/visualizations/ and indexed.
|
|
414
|
-
"""
|
|
415
|
-
inference = Path(__file__).parent / 'inference'
|
|
416
|
-
|
|
417
|
-
file_names = {
|
|
418
|
-
'wikibase-claim.sparql': URIRef('local:inference-wikibase-claim'),
|
|
419
|
-
'wikibase-statement-property.sparql': URIRef(
|
|
420
|
-
'local:inference-statement-property',
|
|
421
|
-
),
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
for file_name, graph_name in file_names.items():
|
|
425
|
-
start_time = time.time()
|
|
426
|
-
self.graph.update(
|
|
427
|
-
update_object=(inference / file_name).read_text(),
|
|
428
|
-
)
|
|
429
|
-
triple_count = len(self.graph.get_context(graph_name))
|
|
430
|
-
duration = datetime.timedelta(seconds=time.time() - start_time)
|
|
431
|
-
self.logger.info(
|
|
432
|
-
f'{file_name}: {triple_count} triple(s), '
|
|
433
|
-
f'inferred at {duration}',
|
|
434
|
-
)
|
|
435
|
-
|
|
436
|
-
def maybe_apply_inference(self):
|
|
437
|
-
"""Apply global OWL RL inference if necessary."""
|
|
438
|
-
if not REASONING_ENABLED:
|
|
439
|
-
return
|
|
440
|
-
|
|
441
|
-
if self.graph.last_not_inferred_source is None:
|
|
442
|
-
return
|
|
443
|
-
|
|
444
|
-
with self.inference_lock:
|
|
445
|
-
self._infer_with_sparql()
|
|
446
|
-
self._infer_with_owl_rl()
|
|
447
|
-
self.logger.info('Inference @ cyberspace: complete.')
|
|
448
|
-
|
|
449
|
-
self.graph.last_not_inferred_source = None
|
|
450
|
-
|
|
451
|
-
def _infer_with_owl_rl(self):
|
|
452
|
-
if not OWL_REASONING_ENABLED:
|
|
453
|
-
return
|
|
454
|
-
|
|
455
|
-
reasoner = reasonable.PyReasoner()
|
|
456
|
-
reasoner.from_graph(self.graph)
|
|
457
|
-
inferred_triples = reasoner.reason()
|
|
458
|
-
inference_graph_name = BNode('_:inference')
|
|
459
|
-
inferred_quads = [
|
|
460
|
-
(*triple, inference_graph_name)
|
|
461
|
-
for triple in inferred_triples
|
|
462
|
-
]
|
|
463
|
-
self.graph.addN(inferred_quads)
|
|
464
|
-
|
|
465
413
|
def _maybe_load_indices(self):
|
|
466
414
|
if not self.graph._indices_loaded:
|
|
467
415
|
for index in INDICES:
|
|
@@ -486,7 +434,7 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
486
434
|
|
|
487
435
|
initBindings = initBindings or {}
|
|
488
436
|
initNs = initNs or {}
|
|
489
|
-
|
|
437
|
+
|
|
490
438
|
if isinstance(strOrQuery, Query):
|
|
491
439
|
query = strOrQuery
|
|
492
440
|
|
|
@@ -494,12 +442,14 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
494
442
|
parse_tree = parseQuery(strOrQuery)
|
|
495
443
|
query = translateQuery(parse_tree, base, initNs)
|
|
496
444
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
445
|
+
# Only extract nanopublications from SELECT/ASK queries, not CONSTRUCT
|
|
446
|
+
if query.algebra.name != 'ConstructQuery':
|
|
447
|
+
self.load_retracting_nanopublications_by_query(
|
|
448
|
+
query=query,
|
|
449
|
+
bindings=initBindings,
|
|
450
|
+
base=base,
|
|
451
|
+
namespaces=initNs,
|
|
452
|
+
)
|
|
503
453
|
|
|
504
454
|
query, urls = extract_mentioned_urls_from_query(
|
|
505
455
|
query=query,
|
|
@@ -508,15 +458,24 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
508
458
|
namespaces=initNs,
|
|
509
459
|
)
|
|
510
460
|
|
|
461
|
+
# Filter out inference graph names (they're not URLs to load)
|
|
462
|
+
urls = {url for url in urls if not str(url).startswith('inference:')}
|
|
463
|
+
|
|
511
464
|
for url in urls:
|
|
512
465
|
try:
|
|
513
466
|
self.load(url)
|
|
514
467
|
except Exception as err:
|
|
515
468
|
self.logger.exception(f'Failed to load {url}: {err}', url, err)
|
|
516
469
|
|
|
517
|
-
|
|
470
|
+
# Run inference if there's new data since last inference run
|
|
471
|
+
# (after URLs are loaded so inference can use the loaded data)
|
|
472
|
+
if self.graph.last_not_inferred_source is not None:
|
|
473
|
+
self.logger.debug(f'Running inference, last_not_inferred_source: {self.graph.last_not_inferred_source}')
|
|
474
|
+
self._run_inference()
|
|
475
|
+
else:
|
|
476
|
+
self.logger.debug('Skipping inference, last_not_inferred_source is None')
|
|
518
477
|
|
|
519
|
-
self.
|
|
478
|
+
NanopubQueryPlugin(graph=self.graph)(query, bindings=initBindings)
|
|
520
479
|
|
|
521
480
|
is_anything_loaded = True
|
|
522
481
|
while is_anything_loaded:
|
|
@@ -531,6 +490,7 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
531
490
|
return query_result
|
|
532
491
|
|
|
533
492
|
for row in bindings:
|
|
493
|
+
break
|
|
534
494
|
for _, maybe_iri in row.items():
|
|
535
495
|
if (
|
|
536
496
|
isinstance(maybe_iri, URIRef)
|
|
@@ -566,12 +526,10 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
566
526
|
|
|
567
527
|
def _follow_is_visualized_with_links(self, uri: URIRef):
|
|
568
528
|
"""Follow `dcterms:isReferencedBy` links."""
|
|
569
|
-
self.logger.info(f'Following links for {uri}…')
|
|
570
529
|
triples = self.graph.triples((uri, DCTERMS.isReferencedBy, None))
|
|
571
530
|
for _, _, visualization in triples:
|
|
572
531
|
if isinstance(visualization, URIRef):
|
|
573
532
|
self.load(visualization)
|
|
574
|
-
self.logger.info('Links followed.')
|
|
575
533
|
|
|
576
534
|
def load( # noqa: C901, WPS210, WPS212, WPS213, WPS231
|
|
577
535
|
self,
|
|
@@ -611,8 +569,6 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
611
569
|
source_uri = normalize_term(source)
|
|
612
570
|
if self._is_loaded(source_uri):
|
|
613
571
|
return Skipped()
|
|
614
|
-
else:
|
|
615
|
-
self.logger.info(f'{source_uri} is not loaded yet')
|
|
616
572
|
|
|
617
573
|
# FIXME This is definitely inefficient. However, python-yaml-ld caches
|
|
618
574
|
# the document, so the performance overhead is not super high.
|
|
@@ -718,8 +674,9 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
718
674
|
for quad in quads
|
|
719
675
|
})
|
|
720
676
|
self.logger.info(
|
|
721
|
-
f'{source} | loaded
|
|
677
|
+
f'{source} | loaded {len(quads)} triples into graphs: {into_graphs}',
|
|
722
678
|
)
|
|
679
|
+
|
|
723
680
|
return Loaded()
|
|
724
681
|
|
|
725
682
|
def resolve_term(self, term: Node, bindings: dict[str, Node]):
|
|
@@ -732,6 +689,51 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
|
|
|
732
689
|
|
|
733
690
|
return term
|
|
734
691
|
|
|
692
|
+
def _run_inference(self): # noqa: WPS231
|
|
693
|
+
"""
|
|
694
|
+
Run inference queries from the inference directory.
|
|
695
|
+
|
|
696
|
+
For each SPARQL file in the inference directory:
|
|
697
|
+
1. Truncate the named graph `local:inference-{filename}`
|
|
698
|
+
2. Execute the CONSTRUCT query
|
|
699
|
+
3. Insert the resulting triples into that graph
|
|
700
|
+
"""
|
|
701
|
+
with self.inference_lock:
|
|
702
|
+
for inference_file in INFERENCE_DIR.glob('*.sparql'):
|
|
703
|
+
filename = inference_file.stem # filename without .sparql extension
|
|
704
|
+
inference_graph = URIRef(f'inference:{filename}')
|
|
705
|
+
|
|
706
|
+
# Truncate the inference graph
|
|
707
|
+
context = self.graph.get_context(inference_graph)
|
|
708
|
+
context.remove((None, None, None))
|
|
709
|
+
|
|
710
|
+
# Read and execute the CONSTRUCT query
|
|
711
|
+
query_text = inference_file.read_text()
|
|
712
|
+
result = self.graph.query(query_text)
|
|
713
|
+
|
|
714
|
+
# CONSTRUCT queries return a SPARQLResult with a graph attribute
|
|
715
|
+
result_graph = result.get('graph') if isinstance(result, dict) else result.graph
|
|
716
|
+
self.logger.debug(f'Inference {filename}: result_graph is {result_graph}, type: {type(result_graph)}')
|
|
717
|
+
if result_graph is not None:
|
|
718
|
+
inferred_quads = [
|
|
719
|
+
(s, p, o, inference_graph)
|
|
720
|
+
for s, p, o in result_graph
|
|
721
|
+
]
|
|
722
|
+
self.logger.debug(f'Inference {filename}: generated {len(inferred_quads)} quads')
|
|
723
|
+
|
|
724
|
+
if inferred_quads:
|
|
725
|
+
self.graph.addN(inferred_quads)
|
|
726
|
+
self.logger.info(
|
|
727
|
+
'Inference {filename}: added {count} triples',
|
|
728
|
+
filename=filename,
|
|
729
|
+
count=len(inferred_quads),
|
|
730
|
+
)
|
|
731
|
+
else:
|
|
732
|
+
self.logger.debug(f'Inference {filename}: result_graph is None')
|
|
733
|
+
|
|
734
|
+
# Clear the flag after running inference
|
|
735
|
+
self.graph.last_not_inferred_source = None
|
|
736
|
+
|
|
735
737
|
def load_retracting_nanopublications_by_query( # noqa: WPS231
|
|
736
738
|
self,
|
|
737
739
|
query: Query,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: iolanta
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.8
|
|
4
4
|
Summary: Semantic Web browser
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Anatoly Scherbakov
|
|
@@ -10,6 +10,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
14
|
Provides-Extra: all
|
|
14
15
|
Requires-Dist: boltons (>=24.0.0)
|
|
15
16
|
Requires-Dist: classes (>=0.4.0)
|
|
@@ -33,7 +34,7 @@ Requires-Dist: rich (>=13.3.1)
|
|
|
33
34
|
Requires-Dist: textual (>=0.83.0)
|
|
34
35
|
Requires-Dist: typer (>=0.9.0)
|
|
35
36
|
Requires-Dist: watchfiles (>=1.0.4)
|
|
36
|
-
Requires-Dist: yaml-ld (>=1.1.
|
|
37
|
+
Requires-Dist: yaml-ld (>=1.1.15)
|
|
37
38
|
Requires-Dist: yarl (>=1.9.4)
|
|
38
39
|
Description-Content-Type: text/markdown
|
|
39
40
|
|
|
@@ -6,17 +6,17 @@ iolanta/cli/formatters/choose.py,sha256=LWzsO_9IBSSgYNIyLlItkp8TNvpW3v6YCQ8-6kbI
|
|
|
6
6
|
iolanta/cli/formatters/csv.py,sha256=ceJ_DTz0beqeK-d6FPBQqqjXrziEfF0FRSLoGZCt_fs,760
|
|
7
7
|
iolanta/cli/formatters/json.py,sha256=Og5B9UrSM_0NWqW5Afpsy6WH8ZfYgPMVXYvT3i-43Jc,748
|
|
8
8
|
iolanta/cli/formatters/pretty.py,sha256=IypZRAr2vNqcXFY6NOIc75mpyfpFWh56aCBlOPDDieQ,2901
|
|
9
|
-
iolanta/cli/main.py,sha256=
|
|
9
|
+
iolanta/cli/main.py,sha256=CZ22-DQY3xHvvUiq1o9XDrpC2an4429yQNOE8LytDkg,4524
|
|
10
10
|
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/data/context.yaml,sha256=
|
|
14
|
+
iolanta/data/context.yaml,sha256=U7qs7fb8YRJWTbvKuubsQ_lIltIbWJDEDjLoy53k_Ck,1629
|
|
15
15
|
iolanta/data/graph-triples.yamlld,sha256=rtn-HfbijaqbmjCrKv-2pVV_aaJhB_9_OqXA_yLznCs,209
|
|
16
|
-
iolanta/data/iolanta.yaml,sha256=
|
|
17
|
-
iolanta/data/textual-browser.yaml,sha256=
|
|
16
|
+
iolanta/data/iolanta.yaml,sha256=eRb7f7Mvv8NN7Hq5NGIqLNvxFflqGae3IvG55F19OKE,1431
|
|
17
|
+
iolanta/data/textual-browser.yaml,sha256=arGPFQMtKK-LkWcDB50fC0jpztkS4T9B4prCDx_WTMo,3090
|
|
18
18
|
iolanta/declension/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
iolanta/declension/data/declension.yamlld,sha256=
|
|
19
|
+
iolanta/declension/data/declension.yamlld,sha256=xpHW458GS6Q2NQJxOzGxqeX-awvtlk6WjAAQUjBmiMw,968
|
|
20
20
|
iolanta/declension/facet.py,sha256=7SsPACjeIGnONLhfjB4KBjqt-FRISVpZenshJzqC0A8,1349
|
|
21
21
|
iolanta/declension/sparql/declension.sparql,sha256=T84bfCNDXodmFEH26S45DyOJHoWz3T4cC7hSwtAcFSw,185
|
|
22
22
|
iolanta/ensure_is_context.py,sha256=9aok8asyEx7KPesOR28VBDb3Ch9kfc3eoCpQSJwj07U,717
|
|
@@ -30,7 +30,7 @@ iolanta/facets/cli/record.py,sha256=-nIhe6hXkoI5LJtZhqBoT8ZkYGxlLwMDbPc-xmwNhrE,
|
|
|
30
30
|
iolanta/facets/cli/sparql/link.sparql,sha256=WtWEfLAvdGc2gP0IhZil6Vglkydc3VO24vk4GwRnR5I,163
|
|
31
31
|
iolanta/facets/cli/sparql/record.sparql,sha256=GBWkmNelvaSDbvl7v0-LsJHdjFPbsSAW49kNFOUeoGQ,63
|
|
32
32
|
iolanta/facets/errors.py,sha256=sEBmnzhFcRIgOT18hfNwyMMjry0waa6IB-jC2NVTA50,4124
|
|
33
|
-
iolanta/facets/facet.py,sha256=
|
|
33
|
+
iolanta/facets/facet.py,sha256=s9XmH-t0tkkVW2wwTdgv7mIW_gaW18rYVfnYgelkUtc,2239
|
|
34
34
|
iolanta/facets/foaf_person_title/__init__.py,sha256=oj4MNVQvv8Dysb27xiWjtZCii8-nT7-WFa3WMWUwbtU,67
|
|
35
35
|
iolanta/facets/foaf_person_title/facet.py,sha256=_lKtRosZWuKpjKZ3Ssdq79jVhiLE53jaf22Rnq4HCxs,634
|
|
36
36
|
iolanta/facets/foaf_person_title/sparql/names.sparql,sha256=p_2hHZXhEaJ8IwGlvLoN0vb0vhGqo44uAVRpDyTzflU,107
|
|
@@ -46,6 +46,10 @@ iolanta/facets/html/default.py,sha256=Dmf_kYiL2M954iigyYsiWrMstwZ1nvxKetuR6aW3xY
|
|
|
46
46
|
iolanta/facets/icon.py,sha256=Dubh9eCvb4kj-ppEJsTno_mn78og8YIRnDrmcefOsgs,495
|
|
47
47
|
iolanta/facets/locator/sparql/get-query-to-facet.sparql,sha256=ZoXrclgZPy0FpPhVVMb6VnIXLIUgIc-Q7Pa5ySsNSSU,114
|
|
48
48
|
iolanta/facets/locator.py,sha256=swDkDqo_N8GEPtkDRh-Tp7npyLuPUaZpZDHZPUc2Om4,9089
|
|
49
|
+
iolanta/facets/mkdocs_material_insiders_markdown/__init__.py,sha256=v5vnYeWJDYIZhXDbuKdhwjkq2Y13dPHNiQuBMAwzEgI,164
|
|
50
|
+
iolanta/facets/mkdocs_material_insiders_markdown/data/mkdocs_material_insiders_markdown.yamlld,sha256=_eTa2_Hqd-QqufBrKD8-wWv1XnKs3QCJar4ONGXH3Nk,549
|
|
51
|
+
iolanta/facets/mkdocs_material_insiders_markdown/facet.py,sha256=EY-H4gR5YgiDVt2pFbhXDuuDlAdo43vuwOvfhqFuRr4,2504
|
|
52
|
+
iolanta/facets/mkdocs_material_insiders_markdown/templates/datatype.jinja2.md,sha256=k9GSdy27mAY3eRL899pk6ZCYr4ZpEY1EuM5RY-OApYM,551
|
|
49
53
|
iolanta/facets/page_title.py,sha256=TwgZK2g_e5UoWYjKNgDzzkmq1EI3cY58680iC8N9kZI,1407
|
|
50
54
|
iolanta/facets/qname.py,sha256=Z2wjDWV90Z4vuwLj31MSf5EBGTb0dxzjlKl-Iv4dPao,533
|
|
51
55
|
iolanta/facets/textual_browser/__init__.py,sha256=sKgDvXOwib9n9d63kdtKCEv26-FoL0VN6zxDmfcheZ8,104
|
|
@@ -53,23 +57,24 @@ iolanta/facets/textual_browser/app.py,sha256=rF34KbWi0L-Mozwzm-wzBS-3OqCcwbaXl0G
|
|
|
53
57
|
iolanta/facets/textual_browser/facet.py,sha256=5mX1l6P-Ga7buzXmItxSpta6G_D4Fvwv8H6mU8-3g80,742
|
|
54
58
|
iolanta/facets/textual_browser/history.py,sha256=b3jTwVkVe0ZBcYkHGJ_zKIV4MSMScDdabmLQIjOZfes,1087
|
|
55
59
|
iolanta/facets/textual_browser/home.py,sha256=GfDD1G2HiwdLkPkNdcYRqVIxDl5tWH9fewh_FJb8G-I,384
|
|
56
|
-
iolanta/facets/textual_browser/location.py,sha256=
|
|
60
|
+
iolanta/facets/textual_browser/location.py,sha256=qWa7xUgaWKYOmiQuwI1TbyvujpKRb1pxJJZ8lFDcjKk,259
|
|
57
61
|
iolanta/facets/textual_browser/models.py,sha256=DqTBjhkkTt5mNwqr4DzNbPSqzV-QtNqfKj7wpn6T3ao,173
|
|
58
62
|
iolanta/facets/textual_browser/page.py,sha256=NkcQ5rSKZRbp63C8ozgsR_iVhcKHGv_SytUCQyGa7ss,786
|
|
59
|
-
iolanta/facets/textual_browser/page_switcher.py,sha256=
|
|
63
|
+
iolanta/facets/textual_browser/page_switcher.py,sha256=2hKDqygVRaf092V3X99gnGLIk044XKKKkA0sFttrc-I,10218
|
|
60
64
|
iolanta/facets/textual_class/__init__.py,sha256=tiL0p-3JspGcBRj4qa3rmoBFAuadk71l2ja2lJN6CEs,75
|
|
61
|
-
iolanta/facets/textual_class/facets.py,sha256=
|
|
65
|
+
iolanta/facets/textual_class/facets.py,sha256=MiGTapgt30ME2fapwdrD_yQj4mhkdmyMAjzxaoLW5Dk,6087
|
|
62
66
|
iolanta/facets/textual_class/sparql/instances.sparql,sha256=v0rHyr0Ha-ioZ2ssv0ytqeO8-Qt1xnX9FKfwSstttzI,230
|
|
67
|
+
iolanta/facets/textual_class/textual-class.yamlld,sha256=HBQCC3Kg41rFfPne9Gx1CXsQ3nQPXmwUXh9hr3AQU5A,586
|
|
63
68
|
iolanta/facets/textual_default/__init__.py,sha256=snxA0FEY9qfAxNv3MlZLrJsXugD4dvs5hLStZWV7soM,158
|
|
64
|
-
iolanta/facets/textual_default/facets.py,sha256=
|
|
65
|
-
iolanta/facets/textual_default/sparql/inverse-properties.sparql,sha256=
|
|
69
|
+
iolanta/facets/textual_default/facets.py,sha256=7rzF8jpu0TSX1uDTEUAKodST12Pd7bbDyDrt_Kk1u3g,5625
|
|
70
|
+
iolanta/facets/textual_default/sparql/inverse-properties.sparql,sha256=2m2q3C6jMQ_8o-0cPgIYrT77l6UnY3oqI37-Ed7p4-c,65
|
|
66
71
|
iolanta/facets/textual_default/sparql/label.sparql,sha256=IWAkkgMKtIZ7Zpg8LUJ5fDZ9tiI8fiRYZo-zT61Fong,121
|
|
67
72
|
iolanta/facets/textual_default/sparql/nodes-for-property.sparql,sha256=J9vg0Pz2HXDlPCeZ6IS2C0wODrpYDuNeD6DYT6UdNsU,68
|
|
68
|
-
iolanta/facets/textual_default/sparql/properties.sparql,sha256=
|
|
73
|
+
iolanta/facets/textual_default/sparql/properties.sparql,sha256=fr33KZ4OiwR5PK5QVibcO5azkZYNC2Ollq2FXIb-TTc,334
|
|
69
74
|
iolanta/facets/textual_default/tcss/default.tcss,sha256=v6k6LvZMndRW4t9Iq-7QF59U_LJTdohRsyavwTY5ruI,69
|
|
70
75
|
iolanta/facets/textual_default/templates/default.md,sha256=CuD5lISsE2eAVnm2z6kfNff-vEgrNG95Wi5LTgkieWY,21
|
|
71
76
|
iolanta/facets/textual_default/triple_uri_ref.py,sha256=XfuNPaAe-YxH8IyrdrHQ641aWh5zVMVs0L0WC3D6A4M,1279
|
|
72
|
-
iolanta/facets/textual_default/widgets.py,sha256=
|
|
77
|
+
iolanta/facets/textual_default/widgets.py,sha256=uusHQzIERESBEyYI0k0bnYirLVZvFtsxikonh195bjw,9362
|
|
73
78
|
iolanta/facets/textual_graph/__init__.py,sha256=DWd2gljzL8SiyYKQdBH78HouF1EMqgCH-w0K5OEmL2I,59
|
|
74
79
|
iolanta/facets/textual_graph/facets.py,sha256=ed6zt7DnAlwWkOB2D3MDQrtKB3tNiegPpZbRKIoz5Zg,876
|
|
75
80
|
iolanta/facets/textual_graph/sparql/triples.sparql,sha256=5rFVGcvZzEHZj2opQQp0YlxJLpEdl-r1RjkPwo8j7t0,145
|
|
@@ -102,13 +107,13 @@ iolanta/facets/title/sparql/title.sparql,sha256=VKHeE9NvV6sFgVGvsLQD9z__J4APj8TD
|
|
|
102
107
|
iolanta/facets/wikibase_statement_title/__init__.py,sha256=_yk1akxgSJOiUBJIc8QGrD2vovvmx_iw_vJDuv1rD7M,91
|
|
103
108
|
iolanta/facets/wikibase_statement_title/facets.py,sha256=gNRqiwOTMxyyHYvb_vIrfd-4ipb8wfyJ4GgPcQdyy9E,726
|
|
104
109
|
iolanta/facets/wikibase_statement_title/sparql/statement-title.sparql,sha256=n07DQWxKqB5c3CA4kacq2HSN0R0dLgnMnLP1AxMo5YA,320
|
|
105
|
-
iolanta/iolanta.py,sha256=
|
|
110
|
+
iolanta/iolanta.py,sha256=7w1Hcq8O1unNs6fmMqOD94kdLWd4XlRISEDiEukJ33c,10127
|
|
106
111
|
iolanta/labeled_triple_set/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
|
-
iolanta/labeled_triple_set/data/labeled_triple_set.yamlld,sha256=
|
|
112
|
+
iolanta/labeled_triple_set/data/labeled_triple_set.yamlld,sha256=P3oAPSPsirpbcRXej-VekuYFTpWqrkysYsxghZc3bTk,1008
|
|
108
113
|
iolanta/labeled_triple_set/labeled_triple_set.py,sha256=o4IgvTvPd0mzBtpgHYd4n1xpujYdAvWBr6gIYwp5vnA,4061
|
|
109
114
|
iolanta/labeled_triple_set/sparql/triples.sparql,sha256=VsCmYN5AX7jSIiFm-SqLcRcOvUVj8yyZI4PSzKROtQw,82
|
|
110
115
|
iolanta/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
111
|
-
iolanta/mcp/cli.py,sha256=
|
|
116
|
+
iolanta/mcp/cli.py,sha256=wmtJgeTijIoDe0C-3uGekVfYlhj2jqL30p_u_NuJzR0,1116
|
|
112
117
|
iolanta/mcp/prompts/nanopublication_assertion_authoring_rules.md,sha256=Z5YL9YwcLHCqA4zQK2ziSQYgyR4SlhUO9LV_zHGf0JQ,2643
|
|
113
118
|
iolanta/mcp/prompts/rules.md,sha256=LddpoNfUACfvWBNJ_ArAyJfP2zlQstlXS2QA6GCl9QI,4651
|
|
114
119
|
iolanta/mermaid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -118,10 +123,10 @@ iolanta/mermaid/models.py,sha256=mlhtkqChpF-5z4Nt3s8a0j64cuT34BUKxLIYNS2RcIA,438
|
|
|
118
123
|
iolanta/mermaid/sparql/ask-has-triples.sparql,sha256=mOYJ_rutEG_15PKTCHSv2GqzbkAawIn1U2kjkIr_Me0,41
|
|
119
124
|
iolanta/mermaid/sparql/graph.sparql,sha256=mDGf05od3CUFhzI6rcqt5ZMVy-gSKDu-WxmV_zpIsVI,62
|
|
120
125
|
iolanta/mermaid/sparql/subgraphs.sparql,sha256=VuoOYr_ZtKXXRrBpAEJek0mBRzR9EV-KnKENgAbkzCs,71
|
|
121
|
-
iolanta/models.py,sha256=
|
|
122
|
-
iolanta/namespaces.py,sha256=
|
|
126
|
+
iolanta/models.py,sha256=2VrJGQE1YXbbVB1K5McCXe2CLAlzOUhA8FvbRI10nCc,3131
|
|
127
|
+
iolanta/namespaces.py,sha256=NiCDzcvJHpnSH0kvEE94xyt0X9R-yqjkI_TEgj_3Pd4,1208
|
|
123
128
|
iolanta/node_to_qname.py,sha256=a82_qpgT87cbekY_76tTkl4Z-6Rz6am4UGIQChUf9Y0,794
|
|
124
|
-
iolanta/parse_quads.py,sha256=
|
|
129
|
+
iolanta/parse_quads.py,sha256=X-3hQAFzRD9U8KCuZMQTVOAapJR4OHkPoRbgJYiVbnk,4539
|
|
125
130
|
iolanta/plugin.py,sha256=MSxpuOIx93AgBahfS8bYh31MEgcwtUSQhj4Js7fgdSI,1096
|
|
126
131
|
iolanta/query_result.py,sha256=VLLBkewUEymtzfB0jeIeRE3Np6pAgo959RPgNsEmiq8,1545
|
|
127
132
|
iolanta/reformat_blank_nodes.py,sha256=MAVcXusUioKzAoTEHAMume5Gt9vBEpxJGrngqFzmkJI,712
|
|
@@ -132,14 +137,14 @@ iolanta/resolvers/pypi.py,sha256=BJA7PGPaFFIxisCp-1-pjWZYNTDRVA5am5Nn8O2WddM,349
|
|
|
132
137
|
iolanta/resolvers/python_import.py,sha256=hFs2Fi7BDjdKllgrGJhTaqjfcT7Vaj0j1b45CJt21B0,522
|
|
133
138
|
iolanta/sparqlspace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
134
139
|
iolanta/sparqlspace/cli.py,sha256=pb6q03lzrU8OaZ4A3QAQEmaFYcQ_-sHUrPhRs6GE88w,1590
|
|
135
|
-
iolanta/sparqlspace/inference/
|
|
136
|
-
iolanta/sparqlspace/inference/
|
|
137
|
-
iolanta/sparqlspace/processor.py,sha256=
|
|
140
|
+
iolanta/sparqlspace/inference/wikidata-prop-label.sparql,sha256=JYLAs28Z3a77cMcv44aZplwwrdqB-yshZn1dDZmRFAU,250
|
|
141
|
+
iolanta/sparqlspace/inference/wikidata-statement-label.sparql,sha256=_Dp9jKCpCp2pLk0uacNUhUvvQ2Hov-WiMFprtuYTRyY,759
|
|
142
|
+
iolanta/sparqlspace/processor.py,sha256=nEmVz7QjYtP33Gr8x7GVrX3DlDSGIRJJornnNCCEu9s,25041
|
|
138
143
|
iolanta/sparqlspace/sparqlspace.py,sha256=Y8_ZPXwuGEXbEes6XQjaQWA2Zv9y8SWxMPDFdqVBGFo,796
|
|
139
144
|
iolanta/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
140
145
|
iolanta/widgets/description.py,sha256=98Qd3FwT9r8sYqKjl9ZEptaVX9jJ2ULWf0uy3j52p5o,800
|
|
141
146
|
iolanta/widgets/mixin.py,sha256=nDRCOc-gizCf1a5DAcYs4hW8eZEd6pHBPFsfm0ncv7E,251
|
|
142
|
-
iolanta-2.1.
|
|
143
|
-
iolanta-2.1.
|
|
144
|
-
iolanta-2.1.
|
|
145
|
-
iolanta-2.1.
|
|
147
|
+
iolanta-2.1.8.dist-info/METADATA,sha256=2M-jlo8FVme0EFFKWO6cUr0yTvB4AnVFmO2d5uk8zMU,2316
|
|
148
|
+
iolanta-2.1.8.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
149
|
+
iolanta-2.1.8.dist-info/entry_points.txt,sha256=Vu0W4D6H74HsTICvD8CDB1wYs6XNSyu55EZVXMo4H84,1718
|
|
150
|
+
iolanta-2.1.8.dist-info/RECORD,,
|
|
@@ -8,6 +8,7 @@ boolean=iolanta.facets.generic:BoolLiteral
|
|
|
8
8
|
icon=iolanta.facets.icon:IconFacet
|
|
9
9
|
labeled-triple-set=iolanta.labeled_triple_set.labeled_triple_set:LabeledTripleSet
|
|
10
10
|
mermaid-graph=iolanta.mermaid.facet:Mermaid
|
|
11
|
+
mkdocs-material-insiders-markdown-datatype=iolanta.facets.mkdocs_material_insiders_markdown:MkDocsMaterialInsidersMarkdownFacet
|
|
11
12
|
qname=iolanta.facets.qname:QNameFacet
|
|
12
13
|
rich-declension-table=iolanta.declension.facet:RichDeclensionTable
|
|
13
14
|
textual-browser=iolanta.facets.textual_browser:TextualBrowserFacet
|
|
@@ -25,7 +26,6 @@ textual-property-pairs=iolanta.facets.textual_property_pairs_table:TextualProper
|
|
|
25
26
|
textual-provenance=iolanta.facets.textual_provenance:TextualProvenanceFacet
|
|
26
27
|
title=iolanta.facets.title:TitleFacet
|
|
27
28
|
title-foaf-person=iolanta.facets.foaf_person_title:FOAFPersonTitle
|
|
28
|
-
wikibase-statement-title=iolanta.facets.wikibase_statement_title:WikibaseStatementTitle
|
|
29
29
|
|
|
30
30
|
[iolanta.plugins]
|
|
31
31
|
base=iolanta:IolantaBase
|