iolanta 2.0.8__py3-none-any.whl → 2.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. iolanta/cli/main.py +45 -25
  2. iolanta/data/graph-triples.yamlld +2 -2
  3. iolanta/data/textual-browser.yaml +23 -22
  4. iolanta/declension/__init__.py +0 -0
  5. iolanta/declension/data/declension.yamlld +39 -0
  6. iolanta/declension/facet.py +44 -0
  7. iolanta/declension/sparql/declension.sparql +8 -0
  8. iolanta/facets/cli/record.py +2 -2
  9. iolanta/facets/facet.py +1 -22
  10. iolanta/facets/foaf_person_title/facet.py +2 -2
  11. iolanta/facets/generic/bool_literal.py +3 -3
  12. iolanta/facets/generic/date_literal.py +1 -1
  13. iolanta/facets/generic/default.py +2 -2
  14. iolanta/facets/html/code_literal.py +3 -3
  15. iolanta/facets/icon.py +1 -1
  16. iolanta/facets/locator.py +1 -4
  17. iolanta/facets/qname.py +2 -2
  18. iolanta/facets/textual_browser/app.py +7 -3
  19. iolanta/facets/textual_browser/facet.py +1 -1
  20. iolanta/facets/textual_browser/page_switcher.py +13 -18
  21. iolanta/facets/textual_class/facets.py +3 -3
  22. iolanta/facets/textual_class/sparql/instances.sparql +4 -1
  23. iolanta/facets/textual_default/facets.py +5 -5
  24. iolanta/facets/textual_default/widgets.py +1 -1
  25. iolanta/facets/textual_graph/facets.py +3 -3
  26. iolanta/facets/textual_graph_triples.py +1 -1
  27. iolanta/facets/textual_link/facet.py +4 -4
  28. iolanta/facets/textual_nanopublication/facet.py +1 -1
  29. iolanta/facets/textual_no_facet_found.py +3 -1
  30. iolanta/facets/textual_ontology/facets.py +3 -3
  31. iolanta/facets/textual_provenance/facets.py +1 -1
  32. iolanta/facets/title/facets.py +3 -5
  33. iolanta/facets/title/sparql/title.sparql +5 -0
  34. iolanta/facets/wikibase_statement_title/facets.py +2 -2
  35. iolanta/iolanta.py +35 -68
  36. iolanta/labeled_triple_set/__init__.py +0 -0
  37. iolanta/labeled_triple_set/data/labeled_triple_set.yamlld +42 -0
  38. iolanta/labeled_triple_set/labeled_triple_set.py +137 -0
  39. iolanta/labeled_triple_set/sparql/triples.sparql +5 -0
  40. iolanta/mermaid/__init__.py +0 -0
  41. iolanta/mermaid/facet.py +127 -0
  42. iolanta/mermaid/mermaid.yamlld +42 -0
  43. iolanta/mermaid/models.py +156 -0
  44. iolanta/mermaid/sparql/graph.sparql +5 -0
  45. iolanta/mermaid/sparql/subgraphs.sparql +3 -0
  46. iolanta/namespaces.py +1 -1
  47. iolanta/resolvers/base.py +2 -1
  48. iolanta/resolvers/dispatch.py +41 -0
  49. iolanta/resolvers/pypi.py +106 -0
  50. iolanta/resolvers/python_import.py +9 -32
  51. iolanta/sparqlspace/processor.py +4 -1
  52. {iolanta-2.0.8.dist-info → iolanta-2.1.4.dist-info}/METADATA +7 -8
  53. {iolanta-2.0.8.dist-info → iolanta-2.1.4.dist-info}/RECORD +55 -41
  54. {iolanta-2.0.8.dist-info → iolanta-2.1.4.dist-info}/WHEEL +1 -1
  55. iolanta-2.1.4.dist-info/entry_points.txt +33 -0
  56. iolanta/data/cli.yaml +0 -30
  57. iolanta/data/html.yaml +0 -15
  58. iolanta-2.0.8.dist-info/entry_points.txt +0 -10
iolanta/cli/main.py CHANGED
@@ -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,6 +10,7 @@ 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
13
+ from rich.table import Table
12
14
  from typer import Argument, Exit, Option, Typer
13
15
  from yarl import URL
14
16
 
@@ -22,23 +24,9 @@ DEFAULT_LANGUAGE = locale.getlocale()[0].split('_')[0]
22
24
  console = Console()
23
25
 
24
26
 
25
- def construct_app() -> Typer:
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(
28
+ no_args_is_help=True,
29
+ )
42
30
 
43
31
 
44
32
  def string_to_node(name: str) -> NotLiteralNode:
@@ -57,6 +45,13 @@ def string_to_node(name: str) -> NotLiteralNode:
57
45
  return URIRef(f'file://{path}')
58
46
 
59
47
 
48
+ def decode_datatype(datatype: str) -> URIRef:
49
+ if datatype.startswith('http'):
50
+ return URIRef(datatype)
51
+
52
+ return URIRef(f'https://iolanta.tech/datatypes/{datatype}')
53
+
54
+
60
55
  @app.command(name='browse')
61
56
  def render_command( # noqa: WPS231, WPS238, WPS210, C901
62
57
  url: Annotated[str, Argument()],
@@ -85,14 +80,32 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
85
80
  ensure_exists=True,
86
81
  ) / 'iolanta.log'
87
82
 
88
- logger = loguru.logger
89
- logger.add(
83
+ # Get the level name first
84
+ level_name = {
85
+ logging.DEBUG: 'DEBUG',
86
+ logging.INFO: 'INFO',
87
+ logging.WARNING: 'WARNING',
88
+ logging.ERROR: 'ERROR',
89
+ }[level]
90
+
91
+ # Configure global loguru logger BEFORE creating Iolanta instance
92
+ loguru.logger.remove()
93
+ loguru.logger.add(
90
94
  log_file_path,
91
- level=level,
95
+ level=level_name,
92
96
  format='{time} {level} {message}',
93
97
  enqueue=True,
94
98
  )
95
-
99
+ loguru.logger.add(
100
+ sys.stderr,
101
+ level=level_name,
102
+ format='{time} | {level:<8} | {name}:{function}:{line} - {message}',
103
+ )
104
+ loguru.logger.level(level_name)
105
+
106
+ # Use the global logger
107
+ logger = loguru.logger
108
+
96
109
  node_url = URL(url)
97
110
  if node_url.scheme and node_url.scheme != 'file':
98
111
  node = URIRef(url)
@@ -101,6 +114,7 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
101
114
  language=Literal(language),
102
115
  logger=logger,
103
116
  )
117
+
104
118
  else:
105
119
  path = Path(node_url.path).absolute()
106
120
  node = URIRef(f'file://{path}')
@@ -113,11 +127,11 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
113
127
  try:
114
128
  renderable = iolanta.render(
115
129
  node=URIRef(node),
116
- as_datatype=URIRef(as_datatype),
130
+ as_datatype=decode_datatype(as_datatype),
117
131
  )
118
132
 
119
133
  except DocumentedError as documented_error:
120
- if iolanta.logger.level in {logging.DEBUG, logging.INFO}:
134
+ if level in {logging.DEBUG, logging.INFO}:
121
135
  raise
122
136
 
123
137
  console.print(
@@ -129,11 +143,17 @@ def render_command( # noqa: WPS231, WPS238, WPS210, C901
129
143
  raise Exit(1)
130
144
 
131
145
  except Exception as err:
132
- if level in {logging.DEBUG, logging.INFO}:
146
+ if iolanta.logger.level in {logging.DEBUG, logging.INFO}:
133
147
  raise
134
148
 
135
149
  console.print(str(err))
136
150
  raise Exit(1)
137
151
 
138
152
  else:
139
- Console().print(renderable)
153
+ # FIXME: An intermediary Literal can be used to dispatch rendering.
154
+ match renderable:
155
+ case Table() as table:
156
+ console.print(table)
157
+
158
+ case unknown:
159
+ print(unknown)
@@ -1,6 +1,6 @@
1
1
  "@context": context.yaml
2
- $id: python://iolanta.facets.textual_graph.GraphFacet
2
+ $id: pkg:pypi/iolanta#textual-graph
3
3
  $: Graph Triples
4
4
  →: https://iolanta.tech/cli/textual
5
- ⪯: python://iolanta.facets.textual_default.InverseProperties
5
+ ⪯: pkg:pypi/iolanta#textual-inverse-properties
6
6
  ↦: ASK WHERE { GRAPH $this { ?s ?p ?o } }
@@ -30,6 +30,8 @@
30
30
  "@id": iolanta:is-preferred-over
31
31
 
32
32
  ↦: iolanta:matches
33
+ iolanta:hasDefaultFacet:
34
+ "@type": "@id"
33
35
 
34
36
  "@included":
35
37
  - $id: iolanta:icon
@@ -42,26 +44,25 @@
42
44
  - $id: https://iolanta.tech/datatypes/icon
43
45
  $: Icon
44
46
  iolanta:hasDefaultFacet:
45
- $id: python://iolanta.facets.icon.IconFacet
47
+ $id: pkg:pypi/iolanta#icon
46
48
  →: https://iolanta.tech/datatypes/icon
47
49
 
48
50
  - $id: np:Nanopublication
49
51
  $: Nanopublication
50
52
  iolanta:hasInstanceFacet:
51
- $id: python://iolanta.facets.textual_nanopublication.NanopublicationFacet
53
+ $id: pkg:pypi/iolanta#textual-nanopublication
52
54
  $: Nanopublication
53
55
  →: https://iolanta.tech/cli/textual
54
56
  ⪯:
55
- - python://iolanta.facets.textual_default.TextualDefaultFacet
56
- - python://iolanta.facets.textual_graph.GraphFacet
57
+ - pkg:pypi/iolanta#textual-properties
58
+ - pkg:pypi/iolanta#textual-graph
57
59
 
58
60
  - $id: https://iolanta.tech/cli/interactive
59
- iolanta:hasDefaultFacet:
60
- $id: python://iolanta.facets.textual_browser.TextualBrowserFacet
61
+ iolanta:hasDefaultFacet: pkg:pypi/iolanta#textual-browser
61
62
 
62
- - $id: python://iolanta.facets.textual_default.TextualDefaultFacet
63
+ - $id: pkg:pypi/iolanta#textual-properties
63
64
  $: Properties
64
- ⪯: python://iolanta.facets.textual_default.InverseProperties
65
+ ⪯: pkg:pypi/iolanta#textual-inverse-properties
65
66
  →: https://iolanta.tech/cli/textual
66
67
  ↦: |
67
68
  ASK WHERE {
@@ -69,7 +70,7 @@
69
70
  FILTER (?graph != <iolanta://_meta>)
70
71
  }
71
72
 
72
- - $id: python://iolanta.facets.textual_default.InverseProperties
73
+ - $id: pkg:pypi/iolanta#textual-inverse-properties
73
74
  $: Inverse Properties
74
75
  →: https://iolanta.tech/cli/textual
75
76
  ↦: |
@@ -80,54 +81,54 @@
80
81
 
81
82
  - $id: "urn:"
82
83
  iolanta:hasFacetByPrefix:
83
- $id: python://iolanta.facets.textual_provenance.TextualProvenanceFacet
84
+ $id: pkg:pypi/iolanta#textual-provenance
84
85
  →: https://iolanta.tech/cli/textual
85
86
 
86
87
  - $id: https://iolanta.tech/cli/link
87
88
  iolanta:hasDefaultFacet:
88
- $id: python://iolanta.facets.textual_link.TextualLinkFacet
89
+ $id: pkg:pypi/iolanta#textual-link
89
90
 
90
91
  - $id: https://wikiba.se/ontology#Statement
91
92
  iolanta:hasInstanceFacet:
92
- $id: python://iolanta.facets.wikibase_statement_title.WikibaseStatementTitle
93
+ $id: pkg:pypi/iolanta#wikibase-statement-title
93
94
  $: Title
94
95
  →: https://iolanta.tech/datatypes/title
95
96
 
96
97
  - $id: rdfs:Class
97
98
  iolanta:hasInstanceFacet:
98
- $id: python://iolanta.facets.textual_class.Class
99
+ $id: pkg:pypi/iolanta#textual-class
99
100
  $: Instances
100
101
  →: https://iolanta.tech/cli/textual
101
102
  ⪯:
102
- - python://iolanta.facets.textual_browser.TextualBrowserFacet
103
- - python://iolanta.facets.textual_default.InverseProperties
103
+ - pkg:pypi/iolanta#textual-browser
104
+ - pkg:pypi/iolanta#textual-inverse-properties
104
105
 
105
106
  - $id: owl:Ontology
106
107
  iolanta:hasInstanceFacet:
107
- $id: python://iolanta.facets.textual_ontology.OntologyFacet
108
+ $id: pkg:pypi/iolanta#textual-ontology
108
109
  $: Ontology
109
110
  →: https://iolanta.tech/cli/textual
110
- ⪯: python://iolanta.facets.textual_default.TextualDefaultFacet
111
+ ⪯: pkg:pypi/iolanta#textual-properties
111
112
 
112
113
  - $id: https://iolanta.tech/datatypes/textual-graph-triples
113
114
  $: Graph Triples
114
115
  iolanta:hasDefaultFacet:
115
- $id: python://iolanta.facets.textual_graph_triples.GraphTriplesFacet
116
+ $id: pkg:pypi/iolanta#textual-graph-triples
116
117
  →: https://iolanta.tech/datatypes/textual-graph-triples
117
118
 
118
119
  - $id: https://iolanta.tech/qname
119
120
  iolanta:hasDefaultFacet:
120
- $id: python://iolanta.facets.qname.QNameFacet
121
+ $id: pkg:pypi/iolanta#qname
121
122
 
122
- - $id: python://iolanta.facets.textual_property_pairs_table.TextualPropertyPairsTableFacet
123
+ - $id: pkg:pypi/iolanta#textual-property-pairs
123
124
  $: Subjects → Objects
124
125
  →: https://iolanta.tech/cli/textual
125
126
  ↦: ASK WHERE { ?subject $this ?object }
126
127
 
127
- - $id: python://iolanta.facets.textual_class.Class
128
+ - $id: pkg:pypi/iolanta#textual-class
128
129
  ↦:
129
130
  - ASK WHERE { ?instance a $this }
130
131
  - ASK WHERE { $this rdfs:subClassOf ?superclass }
131
132
 
132
133
  - $id: https://iolanta.tech/cli/textual
133
- iolanta:when-no-facet-found: python://iolanta.facets.textual_no_facet_found.TextualNoFacetFound
134
+ iolanta:when-no-facet-found: pkg:pypi/iolanta#textual-no-facet-found
File without changes
@@ -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
@@ -0,0 +1,8 @@
1
+ PREFIX lexinfo: <https://www.lexinfo.net/ontology/2.0/lexinfo#>
2
+
3
+ SELECT * WHERE {
4
+ ?declension
5
+ rdf:type $this ;
6
+ lexinfo:person ?person ;
7
+ lexinfo:number ?number .
8
+ }
@@ -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.iri)
20
+ rows = self.stored_query('record.sparql', node=self.this)
21
21
 
22
- caption = self.render(self.iri, as_datatype=IOLANTA['cli/title'])
22
+ caption = self.render(self.this, as_datatype=IOLANTA['cli/title'])
23
23
 
24
24
  table = Table(
25
25
  show_header=False,
iolanta/facets/facet.py CHANGED
@@ -16,28 +16,15 @@ FacetOutput = TypeVar('FacetOutput')
16
16
  class Facet(Generic[FacetOutput]):
17
17
  """Base facet class."""
18
18
 
19
- iri: NotLiteralNode
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.iri))
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.iri,
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.iri, Literal):
12
+ if not isinstance(self.this, Literal):
13
13
  raise NotALiteral(
14
- node=self.iri,
14
+ node=self.this,
15
15
  )
16
16
 
17
- return '✔️' if self.iri.value else '❌'
17
+ return '✔️' if self.this.value else '❌'
@@ -11,7 +11,7 @@ class DateLiteral(Facet):
11
11
 
12
12
  def show(self):
13
13
  """Render date or datetime as a date."""
14
- literal = cast(Literal, self.iri)
14
+ literal = cast(Literal, self.this)
15
15
 
16
16
  date_value = literal.value
17
17
 
@@ -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.iri),
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.iri)
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.iri, Literal):
12
+ if not isinstance(self.this, Literal):
13
13
  raise NotALiteral(
14
- node=self.iri,
14
+ node=self.this,
15
15
  )
16
16
 
17
- return f'<code>{self.iri.value}</code>'
17
+ return f'<code>{self.this.value}</code>'
iolanta/facets/icon.py CHANGED
@@ -15,7 +15,7 @@ class IconFacet(Facet[str]):
15
15
  $iri iolanta:icon ?icon .
16
16
  }
17
17
  """,
18
- iri=self.iri,
18
+ iri=self.this,
19
19
  ),
20
20
  )
21
21
 
iolanta/facets/locator.py CHANGED
@@ -114,9 +114,6 @@ class FacetFinder: # noqa: WPS214
114
114
 
115
115
  def by_sparql(self) -> Iterable[FoundRow]:
116
116
  """Determine facet by SHACL shape of the data."""
117
- if not isinstance(self.node, URIRef):
118
- return
119
-
120
117
  rows = self.iolanta.query(
121
118
  GET_QUERY_TO_FACET,
122
119
  as_datatype=self.as_datatype,
@@ -138,7 +135,7 @@ class FacetFinder: # noqa: WPS214
138
135
 
139
136
  TODO fix this to allow arbitrary prefixes.
140
137
  """
141
- scheme = URL(self.node).scheme
138
+ scheme = URL(str(self.node)).scheme
142
139
  if scheme != 'urn':
143
140
  return []
144
141
 
iolanta/facets/qname.py CHANGED
@@ -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.iri,
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.iri)
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, iri: Node):
48
+ def __init__(self, iolanta: Iolanta, this: Node):
49
49
  """Set up parameters for the browser."""
50
50
  self.iolanta = iolanta
51
- self.iri = iri
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
- self.iolanta.logger.remove(0)
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(
@@ -20,7 +20,7 @@ class TextualBrowserFacet(Facet[ReturnType | None]):
20
20
 
21
21
  app = IolantaBrowser(
22
22
  iolanta=self.iolanta,
23
- iri=self.iri,
23
+ this=self.this,
24
24
  )
25
25
  try:
26
26
  app.run()