oarepo-runtime 2.0.0.dev45__tar.gz → 2.0.0.dev46__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 (51) hide show
  1. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/PKG-INFO +1 -1
  2. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/__init__.py +1 -1
  3. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/resources/signposting/__init__.py +53 -35
  4. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/.gitignore +0 -0
  5. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/LICENSE +0 -0
  6. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/README.md +0 -0
  7. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/api.py +0 -0
  8. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/cli/__init__.py +0 -0
  9. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/cli/search.py +0 -0
  10. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/config.py +0 -0
  11. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/ext.py +0 -0
  12. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/info/__init__.py +0 -0
  13. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/info/views.py +0 -0
  14. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/proxies.py +0 -0
  15. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/py.typed +0 -0
  16. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/__init__.py +0 -0
  17. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/drafts.py +0 -0
  18. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/mapping.py +0 -0
  19. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/pid_providers.py +0 -0
  20. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/systemfields/__init__.py +0 -0
  21. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/systemfields/base.py +0 -0
  22. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/systemfields/custom_fields.py +0 -0
  23. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/systemfields/mapping.py +0 -0
  24. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/systemfields/publication_status.py +0 -0
  25. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/systemfields/relations.py +0 -0
  26. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/records/systemfields/selectors.py +0 -0
  27. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/resources/__init__.py +0 -0
  28. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/resources/config.py +0 -0
  29. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/__init__.py +0 -0
  30. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/config/__init__.py +0 -0
  31. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/config/components.py +0 -0
  32. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/config/link_conditions.py +0 -0
  33. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/config/permissions.py +0 -0
  34. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/facets/__init__.py +0 -0
  35. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/facets/base.py +0 -0
  36. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/facets/date.py +0 -0
  37. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/facets/nested_facet.py +0 -0
  38. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/facets/params.py +0 -0
  39. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/facets/utils.py +0 -0
  40. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/generators.py +0 -0
  41. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/records/__init__.py +0 -0
  42. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/records/custom_fields.py +0 -0
  43. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/records/links.py +0 -0
  44. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/records/mapping.py +0 -0
  45. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/results.py +0 -0
  46. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/schema/__init__.py +0 -0
  47. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/schema/i18n.py +0 -0
  48. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/schema/i18n_ui.py +0 -0
  49. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/services/schema/ui.py +0 -0
  50. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/oarepo_runtime/typing.py +0 -0
  51. {oarepo_runtime-2.0.0.dev45 → oarepo_runtime-2.0.0.dev46}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oarepo-runtime
3
- Version: 2.0.0.dev45
3
+ Version: 2.0.0.dev46
4
4
  Summary: A set of runtime extensions of Invenio repository
5
5
  Project-URL: Homepage, https://github.com/oarepo/oarepo-runtime
6
6
  License-Expression: MIT
@@ -19,6 +19,6 @@ from .api import Model
19
19
  from .ext import OARepoRuntime
20
20
  from .proxies import current_runtime
21
21
 
22
- __version__ = "2.0.0dev45"
22
+ __version__ = "2.0.0dev46"
23
23
 
24
24
  __all__ = ("Model", "OARepoRuntime", "__version__", "current_runtime")
@@ -31,18 +31,21 @@ from __future__ import annotations
31
31
 
32
32
  from collections import defaultdict
33
33
  from typing import Any, Literal, cast, overload
34
- from urllib.parse import urljoin
34
+ from urllib.parse import quote, urljoin, urlparse
35
35
 
36
36
  from signposting import AbsoluteURI, LinkRel, Signpost
37
37
 
38
38
  from oarepo_runtime.ext import ExportRepresentation
39
39
  from oarepo_runtime.proxies import current_runtime
40
40
 
41
+ LINK_PREFIX = "Link: "
42
+ TEXT_HTML_TYPE = "text/html"
43
+
41
44
 
42
45
  def signpost_link_to_str(signpost_link: Signpost) -> str:
43
46
  """Convert a signpost link to string."""
44
47
  link_str = str(signpost_link)
45
- if link_str[:6] == "Link: ":
48
+ if link_str.startswith(LINK_PREFIX):
46
49
  return f"{link_str[6:]}"
47
50
  raise ValueError(f"Invalid signpost link: {link_str}") # pragma: no cover
48
51
 
@@ -73,18 +76,20 @@ def signpost_link_to_additional_link(
73
76
  if as_dict:
74
77
  return {
75
78
  "anchor": link.target,
76
- str(LinkRel.collection): [{"href": landing_page_url, "type": "text/html"}],
79
+ str(LinkRel.collection): [{"href": landing_page_url, "type": TEXT_HTML_TYPE}],
77
80
  }
78
81
  return Signpost(
79
- rel=LinkRel.collection, target=landing_page_url, media_type="text/html", context=link.target
82
+ rel=LinkRel.collection, target=landing_page_url, media_type=TEXT_HTML_TYPE, context=link.target
80
83
  )
81
84
  case LinkRel.describedby:
82
85
  if as_dict:
83
86
  return {
84
87
  "anchor": link.target,
85
- str(LinkRel.describes): [{"href": landing_page_url, "type": "text/html"}],
88
+ str(LinkRel.describes): [{"href": landing_page_url, "type": TEXT_HTML_TYPE}],
86
89
  }
87
- return Signpost(rel=LinkRel.describes, target=landing_page_url, media_type="text/html", context=link.target)
90
+ return Signpost(
91
+ rel=LinkRel.describes, target=landing_page_url, media_type=TEXT_HTML_TYPE, context=link.target
92
+ )
88
93
  case LinkRel.cite_as:
89
94
  return None
90
95
  # anchor is generated only for item & describedby, not for license
@@ -146,16 +151,17 @@ def list_of_signpost_links_to_http_header(links_list: list[Signpost]) -> str:
146
151
  Returns: signpost header with formatted links.
147
152
 
148
153
  """
149
- links = [str(link)[6:] for link in links_list if str(link)[:6] == "Link: "]
150
- return f"Link: {', '.join(links)}"
154
+ links = [str(link)[6:] for link in links_list if str(link).startswith(LINK_PREFIX)]
155
+ return f"{LINK_PREFIX}{', '.join(links)}"
151
156
 
152
157
 
153
- def create_linkset(datacite_dict: dict, record_dict: dict) -> str:
158
+ def create_linkset(datacite_dict: dict, record_dict: dict, include_reverse_relations: bool = True) -> str:
154
159
  """Create a linkset for the record item in the application/linkset format.
155
160
 
156
161
  Args:
157
162
  datacite_dict: dictionary with datacite data
158
163
  record_dict: record item dict, for which signpost links should be generated
164
+ include_reverse_relations: if True, inverse relations are included in the linkset
159
165
 
160
166
  Returns: linkset in string format
161
167
 
@@ -165,20 +171,23 @@ def create_linkset(datacite_dict: dict, record_dict: dict) -> str:
165
171
  if not landing_page_url: # pragma: no cover
166
172
  return ""
167
173
  landing_page_links = landing_page_signpost_links_list(datacite_dict, record_dict, short=False)
168
- additional_links: list[Signpost] = get_additional_links(landing_page_links, landing_page_url, as_dict=False)
169
- anchored_links = [
170
- anchor_signpost_link(signpost_link, landing_page_url) for signpost_link in landing_page_links
171
- ] + additional_links
172
- links = [str(link)[6:] for link in anchored_links if str(link)[:6] == "Link: "]
174
+ anchored_links = [anchor_signpost_link(signpost_link, landing_page_url) for signpost_link in landing_page_links]
175
+ if include_reverse_relations:
176
+ additional_links: list[Signpost] = get_additional_links(landing_page_links, landing_page_url, as_dict=False)
177
+ anchored_links.extend(additional_links)
178
+ links = [str(link)[6:] for link in anchored_links if str(link).startswith(LINK_PREFIX)]
173
179
  return ", ".join(links)
174
180
 
175
181
 
176
- def create_linkset_json(datacite_dict: dict, record_dict: dict) -> dict[str, list[dict[str, Any]]]:
182
+ def create_linkset_json(
183
+ datacite_dict: dict, record_dict: dict, include_reverse_relations: bool = True
184
+ ) -> dict[str, list[dict[str, Any]]]:
177
185
  """Create a linkset for the record item in the application/linkset+json format.
178
186
 
179
187
  Args:
180
188
  datacite_dict: dictionary with datacite data
181
189
  record_dict: record item dict, for which signpost links should be generated
190
+ include_reverse_relations: if True, inverse relations are included in the linkset
182
191
 
183
192
  Returns: linkset in JSON format
184
193
 
@@ -194,12 +203,16 @@ def create_linkset_json(datacite_dict: dict, record_dict: dict) -> dict[str, lis
194
203
  links_json = defaultdict(list)
195
204
  links_json["anchor"] = landing_page_url
196
205
 
197
- additional_links: list[dict[str, Any]] = get_additional_links(landing_page_links, landing_page_url)
198
206
  for link_relation_from_dict, list_of_links_for_relation in dict_of_links_by_relation.items():
199
207
  for link in list_of_links_for_relation:
200
208
  links_json[link_relation_from_dict].append(signpost_link_to_dict(link))
201
209
 
202
- return {"linkset": [dict(links_json), *[x for x in additional_links if x]]}
210
+ json_linkset = {"linkset": [dict(links_json)]}
211
+ if include_reverse_relations:
212
+ additional_links: list[dict[str, Any]] = get_additional_links(landing_page_links, landing_page_url)
213
+ for additional_link in additional_links:
214
+ json_linkset["linkset"].append(additional_link)
215
+ return json_linkset
203
216
 
204
217
 
205
218
  def file_content_signpost_links_list(record_dict: dict) -> list[Signpost]:
@@ -229,7 +242,7 @@ def file_content_signpost_links_list(record_dict: dict) -> list[Signpost]:
229
242
  Signpost(
230
243
  rel=LinkRel.collection,
231
244
  target=landing_page_url,
232
- media_type="text/html",
245
+ media_type=TEXT_HTML_TYPE,
233
246
  ),
234
247
  ]
235
248
 
@@ -258,7 +271,7 @@ def export_format_signpost_links_list(record_dict: dict) -> list[Signpost]:
258
271
  target=landing_page_url,
259
272
  media_type="application/linkset+json",
260
273
  ),
261
- Signpost(rel=LinkRel.describes, target=landing_page_url, media_type="text/html"),
274
+ Signpost(rel=LinkRel.describes, target=landing_page_url, media_type=TEXT_HTML_TYPE),
262
275
  ]
263
276
 
264
277
 
@@ -274,23 +287,29 @@ def landing_page_signpost_links_list(datacite_dict: dict, record_dict: dict, sho
274
287
 
275
288
  """
276
289
  signposting_links: list[Signpost] = []
277
- record_files = record_dict.get("files", {}).get("entries", {})
278
- model = current_runtime.models_by_schema[record_dict["$schema"]]
279
-
280
- # author - prvni tri
281
290
  creators = datacite_dict.get("creators", [])
291
+ record_files = record_dict.get("files", {}).get("entries", {})
292
+ record_file_values = record_files.values()
282
293
  if short:
294
+ record_file_values = list(record_file_values)[:3]
283
295
  creators = creators[:3]
296
+ model = current_runtime.models_by_schema[record_dict["$schema"]]
297
+
298
+ # authors
284
299
  for attribute in creators:
285
300
  signposting_links.extend(
286
301
  Signpost(rel=LinkRel.author, target=name_identifier["nameIdentifier"])
287
302
  for name_identifier in attribute["nameIdentifiers"]
303
+ if all(
304
+ [urlparse(name_identifier["nameIdentifier"]).scheme, urlparse(name_identifier["nameIdentifier"]).netloc]
305
+ )
288
306
  )
289
307
 
290
308
  # cite-as = DOI
291
- signposting_links.append(
292
- Signpost(rel=LinkRel.cite_as, target=urljoin("https://doi.org/", datacite_dict.get("doi")))
293
- )
309
+ if datacite_dict.get("doi"):
310
+ signposting_links.append(
311
+ Signpost(rel=LinkRel.cite_as, target=urljoin("https://doi.org/", datacite_dict.get("doi")))
312
+ )
294
313
 
295
314
  # describedby
296
315
  for model_export in model.exports:
@@ -304,17 +323,14 @@ def landing_page_signpost_links_list(datacite_dict: dict, record_dict: dict, sho
304
323
  Signpost(rel=LinkRel.describedby, target=model_export_url, media_type=model_export.mimetype)
305
324
  )
306
325
 
307
- # item
308
- record_file_values = record_files.values()
309
- if short:
310
- record_file_values = list(record_file_values)[:3]
326
+ # items
311
327
  record_files_url = record_dict.get("links", {}).get("files")
312
328
  if record_files_url:
313
329
  signposting_links.extend(
314
330
  Signpost(
315
331
  rel=LinkRel.item,
316
332
  media_type=record_file.get("mimetype"),
317
- target=f"{record_files_url}/{record_file.get('key')}",
333
+ target=f"{record_files_url}/{quote(record_file.get('key'))}",
318
334
  )
319
335
  for record_file in record_file_values
320
336
  )
@@ -341,21 +357,23 @@ def landing_page_signpost_links_list(datacite_dict: dict, record_dict: dict, sho
341
357
  return signposting_links
342
358
 
343
359
 
344
- def record_dict_to_linkset(record_dict: dict) -> str:
360
+ def record_dict_to_linkset(record_dict: dict, include_reverse_relations: bool = True) -> str:
345
361
  """Create a linkset from the dictionary of a record item. Get datacite to build linkset from model exports."""
346
362
  datacite_dict = current_runtime.get_export_from_serialized_record(
347
363
  record_dict=record_dict,
348
364
  representation=ExportRepresentation.DICTIONARY,
349
365
  export_mimetype="application/vnd.datacite.datacite+json",
350
366
  )
351
- return create_linkset(datacite_dict, record_dict)
367
+ return create_linkset(datacite_dict, record_dict, include_reverse_relations)
352
368
 
353
369
 
354
- def record_dict_to_json_linkset(record_dict: dict) -> dict[str, list[dict[str, Any]]]:
370
+ def record_dict_to_json_linkset(
371
+ record_dict: dict, include_reverse_relations: bool = True
372
+ ) -> dict[str, list[dict[str, Any]]]:
355
373
  """Create a JSON linkset from the dictionary of a record item. Get datacite to build linkset from model exports."""
356
374
  datacite_dict = current_runtime.get_export_from_serialized_record(
357
375
  record_dict=record_dict,
358
376
  representation=ExportRepresentation.DICTIONARY,
359
377
  export_mimetype="application/vnd.datacite.datacite+json",
360
378
  )
361
- return create_linkset_json(datacite_dict, record_dict)
379
+ return create_linkset_json(datacite_dict, record_dict, include_reverse_relations)