iolanta 2.0.6__py3-none-any.whl → 2.0.8__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iolanta
3
- Version: 2.0.6
3
+ Version: 2.0.8
4
4
  Summary: Semantic Web browser
5
5
  License: MIT
6
6
  Author: Anatoly Scherbakov
@@ -32,7 +32,7 @@ Requires-Dist: rich (>=13.3.1)
32
32
  Requires-Dist: textual (>=0.83.0)
33
33
  Requires-Dist: typer (>=0.9.0)
34
34
  Requires-Dist: watchfiles (>=1.0.4,<2.0.0)
35
- Requires-Dist: yaml-ld (>=1.1.9)
35
+ Requires-Dist: yaml-ld (>=1.1.10)
36
36
  Requires-Dist: yarl (>=1.9.4)
37
37
  Description-Content-Type: text/markdown
38
38
 
@@ -1,4 +1,4 @@
1
- iolanta/__init__.py,sha256=BvLP-LYFmNYS5F8VPXdzpEEMk8zcm9NMmlUWw9yEtj0,153
1
+ iolanta/__init__.py,sha256=d6a_MUaocIgrpgC49Bu5N3DHLP0uBc07CLTjPRpKArI,111
2
2
  iolanta/base_plugin.py,sha256=vI4DRSIITlKZw8x7Q58BFkChWlg1h8zV-tuNvIKURBI,86
3
3
  iolanta/cli/__init__.py,sha256=IV6_RPmrbpPWbdKojuFczwaJAaKm1DIDQh5aZWbeR1U,69
4
4
  iolanta/cli/formatters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -28,7 +28,7 @@ iolanta/facets/cli/record.py,sha256=lBsECxLkwVSXC-yHmUwfosxAdLBI-0UoqHe8GOCablY,
28
28
  iolanta/facets/cli/sparql/link.sparql,sha256=WtWEfLAvdGc2gP0IhZil6Vglkydc3VO24vk4GwRnR5I,163
29
29
  iolanta/facets/cli/sparql/record.sparql,sha256=GBWkmNelvaSDbvl7v0-LsJHdjFPbsSAW49kNFOUeoGQ,63
30
30
  iolanta/facets/errors.py,sha256=sEBmnzhFcRIgOT18hfNwyMMjry0waa6IB-jC2NVTA50,4124
31
- iolanta/facets/facet.py,sha256=QByUVrvt_XVBoVhfuyk6lKO--pauhMEN79GWmgejdIo,2822
31
+ iolanta/facets/facet.py,sha256=gAOkosh9B_Lufh3ia9W24hgt4LEIhG-UJcQF4BzMvno,2600
32
32
  iolanta/facets/foaf_person_title/__init__.py,sha256=oj4MNVQvv8Dysb27xiWjtZCii8-nT7-WFa3WMWUwbtU,67
33
33
  iolanta/facets/foaf_person_title/facet.py,sha256=Q9TajjGp1v729quDzAM_Lfzawls3yujp1Z_6jXrG3gY,632
34
34
  iolanta/facets/foaf_person_title/sparql/names.sparql,sha256=p_2hHZXhEaJ8IwGlvLoN0vb0vhGqo44uAVRpDyTzflU,107
@@ -66,7 +66,7 @@ iolanta/facets/textual_default/sparql/properties.sparql,sha256=stDbvFP4g6YKYphpN
66
66
  iolanta/facets/textual_default/tcss/default.tcss,sha256=v6k6LvZMndRW4t9Iq-7QF59U_LJTdohRsyavwTY5ruI,69
67
67
  iolanta/facets/textual_default/templates/default.md,sha256=CuD5lISsE2eAVnm2z6kfNff-vEgrNG95Wi5LTgkieWY,21
68
68
  iolanta/facets/textual_default/triple_uri_ref.py,sha256=XfuNPaAe-YxH8IyrdrHQ641aWh5zVMVs0L0WC3D6A4M,1279
69
- iolanta/facets/textual_default/widgets.py,sha256=0f8gJmo447O5e_KwVxyb3hdVNzDJQTUf9GmRnp6hfrA,9183
69
+ iolanta/facets/textual_default/widgets.py,sha256=9qZbJfLvf9yilyQjW6IlCk1AiD8gTmfvaFuLLGQMnGU,9177
70
70
  iolanta/facets/textual_graph/__init__.py,sha256=DWd2gljzL8SiyYKQdBH78HouF1EMqgCH-w0K5OEmL2I,59
71
71
  iolanta/facets/textual_graph/facets.py,sha256=NGg0i1XYmdR8gjMd-D4Ckvu_n7m7s1FA68VSUm7cpj0,873
72
72
  iolanta/facets/textual_graph/sparql/triples.sparql,sha256=5rFVGcvZzEHZj2opQQp0YlxJLpEdl-r1RjkPwo8j7t0,145
@@ -79,7 +79,7 @@ iolanta/facets/textual_nanopublication/models.py,sha256=MphggSvKmYac6v866GOKW5lc
79
79
  iolanta/facets/textual_nanopublication/nanopublication_widget.py,sha256=sQPgEx25XJ15VqB5zjZuz2q2bf_B5GWXEp32FAufxQ4,2387
80
80
  iolanta/facets/textual_nanopublication/term_list_widget.py,sha256=NZNATKjFmgI2sE5R0ebyQh5Qk2g-kf-MT4YZ-Vw78M4,992
81
81
  iolanta/facets/textual_nanopublication/term_widget.py,sha256=uI5msCTSIYumAIS3I8nBfUz57_vRzvCKkouevrS3Qwk,3536
82
- iolanta/facets/textual_no_facet_found.py,sha256=gYRSAYDX0t6EHln0S8msLZE27Svfef8iPVfZQ3Vf8Ns,1625
82
+ iolanta/facets/textual_no_facet_found.py,sha256=xNAQslZuMU-HLZh6250Siz3EnSE_ZVt-YhksUTiU_Ag,2485
83
83
  iolanta/facets/textual_ontology/__init__.py,sha256=3H6bfYaEbXFr90C6ZpGWC4O-24uaO18tnTXx7mckQSA,94
84
84
  iolanta/facets/textual_ontology/facets.py,sha256=60g8ANmePb9_i_-d4ui-FdtNwg9aktrOKXHkTQtLp1w,3338
85
85
  iolanta/facets/textual_ontology/sparql/terms.sparql,sha256=oVLxN452nqog_95qRaTWnvar6rxPNxPrRonSo7oFFTg,324
@@ -90,49 +90,32 @@ iolanta/facets/textual_provenance/facets.py,sha256=vv3UQsI2duB36DW5Zkw3sqgAXBPmK
90
90
  iolanta/facets/textual_provenance/sparql/graphs.sparql,sha256=B45uKFd-1vrBuMDSbTURjUUEjHt51vAbqdL4tUcgMvk,103
91
91
  iolanta/facets/textual_provenance/sparql/triples.sparql,sha256=V-EdVuWbGHY3MspbJIMpwxPQautLDqJJV-AmihDjSHc,53
92
92
  iolanta/facets/title/__init__.py,sha256=fxpkG-YvHDp6eiVL3o7BbwhPMZZe-1R2Qi6S36QCTf8,77
93
- iolanta/facets/title/facets.py,sha256=v7YifoXqrpTlJscgVM_USfherpoXB_QP_LO5u3AwIwg,792
94
- iolanta/facets/title/sparql/title.sparql,sha256=4rz47tjwX2OJavWMzftaYKil1-ZHB76ZwLGVCwMbn5s,746
93
+ iolanta/facets/title/facets.py,sha256=kxZv-lRpqVz1-tRoqU1iqvzVcOjM0ebEs-wpR3Lc2eQ,812
94
+ iolanta/facets/title/sparql/title.sparql,sha256=_bm6KQrUB97EOc0CtAD3456qUzpKrY9eqhzrV4iRUqk,920
95
95
  iolanta/facets/wikibase_statement_title/__init__.py,sha256=_yk1akxgSJOiUBJIc8QGrD2vovvmx_iw_vJDuv1rD7M,91
96
96
  iolanta/facets/wikibase_statement_title/facets.py,sha256=mUH7twlAgoeX7DgLQuRBQv4ORT6GWbN-0eJ1aliSfiQ,724
97
97
  iolanta/facets/wikibase_statement_title/sparql/statement-title.sparql,sha256=n07DQWxKqB5c3CA4kacq2HSN0R0dLgnMnLP1AxMo5YA,320
98
- iolanta/iolanta.py,sha256=wCt_7aUz9TOvZTJvpJQ-qVWkOpmM531uyxIk9l3n-lk,14229
99
- iolanta/loaders/__init__.py,sha256=QTiKCsQc1BTS-IlY2CQsN9iVpEIPqYFvI9ERMYVZCbU,99
100
- iolanta/loaders/base.py,sha256=-DxYwqG1bfDXB2p_S-mKpkc_3Sh14OHhePbe65Iq3-s,3381
101
- iolanta/loaders/data_type_choice.py,sha256=zRUXBIzjvuW28P_dhMDVevE9C8EFEIx2_X39WydWrtM,1982
102
- iolanta/loaders/dict_loader.py,sha256=8eklbLFsNoQNuR7UDXY6oMXH2nekaK1WQLb42MjjYuk,1696
103
- iolanta/loaders/errors.py,sha256=EfalDnabuC2YjmJUOhTfs-5yeskVclhYcSoMuxJCRL4,472
104
- iolanta/loaders/http.py,sha256=mJMmprcl2X7a8p1YjfuWcOaJQm3xSM00E9sfDK_PMNo,3654
105
- iolanta/loaders/local_directory.py,sha256=tYOmtKkct8lcWM_dqm75932mPyc6ulMc4_9mseWCd9I,4557
106
- iolanta/loaders/local_file.py,sha256=MCbcu7DtiuoJye1xvTfuts-b2KCYjfg4tAYRZqgFelo,3064
107
- iolanta/loaders/scheme_choice.py,sha256=GHA4JAD-Qq3uNdej4vs_bCrN1WMRshVRvOMxaYyPHsE,2104
108
- iolanta/models.py,sha256=L0iFaga4-PCaWP18WmT03NLK_oT7q49V0WMTQskoffI,2824
109
- iolanta/namespaces.py,sha256=fyWDCGPwU8Cs8d-Vmci4H0-fuIe7BMSevvEKFvG7Gf4,1153
98
+ iolanta/iolanta.py,sha256=y95nu0BbllQqWIBv19FUAbS-l4-qNFA4LWcbZdseTyU,11330
99
+ iolanta/models.py,sha256=M-1dTxPwjTyUgQ4VCOiH6Q7ltNJiDPG0l1XQH430Omo,3250
100
+ iolanta/namespaces.py,sha256=VJ3BLTji3UmqD3N1Om2voAoyYPtF4o-8FXN2Uq_4sPc,1194
110
101
  iolanta/node_to_qname.py,sha256=a82_qpgT87cbekY_76tTkl4Z-6Rz6am4UGIQChUf9Y0,794
111
- iolanta/parse_quads.py,sha256=2UydATeDassOrpjWfjwWnMjnSS5RZw5KBFIeKHGJ36M,2660
112
- iolanta/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
113
- iolanta/parsers/base.py,sha256=ZFjj0BLzW4985BdC6PwbngenhMuSYW5mNLpprZRWjhA,1048
114
- iolanta/parsers/dict_parser.py,sha256=t_OK2meUh49DqSaOYkSgEwxMKUNNgjJY8rZAyL4NQKI,4546
115
- iolanta/parsers/errors.py,sha256=4Tqi9WD8-AmnZ2efHGty9VSLb--Efd4A6tMqGF3ffDY,600
116
- iolanta/parsers/json.py,sha256=3VrDiz-SaVXP9_B03Gl62VSIk2fKeRrrb2hpTLxqBk4,967
117
- iolanta/parsers/markdown.py,sha256=wv-PhszgoDOzWdisykIeZyYBD1edCVmw7UQ8jEn4siw,1669
118
- iolanta/parsers/yaml.py,sha256=MeTe5_OaDK27XB38AzxjqWfCxybAm4tqgqn7LLh-YB0,1244
102
+ iolanta/parse_quads.py,sha256=nKUGS_OVpCA6PFA5rOd6Qa5ik_eQhCL-Mlv1zDXk_Co,4541
119
103
  iolanta/plugin.py,sha256=MSxpuOIx93AgBahfS8bYh31MEgcwtUSQhj4Js7fgdSI,1096
120
104
  iolanta/query_result.py,sha256=VLLBkewUEymtzfB0jeIeRE3Np6pAgo959RPgNsEmiq8,1545
121
105
  iolanta/reformat_blank_nodes.py,sha256=MAVcXusUioKzAoTEHAMume5Gt9vBEpxJGrngqFzmkJI,712
122
106
  iolanta/resolvers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
107
  iolanta/resolvers/base.py,sha256=cc9bcrVZ0wTwn85I-IYCwcIRU5Lwaph8D00C0dwSOm8,302
124
108
  iolanta/resolvers/python_import.py,sha256=kDOhApBDFfxnrDgK9M7ztMkqXfcny81Zo86FgPFb-LI,1301
125
- iolanta/shortcuts.py,sha256=j8b0E_yeoas8GumsPOfxO2v2jO0noqpmKJ6LFxFfsu4,1892
126
109
  iolanta/sparqlspace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
110
  iolanta/sparqlspace/cli.py,sha256=pb6q03lzrU8OaZ4A3QAQEmaFYcQ_-sHUrPhRs6GE88w,1590
128
111
  iolanta/sparqlspace/inference/wikibase-claim.sparql,sha256=JSawj3VTc9ZPoU9mvh1w1AMYb3cWyZ3x1rEYWUsKZ6A,209
129
112
  iolanta/sparqlspace/inference/wikibase-statement-property.sparql,sha256=SkSHZZlxWVDwBM3aLo0Q7hLuOj9BsIQnXtcuAuwaxqU,240
130
- iolanta/sparqlspace/processor.py,sha256=CXxdi7ORpddXxPh0UlnRG7oqNT9q-WdSPMxqB4CgOis,23570
113
+ iolanta/sparqlspace/processor.py,sha256=0Rk7ZeLWifdnmnKL5EZc39JRuMfsxT2RBUv6vgg3di0,23995
131
114
  iolanta/sparqlspace/sparqlspace.py,sha256=Y8_ZPXwuGEXbEes6XQjaQWA2Zv9y8SWxMPDFdqVBGFo,796
132
115
  iolanta/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
- iolanta/widgets/description.py,sha256=Qj5R2wgxJzlAHU0LHyKIoZSCkGk4VBuImWIyiUallhs,215
116
+ iolanta/widgets/description.py,sha256=98Qd3FwT9r8sYqKjl9ZEptaVX9jJ2ULWf0uy3j52p5o,800
134
117
  iolanta/widgets/mixin.py,sha256=nDRCOc-gizCf1a5DAcYs4hW8eZEd6pHBPFsfm0ncv7E,251
135
- iolanta-2.0.6.dist-info/METADATA,sha256=zqVS0cP1WoIfWm-4NCgDrrryi5uxKwILIyquK8khpGA,2230
136
- iolanta-2.0.6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
137
- iolanta-2.0.6.dist-info/entry_points.txt,sha256=z9RPLmGuz3tYGPV7Qf4nNjuSJYdTUS9enC4595poe-M,221
138
- iolanta-2.0.6.dist-info/RECORD,,
118
+ iolanta-2.0.8.dist-info/METADATA,sha256=K8cM_R2W4mlmyhFEMVh1J1LYjQg09-uJcSdRJXqTQg4,2231
119
+ iolanta-2.0.8.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
120
+ iolanta-2.0.8.dist-info/entry_points.txt,sha256=z9RPLmGuz3tYGPV7Qf4nNjuSJYdTUS9enC4595poe-M,221
121
+ iolanta-2.0.8.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- from iolanta.loaders.base import Loader
2
- from iolanta.loaders.local_directory import LocalDirectory
iolanta/loaders/base.py DELETED
@@ -1,124 +0,0 @@
1
- from abc import ABC
2
- from dataclasses import dataclass
3
- from logging import Logger
4
- from typing import (
5
- Any,
6
- Dict,
7
- Generic,
8
- Iterable,
9
- Optional,
10
- TextIO,
11
- TypedDict,
12
- TypeVar,
13
- )
14
-
15
- from rdflib import URIRef
16
- from yarl import URL
17
-
18
- from iolanta.conversions import url_to_iri
19
- from iolanta.ensure_is_context import ensure_is_context
20
- from iolanta.models import LDContext, LDDocument, Quad
21
- from iolanta.namespaces import PYTHON
22
-
23
- SourceType = TypeVar('SourceType')
24
-
25
-
26
- PyLDOptions = Dict[str, Any] # type: ignore
27
-
28
- PyLDResponse = TypedDict(
29
- 'PyLDResponse', {
30
- 'contentType': str,
31
- 'contextUrl': Optional[str],
32
- 'documentUrl': str,
33
- 'document': LDDocument,
34
- },
35
- )
36
-
37
-
38
- def term_for_python_class(cls: type) -> URIRef:
39
- """Construct term for Python class."""
40
- return PYTHON.term(f'{cls.__module__}.{cls.__qualname__}')
41
-
42
-
43
- # noinspection TaskProblemsInspection
44
- @dataclass(frozen=True)
45
- class Loader(ABC, Generic[SourceType]):
46
- """
47
- Base class for loaders.
48
-
49
- Loader receives a URL (or a path) to certain location. It is responsible for
50
- reading data from that location and returning it as a stream of RDF quads.
51
-
52
- Usually, depending on the data format, Loader leverages Parsers for that
53
- purpose.
54
- """
55
-
56
- logger: Logger
57
-
58
- @classmethod
59
- def loader_class_iri(cls) -> URIRef:
60
- """Import path to the loader class."""
61
- return term_for_python_class(cls)
62
-
63
- def choose_parser_class(self, source: SourceType):
64
- """Find which parser class to use for this URL."""
65
- raise NotImplementedError(
66
- f'{self}.choose_parser_class() is not implemented.',
67
- )
68
-
69
- def as_jsonld_document(
70
- self,
71
- source: SourceType,
72
- iri: Optional[URIRef] = None,
73
- ) -> LDDocument:
74
- """Represent a file as a JSON-LD document."""
75
- raise NotImplementedError(
76
- f'{self}.as_jsonld_document() is not implemented.',
77
- )
78
-
79
- def as_file(self, source: SourceType) -> TextIO:
80
- """Construct a file-like object."""
81
- raise NotImplementedError()
82
-
83
- def as_quad_stream(
84
- self,
85
- source: SourceType,
86
- iri: Optional[URIRef],
87
- root_loader: 'Loader[SourceType]',
88
- context: Optional[LDContext] = None,
89
- ) -> Iterable[Quad]:
90
- """Convert data into a stream of RDF quads."""
91
- raise NotImplementedError(
92
- f'{self}.as_quad_stream() is not implemented.',
93
- )
94
-
95
- def find_context(self, source: SourceType) -> LDContext:
96
- """Find context for the file."""
97
- raise NotImplementedError(
98
- f'{self}.find_context() is not implemented.',
99
- )
100
-
101
- def __call__(self, source: str, options: PyLDOptions) -> PyLDResponse:
102
- """
103
- Call the loader to retrieve the document in a PYLD friendly format.
104
-
105
- Used to resolve remote contexts.
106
-
107
- The type of `source` parameter is intentionally `str`: that's the only
108
- thing which pyld can do.
109
- """
110
- source = URL(source)
111
-
112
- document = ensure_is_context(
113
- self.as_jsonld_document(
114
- source=URL(source),
115
- iri=url_to_iri(source),
116
- ),
117
- )
118
-
119
- return {
120
- 'document': document,
121
- 'contextUrl': None,
122
- 'documentUrl': source,
123
- 'contentType': 'application/ld+json',
124
- }
@@ -1,66 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Any, Dict, Iterable, Optional, TextIO
3
-
4
- from rdflib import URIRef
5
- from yarl import URL
6
-
7
- from iolanta.loaders.base import Loader, SourceType
8
- from iolanta.models import LDContext, LDDocument, Quad
9
-
10
-
11
- @dataclass(frozen=True)
12
- class DataTypeChoiceLoader(Loader[Any]): # type: ignore
13
- """Try to load a file via several loaders."""
14
-
15
- loader_by_data_type: Dict[type, Loader[Any]] # type: ignore
16
-
17
- def choose_parser_class(self, source: SourceType):
18
- raise ValueError('choose_parser_class')
19
-
20
- def as_file(self, source: SourceType) -> TextIO:
21
- raise ValueError('as_file')
22
-
23
- def find_context(self, source: SourceType) -> LDContext:
24
- raise ValueError('find_context')
25
-
26
- def resolve_loader(self, source: Any): # type: ignore
27
- """Find loader instance by URL."""
28
- for source_type, loader in self.loader_by_data_type.items():
29
- if isinstance(source, source_type):
30
- return loader
31
-
32
- source_type = type(source)
33
- raise ValueError(
34
- f'Cannot find a loader for source: {source} '
35
- f'of type: {source_type}',
36
- )
37
-
38
- def as_jsonld_document(
39
- self,
40
- source: URL,
41
- iri: Optional[URIRef] = None,
42
- ) -> LDDocument:
43
- """Represent a file as a JSON-LD document."""
44
- return self.resolve_loader(
45
- source=source,
46
- ).as_jsonld_document(
47
- source=source,
48
- iri=iri,
49
- )
50
-
51
- def as_quad_stream(
52
- self,
53
- source: str,
54
- iri: Optional[URIRef],
55
- root_loader: Optional[Loader[URL]] = None,
56
- context: Optional[LDContext] = None,
57
- ) -> Iterable[Quad]:
58
- """Convert data into a stream of RDF quads."""
59
- return self.resolve_loader(
60
- source=source,
61
- ).as_quad_stream(
62
- source=source,
63
- iri=iri,
64
- root_loader=root_loader or self,
65
- context=context,
66
- )
@@ -1,57 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Iterable, Optional, TextIO, Type
3
-
4
- from rdflib import Literal, URIRef
5
-
6
- from iolanta.conversions import url_to_iri
7
- from iolanta.loaders.base import Loader
8
- from iolanta.loaders.errors import IsAContext, ParserNotFound
9
- from iolanta.models import LDContext, LDDocument, Quad
10
- from iolanta.namespaces import IOLANTA
11
- from iolanta.parsers.base import Parser
12
- from iolanta.parsers.dict_parser import DictParser
13
- from iolanta.parsers.json import JSON
14
- from iolanta.parsers.markdown import Markdown
15
- from iolanta.parsers.yaml import YAML
16
-
17
-
18
- @dataclass(frozen=True)
19
- class DictLoader(Loader[LDDocument]):
20
- """
21
- Retrieve Linked Data from a file on local disk.
22
-
23
- Requires a dict of raw JSON-LD data.
24
- """
25
-
26
- def find_context(self, source: str) -> LDContext:
27
- raise ValueError('???WTF?')
28
-
29
- def choose_parser_class(self, source: LDDocument) -> Type[Parser]:
30
- return DictParser(source)
31
-
32
- def as_quad_stream(
33
- self,
34
- source: LDDocument,
35
- root_loader: Loader[LDDocument],
36
- iri: Optional[URIRef] = None,
37
- context: Optional[LDContext] = None,
38
- ) -> Iterable[Quad]:
39
- """Extract a sequence of quads."""
40
- yield from DictParser().as_quad_stream(
41
- raw_data=source,
42
- iri=iri,
43
- context=context,
44
- root_loader=root_loader,
45
- )
46
-
47
- def as_file(self, source: LDDocument) -> TextIO:
48
- """Construct a file-like object."""
49
- raise ValueError('FOO')
50
-
51
- def as_jsonld_document(
52
- self,
53
- source: LDDocument,
54
- iri: Optional[URIRef] = None,
55
- ) -> LDDocument:
56
- """As JSON-LD document."""
57
- return source
iolanta/loaders/errors.py DELETED
@@ -1,29 +0,0 @@
1
- from dataclasses import dataclass
2
- from pathlib import Path
3
-
4
- from documented import DocumentedError
5
- from yarl import URL
6
-
7
-
8
- @dataclass
9
- class IsAContext(DocumentedError):
10
- """
11
- The provided file is a context.
12
-
13
- - Path: {self.path}
14
-
15
- This file is not a piece of data and cannot be loaded into the graph.
16
- """
17
-
18
- path: URL
19
-
20
-
21
- @dataclass
22
- class ParserNotFound(DocumentedError):
23
- """
24
- Parser not found.
25
-
26
- Path: {self.path}
27
- """
28
-
29
- path: Path
iolanta/loaders/http.py DELETED
@@ -1,127 +0,0 @@
1
- import json
2
- import re
3
- from dataclasses import dataclass, field
4
- from functools import reduce
5
- from io import StringIO
6
- from pathlib import Path
7
- from typing import Iterable, List, Optional, TextIO, Type, Union
8
-
9
- from documented import DocumentedError
10
- from rdflib import URIRef
11
- from rdflib.parser import URLInputSource
12
- from requests import Response
13
- from yarl import URL
14
-
15
- from iolanta.context import merge
16
- from iolanta.conversions import url_to_iri, url_to_path
17
- from iolanta.loaders.base import Loader
18
- from iolanta.loaders.errors import IsAContext, ParserNotFound
19
- from iolanta.loaders.local_file import choose_parser_by_extension
20
- from iolanta.models import LDContext, LDDocument, Quad
21
- from iolanta.parsers.base import Parser
22
- from iolanta.parsers.json import JSON
23
- from iolanta.parsers.markdown import Markdown
24
- from iolanta.parsers.yaml import YAML
25
-
26
-
27
- @dataclass(frozen=True)
28
- class HTTP(Loader[URL]):
29
- """
30
- Retrieve Linked Data from a file on the Web.
31
- """
32
-
33
- context: LDContext = field(default_factory=dict)
34
-
35
- def choose_parser_class(self, source: URL, response: Response):
36
- # FIXME hard code. Make this extensible.
37
- try:
38
- return choose_parser_by_extension(source)
39
- except ParserNotFound:
40
- content_type = response.headers['Content-Type']
41
-
42
- raise ValueError(f'Content type: {content_type}')
43
-
44
- def extract_alternate_url(
45
- self,
46
- source: URL,
47
- response: Response,
48
- ) -> URL | None:
49
- link = response.headers.get('Link')
50
-
51
- if link is None:
52
- return None
53
-
54
- match = re.match(
55
- r'<([^>]+)>; rel="alternate"; type="application/ld\+json"',
56
- link,
57
- )
58
- if match is None:
59
- return None
60
-
61
- return source / match.group(1)
62
-
63
- def as_jsonld_document(
64
- self,
65
- source: URL,
66
- iri: Optional[URIRef] = None,
67
- ) -> LDDocument:
68
- if iri is None:
69
- iri = url_to_iri(source)
70
-
71
- response = source.get()
72
- response.raise_for_status()
73
- alternate_url = self.extract_alternate_url(
74
- source=source,
75
- response=response,
76
- )
77
- if alternate_url is not None:
78
- return self.as_jsonld_document(
79
- source=alternate_url,
80
- iri=iri,
81
- )
82
-
83
- # `response.text` doesn't work.
84
- # Reasoning: https://stackoverflow.com/a/72621231/1245471
85
- response_as_file = StringIO(response.content.decode('utf-8'))
86
-
87
- parser_class: Type[Parser] = self.choose_parser_class(
88
- source=source,
89
- response=response,
90
- )
91
- try:
92
- document = parser_class().as_jsonld_document(response_as_file)
93
- except Exception:
94
- raise ValueError(response)
95
-
96
- if iri is not None and isinstance(document, dict):
97
- document.setdefault('@id', str(iri))
98
-
99
- return document
100
-
101
- def as_file(self, source: URL) -> TextIO:
102
- raise ValueError('!!!')
103
-
104
- def as_quad_stream(
105
- self,
106
- source: URL,
107
- iri: Optional[URIRef],
108
- root_loader: 'Loader[URL]',
109
- ) -> Iterable[Quad]:
110
- try:
111
- parser_class = self.choose_parser_class(source)
112
- except ParserNotFound:
113
- return []
114
-
115
- if iri is None:
116
- iri = url_to_iri(source)
117
-
118
- with source.open() as text_io:
119
- return parser_class().as_quad_stream(
120
- raw_data=text_io,
121
- iri=iri,
122
- context=self.context,
123
- root_loader=root_loader,
124
- )
125
-
126
- def find_context(self, source: str) -> LDContext:
127
- raise ValueError('??!!?')
@@ -1,148 +0,0 @@
1
- import dataclasses
2
- from dataclasses import dataclass, field
3
- from functools import reduce
4
- from pathlib import Path
5
- from typing import Iterable, List, Optional, TextIO, Type
6
-
7
- from rdflib import URIRef
8
-
9
- from iolanta.context import merge
10
- from iolanta.conversions import path_to_iri
11
- from iolanta.ensure_is_context import NotAContext, ensure_is_context
12
- from iolanta.loaders.base import Loader, SourceType
13
- from iolanta.loaders.local_file import LocalFile
14
- from iolanta.models import LDContext, LDDocument, Quad
15
- from iolanta.namespaces import IOLANTA
16
- from iolanta.parsers.base import Parser
17
-
18
-
19
- def merge_contexts(*contexts: LDContext) -> LDContext:
20
- return reduce(
21
- merge,
22
- filter(bool, contexts),
23
- {},
24
- )
25
-
26
-
27
- @dataclass(frozen=True)
28
- class LocalDirectory(Loader[Path]):
29
- """
30
- Retrieve Linked Data from a file on local disk.
31
-
32
- Requires Path with file:// scheme as input.
33
- """
34
-
35
- context_filenames: List[str] = field(
36
- default_factory=lambda: [
37
- 'context.yaml',
38
- 'context.yml',
39
- 'context.json',
40
- ],
41
- )
42
- include_hidden_directories: bool = False
43
-
44
- def find_context(self, source: SourceType) -> LDContext:
45
- raise ValueError('?!!!???')
46
-
47
- def directory_level_context(self, path: Path) -> Optional[LDContext]:
48
- for file_name in self.context_filenames:
49
- if (context_path := path / file_name).is_file():
50
- document = LocalFile(logger=self.logger).as_jsonld_document(
51
- source=context_path,
52
- )
53
-
54
- if document:
55
- try:
56
- return ensure_is_context(document)
57
- except NotAContext as err:
58
- raise dataclasses.replace(
59
- err,
60
- path=context_path,
61
- )
62
- return None
63
-
64
- def choose_parser_class(self, source: Path) -> Type[Parser]:
65
- """Choose parser class based on file extension."""
66
- raise ValueError('This is a directory')
67
-
68
- def as_quad_stream(
69
- self,
70
- source: Path,
71
- iri: Optional[URIRef],
72
- root_loader: Loader[Path],
73
- context: Optional[LDContext] = None,
74
- ) -> Iterable[Quad]:
75
- """Extract a sequence of quads from a local file."""
76
- if iri is None:
77
- iri = path_to_iri(source.absolute())
78
-
79
- if not source.is_dir():
80
- yield from LocalFile(logger=self.logger).as_quad_stream(
81
- source=source,
82
- root_loader=root_loader,
83
- iri=iri,
84
- context=context,
85
- )
86
- return
87
-
88
- context = merge_contexts(
89
- context,
90
- self.directory_level_context(source),
91
- )
92
-
93
- for child in source.iterdir():
94
- if not iri.endswith('/'):
95
- iri = URIRef(f'{iri}/')
96
-
97
- child_iri = URIRef(f'{iri}{child.name}')
98
-
99
- if child.is_dir():
100
- if (
101
- not self.include_hidden_directories
102
- and child.name.startswith('.')
103
- ):
104
- self.logger.info(
105
- 'Skipping a hidden directory: %s',
106
- child,
107
- )
108
- continue
109
-
110
- child_iri += '/'
111
-
112
- yield from LocalDirectory(logger=self.logger).as_quad_stream(
113
- source=child,
114
- iri=child_iri,
115
- root_loader=root_loader,
116
- context=context,
117
- )
118
-
119
- elif child.stem != 'context':
120
- yield from LocalFile(logger=self.logger).as_quad_stream(
121
- source=child,
122
- iri=child_iri,
123
- root_loader=root_loader,
124
- context=context,
125
- )
126
-
127
- if iri is not None:
128
- yield Quad(
129
- subject=child_iri,
130
- predicate=IOLANTA.isChildOf,
131
- object=iri,
132
- graph=URIRef(
133
- 'https://iolanta.tech/loaders/local-directory',
134
- ),
135
- )
136
-
137
- def as_file(self, source: Path) -> TextIO:
138
- """Construct a file-like object."""
139
- with source.open() as text_io:
140
- return text_io
141
-
142
- def as_jsonld_document(
143
- self,
144
- source: Path,
145
- iri: Optional[URIRef] = None,
146
- ) -> LDDocument:
147
- """As JSON-LD document."""
148
- raise ValueError('This is a directory.')