iolanta 1.2.8__tar.gz → 1.2.10__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 (134) hide show
  1. {iolanta-1.2.8 → iolanta-1.2.10}/PKG-INFO +30 -4
  2. iolanta-1.2.10/README.md +30 -0
  3. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cyberspace/processor.py +78 -25
  4. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/page_title.py +1 -2
  5. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/page_switcher.py +8 -1
  6. {iolanta-1.2.8 → iolanta-1.2.10}/pyproject.toml +2 -2
  7. iolanta-1.2.8/README.md +0 -4
  8. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/__init__.py +0 -0
  9. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/base_plugin.py +0 -0
  10. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/__init__.py +0 -0
  11. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/formatters/__init__.py +0 -0
  12. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/formatters/choose.py +0 -0
  13. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/formatters/csv.py +0 -0
  14. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/formatters/json.py +0 -0
  15. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/formatters/pretty.py +0 -0
  16. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/main.py +0 -0
  17. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/models.py +0 -0
  18. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cli/pretty_print.py +0 -0
  19. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/context.py +0 -0
  20. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/conversions.py +0 -0
  21. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cyberspace/__init__.py +0 -0
  22. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cyberspace/inference/wikibase-claim.sparql +0 -0
  23. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/cyberspace/inference/wikibase-statement-property.sparql +0 -0
  24. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/data/cli.yaml +0 -0
  25. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/data/context.yaml +0 -0
  26. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/data/html.yaml +0 -0
  27. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/data/iolanta.yaml +0 -0
  28. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/data/textual-browser.yaml +0 -0
  29. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/ensure_is_context.py +0 -0
  30. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/entry_points.py +0 -0
  31. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/errors.py +0 -0
  32. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/__init__.py +0 -0
  33. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/cli/__init__.py +0 -0
  34. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/cli/base.py +0 -0
  35. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/cli/default.py +0 -0
  36. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/cli/record.py +0 -0
  37. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/cli/sparql/link.sparql +0 -0
  38. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/cli/sparql/record.sparql +0 -0
  39. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/errors.py +0 -0
  40. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/facet.py +0 -0
  41. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/foaf_person_title/__init__.py +0 -0
  42. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/foaf_person_title/facet.py +0 -0
  43. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/foaf_person_title/sparql/names.sparql +0 -0
  44. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/generic/__init__.py +0 -0
  45. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/generic/bool_literal.py +0 -0
  46. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/generic/date_literal.py +0 -0
  47. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/generic/default.py +0 -0
  48. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/generic/sparql/default.sparql +0 -0
  49. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/html/__init__.py +0 -0
  50. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/html/base.py +0 -0
  51. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/html/code_literal.py +0 -0
  52. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/html/default.py +0 -0
  53. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/icon.py +0 -0
  54. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/locator.py +0 -0
  55. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/qname.py +0 -0
  56. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/__init__.py +0 -0
  57. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/app.py +0 -0
  58. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/facet.py +0 -0
  59. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/history.py +0 -0
  60. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/home.py +0 -0
  61. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/location.py +0 -0
  62. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/models.py +0 -0
  63. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_browser/page.py +0 -0
  64. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_class/__init__.py +0 -0
  65. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_class/facets.py +0 -0
  66. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_class/sparql/instances.sparql +0 -0
  67. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/__init__.py +0 -0
  68. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/facets.py +0 -0
  69. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/sparql/inverse-properties.sparql +0 -0
  70. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/sparql/label.sparql +0 -0
  71. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/sparql/nodes-for-property.sparql +0 -0
  72. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/sparql/properties.sparql +0 -0
  73. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/tcss/default.tcss +0 -0
  74. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/templates/default.md +0 -0
  75. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/triple_uri_ref.py +0 -0
  76. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_default/widgets.py +0 -0
  77. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_graph/__init__.py +0 -0
  78. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_graph/facets.py +0 -0
  79. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_graph/sparql/triples.sparql +0 -0
  80. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_graph_triples.py +0 -0
  81. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_link/__init__.py +0 -0
  82. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_link/facet.py +0 -0
  83. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_nanopublication/__init__.py +0 -0
  84. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_nanopublication/facet.py +0 -0
  85. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_nanopublication/models.py +0 -0
  86. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_nanopublication/nanopublication_widget.py +0 -0
  87. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_nanopublication/term_list_widget.py +0 -0
  88. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_nanopublication/term_widget.py +0 -0
  89. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_ontology/__init__.py +0 -0
  90. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_ontology/facets.py +0 -0
  91. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_ontology/sparql/terms.sparql +0 -0
  92. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_ontology/sparql/visualization-vocab.sparql +0 -0
  93. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_provenance/__init__.py +0 -0
  94. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_provenance/facets.py +0 -0
  95. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_provenance/sparql/graphs.sparql +0 -0
  96. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/textual_provenance/sparql/triples.sparql +0 -0
  97. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/title/__init__.py +0 -0
  98. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/title/facets.py +0 -0
  99. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/title/sparql/title.sparql +0 -0
  100. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/wikibase_statement_title/__init__.py +0 -0
  101. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/wikibase_statement_title/facets.py +0 -0
  102. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/facets/wikibase_statement_title/sparql/statement-title.sparql +0 -0
  103. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/iolanta.py +0 -0
  104. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/__init__.py +0 -0
  105. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/base.py +0 -0
  106. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/data_type_choice.py +0 -0
  107. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/dict_loader.py +0 -0
  108. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/errors.py +0 -0
  109. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/http.py +0 -0
  110. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/local_directory.py +0 -0
  111. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/local_file.py +0 -0
  112. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/loaders/scheme_choice.py +0 -0
  113. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/models.py +0 -0
  114. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/namespaces.py +0 -0
  115. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/node_to_qname.py +0 -0
  116. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parse_quads.py +0 -0
  117. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parsers/__init__.py +0 -0
  118. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parsers/base.py +0 -0
  119. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parsers/dict_parser.py +0 -0
  120. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parsers/errors.py +0 -0
  121. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parsers/json.py +0 -0
  122. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parsers/markdown.py +0 -0
  123. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/parsers/yaml.py +0 -0
  124. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/plugin.py +0 -0
  125. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/reformat_blank_nodes.py +0 -0
  126. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/resolvers/__init__.py +0 -0
  127. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/resolvers/base.py +0 -0
  128. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/resolvers/python_import.py +0 -0
  129. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/shortcuts.py +0 -0
  130. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/stack.py +0 -0
  131. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/widgets/__init__.py +0 -0
  132. {iolanta-1.2.8 → iolanta-1.2.10}/iolanta/widgets/mixin.py +0 -0
  133. {iolanta-1.2.8 → iolanta-1.2.10}/ldflex/__init__.py +0 -0
  134. {iolanta-1.2.8 → iolanta-1.2.10}/ldflex/ldflex.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iolanta
3
- Version: 1.2.8
3
+ Version: 1.2.10
4
4
  Summary: Semantic Web browser
5
5
  License: MIT
6
6
  Author: Anatoly Scherbakov
@@ -33,12 +33,38 @@ 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,<2.0.0)
36
- Requires-Dist: yaml-ld (>=1.1.3)
36
+ Requires-Dist: yaml-ld (>=1.1.5)
37
37
  Requires-Dist: yarl (>=1.9.4)
38
38
  Description-Content-Type: text/markdown
39
39
 
40
- # iolanta
40
+ # iolanta | Linked Data browser
41
41
 
42
- Stub repo for the iolanta browser.
42
+ ---
43
43
 
44
+ [![Build Status](https://github.com/iolanta-tech/iolanta/workflows/test/badge.svg?branch=master&event=push)](https://github.com/iolanta-tech/iolanta/actions?query=workflow%3Atest)
45
+ [![codecov](https://codecov.io/gh/iolanta-tech/iolanta/branch/master/graph/badge.svg)](https://codecov.io/gh/iolanta-tech/iolanta)
46
+ [![Python Version](https://img.shields.io/pypi/pyversions/iolanta.svg)](https://pypi.org/project/iolanta/)
47
+ [![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide)
48
+
49
+ ![Iolanta cover image](docs/assets/cover.webp)
50
+
51
+ ## 📦 Install with `pip`
52
+
53
+ ```shell
54
+ pip install iolanta
55
+ ```
56
+
57
+ ## Try it out!
58
+
59
+ Explore a Nanopublication:
60
+
61
+ ```shell
62
+ iolanta https://w3id.org/np/RA7OYmnx-3ln_AY233lElN01wSDJWDOXPz061Ah93EQ2I
63
+ ```
64
+
65
+
66
+
67
+ ![](docs/screenshots/w3id.org.np.ra7oymnx-3ln_ay233leln01wsdjwdoxpz061ah93eq2i.svg)
68
+
69
+ See more [in the docs](https://iolanta.tech).
44
70
 
@@ -0,0 +1,30 @@
1
+ # iolanta | Linked Data browser
2
+
3
+ ---
4
+
5
+ [![Build Status](https://github.com/iolanta-tech/iolanta/workflows/test/badge.svg?branch=master&event=push)](https://github.com/iolanta-tech/iolanta/actions?query=workflow%3Atest)
6
+ [![codecov](https://codecov.io/gh/iolanta-tech/iolanta/branch/master/graph/badge.svg)](https://codecov.io/gh/iolanta-tech/iolanta)
7
+ [![Python Version](https://img.shields.io/pypi/pyversions/iolanta.svg)](https://pypi.org/project/iolanta/)
8
+ [![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide)
9
+
10
+ ![Iolanta cover image](docs/assets/cover.webp)
11
+
12
+ ## 📦 Install with `pip`
13
+
14
+ ```shell
15
+ pip install iolanta
16
+ ```
17
+
18
+ ## Try it out!
19
+
20
+ Explore a Nanopublication:
21
+
22
+ ```shell
23
+ iolanta https://w3id.org/np/RA7OYmnx-3ln_AY233lElN01wSDJWDOXPz061Ah93EQ2I
24
+ ```
25
+
26
+
27
+
28
+ ![](docs/screenshots/w3id.org.np.ra7oymnx-3ln_ay233leln01wsdjwdoxpz061ah93eq2i.svg)
29
+
30
+ See more [in the docs](https://iolanta.tech).
@@ -50,6 +50,9 @@ NORMALIZE_TERMS_MAP = MappingProxyType({
50
50
 
51
51
  REASONING_ENABLED = True
52
52
  OWL_REASONING_ENABLED = False
53
+ INDICES = [
54
+ URIRef('https://iolanta.tech/visualizations/index.yaml'),
55
+ ]
53
56
 
54
57
 
55
58
  REDIRECTS = MappingProxyType({
@@ -67,7 +70,10 @@ REDIRECTS = MappingProxyType({
67
70
  # This one does not answer via HTTPS :(
68
71
  URIRef('https://xmlns.com/foaf/0.1/'): URIRef('http://xmlns.com/foaf/0.1/'),
69
72
  URIRef('https://www.nanopub.org/nschema'): URIRef(
70
- 'https://www.nanopub.net/nschema',
73
+ 'https://www.nanopub.net/nschema#',
74
+ ),
75
+ URIRef('https://nanopub.org/nschema'): URIRef(
76
+ 'https://nanopub.net/nschema#',
71
77
  ),
72
78
  URIRef(PROV): URIRef('https://www.w3.org/ns/prov-o'),
73
79
  })
@@ -278,6 +284,15 @@ def _extract_nanopublication_uris(
278
284
  )
279
285
 
280
286
 
287
+ def apply_redirect(source: URIRef) -> URIRef:
288
+ """Rewrite the URL."""
289
+ for pattern, destination in REDIRECTS.items():
290
+ if source.startswith(pattern):
291
+ return destination
292
+
293
+ return source
294
+
295
+
281
296
  @dataclasses.dataclass(frozen=True)
282
297
  class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
283
298
  """
@@ -294,6 +309,7 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
294
309
  def __post_init__(self):
295
310
  """Note that we do not presently need OWL inference."""
296
311
  self.graph.last_not_inferred_source = None
312
+ self.graph._indices_loaded = False
297
313
 
298
314
  def _infer_with_sparql(self):
299
315
  """
@@ -353,17 +369,12 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
353
369
  ]
354
370
  self.graph.addN(inferred_quads)
355
371
 
356
- def _apply_redirect(self, source: URIRef) -> URIRef:
357
- for pattern, destination in REDIRECTS.items():
358
- if source.startswith(pattern):
359
- self.logger.info(
360
- 'Rewriting: {source} → {destination}',
361
- source=source,
362
- destination=destination,
363
- )
364
- return destination
372
+ def _maybe_load_indices(self):
373
+ if not self.graph._indices_loaded:
374
+ for index in INDICES:
375
+ self.load(index)
365
376
 
366
- return source
377
+ self.graph._indices_loaded = True
367
378
 
368
379
  def query( # noqa: WPS211, WPS210, WPS231, C901
369
380
  self,
@@ -378,6 +389,8 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
378
389
  namespaces. The given base is used to resolve relative URIs in
379
390
  the query and will be overridden by any BASE given in the query.
380
391
  """
392
+ self._maybe_load_indices()
393
+
381
394
  initBindings = initBindings or {}
382
395
  initNs = initNs or {}
383
396
 
@@ -406,7 +419,7 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
406
419
  try:
407
420
  self.load(url)
408
421
  except Exception as err:
409
- self.logger.error('Failed to load %s: %s', url, err)
422
+ self.logger.error(f'Failed to load {url}: {err}', url, err)
410
423
 
411
424
  self.maybe_apply_inference()
412
425
 
@@ -432,6 +445,34 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
432
445
  query_result['bindings'] = bindings
433
446
  return query_result
434
447
 
448
+ def _is_loaded(self, uri: URIRef) -> bool:
449
+ """Find out if this URI in the graph already."""
450
+ return funcy.first(
451
+ self.graph.quads((
452
+ uri,
453
+ IOLANTA['last-loaded-time'],
454
+ None,
455
+ URIRef('iolanta://_meta'),
456
+ )),
457
+ ) is not None
458
+
459
+ def _mark_as_loaded(self, uri: URIRef):
460
+ self.graph.add((
461
+ uri,
462
+ IOLANTA['last-loaded-time'],
463
+ Literal(datetime.datetime.now()),
464
+ URIRef('iolanta://_meta'),
465
+ ))
466
+
467
+ def _follow_is_visualized_with_links(self, uri: URIRef):
468
+ """Follow `iolanta:is-visualized-with` links."""
469
+ self.logger.info(f'Following links for {uri}…')
470
+ triples = self.graph.triples((uri, IOLANTA['visualized-with'], None))
471
+ for _, _, visualization in triples:
472
+ if isinstance(visualization, URIRef):
473
+ self.load(visualization)
474
+ self.logger.info('Links followed.')
475
+
435
476
  def load( # noqa: C901, WPS210, WPS212, WPS213, WPS231
436
477
  self,
437
478
  source: URIRef,
@@ -448,25 +489,30 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
448
489
  # fails.
449
490
  return Skipped()
450
491
 
451
- new_source = self._apply_redirect(source)
492
+ if url.fragment:
493
+ # Fragment on an HTML page resolves to that same page. Let us remove
494
+ # this ambiguity, then.
495
+ # TODO: It works differently for JSON-LD documents AFAIK. Need to
496
+ # double check that.
497
+ url = url.with_fragment(None)
498
+ source = URIRef(str(f'{url}#'))
499
+
500
+ self._follow_is_visualized_with_links(source)
501
+
502
+ new_source = apply_redirect(source)
452
503
  if new_source != source:
504
+ self.logger.info(
505
+ 'Rewriting: {source} → {new_source}',
506
+ source=source,
507
+ new_source=new_source,
508
+ )
453
509
  return self.load(new_source)
454
510
 
455
511
  source_uri = normalize_term(source)
456
- existing_triple = funcy.first(
457
- self.graph.quads(
458
- (
459
- None,
460
- None,
461
- None,
462
- source_uri,
463
- ),
464
- ),
465
- )
466
- if existing_triple is not None:
512
+ if self._is_loaded(source_uri):
467
513
  return Skipped()
468
514
  else:
469
- self.logger.info(f'Existing triples not found for {source_uri}')
515
+ self.logger.info(f'{source_uri} is not loaded yet')
470
516
 
471
517
  # FIXME This is definitely inefficient. However, python-yaml-ld caches
472
518
  # the document, so the performance overhead is not super high.
@@ -510,6 +556,8 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
510
556
  RDFS.Class,
511
557
  ))
512
558
 
559
+ self._mark_as_loaded(source_uri)
560
+
513
561
  return Loaded()
514
562
 
515
563
  except Exception as err:
@@ -533,6 +581,9 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
533
581
  RDF.type,
534
582
  RDFS.Class,
535
583
  ))
584
+
585
+ self._mark_as_loaded(source_uri)
586
+
536
587
  return Loaded()
537
588
 
538
589
  if _resolved_source:
@@ -557,6 +608,8 @@ class GlobalSPARQLProcessor(Processor): # noqa: WPS338, WPS214
557
608
  RDFS.Class,
558
609
  ))
559
610
 
611
+ self._mark_as_loaded(source_uri)
612
+
560
613
  try: # noqa: WPS225
561
614
  ld_rdf = yaml_ld.to_rdf(source)
562
615
  except ConnectionError as name_resolution_error:
@@ -45,8 +45,7 @@ class PageTitle(IolantaWidgetMixin, Static):
45
45
  title = event.worker.result
46
46
  if self.extra:
47
47
  title = f'{title} {self.extra}'
48
- self.renderable = title
49
- self.refresh()
48
+ self.update(title)
50
49
 
51
50
  case WorkerState.ERROR:
52
51
  raise ValueError(event)
@@ -258,6 +258,10 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
258
258
  return not is_loading
259
259
  case 'abort':
260
260
  return is_loading
261
+ case 'back':
262
+ return bool(self.history.past)
263
+ case 'forward':
264
+ return bool(self.history.future)
261
265
 
262
266
  return True
263
267
 
@@ -288,12 +292,15 @@ class PageSwitcher(IolantaWidgetMixin, ContentSwitcher): # noqa: WPS214
288
292
  def action_back(self):
289
293
  """Go backward."""
290
294
  self.current = self.history.back().page_id
291
- self.focus()
295
+ if page := self.visible_content:
296
+ page.focus()
292
297
 
293
298
  def action_forward(self):
294
299
  """Go forward."""
295
300
  self.current = self.history.forward().page_id
296
301
  self.focus()
302
+ if page := self.visible_content:
303
+ page.focus()
297
304
 
298
305
 
299
306
  class ConsoleSwitcher(ContentSwitcher):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "iolanta"
3
- version = "1.2.8"
3
+ version = "1.2.10"
4
4
  description = "Semantic Web browser"
5
5
  authors = ["Anatoly Scherbakov <altaisoft@gmail.com>"]
6
6
  license = "MIT"
@@ -29,7 +29,7 @@ textual = ">=0.83.0"
29
29
  iolanta-tables = {version = "^0.1.7", optional = true}
30
30
  yarl = ">=1.9.4"
31
31
  boltons = ">=24.0.0"
32
- yaml-ld = ">=1.1.3"
32
+ yaml-ld = ">=1.1.5"
33
33
  reasonable = ">=0.2.6"
34
34
  oxrdflib = ">=0.4.0"
35
35
  loguru = ">=0.7.3"
iolanta-1.2.8/README.md DELETED
@@ -1,4 +0,0 @@
1
- # iolanta
2
-
3
- Stub repo for the iolanta browser.
4
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes