iolanta 2.0.1__tar.gz → 2.0.5__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.0.1 → iolanta-2.0.5}/PKG-INFO +1 -1
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/data/context.yaml +15 -0
- iolanta-2.0.5/iolanta/data/graph-triples.yamlld +6 -0
- iolanta-2.0.5/iolanta/data/textual-browser.yaml +127 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/facet.py +5 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/locator.py +32 -1
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_class/facets.py +35 -46
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_class/sparql/instances.sparql +1 -1
- iolanta-2.0.5/iolanta/facets/textual_property_pairs_table.py +133 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/iolanta.py +3 -3
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/parse_quads.py +0 -7
- iolanta-2.0.5/iolanta/sparqlspace/cli.py +64 -0
- {iolanta-2.0.1/iolanta/cyberspace → iolanta-2.0.5/iolanta/sparqlspace}/processor.py +113 -72
- iolanta-2.0.5/iolanta/sparqlspace/sparqlspace.py +32 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/pyproject.toml +3 -3
- iolanta-2.0.1/iolanta/data/textual-browser.yaml +0 -109
- {iolanta-2.0.1 → iolanta-2.0.5}/README.md +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/base_plugin.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/formatters/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/formatters/choose.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/formatters/csv.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/formatters/json.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/formatters/pretty.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/main.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/models.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/cli/pretty_print.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/context.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/conversions.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/data/cli.yaml +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/data/html.yaml +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/data/iolanta.yaml +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/ensure_is_context.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/entry_points.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/errors.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/cli/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/cli/base.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/cli/default.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/cli/record.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/cli/sparql/link.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/cli/sparql/record.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/errors.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/foaf_person_title/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/foaf_person_title/facet.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/foaf_person_title/sparql/names.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/generic/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/generic/bool_literal.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/generic/date_literal.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/generic/default.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/generic/sparql/default.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/html/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/html/base.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/html/code_literal.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/html/default.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/icon.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/page_title.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/qname.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/app.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/facet.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/history.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/home.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/location.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/models.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/page.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_browser/page_switcher.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_class/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/facets.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/sparql/inverse-properties.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/sparql/label.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/sparql/nodes-for-property.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/sparql/properties.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/tcss/default.tcss +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/templates/default.md +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/triple_uri_ref.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_default/widgets.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_graph/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_graph/facets.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_graph/sparql/triples.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_graph_triples.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_link/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_link/facet.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_nanopublication/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_nanopublication/facet.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_nanopublication/models.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_nanopublication/nanopublication_widget.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_nanopublication/term_list_widget.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_nanopublication/term_widget.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_ontology/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_ontology/facets.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_ontology/sparql/terms.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_ontology/sparql/visualization-vocab.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_provenance/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_provenance/facets.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_provenance/sparql/graphs.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/textual_provenance/sparql/triples.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/title/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/title/facets.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/title/sparql/title.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/wikibase_statement_title/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/wikibase_statement_title/facets.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/facets/wikibase_statement_title/sparql/statement-title.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/base.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/data_type_choice.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/dict_loader.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/errors.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/http.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/local_directory.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/local_file.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/loaders/scheme_choice.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/models.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/namespaces.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/node_to_qname.py +0 -0
- {iolanta-2.0.1/iolanta/cyberspace → iolanta-2.0.5/iolanta/parsers}/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/parsers/base.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/parsers/dict_parser.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/parsers/errors.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/parsers/json.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/parsers/markdown.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/parsers/yaml.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/plugin.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/query_result.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/reformat_blank_nodes.py +0 -0
- {iolanta-2.0.1/iolanta/parsers → iolanta-2.0.5/iolanta/resolvers}/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/resolvers/base.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/resolvers/python_import.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/shortcuts.py +0 -0
- {iolanta-2.0.1/iolanta/resolvers → iolanta-2.0.5/iolanta/sparqlspace}/__init__.py +0 -0
- {iolanta-2.0.1/iolanta/cyberspace → iolanta-2.0.5/iolanta/sparqlspace}/inference/wikibase-claim.sparql +0 -0
- {iolanta-2.0.1/iolanta/cyberspace → iolanta-2.0.5/iolanta/sparqlspace}/inference/wikibase-statement-property.sparql +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/widgets/__init__.py +0 -0
- {iolanta-2.0.1 → iolanta-2.0.5}/iolanta/widgets/mixin.py +0 -0
|
@@ -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
|
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
np: https://www.nanopub.org/nschema#
|
|
10
|
+
dcterms: https://purl.org/dc/terms/
|
|
11
|
+
xsd: https://www.w3.org/2001/XMLSchema#
|
|
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
|
+
|
|
31
|
+
"@included":
|
|
32
|
+
- $id: iolanta:icon
|
|
33
|
+
$: Icon
|
|
34
|
+
⊆: xsd:string
|
|
35
|
+
|
|
36
|
+
- $id: dcterms:creator
|
|
37
|
+
iolanta:icon: ©️
|
|
38
|
+
|
|
39
|
+
- $id: https://iolanta.tech/datatypes/icon
|
|
40
|
+
$: Icon
|
|
41
|
+
iolanta:hasDefaultFacet:
|
|
42
|
+
$id: python://iolanta.facets.icon.IconFacet
|
|
43
|
+
→: https://iolanta.tech/datatypes/icon
|
|
44
|
+
|
|
45
|
+
- $id: np:Nanopublication
|
|
46
|
+
$: Nanopublication
|
|
47
|
+
iolanta:hasInstanceFacet:
|
|
48
|
+
$id: python://iolanta.facets.textual_nanopublication.NanopublicationFacet
|
|
49
|
+
$: Nanopublication
|
|
50
|
+
→: https://iolanta.tech/cli/textual
|
|
51
|
+
⪯:
|
|
52
|
+
- python://iolanta.facets.textual_default.TextualDefaultFacet
|
|
53
|
+
- python://iolanta.facets.textual_graph.GraphFacet
|
|
54
|
+
|
|
55
|
+
- $id: https://iolanta.tech/cli/interactive
|
|
56
|
+
iolanta:hasDefaultFacet:
|
|
57
|
+
$id: python://iolanta.facets.textual_browser.TextualBrowserFacet
|
|
58
|
+
|
|
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
|
+
}
|
|
68
|
+
|
|
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
|
+
}
|
|
77
|
+
|
|
78
|
+
- $id: "urn:"
|
|
79
|
+
iolanta:hasFacetByPrefix:
|
|
80
|
+
$id: python://iolanta.facets.textual_provenance.TextualProvenanceFacet
|
|
81
|
+
→: https://iolanta.tech/cli/textual
|
|
82
|
+
|
|
83
|
+
- $id: https://iolanta.tech/cli/link
|
|
84
|
+
iolanta:hasDefaultFacet:
|
|
85
|
+
$id: python://iolanta.facets.textual_link.TextualLinkFacet
|
|
86
|
+
|
|
87
|
+
- $id: https://wikiba.se/ontology#Statement
|
|
88
|
+
iolanta:hasInstanceFacet:
|
|
89
|
+
$id: python://iolanta.facets.wikibase_statement_title.WikibaseStatementTitle
|
|
90
|
+
$: Title
|
|
91
|
+
→: https://iolanta.tech/datatypes/title
|
|
92
|
+
|
|
93
|
+
- $id: rdfs:Class
|
|
94
|
+
iolanta:hasInstanceFacet:
|
|
95
|
+
$id: python://iolanta.facets.textual_class.Class
|
|
96
|
+
$: Instances
|
|
97
|
+
→: https://iolanta.tech/cli/textual
|
|
98
|
+
⪯:
|
|
99
|
+
- python://iolanta.facets.textual_browser.TextualBrowserFacet
|
|
100
|
+
- python://iolanta.facets.textual_default.InverseProperties
|
|
101
|
+
|
|
102
|
+
- $id: owl:Ontology
|
|
103
|
+
iolanta:hasInstanceFacet:
|
|
104
|
+
$id: python://iolanta.facets.textual_ontology.OntologyFacet
|
|
105
|
+
$: Ontology
|
|
106
|
+
→: https://iolanta.tech/cli/textual
|
|
107
|
+
⪯: python://iolanta.facets.textual_default.TextualDefaultFacet
|
|
108
|
+
|
|
109
|
+
- $id: https://iolanta.tech/datatypes/textual-graph-triples
|
|
110
|
+
$: Graph Triples
|
|
111
|
+
iolanta:hasDefaultFacet:
|
|
112
|
+
$id: python://iolanta.facets.textual_graph_triples.GraphTriplesFacet
|
|
113
|
+
→: https://iolanta.tech/datatypes/textual-graph-triples
|
|
114
|
+
|
|
115
|
+
- $id: https://iolanta.tech/qname
|
|
116
|
+
iolanta:hasDefaultFacet:
|
|
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 }
|
|
@@ -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."""
|
|
@@ -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
|
+
)
|
|
@@ -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 = [
|
|
@@ -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
|
+
)
|