iolanta 2.1.4__tar.gz → 2.1.7__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.
Files changed (151) hide show
  1. {iolanta-2.1.4 → iolanta-2.1.7}/PKG-INFO +6 -3
  2. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/main.py +44 -24
  3. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/data/context.yaml +1 -1
  4. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/data/iolanta.yaml +1 -1
  5. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/data/textual-browser.yaml +1 -7
  6. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/declension/data/declension.yamlld +1 -1
  7. iolanta-2.1.7/iolanta/facets/locator/sparql/get-query-to-facet.sparql +5 -0
  8. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/locator.py +4 -7
  9. iolanta-2.1.7/iolanta/facets/mkdocs_material_insiders_markdown/__init__.py +4 -0
  10. iolanta-2.1.7/iolanta/facets/mkdocs_material_insiders_markdown/data/mkdocs_material_insiders_markdown.yamlld +20 -0
  11. iolanta-2.1.7/iolanta/facets/mkdocs_material_insiders_markdown/facet.py +86 -0
  12. iolanta-2.1.7/iolanta/facets/mkdocs_material_insiders_markdown/templates/datatype.jinja2.md +24 -0
  13. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/page_switcher.py +1 -1
  14. iolanta-2.1.7/iolanta/facets/textual_graphs/__init__.py +6 -0
  15. iolanta-2.1.7/iolanta/facets/textual_graphs/data/textual_graphs.yamlld +23 -0
  16. iolanta-2.1.7/iolanta/facets/textual_graphs/facets.py +138 -0
  17. iolanta-2.1.7/iolanta/facets/textual_graphs/sparql/graphs.sparql +5 -0
  18. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/iolanta.py +4 -3
  19. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/labeled_triple_set/data/labeled_triple_set.yamlld +1 -1
  20. iolanta-2.1.7/iolanta/mcp/cli.py +39 -0
  21. iolanta-2.1.7/iolanta/mcp/prompts/nanopublication_assertion_authoring_rules.md +63 -0
  22. iolanta-2.1.7/iolanta/mcp/prompts/rules.md +83 -0
  23. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/mermaid/facet.py +0 -3
  24. iolanta-2.1.7/iolanta/mermaid/mermaid.yamlld +25 -0
  25. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/mermaid/models.py +4 -2
  26. iolanta-2.1.7/iolanta/mermaid/sparql/ask-has-triples.sparql +3 -0
  27. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/models.py +0 -3
  28. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/namespaces.py +2 -2
  29. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/parse_quads.py +2 -2
  30. iolanta-2.1.7/iolanta/sparqlspace/inference/wikidata-prop-label.sparql +10 -0
  31. iolanta-2.1.7/iolanta/sparqlspace/inference/wikidata-statement-label.sparql +27 -0
  32. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/sparqlspace/processor.py +80 -78
  33. iolanta-2.1.7/iolanta/widgets/__init__.py +0 -0
  34. {iolanta-2.1.4 → iolanta-2.1.7}/pyproject.toml +8 -4
  35. iolanta-2.1.4/iolanta/mermaid/mermaid.yamlld +0 -42
  36. iolanta-2.1.4/iolanta/sparqlspace/inference/wikibase-claim.sparql +0 -9
  37. iolanta-2.1.4/iolanta/sparqlspace/inference/wikibase-statement-property.sparql +0 -9
  38. {iolanta-2.1.4 → iolanta-2.1.7}/README.md +0 -0
  39. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/__init__.py +0 -0
  40. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/base_plugin.py +0 -0
  41. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/__init__.py +0 -0
  42. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/formatters/__init__.py +0 -0
  43. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/formatters/choose.py +0 -0
  44. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/formatters/csv.py +0 -0
  45. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/formatters/json.py +0 -0
  46. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/formatters/pretty.py +0 -0
  47. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/models.py +0 -0
  48. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/cli/pretty_print.py +0 -0
  49. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/context.py +0 -0
  50. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/conversions.py +0 -0
  51. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/data/graph-triples.yamlld +0 -0
  52. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/declension/__init__.py +0 -0
  53. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/declension/facet.py +0 -0
  54. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/declension/sparql/declension.sparql +0 -0
  55. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/ensure_is_context.py +0 -0
  56. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/entry_points.py +0 -0
  57. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/errors.py +0 -0
  58. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/__init__.py +0 -0
  59. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/cli/__init__.py +0 -0
  60. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/cli/base.py +0 -0
  61. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/cli/default.py +0 -0
  62. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/cli/record.py +0 -0
  63. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/cli/sparql/link.sparql +0 -0
  64. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/cli/sparql/record.sparql +0 -0
  65. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/errors.py +0 -0
  66. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/facet.py +0 -0
  67. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/foaf_person_title/__init__.py +0 -0
  68. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/foaf_person_title/facet.py +0 -0
  69. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/foaf_person_title/sparql/names.sparql +0 -0
  70. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/generic/__init__.py +0 -0
  71. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/generic/bool_literal.py +0 -0
  72. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/generic/date_literal.py +0 -0
  73. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/generic/default.py +0 -0
  74. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/generic/sparql/default.sparql +0 -0
  75. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/html/__init__.py +0 -0
  76. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/html/base.py +0 -0
  77. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/html/code_literal.py +0 -0
  78. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/html/default.py +0 -0
  79. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/icon.py +0 -0
  80. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/page_title.py +0 -0
  81. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/qname.py +0 -0
  82. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/__init__.py +0 -0
  83. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/app.py +0 -0
  84. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/facet.py +0 -0
  85. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/history.py +0 -0
  86. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/home.py +0 -0
  87. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/location.py +0 -0
  88. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/models.py +0 -0
  89. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_browser/page.py +0 -0
  90. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_class/__init__.py +0 -0
  91. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_class/facets.py +0 -0
  92. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_class/sparql/instances.sparql +0 -0
  93. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/__init__.py +0 -0
  94. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/facets.py +0 -0
  95. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/sparql/inverse-properties.sparql +0 -0
  96. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/sparql/label.sparql +0 -0
  97. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/sparql/nodes-for-property.sparql +0 -0
  98. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/sparql/properties.sparql +0 -0
  99. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/tcss/default.tcss +0 -0
  100. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/templates/default.md +0 -0
  101. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/triple_uri_ref.py +0 -0
  102. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_default/widgets.py +0 -0
  103. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_graph/__init__.py +0 -0
  104. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_graph/facets.py +0 -0
  105. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_graph/sparql/triples.sparql +0 -0
  106. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_graph_triples.py +0 -0
  107. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_link/__init__.py +0 -0
  108. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_link/facet.py +0 -0
  109. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_nanopublication/__init__.py +0 -0
  110. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_nanopublication/facet.py +0 -0
  111. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_nanopublication/models.py +0 -0
  112. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_nanopublication/nanopublication_widget.py +0 -0
  113. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_nanopublication/term_list_widget.py +0 -0
  114. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_nanopublication/term_widget.py +0 -0
  115. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_no_facet_found.py +0 -0
  116. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_ontology/__init__.py +0 -0
  117. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_ontology/facets.py +0 -0
  118. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_ontology/sparql/terms.sparql +0 -0
  119. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_ontology/sparql/visualization-vocab.sparql +0 -0
  120. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_property_pairs_table.py +0 -0
  121. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_provenance/__init__.py +0 -0
  122. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_provenance/facets.py +0 -0
  123. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_provenance/sparql/graphs.sparql +0 -0
  124. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/textual_provenance/sparql/triples.sparql +0 -0
  125. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/title/__init__.py +0 -0
  126. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/title/facets.py +0 -0
  127. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/title/sparql/title.sparql +0 -0
  128. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/wikibase_statement_title/__init__.py +0 -0
  129. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/wikibase_statement_title/facets.py +0 -0
  130. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/facets/wikibase_statement_title/sparql/statement-title.sparql +0 -0
  131. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/labeled_triple_set/__init__.py +0 -0
  132. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/labeled_triple_set/labeled_triple_set.py +0 -0
  133. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/labeled_triple_set/sparql/triples.sparql +0 -0
  134. {iolanta-2.1.4/iolanta/mermaid → iolanta-2.1.7/iolanta/mcp}/__init__.py +0 -0
  135. {iolanta-2.1.4/iolanta/resolvers → iolanta-2.1.7/iolanta/mermaid}/__init__.py +0 -0
  136. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/mermaid/sparql/graph.sparql +0 -0
  137. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/mermaid/sparql/subgraphs.sparql +0 -0
  138. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/node_to_qname.py +0 -0
  139. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/plugin.py +0 -0
  140. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/query_result.py +0 -0
  141. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/reformat_blank_nodes.py +0 -0
  142. {iolanta-2.1.4/iolanta/sparqlspace → iolanta-2.1.7/iolanta/resolvers}/__init__.py +0 -0
  143. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/resolvers/base.py +0 -0
  144. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/resolvers/dispatch.py +0 -0
  145. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/resolvers/pypi.py +0 -0
  146. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/resolvers/python_import.py +0 -0
  147. {iolanta-2.1.4/iolanta/widgets → iolanta-2.1.7/iolanta/sparqlspace}/__init__.py +0 -0
  148. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/sparqlspace/cli.py +0 -0
  149. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/sparqlspace/sparqlspace.py +0 -0
  150. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/widgets/description.py +0 -0
  151. {iolanta-2.1.4 → iolanta-2.1.7}/iolanta/widgets/mixin.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: iolanta
3
- Version: 2.1.4
3
+ Version: 2.1.7
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)
@@ -17,9 +18,11 @@ Requires-Dist: deepmerge (>=0.1.1)
17
18
  Requires-Dist: diskcache (>=5.6.3)
18
19
  Requires-Dist: documented (>=0.1.1)
19
20
  Requires-Dist: dominate (>=2.6.0)
21
+ Requires-Dist: fastmcp (>=2.12.4,<3.0.0)
20
22
  Requires-Dist: funcy (>=2.0)
21
23
  Requires-Dist: loguru (>=0.7.3)
22
24
  Requires-Dist: more-itertools (>=9.0.0)
25
+ Requires-Dist: nanopub (>=2.1.0,<3.0.0)
23
26
  Requires-Dist: owlrl (>=6.0.2)
24
27
  Requires-Dist: oxrdflib (>=0.4.0)
25
28
  Requires-Dist: packageurl-python (>=0.17.5)
@@ -31,7 +34,7 @@ Requires-Dist: rich (>=13.3.1)
31
34
  Requires-Dist: textual (>=0.83.0)
32
35
  Requires-Dist: typer (>=0.9.0)
33
36
  Requires-Dist: watchfiles (>=1.0.4)
34
- Requires-Dist: yaml-ld (>=1.1.12)
37
+ Requires-Dist: yaml-ld (>=1.1.15)
35
38
  Requires-Dist: yarl (>=1.9.4)
36
39
  Description-Content-Type: text/markdown
37
40
 
@@ -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, Exit, Option, Typer, Context
15
15
  from yarl import URL
16
16
 
17
17
  from iolanta.cli.models import LogLevel
@@ -24,9 +24,7 @@ DEFAULT_LANGUAGE = locale.getlocale()[0].split('_')[0]
24
24
  console = Console()
25
25
 
26
26
 
27
- app = Typer(
28
- no_args_is_help=True,
29
- )
27
+ app = Typer(no_args_is_help=True)
30
28
 
31
29
 
32
30
  def string_to_node(name: str) -> NotLiteralNode:
@@ -52,19 +50,10 @@ def decode_datatype(datatype: str) -> URIRef:
52
50
  return URIRef(f'https://iolanta.tech/datatypes/{datatype}')
53
51
 
54
52
 
55
- @app.command(name='browse')
56
- def render_command( # noqa: WPS231, WPS238, WPS210, C901
57
- url: Annotated[str, Argument()],
58
- as_datatype: Annotated[
59
- str, Option(
60
- '--as',
61
- ),
62
- ] = 'https://iolanta.tech/cli/interactive',
63
- language: Annotated[
64
- str, Option(
65
- help='Data language to prefer.',
66
- ),
67
- ] = DEFAULT_LANGUAGE,
53
+ def render_and_return(
54
+ url: str,
55
+ as_datatype: str,
56
+ language: str = DEFAULT_LANGUAGE,
68
57
  log_level: LogLevel = LogLevel.ERROR,
69
58
  ):
70
59
  """Render a given URL."""
@@ -124,13 +113,38 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
124
113
  project_root=path,
125
114
  )
126
115
 
127
- try:
128
- renderable = iolanta.render(
129
- node=URIRef(node),
130
- as_datatype=decode_datatype(as_datatype),
131
- )
116
+ return iolanta.render(
117
+ node=URIRef(node),
118
+ as_datatype=decode_datatype(as_datatype),
119
+ )
120
+
132
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)
133
140
  except DocumentedError as documented_error:
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
+
134
148
  if level in {logging.DEBUG, logging.INFO}:
135
149
  raise
136
150
 
@@ -143,12 +157,18 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
143
157
  raise Exit(1)
144
158
 
145
159
  except Exception as err:
146
- if iolanta.logger.level in {logging.DEBUG, logging.INFO}:
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
+
167
+ if level in {logging.DEBUG, logging.INFO}:
147
168
  raise
148
169
 
149
170
  console.print(str(err))
150
171
  raise Exit(1)
151
-
152
172
  else:
153
173
  # FIXME: An intermediary Literal can be used to dispatch rendering.
154
174
  match renderable:
@@ -1,5 +1,5 @@
1
1
  "@context":
2
- rdfs: "https://www.w3.org/2000/01/rdf-schema#"
2
+ rdfs: "http://www.w3.org/2000/01/rdf-schema#"
3
3
  rdf: https://www.w3.org/1999/02/22-rdf-syntax-ns#
4
4
  iolanta: https://iolanta.tech/
5
5
  owl: https://www.w3.org/2002/07/owl#
@@ -4,7 +4,7 @@
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: "https://www.w3.org/2000/01/rdf-schema#"
7
+ rdfs: "http://www.w3.org/2000/01/rdf-schema#"
8
8
  rdf: https://www.w3.org/1999/02/22-rdf-syntax-ns#
9
9
 
10
10
  $included:
@@ -4,7 +4,7 @@
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: "https://www.w3.org/2000/01/rdf-schema#"
7
+ rdfs: "http://www.w3.org/2000/01/rdf-schema#"
8
8
  rdf: https://www.w3.org/1999/02/22-rdf-syntax-ns#
9
9
  np: https://www.nanopub.org/nschema#
10
10
  dcterms: https://purl.org/dc/terms/
@@ -88,12 +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
91
  - $id: rdfs:Class
98
92
  iolanta:hasInstanceFacet:
99
93
  $id: pkg:pypi/iolanta#textual-class
@@ -4,7 +4,7 @@
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: "https://www.w3.org/2000/01/rdf-schema#"
7
+ rdfs: "http://www.w3.org/2000/01/rdf-schema#"
8
8
  rdf: https://www.w3.org/1999/02/22-rdf-syntax-ns#
9
9
  dcterms: https://purl.org/dc/terms/
10
10
  dcam: https://purl.org/dc/dcam/
@@ -0,0 +1,5 @@
1
+ SELECT ?facet ?match WHERE {
2
+ ?facet
3
+ iolanta:matches ?match ;
4
+ iolanta:outputs $as_datatype .
5
+ }
@@ -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
- SELECT ?facet ?match WHERE {
23
- ?facet
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
@@ -0,0 +1,4 @@
1
+ from iolanta.facets.mkdocs_material_insiders_markdown.facet import MkDocsMaterialInsidersMarkdownFacet
2
+
3
+ __all__ = ['MkDocsMaterialInsidersMarkdownFacet']
4
+
@@ -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: https://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 %}
@@ -323,7 +323,7 @@ class DevConsole(RichLog):
323
323
 
324
324
  def __init__(self):
325
325
  """Set default props for console."""
326
- super().__init__(highlight=True, markup=True, id='console')
326
+ super().__init__(highlight=False, markup=False, id='console')
327
327
 
328
328
  def action_close(self):
329
329
  """Close the dev console."""
@@ -0,0 +1,6 @@
1
+ """Facet to render named graphs."""
2
+
3
+ from iolanta.facets.textual_graphs.facets import Graphs
4
+
5
+ __all__ = ['Graphs']
6
+
@@ -0,0 +1,23 @@
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
+ rdfg: http://www.w3.org/2009/rdfg#
6
+
7
+ $: rdfs:label
8
+ iolanta:is-preferred-over:
9
+ "@type": "@id"
10
+
11
+ iolanta:outputs:
12
+ "@type": "@id"
13
+
14
+ $id: rdfg:Graph
15
+ iolanta:facet:
16
+ $id: pkg:pypi/iolanta#textual-graphs
17
+ $: Named Graphs
18
+
19
+ iolanta:outputs: https://iolanta.tech/cli/textual
20
+
21
+ iolanta:is-preferred-over:
22
+ - pkg:pypi/iolanta#textual-properties
23
+ - pkg:pypi/iolanta#textual-graph-triples
@@ -0,0 +1,138 @@
1
+ from collections import defaultdict
2
+ from pathlib import Path
3
+ from typing import Iterable, NamedTuple
4
+
5
+ import funcy
6
+ from rdflib import Literal, Node
7
+ from textual.containers import Vertical
8
+ from textual.coordinate import Coordinate
9
+ from textual.widgets import DataTable
10
+
11
+ from iolanta.facets.facet import Facet
12
+ from iolanta.facets.page_title import PageTitle
13
+ from iolanta.models import NotLiteralNode
14
+ from iolanta.namespaces import DATATYPES
15
+ from iolanta.widgets.mixin import IolantaWidgetMixin
16
+
17
+
18
+ class GraphRow(NamedTuple):
19
+ """A row in the graphs table."""
20
+
21
+ graph: NotLiteralNode
22
+ count: int
23
+
24
+
25
+ class GraphsTable(IolantaWidgetMixin, DataTable):
26
+ """Render graphs as a table with graph URI and triple count."""
27
+
28
+ BINDINGS = [
29
+ ('enter', 'goto', 'Goto'),
30
+ ]
31
+
32
+ def __init__(self, rows: Iterable[GraphRow]):
33
+ """Construct."""
34
+ super().__init__(show_header=True, cell_padding=1)
35
+ self.graph_rows = list(rows)
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 = str(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=title,
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, (graph, _count) in enumerate(self.graph_rows):
62
+ yield Coordinate(row_number, 0), graph
63
+
64
+ @funcy.cached_property
65
+ def node_to_coordinates(self) -> defaultdict[Node, list[Coordinate]]:
66
+ """Map node to coordinates where it appears."""
67
+ node_to_coordinate = [
68
+ (node, coordinate)
69
+ for coordinate, node in self.coordinate_to_node.items()
70
+ ]
71
+ return funcy.group_values(node_to_coordinate)
72
+
73
+ def format_as_loading(self, node: Node) -> str:
74
+ """Intermediate version of a value while it is loading."""
75
+ if isinstance(node, Literal):
76
+ node_text = f'⌛ {node}'
77
+ else:
78
+ node_text = self.iolanta.node_as_qname(node)
79
+ node_text = f'⌛ {node_text}'
80
+
81
+ return node_text
82
+
83
+ def on_mount(self):
84
+ """Fill the table and start rendering."""
85
+ self.add_columns('Graph', 'Triples Count')
86
+ self.cell_padding = 1
87
+
88
+ for graph, count in self.graph_rows:
89
+ self.add_row(
90
+ self.format_as_loading(graph),
91
+ str(count),
92
+ )
93
+
94
+ self.run_worker(
95
+ self.render_human_readable_cells,
96
+ thread=True,
97
+ )
98
+
99
+ def action_goto(self):
100
+ """Navigate to the selected graph."""
101
+ if self.cursor_coordinate:
102
+ node = self.coordinate_to_node.get(self.cursor_coordinate)
103
+ if node is not None:
104
+ self.app.action_goto(node)
105
+
106
+
107
+ class GraphsBody(Vertical):
108
+ """Container for graphs table."""
109
+
110
+ DEFAULT_CSS = """
111
+ GraphsBody {
112
+ height: auto;
113
+ max-height: 100%;
114
+ }
115
+ """
116
+
117
+
118
+ class Graphs(Facet):
119
+ """Render named graphs as a table."""
120
+
121
+ META = Path(__file__).parent / 'data' / 'textual_graphs.yamlld'
122
+
123
+ def show(self):
124
+ """Construct the table."""
125
+ rows = self.stored_query('graphs.sparql')
126
+
127
+ return GraphsBody(
128
+ PageTitle(self.this),
129
+ GraphsTable(
130
+ [
131
+ GraphRow(
132
+ graph=row['graph'],
133
+ count=int(row['count'].value),
134
+ )
135
+ for row in rows
136
+ ],
137
+ ),
138
+ )
@@ -0,0 +1,5 @@
1
+ SELECT ?graph (COUNT(?s) AS ?count) WHERE {
2
+ GRAPH ?graph {
3
+ ?s ?p ?o .
4
+ }
5
+ } GROUP BY ?graph ORDER BY DESC(?count) ?graph
@@ -119,7 +119,7 @@ class Iolanta: # noqa: WPS214
119
119
  processor='sparqlspace',
120
120
  initBindings=kwargs,
121
121
  )
122
- except ParseException as err:
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
- self.logger.error(f'{source} | {yaml_ld_error}')
175
- continue
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
@@ -4,7 +4,7 @@
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: "https://www.w3.org/2000/01/rdf-schema#"
7
+ rdfs: "http://www.w3.org/2000/01/rdf-schema#"
8
8
  rdf: https://www.w3.org/1999/02/22-rdf-syntax-ns#
9
9
  dcterms: https://purl.org/dc/terms/
10
10
  dcam: https://purl.org/dc/dcam/
@@ -0,0 +1,39 @@
1
+ from typing import Annotated
2
+ from fastmcp import FastMCP
3
+ from pathlib import Path
4
+
5
+ from iolanta.cli.main import render_and_return
6
+
7
+ mcp = FastMCP("Iolanta MCP Server")
8
+
9
+
10
+ @mcp.tool()
11
+ def render_uri(
12
+ 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
+ ) -> str:
15
+ """Render a URI."""
16
+ result = render_and_return(uri, as_format)
17
+ return str(result)
18
+
19
+
20
+ @mcp.prompt(description="How to author Linked Data with Iolanta")
21
+ def ld_authoring_rules() -> str:
22
+ """How to author Linked Data with Iolanta."""
23
+ rules_path = Path(__file__).parent / 'prompts' / 'rules.md'
24
+ return rules_path.read_text()
25
+
26
+
27
+ @mcp.prompt(description="How to author nanopublication assertions with Iolanta")
28
+ def nanopublication_assertion_authoring_rules() -> str:
29
+ """How to author nanopublication assertions with Iolanta."""
30
+ rules_path = Path(__file__).parent / 'prompts' / 'nanopublication_assertion_authoring_rules.md'
31
+ return rules_path.read_text()
32
+
33
+
34
+ def app():
35
+ mcp.run()
36
+
37
+
38
+ if __name__ == "__main__":
39
+ app()