iolanta 2.1.1__tar.gz → 2.1.6__tar.gz
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-2.1.1 → iolanta-2.1.6}/PKG-INFO +7 -7
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/main.py +83 -43
- iolanta-2.1.6/iolanta/declension/data/declension.yamlld +39 -0
- iolanta-2.1.6/iolanta/declension/facet.py +44 -0
- iolanta-2.1.6/iolanta/declension/sparql/declension.sparql +8 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/cli/record.py +2 -2
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/facet.py +1 -22
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/foaf_person_title/facet.py +2 -2
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/generic/bool_literal.py +3 -3
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/generic/date_literal.py +1 -1
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/generic/default.py +2 -2
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/html/code_literal.py +3 -3
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/icon.py +1 -1
- iolanta-2.1.6/iolanta/facets/locator/sparql/get-query-to-facet.sparql +5 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/locator.py +5 -11
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/qname.py +2 -2
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/app.py +7 -3
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/facet.py +1 -1
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/page_switcher.py +13 -18
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_class/facets.py +3 -3
- iolanta-2.1.6/iolanta/facets/textual_class/sparql/instances.sparql +8 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/facets.py +5 -5
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/widgets.py +1 -1
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_graph/facets.py +3 -3
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_graph_triples.py +1 -1
- iolanta-2.1.6/iolanta/facets/textual_graphs/__init__.py +6 -0
- iolanta-2.1.6/iolanta/facets/textual_graphs/data/textual_graphs.yamlld +23 -0
- iolanta-2.1.6/iolanta/facets/textual_graphs/facets.py +138 -0
- iolanta-2.1.6/iolanta/facets/textual_graphs/sparql/graphs.sparql +5 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_link/facet.py +4 -4
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_nanopublication/facet.py +1 -1
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_no_facet_found.py +3 -1
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_ontology/facets.py +3 -3
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_provenance/facets.py +1 -1
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/title/facets.py +1 -4
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/wikibase_statement_title/facets.py +2 -2
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/iolanta.py +2 -2
- iolanta-2.1.1/iolanta/mermaid/mermaid.yamlld → iolanta-2.1.6/iolanta/labeled_triple_set/data/labeled_triple_set.yamlld +5 -5
- iolanta-2.1.6/iolanta/labeled_triple_set/labeled_triple_set.py +137 -0
- iolanta-2.1.6/iolanta/labeled_triple_set/sparql/triples.sparql +5 -0
- iolanta-2.1.6/iolanta/mcp/cli.py +39 -0
- iolanta-2.1.6/iolanta/mcp/prompts/nanopublication_assertion_authoring_rules.md +63 -0
- iolanta-2.1.6/iolanta/mcp/prompts/rules.md +83 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/mermaid/facet.py +0 -3
- iolanta-2.1.6/iolanta/mermaid/mermaid.yamlld +25 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/mermaid/models.py +38 -9
- iolanta-2.1.6/iolanta/mermaid/sparql/ask-has-triples.sparql +3 -0
- iolanta-2.1.6/iolanta/resolvers/__init__.py +0 -0
- iolanta-2.1.6/iolanta/sparqlspace/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/sparqlspace/processor.py +6 -3
- iolanta-2.1.6/iolanta/widgets/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/pyproject.toml +10 -4
- iolanta-2.1.1/iolanta/facets/textual_class/sparql/instances.sparql +0 -5
- {iolanta-2.1.1 → iolanta-2.1.6}/README.md +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/base_plugin.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/formatters/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/formatters/choose.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/formatters/csv.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/formatters/json.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/formatters/pretty.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/models.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/cli/pretty_print.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/context.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/conversions.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/data/context.yaml +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/data/graph-triples.yamlld +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/data/iolanta.yaml +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/data/textual-browser.yaml +0 -0
- {iolanta-2.1.1/iolanta/mermaid → iolanta-2.1.6/iolanta/declension}/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/ensure_is_context.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/entry_points.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/errors.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/cli/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/cli/base.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/cli/default.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/cli/sparql/link.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/cli/sparql/record.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/errors.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/foaf_person_title/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/foaf_person_title/sparql/names.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/generic/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/generic/sparql/default.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/html/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/html/base.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/html/default.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/page_title.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/history.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/home.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/location.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/models.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_browser/page.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_class/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/sparql/inverse-properties.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/sparql/label.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/sparql/nodes-for-property.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/sparql/properties.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/tcss/default.tcss +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/templates/default.md +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_default/triple_uri_ref.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_graph/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_graph/sparql/triples.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_link/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_nanopublication/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_nanopublication/models.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_nanopublication/nanopublication_widget.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_nanopublication/term_list_widget.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_nanopublication/term_widget.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_ontology/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_ontology/sparql/terms.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_ontology/sparql/visualization-vocab.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_property_pairs_table.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_provenance/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_provenance/sparql/graphs.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/textual_provenance/sparql/triples.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/title/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/title/sparql/title.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/wikibase_statement_title/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/facets/wikibase_statement_title/sparql/statement-title.sparql +0 -0
- {iolanta-2.1.1/iolanta/resolvers → iolanta-2.1.6/iolanta/labeled_triple_set}/__init__.py +0 -0
- {iolanta-2.1.1/iolanta/sparqlspace → iolanta-2.1.6/iolanta/mcp}/__init__.py +0 -0
- {iolanta-2.1.1/iolanta/widgets → iolanta-2.1.6/iolanta/mermaid}/__init__.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/mermaid/sparql/graph.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/mermaid/sparql/subgraphs.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/models.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/namespaces.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/node_to_qname.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/parse_quads.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/plugin.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/query_result.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/reformat_blank_nodes.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/resolvers/base.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/resolvers/dispatch.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/resolvers/pypi.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/resolvers/python_import.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/sparqlspace/cli.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/sparqlspace/inference/wikibase-claim.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/sparqlspace/inference/wikibase-statement-property.sparql +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/sparqlspace/sparqlspace.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/widgets/description.py +0 -0
- {iolanta-2.1.1 → iolanta-2.1.6}/iolanta/widgets/mixin.py +0 -0
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: iolanta
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.6
|
|
4
4
|
Summary: Semantic Web browser
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Anatoly Scherbakov
|
|
7
7
|
Author-email: altaisoft@gmail.com
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.12,<4.0
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
13
|
Provides-Extra: all
|
|
15
14
|
Requires-Dist: boltons (>=24.0.0)
|
|
16
15
|
Requires-Dist: classes (>=0.4.0)
|
|
@@ -18,10 +17,11 @@ Requires-Dist: deepmerge (>=0.1.1)
|
|
|
18
17
|
Requires-Dist: diskcache (>=5.6.3)
|
|
19
18
|
Requires-Dist: documented (>=0.1.1)
|
|
20
19
|
Requires-Dist: dominate (>=2.6.0)
|
|
20
|
+
Requires-Dist: fastmcp (>=2.12.4,<3.0.0)
|
|
21
21
|
Requires-Dist: funcy (>=2.0)
|
|
22
22
|
Requires-Dist: loguru (>=0.7.3)
|
|
23
23
|
Requires-Dist: more-itertools (>=9.0.0)
|
|
24
|
-
Requires-Dist: nanopub (>=2.0.
|
|
24
|
+
Requires-Dist: nanopub (>=2.1.0,<3.0.0)
|
|
25
25
|
Requires-Dist: owlrl (>=6.0.2)
|
|
26
26
|
Requires-Dist: oxrdflib (>=0.4.0)
|
|
27
27
|
Requires-Dist: packageurl-python (>=0.17.5)
|
|
@@ -33,7 +33,7 @@ Requires-Dist: rich (>=13.3.1)
|
|
|
33
33
|
Requires-Dist: textual (>=0.83.0)
|
|
34
34
|
Requires-Dist: typer (>=0.9.0)
|
|
35
35
|
Requires-Dist: watchfiles (>=1.0.4)
|
|
36
|
-
Requires-Dist: yaml-ld (>=1.1.
|
|
36
|
+
Requires-Dist: yaml-ld (>=1.1.14,<2.0.0)
|
|
37
37
|
Requires-Dist: yarl (>=1.9.4)
|
|
38
38
|
Description-Content-Type: text/markdown
|
|
39
39
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import locale
|
|
2
2
|
import logging
|
|
3
|
+
import sys
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Annotated
|
|
5
6
|
|
|
@@ -9,7 +10,8 @@ from documented import DocumentedError
|
|
|
9
10
|
from rdflib import Literal, URIRef
|
|
10
11
|
from rich.console import Console
|
|
11
12
|
from rich.markdown import Markdown
|
|
12
|
-
from
|
|
13
|
+
from rich.table import Table
|
|
14
|
+
from typer import Argument, Exit, Option, Typer, Context
|
|
13
15
|
from yarl import URL
|
|
14
16
|
|
|
15
17
|
from iolanta.cli.models import LogLevel
|
|
@@ -22,23 +24,7 @@ DEFAULT_LANGUAGE = locale.getlocale()[0].split('_')[0]
|
|
|
22
24
|
console = Console()
|
|
23
25
|
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
"""
|
|
27
|
-
Construct Typer app.
|
|
28
|
-
|
|
29
|
-
FIXME: Remove this function, just create the app on module level.
|
|
30
|
-
"""
|
|
31
|
-
iolanta = Iolanta()
|
|
32
|
-
|
|
33
|
-
return Typer(
|
|
34
|
-
no_args_is_help=True,
|
|
35
|
-
context_settings={
|
|
36
|
-
'obj': iolanta,
|
|
37
|
-
},
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
app = construct_app()
|
|
27
|
+
app = Typer(no_args_is_help=True)
|
|
42
28
|
|
|
43
29
|
|
|
44
30
|
def string_to_node(name: str) -> NotLiteralNode:
|
|
@@ -57,19 +43,17 @@ def string_to_node(name: str) -> NotLiteralNode:
|
|
|
57
43
|
return URIRef(f'file://{path}')
|
|
58
44
|
|
|
59
45
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
),
|
|
72
|
-
] = DEFAULT_LANGUAGE,
|
|
46
|
+
def decode_datatype(datatype: str) -> URIRef:
|
|
47
|
+
if datatype.startswith('http'):
|
|
48
|
+
return URIRef(datatype)
|
|
49
|
+
|
|
50
|
+
return URIRef(f'https://iolanta.tech/datatypes/{datatype}')
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def render_and_return(
|
|
54
|
+
url: str,
|
|
55
|
+
as_datatype: str,
|
|
56
|
+
language: str = DEFAULT_LANGUAGE,
|
|
73
57
|
log_level: LogLevel = LogLevel.ERROR,
|
|
74
58
|
):
|
|
75
59
|
"""Render a given URL."""
|
|
@@ -85,14 +69,32 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
|
|
|
85
69
|
ensure_exists=True,
|
|
86
70
|
) / 'iolanta.log'
|
|
87
71
|
|
|
88
|
-
|
|
89
|
-
|
|
72
|
+
# Get the level name first
|
|
73
|
+
level_name = {
|
|
74
|
+
logging.DEBUG: 'DEBUG',
|
|
75
|
+
logging.INFO: 'INFO',
|
|
76
|
+
logging.WARNING: 'WARNING',
|
|
77
|
+
logging.ERROR: 'ERROR',
|
|
78
|
+
}[level]
|
|
79
|
+
|
|
80
|
+
# Configure global loguru logger BEFORE creating Iolanta instance
|
|
81
|
+
loguru.logger.remove()
|
|
82
|
+
loguru.logger.add(
|
|
90
83
|
log_file_path,
|
|
91
|
-
level=
|
|
84
|
+
level=level_name,
|
|
92
85
|
format='{time} {level} {message}',
|
|
93
86
|
enqueue=True,
|
|
94
87
|
)
|
|
95
|
-
|
|
88
|
+
loguru.logger.add(
|
|
89
|
+
sys.stderr,
|
|
90
|
+
level=level_name,
|
|
91
|
+
format='{time} | {level:<8} | {name}:{function}:{line} - {message}',
|
|
92
|
+
)
|
|
93
|
+
loguru.logger.level(level_name)
|
|
94
|
+
|
|
95
|
+
# Use the global logger
|
|
96
|
+
logger = loguru.logger
|
|
97
|
+
|
|
96
98
|
node_url = URL(url)
|
|
97
99
|
if node_url.scheme and node_url.scheme != 'file':
|
|
98
100
|
node = URIRef(url)
|
|
@@ -101,6 +103,7 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
|
|
|
101
103
|
language=Literal(language),
|
|
102
104
|
logger=logger,
|
|
103
105
|
)
|
|
106
|
+
|
|
104
107
|
else:
|
|
105
108
|
path = Path(node_url.path).absolute()
|
|
106
109
|
node = URIRef(f'file://{path}')
|
|
@@ -110,14 +113,39 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
|
|
|
110
113
|
project_root=path,
|
|
111
114
|
)
|
|
112
115
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
return iolanta.render(
|
|
117
|
+
node=URIRef(node),
|
|
118
|
+
as_datatype=decode_datatype(as_datatype),
|
|
119
|
+
)
|
|
120
|
+
|
|
118
121
|
|
|
122
|
+
@app.command(name='render')
|
|
123
|
+
def render_command( # noqa: WPS231, WPS238, WPS210, C901
|
|
124
|
+
url: Annotated[str, Argument()],
|
|
125
|
+
as_datatype: Annotated[
|
|
126
|
+
str, Option(
|
|
127
|
+
'--as',
|
|
128
|
+
),
|
|
129
|
+
] = 'https://iolanta.tech/cli/interactive',
|
|
130
|
+
language: Annotated[
|
|
131
|
+
str, Option(
|
|
132
|
+
help='Data language to prefer.',
|
|
133
|
+
),
|
|
134
|
+
] = DEFAULT_LANGUAGE,
|
|
135
|
+
log_level: LogLevel = LogLevel.ERROR,
|
|
136
|
+
):
|
|
137
|
+
"""Render a given URL."""
|
|
138
|
+
try:
|
|
139
|
+
renderable = render_and_return(url, as_datatype, language, log_level)
|
|
119
140
|
except DocumentedError as documented_error:
|
|
120
|
-
|
|
141
|
+
level = {
|
|
142
|
+
LogLevel.DEBUG: logging.DEBUG,
|
|
143
|
+
LogLevel.INFO: logging.INFO,
|
|
144
|
+
LogLevel.WARNING: logging.WARNING,
|
|
145
|
+
LogLevel.ERROR: logging.ERROR,
|
|
146
|
+
}[log_level]
|
|
147
|
+
|
|
148
|
+
if level in {logging.DEBUG, logging.INFO}:
|
|
121
149
|
raise
|
|
122
150
|
|
|
123
151
|
console.print(
|
|
@@ -129,11 +157,23 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
|
|
|
129
157
|
raise Exit(1)
|
|
130
158
|
|
|
131
159
|
except Exception as err:
|
|
160
|
+
level = {
|
|
161
|
+
LogLevel.DEBUG: logging.DEBUG,
|
|
162
|
+
LogLevel.INFO: logging.INFO,
|
|
163
|
+
LogLevel.WARNING: logging.WARNING,
|
|
164
|
+
LogLevel.ERROR: logging.ERROR,
|
|
165
|
+
}[log_level]
|
|
166
|
+
|
|
132
167
|
if level in {logging.DEBUG, logging.INFO}:
|
|
133
168
|
raise
|
|
134
169
|
|
|
135
170
|
console.print(str(err))
|
|
136
171
|
raise Exit(1)
|
|
137
|
-
|
|
138
172
|
else:
|
|
139
|
-
|
|
173
|
+
# FIXME: An intermediary Literal can be used to dispatch rendering.
|
|
174
|
+
match renderable:
|
|
175
|
+
case Table() as table:
|
|
176
|
+
console.print(table)
|
|
177
|
+
|
|
178
|
+
case unknown:
|
|
179
|
+
print(unknown)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"@context":
|
|
2
|
+
"@import": https://json-ld.org/contexts/dollar-convenience.jsonld
|
|
3
|
+
vann: https://purl.org/vocab/vann/
|
|
4
|
+
foaf: https://xmlns.com/foaf/0.1/
|
|
5
|
+
owl: https://www.w3.org/2002/07/owl#
|
|
6
|
+
iolanta: https://iolanta.tech/
|
|
7
|
+
rdfs: "https://www.w3.org/2000/01/rdf-schema#"
|
|
8
|
+
rdf: https://www.w3.org/1999/02/22-rdf-syntax-ns#
|
|
9
|
+
dcterms: https://purl.org/dc/terms/
|
|
10
|
+
dcam: https://purl.org/dc/dcam/
|
|
11
|
+
|
|
12
|
+
iolanta:outputs:
|
|
13
|
+
"@type": "@id"
|
|
14
|
+
|
|
15
|
+
iolanta:when-no-facet-found:
|
|
16
|
+
"@type": "@id"
|
|
17
|
+
|
|
18
|
+
$: rdfs:label
|
|
19
|
+
→:
|
|
20
|
+
"@type": "@id"
|
|
21
|
+
"@id": iolanta:outputs
|
|
22
|
+
|
|
23
|
+
⊆:
|
|
24
|
+
"@type": "@id"
|
|
25
|
+
"@id": rdfs:subClassOf
|
|
26
|
+
|
|
27
|
+
⪯:
|
|
28
|
+
"@type": "@id"
|
|
29
|
+
"@id": iolanta:is-preferred-over
|
|
30
|
+
|
|
31
|
+
↦: iolanta:matches
|
|
32
|
+
iolanta:hasDefaultFacet:
|
|
33
|
+
"@type": "@id"
|
|
34
|
+
|
|
35
|
+
$id: https://w3id.org/np/RASSJ01s2tPPJfFVx__m9gHtY4ct1YSd1ntL3R1OaQfLI/EasternArmenianPersonalPronoun
|
|
36
|
+
iolanta:facet:
|
|
37
|
+
$id: pkg:pypi/iolanta#rich-declension-table
|
|
38
|
+
$: Declension Table
|
|
39
|
+
→: https://iolanta.tech/datatypes/rich
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import funcy
|
|
4
|
+
from docutils.nodes import row
|
|
5
|
+
from rdflib import Literal, Namespace
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
|
|
8
|
+
from iolanta import Facet
|
|
9
|
+
from iolanta.namespaces import DATATYPES, LOCAL
|
|
10
|
+
|
|
11
|
+
LEXINFO = Namespace('https://www.lexinfo.net/ontology/2.0/lexinfo#')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RichDeclensionTable(Facet[Table]):
|
|
15
|
+
"""Declension forms of something."""
|
|
16
|
+
|
|
17
|
+
META = Path(__file__).parent / 'data' / 'declension.yamlld'
|
|
18
|
+
|
|
19
|
+
def show(self) -> Table:
|
|
20
|
+
"""Render declension forms of something."""
|
|
21
|
+
rows = self.stored_query('declension.sparql', this=self.this)
|
|
22
|
+
form_by_number_and_person = [
|
|
23
|
+
((row['number'], row['person']), self.render(row['declension'], as_datatype=DATATYPES.title))
|
|
24
|
+
for row in rows
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
declensions = funcy.group_values(form_by_number_and_person)
|
|
28
|
+
|
|
29
|
+
table = Table('', 'Singular', 'Plural', title='Declension')
|
|
30
|
+
|
|
31
|
+
table_rows = [
|
|
32
|
+
[
|
|
33
|
+
', '.join(declensions[number, person])
|
|
34
|
+
for number in [LEXINFO.singular, LEXINFO.plural]
|
|
35
|
+
]
|
|
36
|
+
for person in [LEXINFO.firstPerson, LEXINFO.secondPerson, LEXINFO.thirdPerson]
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
row_titles = ['1st', '2nd', '3rd']
|
|
40
|
+
|
|
41
|
+
for title, table_row in zip(row_titles, table_rows):
|
|
42
|
+
table.add_row(title, *table_row)
|
|
43
|
+
|
|
44
|
+
return table
|
|
@@ -17,9 +17,9 @@ class Record(RichFacet):
|
|
|
17
17
|
|
|
18
18
|
def show(self) -> Renderable:
|
|
19
19
|
return "RECORD"
|
|
20
|
-
rows = self.stored_query('record.sparql', node=self.
|
|
20
|
+
rows = self.stored_query('record.sparql', node=self.this)
|
|
21
21
|
|
|
22
|
-
caption = self.render(self.
|
|
22
|
+
caption = self.render(self.this, as_datatype=IOLANTA['cli/title'])
|
|
23
23
|
|
|
24
24
|
table = Table(
|
|
25
25
|
show_header=False,
|
|
@@ -16,28 +16,15 @@ FacetOutput = TypeVar('FacetOutput')
|
|
|
16
16
|
class Facet(Generic[FacetOutput]):
|
|
17
17
|
"""Base facet class."""
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
this: Node
|
|
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
|
-
|
|
28
23
|
@property
|
|
29
24
|
def stored_queries_path(self) -> Path:
|
|
30
25
|
"""Construct directory for stored queries for this facet."""
|
|
31
26
|
return Path(inspect.getfile(self.__class__)).parent / 'sparql'
|
|
32
27
|
|
|
33
|
-
@cached_property
|
|
34
|
-
def uriref(self) -> NotLiteralNode:
|
|
35
|
-
"""Format as URIRef."""
|
|
36
|
-
if isinstance(self.iri, BNode):
|
|
37
|
-
return self.iri
|
|
38
|
-
|
|
39
|
-
return URIRef(self.iri)
|
|
40
|
-
|
|
41
28
|
def query(
|
|
42
29
|
self,
|
|
43
30
|
query_text: str,
|
|
@@ -60,14 +47,6 @@ class Facet(Generic[FacetOutput]):
|
|
|
60
47
|
as_datatype=as_datatype,
|
|
61
48
|
)
|
|
62
49
|
|
|
63
|
-
def render_all(
|
|
64
|
-
self,
|
|
65
|
-
node: Node,
|
|
66
|
-
as_datatype: NotLiteralNode,
|
|
67
|
-
) -> Iterable[Any]:
|
|
68
|
-
"""Render all we can."""
|
|
69
|
-
return self.iolanta.render_all(node=node, as_datatype=as_datatype)
|
|
70
|
-
|
|
71
50
|
def stored_query(self, file_name: str, **kwargs: SPARQLQueryArgument):
|
|
72
51
|
"""Execute a stored SPARQL query."""
|
|
73
52
|
query_text = (self.stored_queries_path / file_name).read_text()
|
|
@@ -9,12 +9,12 @@ class FOAFPersonTitle(Facet[str]):
|
|
|
9
9
|
|
|
10
10
|
def show(self) -> str:
|
|
11
11
|
"""Render full name of a person."""
|
|
12
|
-
row = funcy.first(self.stored_query('names.sparql', person=self.
|
|
12
|
+
row = funcy.first(self.stored_query('names.sparql', person=self.this))
|
|
13
13
|
|
|
14
14
|
if row is None:
|
|
15
15
|
# Render default title.
|
|
16
16
|
return self.render(
|
|
17
|
-
self.
|
|
17
|
+
self.this,
|
|
18
18
|
as_datatype=DATATYPES['fallback-title'],
|
|
19
19
|
)
|
|
20
20
|
|
|
@@ -9,9 +9,9 @@ class BoolLiteral(Facet):
|
|
|
9
9
|
|
|
10
10
|
def show(self):
|
|
11
11
|
"""Render as icon."""
|
|
12
|
-
if not isinstance(self.
|
|
12
|
+
if not isinstance(self.this, Literal):
|
|
13
13
|
raise NotALiteral(
|
|
14
|
-
node=self.
|
|
14
|
+
node=self.this,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
return '✔️' if self.
|
|
17
|
+
return '✔️' if self.this.value else '❌'
|
|
@@ -27,7 +27,7 @@ class DefaultMixin(Facet[FacetOutput]):
|
|
|
27
27
|
def description(self) -> Description:
|
|
28
28
|
return Description(
|
|
29
29
|
**funcy.first(
|
|
30
|
-
self.stored_query('default.sparql', iri=self.
|
|
30
|
+
self.stored_query('default.sparql', iri=self.this),
|
|
31
31
|
),
|
|
32
32
|
)
|
|
33
33
|
|
|
@@ -59,7 +59,7 @@ class DefaultMixin(Facet[FacetOutput]):
|
|
|
59
59
|
return label
|
|
60
60
|
|
|
61
61
|
def render_fallback(self) -> str:
|
|
62
|
-
string_iri = str(self.
|
|
62
|
+
string_iri = str(self.this)
|
|
63
63
|
|
|
64
64
|
if string_iri.startswith('local:'):
|
|
65
65
|
string_iri = string_iri.removeprefix(
|
|
@@ -9,9 +9,9 @@ class CodeLiteral(Facet):
|
|
|
9
9
|
|
|
10
10
|
def show(self):
|
|
11
11
|
"""Render as icon."""
|
|
12
|
-
if not isinstance(self.
|
|
12
|
+
if not isinstance(self.this, Literal):
|
|
13
13
|
raise NotALiteral(
|
|
14
|
-
node=self.
|
|
14
|
+
node=self.this,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
return f'<code>{self.
|
|
17
|
+
return f'<code>{self.this.value}</code>'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from functools import cached_property
|
|
3
3
|
from graphlib import TopologicalSorter
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from typing import Iterable, List, TypedDict
|
|
5
6
|
|
|
6
7
|
import funcy
|
|
@@ -18,13 +19,9 @@ class FoundRow(TypedDict):
|
|
|
18
19
|
output_datatype: NotLiteralNode
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
GET_QUERY_TO_FACET =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
iolanta:matches ?match ;
|
|
25
|
-
iolanta:outputs $as_datatype .
|
|
26
|
-
}
|
|
27
|
-
"""
|
|
22
|
+
GET_QUERY_TO_FACET = (
|
|
23
|
+
Path(__file__).parent / 'locator' / 'sparql' / 'get-query-to-facet.sparql'
|
|
24
|
+
).read_text()
|
|
28
25
|
|
|
29
26
|
|
|
30
27
|
def reorder_rows_by_facet_preferences( # noqa: WPS214, WPS210
|
|
@@ -114,9 +111,6 @@ class FacetFinder: # noqa: WPS214
|
|
|
114
111
|
|
|
115
112
|
def by_sparql(self) -> Iterable[FoundRow]:
|
|
116
113
|
"""Determine facet by SHACL shape of the data."""
|
|
117
|
-
if not isinstance(self.node, URIRef):
|
|
118
|
-
return
|
|
119
|
-
|
|
120
114
|
rows = self.iolanta.query(
|
|
121
115
|
GET_QUERY_TO_FACET,
|
|
122
116
|
as_datatype=self.as_datatype,
|
|
@@ -138,7 +132,7 @@ class FacetFinder: # noqa: WPS214
|
|
|
138
132
|
|
|
139
133
|
TODO fix this to allow arbitrary prefixes.
|
|
140
134
|
"""
|
|
141
|
-
scheme = URL(self.node).scheme
|
|
135
|
+
scheme = URL(str(self.node)).scheme
|
|
142
136
|
if scheme != 'urn':
|
|
143
137
|
return []
|
|
144
138
|
|
|
@@ -9,11 +9,11 @@ class QNameFacet(Facet[str]):
|
|
|
9
9
|
def show(self) -> str:
|
|
10
10
|
"""Return a qname."""
|
|
11
11
|
qname: ComputedQName | NotLiteralNode = node_to_qname(
|
|
12
|
-
self.
|
|
12
|
+
self.this,
|
|
13
13
|
self.iolanta.graph,
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
if isinstance(qname, ComputedQName):
|
|
17
17
|
return f'{qname.namespace_name}:{qname.term}'
|
|
18
18
|
|
|
19
|
-
return str(self.
|
|
19
|
+
return str(self.this)
|
|
@@ -45,10 +45,10 @@ def _log_message_to_dev_console(app: App):
|
|
|
45
45
|
class IolantaBrowser(App): # noqa: WPS214, WPS230
|
|
46
46
|
"""Browse Linked Data."""
|
|
47
47
|
|
|
48
|
-
def __init__(self, iolanta: Iolanta,
|
|
48
|
+
def __init__(self, iolanta: Iolanta, this: Node):
|
|
49
49
|
"""Set up parameters for the browser."""
|
|
50
50
|
self.iolanta = iolanta
|
|
51
|
-
self.
|
|
51
|
+
self.this = this
|
|
52
52
|
self.renderers = ThreadPoolExecutor()
|
|
53
53
|
super().__init__()
|
|
54
54
|
|
|
@@ -79,7 +79,11 @@ class IolantaBrowser(App): # noqa: WPS214, WPS230
|
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
# Disable stderr logging, to not break the TUI.
|
|
82
|
-
|
|
82
|
+
# Remove only the stderr handler, keep file handler
|
|
83
|
+
for handler_id in list(self.iolanta.logger._core.handlers.keys()):
|
|
84
|
+
handler = self.iolanta.logger._core.handlers[handler_id]
|
|
85
|
+
if hasattr(handler, 'sink') and str(handler.sink) == '<stderr>':
|
|
86
|
+
self.iolanta.logger.remove(handler_id)
|
|
83
87
|
|
|
84
88
|
# Log to the dev console.
|
|
85
89
|
self.iolanta.logger.add(
|
|
@@ -5,7 +5,7 @@ from dataclasses import dataclass
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
import watchfiles
|
|
8
|
-
from rdflib import BNode, URIRef
|
|
8
|
+
from rdflib import BNode, Node, URIRef
|
|
9
9
|
from textual.widgets import ContentSwitcher, RichLog
|
|
10
10
|
from textual.worker import Worker, WorkerState
|
|
11
11
|
|
|
@@ -74,7 +74,7 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
74
74
|
|
|
75
75
|
def on_mount(self):
|
|
76
76
|
"""Navigate to the initial page."""
|
|
77
|
-
self.action_goto(self.app.
|
|
77
|
+
self.action_goto(self.app.this)
|
|
78
78
|
if self.iolanta.project_root:
|
|
79
79
|
self.run_worker(
|
|
80
80
|
self._watch_files,
|
|
@@ -94,24 +94,24 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
94
94
|
|
|
95
95
|
def render_iri( # noqa: WPS210
|
|
96
96
|
self,
|
|
97
|
-
|
|
97
|
+
this: NotLiteralNode,
|
|
98
98
|
facet_iri: URIRef | None,
|
|
99
99
|
is_reload: bool,
|
|
100
100
|
) -> RenderResult:
|
|
101
101
|
"""Render an IRI in a thread."""
|
|
102
|
-
self.
|
|
102
|
+
self.this = this
|
|
103
103
|
iolanta: Iolanta = self.iolanta
|
|
104
104
|
|
|
105
105
|
as_datatype = URIRef('https://iolanta.tech/cli/textual')
|
|
106
106
|
choices = FacetFinder(
|
|
107
107
|
iolanta=self.iolanta,
|
|
108
|
-
node=
|
|
108
|
+
node=this,
|
|
109
109
|
as_datatype=as_datatype,
|
|
110
110
|
).choices()
|
|
111
111
|
|
|
112
112
|
if not choices:
|
|
113
113
|
raise FacetNotFound(
|
|
114
|
-
node=self.
|
|
114
|
+
node=self.this,
|
|
115
115
|
as_datatype=as_datatype,
|
|
116
116
|
node_types=[],
|
|
117
117
|
)
|
|
@@ -139,7 +139,7 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
139
139
|
facet_class = iolanta.facet_resolver.resolve(facet_iri)
|
|
140
140
|
|
|
141
141
|
facet = facet_class(
|
|
142
|
-
|
|
142
|
+
this=self.this,
|
|
143
143
|
iolanta=iolanta,
|
|
144
144
|
as_datatype=URIRef('https://iolanta.tech/cli/textual'),
|
|
145
145
|
)
|
|
@@ -149,13 +149,13 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
149
149
|
|
|
150
150
|
except Exception as err:
|
|
151
151
|
raise FacetError(
|
|
152
|
-
node=self.
|
|
152
|
+
node=self.this,
|
|
153
153
|
facet_iri=facet_iri,
|
|
154
154
|
error=err,
|
|
155
155
|
) from err
|
|
156
156
|
|
|
157
157
|
return RenderResult(
|
|
158
|
-
iri=
|
|
158
|
+
iri=this,
|
|
159
159
|
renderable=renderable,
|
|
160
160
|
flip_options=flip_options,
|
|
161
161
|
facet_iri=facet_iri,
|
|
@@ -222,7 +222,7 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
222
222
|
self.run_worker(
|
|
223
223
|
functools.partial(
|
|
224
224
|
self.render_iri,
|
|
225
|
-
|
|
225
|
+
this=self.history.current.url,
|
|
226
226
|
facet_iri=self.history.current.facet_iri,
|
|
227
227
|
is_reload=True,
|
|
228
228
|
),
|
|
@@ -267,19 +267,14 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
|
|
|
267
267
|
|
|
268
268
|
def action_goto(
|
|
269
269
|
self,
|
|
270
|
-
|
|
270
|
+
this: Node,
|
|
271
271
|
facet_iri: str | None = None,
|
|
272
272
|
):
|
|
273
273
|
"""Go to an IRI."""
|
|
274
|
-
if destination.startswith('_:'):
|
|
275
|
-
iri = BNode(destination)
|
|
276
|
-
else:
|
|
277
|
-
iri = URIRef(destination)
|
|
278
|
-
|
|
279
274
|
self.run_worker(
|
|
280
275
|
functools.partial(
|
|
281
276
|
self.render_iri,
|
|
282
|
-
|
|
277
|
+
this=this,
|
|
283
278
|
facet_iri=facet_iri and URIRef(facet_iri),
|
|
284
279
|
is_reload=False,
|
|
285
280
|
),
|
|
@@ -328,7 +323,7 @@ class DevConsole(RichLog):
|
|
|
328
323
|
|
|
329
324
|
def __init__(self):
|
|
330
325
|
"""Set default props for console."""
|
|
331
|
-
super().__init__(highlight=
|
|
326
|
+
super().__init__(highlight=False, markup=False, id='console')
|
|
332
327
|
|
|
333
328
|
def action_close(self):
|
|
334
329
|
"""Close the dev console."""
|