oarepo-runtime 1.10.3__py3-none-any.whl → 2.0.0.dev4__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 (171) hide show
  1. oarepo_runtime/__init__.py +24 -0
  2. oarepo_runtime/api.py +210 -0
  3. oarepo_runtime/cli/__init__.py +10 -21
  4. oarepo_runtime/cli/search.py +34 -0
  5. oarepo_runtime/config.py +98 -13
  6. oarepo_runtime/ext.py +64 -82
  7. oarepo_runtime/proxies.py +21 -5
  8. oarepo_runtime/records/__init__.py +11 -50
  9. oarepo_runtime/records/drafts.py +24 -18
  10. oarepo_runtime/records/mapping.py +84 -0
  11. oarepo_runtime/records/pid_providers.py +43 -7
  12. oarepo_runtime/records/systemfields/__init__.py +15 -33
  13. oarepo_runtime/records/systemfields/mapping.py +41 -24
  14. oarepo_runtime/records/systemfields/publication_status.py +61 -0
  15. oarepo_runtime/services/__init__.py +12 -0
  16. oarepo_runtime/services/config/__init__.py +15 -21
  17. oarepo_runtime/services/config/link_conditions.py +69 -75
  18. oarepo_runtime/services/config/permissions.py +62 -0
  19. oarepo_runtime/services/facets/__init__.py +12 -33
  20. oarepo_runtime/services/facets/params.py +45 -110
  21. oarepo_runtime/services/records/__init__.py +14 -1
  22. oarepo_runtime/services/records/links.py +21 -11
  23. oarepo_runtime/services/records/mapping.py +42 -0
  24. oarepo_runtime/services/results.py +98 -109
  25. oarepo_runtime/services/schema/__init__.py +12 -44
  26. oarepo_runtime/services/schema/i18n.py +47 -22
  27. oarepo_runtime/services/schema/i18n_ui.py +61 -24
  28. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/METADATA +10 -21
  29. oarepo_runtime-2.0.0.dev4.dist-info/RECORD +32 -0
  30. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/WHEEL +1 -2
  31. oarepo_runtime-2.0.0.dev4.dist-info/entry_points.txt +5 -0
  32. oarepo_runtime/cli/assets.py +0 -145
  33. oarepo_runtime/cli/base.py +0 -25
  34. oarepo_runtime/cli/cf.py +0 -15
  35. oarepo_runtime/cli/check.py +0 -167
  36. oarepo_runtime/cli/configuration.py +0 -51
  37. oarepo_runtime/cli/fixtures.py +0 -167
  38. oarepo_runtime/cli/index.py +0 -272
  39. oarepo_runtime/cli/permissions/__init__.py +0 -6
  40. oarepo_runtime/cli/permissions/base.py +0 -26
  41. oarepo_runtime/cli/permissions/evaluate.py +0 -63
  42. oarepo_runtime/cli/permissions/list.py +0 -239
  43. oarepo_runtime/cli/permissions/search.py +0 -121
  44. oarepo_runtime/cli/validate.py +0 -150
  45. oarepo_runtime/datastreams/__init__.py +0 -38
  46. oarepo_runtime/datastreams/asynchronous.py +0 -247
  47. oarepo_runtime/datastreams/catalogue.py +0 -150
  48. oarepo_runtime/datastreams/datastreams.py +0 -152
  49. oarepo_runtime/datastreams/errors.py +0 -54
  50. oarepo_runtime/datastreams/ext.py +0 -41
  51. oarepo_runtime/datastreams/fixtures.py +0 -265
  52. oarepo_runtime/datastreams/json.py +0 -4
  53. oarepo_runtime/datastreams/readers/__init__.py +0 -39
  54. oarepo_runtime/datastreams/readers/attachments.py +0 -51
  55. oarepo_runtime/datastreams/readers/excel.py +0 -123
  56. oarepo_runtime/datastreams/readers/json.py +0 -27
  57. oarepo_runtime/datastreams/readers/service.py +0 -54
  58. oarepo_runtime/datastreams/readers/yaml.py +0 -14
  59. oarepo_runtime/datastreams/semi_asynchronous.py +0 -91
  60. oarepo_runtime/datastreams/synchronous.py +0 -70
  61. oarepo_runtime/datastreams/transformers.py +0 -18
  62. oarepo_runtime/datastreams/types.py +0 -323
  63. oarepo_runtime/datastreams/utils.py +0 -131
  64. oarepo_runtime/datastreams/writers/__init__.py +0 -21
  65. oarepo_runtime/datastreams/writers/attachments_file.py +0 -92
  66. oarepo_runtime/datastreams/writers/attachments_service.py +0 -118
  67. oarepo_runtime/datastreams/writers/publish.py +0 -70
  68. oarepo_runtime/datastreams/writers/service.py +0 -175
  69. oarepo_runtime/datastreams/writers/utils.py +0 -30
  70. oarepo_runtime/datastreams/writers/validation_errors.py +0 -20
  71. oarepo_runtime/datastreams/writers/yaml.py +0 -56
  72. oarepo_runtime/ext_config.py +0 -67
  73. oarepo_runtime/i18n/__init__.py +0 -3
  74. oarepo_runtime/info/__init__.py +0 -0
  75. oarepo_runtime/info/check.py +0 -95
  76. oarepo_runtime/info/permissions/__init__.py +0 -0
  77. oarepo_runtime/info/permissions/debug.py +0 -191
  78. oarepo_runtime/info/views.py +0 -586
  79. oarepo_runtime/profile.py +0 -60
  80. oarepo_runtime/records/dumpers/__init__.py +0 -8
  81. oarepo_runtime/records/dumpers/edtf_interval.py +0 -38
  82. oarepo_runtime/records/dumpers/multilingual_dumper.py +0 -34
  83. oarepo_runtime/records/entity_resolvers/__init__.py +0 -13
  84. oarepo_runtime/records/entity_resolvers/proxies.py +0 -57
  85. oarepo_runtime/records/mappings/__init__.py +0 -0
  86. oarepo_runtime/records/mappings/rdm_parent_mapping.json +0 -483
  87. oarepo_runtime/records/owners/__init__.py +0 -3
  88. oarepo_runtime/records/owners/registry.py +0 -22
  89. oarepo_runtime/records/relations/__init__.py +0 -22
  90. oarepo_runtime/records/relations/base.py +0 -296
  91. oarepo_runtime/records/relations/internal.py +0 -46
  92. oarepo_runtime/records/relations/lookup.py +0 -28
  93. oarepo_runtime/records/relations/pid_relation.py +0 -102
  94. oarepo_runtime/records/systemfields/featured_file.py +0 -45
  95. oarepo_runtime/records/systemfields/has_draftcheck.py +0 -47
  96. oarepo_runtime/records/systemfields/icu.py +0 -371
  97. oarepo_runtime/records/systemfields/owner.py +0 -115
  98. oarepo_runtime/records/systemfields/record_status.py +0 -35
  99. oarepo_runtime/records/systemfields/selectors.py +0 -98
  100. oarepo_runtime/records/systemfields/synthetic.py +0 -130
  101. oarepo_runtime/resources/__init__.py +0 -4
  102. oarepo_runtime/resources/config.py +0 -12
  103. oarepo_runtime/resources/file_resource.py +0 -15
  104. oarepo_runtime/resources/json_serializer.py +0 -27
  105. oarepo_runtime/resources/localized_ui_json_serializer.py +0 -54
  106. oarepo_runtime/resources/resource.py +0 -53
  107. oarepo_runtime/resources/responses.py +0 -20
  108. oarepo_runtime/services/components.py +0 -429
  109. oarepo_runtime/services/config/draft_link.py +0 -23
  110. oarepo_runtime/services/config/permissions_presets.py +0 -174
  111. oarepo_runtime/services/config/service.py +0 -117
  112. oarepo_runtime/services/custom_fields/__init__.py +0 -80
  113. oarepo_runtime/services/custom_fields/mappings.py +0 -188
  114. oarepo_runtime/services/entity/__init__.py +0 -0
  115. oarepo_runtime/services/entity/config.py +0 -14
  116. oarepo_runtime/services/entity/schema.py +0 -9
  117. oarepo_runtime/services/entity/service.py +0 -48
  118. oarepo_runtime/services/expansions/__init__.py +0 -0
  119. oarepo_runtime/services/expansions/expandable_fields.py +0 -21
  120. oarepo_runtime/services/expansions/service.py +0 -4
  121. oarepo_runtime/services/facets/base.py +0 -12
  122. oarepo_runtime/services/facets/date.py +0 -72
  123. oarepo_runtime/services/facets/enum.py +0 -11
  124. oarepo_runtime/services/facets/facet_groups_names.py +0 -17
  125. oarepo_runtime/services/facets/max_facet.py +0 -13
  126. oarepo_runtime/services/facets/multilingual_facet.py +0 -33
  127. oarepo_runtime/services/facets/nested_facet.py +0 -32
  128. oarepo_runtime/services/facets/year_histogram.py +0 -200
  129. oarepo_runtime/services/files/__init__.py +0 -8
  130. oarepo_runtime/services/files/components.py +0 -62
  131. oarepo_runtime/services/files/service.py +0 -16
  132. oarepo_runtime/services/generators.py +0 -10
  133. oarepo_runtime/services/permissions/__init__.py +0 -3
  134. oarepo_runtime/services/permissions/generators.py +0 -103
  135. oarepo_runtime/services/relations/__init__.py +0 -0
  136. oarepo_runtime/services/relations/components.py +0 -15
  137. oarepo_runtime/services/relations/errors.py +0 -18
  138. oarepo_runtime/services/relations/mapping.py +0 -38
  139. oarepo_runtime/services/schema/cf.py +0 -13
  140. oarepo_runtime/services/schema/i18n_validation.py +0 -7
  141. oarepo_runtime/services/schema/marshmallow.py +0 -44
  142. oarepo_runtime/services/schema/marshmallow_to_json_schema.py +0 -72
  143. oarepo_runtime/services/schema/oneofschema.py +0 -192
  144. oarepo_runtime/services/schema/polymorphic.py +0 -21
  145. oarepo_runtime/services/schema/rdm.py +0 -146
  146. oarepo_runtime/services/schema/rdm_ui.py +0 -156
  147. oarepo_runtime/services/schema/ui.py +0 -251
  148. oarepo_runtime/services/schema/validation.py +0 -70
  149. oarepo_runtime/services/search.py +0 -282
  150. oarepo_runtime/services/service.py +0 -61
  151. oarepo_runtime/tasks.py +0 -6
  152. oarepo_runtime/translations/cs/LC_MESSAGES/messages.mo +0 -0
  153. oarepo_runtime/translations/cs/LC_MESSAGES/messages.po +0 -95
  154. oarepo_runtime/translations/default_translations.py +0 -6
  155. oarepo_runtime/translations/en/LC_MESSAGES/messages.mo +0 -0
  156. oarepo_runtime/translations/en/LC_MESSAGES/messages.po +0 -97
  157. oarepo_runtime/translations/messages.pot +0 -100
  158. oarepo_runtime/uow.py +0 -146
  159. oarepo_runtime/utils/__init__.py +0 -0
  160. oarepo_runtime/utils/functools.py +0 -37
  161. oarepo_runtime/utils/identity_utils.py +0 -35
  162. oarepo_runtime/utils/index.py +0 -11
  163. oarepo_runtime/utils/path.py +0 -97
  164. oarepo_runtime-1.10.3.dist-info/RECORD +0 -163
  165. oarepo_runtime-1.10.3.dist-info/entry_points.txt +0 -16
  166. oarepo_runtime-1.10.3.dist-info/top_level.txt +0 -2
  167. tests/marshmallow_to_json/__init__.py +0 -0
  168. tests/marshmallow_to_json/test_datacite_ui_schema.py +0 -1410
  169. tests/marshmallow_to_json/test_simple_schema.py +0 -52
  170. tests/pkg_data/__init__.py +0 -0
  171. {oarepo_runtime-1.10.3.dist-info → oarepo_runtime-2.0.0.dev4.dist-info}/licenses/LICENSE +0 -0
@@ -1,586 +0,0 @@
1
- import importlib
2
- import json
3
- import logging
4
- import os
5
- import re
6
- from functools import cached_property
7
- from urllib.parse import urljoin, urlparse, urlunparse
8
-
9
- import importlib_metadata
10
- import importlib_resources
11
- import marshmallow as ma
12
- from flask import current_app, request, url_for
13
- from flask.ctx import RequestContext
14
- from flask.globals import _cv_request
15
- from flask_resources import (
16
- Resource,
17
- ResourceConfig,
18
- from_conf,
19
- request_parser,
20
- resource_requestctx,
21
- response_handler,
22
- route,
23
- )
24
- from flask_restful import abort
25
- from invenio_base.utils import obj_or_import_string
26
- from invenio_jsonschemas import current_jsonschemas
27
- from invenio_records_resources.proxies import (
28
- current_service_registry,
29
- current_transfer_registry,
30
- )
31
- from invenio_records_resources.records.api import Record
32
-
33
- logger = logging.getLogger("oarepo_runtime.info")
34
-
35
-
36
- class InfoConfig(ResourceConfig):
37
- blueprint_name = "oarepo_runtime_info"
38
- url_prefix = "/.well-known/repository"
39
-
40
- schema_view_args = {"schema": ma.fields.Str()}
41
- model_view_args = {"model": ma.fields.Str()}
42
-
43
- def __init__(self, app):
44
- self.app = app
45
-
46
- @cached_property
47
- def components(self):
48
- return tuple(
49
- obj_or_import_string(x)
50
- for x in self.app.config.get("INFO_ENDPOINT_COMPONENTS", [])
51
- )
52
-
53
-
54
- schema_view_args = request_parser(from_conf("schema_view_args"), location="view_args")
55
- model_view_args = request_parser(from_conf("model_view_args"), location="view_args")
56
-
57
-
58
- class InfoResource(Resource):
59
- def create_url_rules(self):
60
- return [
61
- route("GET", "/", self.repository),
62
- route("GET", "/models", self.models),
63
- route("GET", "/schema/<path:schema>", self.schema),
64
- route("GET", "/models/<model>", self.model),
65
- ]
66
-
67
- @cached_property
68
- def components(self):
69
- return [x(self) for x in self.config.components]
70
-
71
- @response_handler()
72
- def repository(self):
73
- """Repository endpoint."""
74
- links = {
75
- "self": url_for(request.endpoint, _external=True),
76
- "api": replace_path_in_url(
77
- url_for(request.endpoint, _external=True), "/api"
78
- ),
79
- "models": url_for("oarepo_runtime_info.models", _external=True),
80
- }
81
- try:
82
- import invenio_requests # noqa
83
-
84
- links["requests"] = api_url_for("requests.search", _external=True)
85
- except ImportError:
86
- pass
87
-
88
- ret = {
89
- "schema": "local://introspection-v1.0.0",
90
- "name": current_app.config.get("THEME_SITENAME", ""),
91
- "description": current_app.config.get("REPOSITORY_DESCRIPTION", ""),
92
- "version": os.environ.get("DEPLOYMENT_VERSION", "local development"),
93
- "invenio_version": get_package_version("oarepo"),
94
- "transfers": list(current_transfer_registry.get_transfer_types()),
95
- "links": links,
96
- "features": [
97
- *_add_feature_if_can_import("drafts", "invenio_drafts_resources"),
98
- *_add_feature_if_can_import("workflows", "oarepo_workflows"),
99
- *_add_feature_if_can_import("requests", "invenio_requests"),
100
- *_add_feature_if_can_import("communities", "invenio_communities"),
101
- *_add_feature_if_can_import("request_types", "oarepo_requests"),
102
- ],
103
- }
104
- if len(self.model_data) == 1:
105
- ret["default_model"] = self.model_data[0]["name"]
106
-
107
- self.call_components("repository", data=ret)
108
- return ret, 200
109
-
110
- @cached_property
111
- def model_data(self):
112
- data = []
113
- # iterate entrypoint oarepo.models
114
- for model in importlib_metadata.entry_points().select(group="oarepo.models"):
115
- package_name, file_name = model.value.split(":")
116
- model_data = json.loads(
117
- importlib_resources.files(package_name).joinpath(file_name).read_text()
118
- )
119
- model_data = model_data.get("model", {})
120
- if model_data.get("type") != "model":
121
- continue
122
-
123
- resource_config_class = self._get_resource_config_class(model_data)
124
- service = self._get_service(model_data)
125
- service_class = self._get_service_class(model_data)
126
- if not service or type(service) != service_class:
127
- continue
128
-
129
- # check if the service class is inside OAREPO_GLOBAL_SEARCH and if not, skip it
130
- global_search_models = current_app.config.get("GLOBAL_SEARCH_MODELS", [])
131
- for global_model in global_search_models:
132
- if global_model["model_service"] == model_data["service"]["class"]:
133
- break
134
- else:
135
- continue
136
-
137
- model_features = self._get_model_features(model_data)
138
-
139
- links = {
140
- "html": self._get_model_html_endpoint(model_data),
141
- "model": self._get_model_model_endpoint(model.name),
142
- # "openapi": url_for(self._get_model_openapi_endpoint(model_data), _external=True)
143
- }
144
-
145
- links["records"] = self._get_model_api_endpoint(model_data)
146
- if "drafts" in model_features:
147
- links["drafts"] = self._get_model_draft_endpoint(model_data)
148
- links["deposit"] = links["records"]
149
-
150
- data.append(
151
- {
152
- "schema": "local://" + model_data["json-schema-settings"]["name"],
153
- "type": model_data.get(
154
- "model-name", model_data.get("module", {}).get("base", "")
155
- ).lower(),
156
- "name": model_data.get(
157
- "model-name", model_data.get("module", {}).get("base", "")
158
- ).lower(),
159
- "description": model_data.get("model-description", ""),
160
- "version": model_data["json-schema-settings"]["version"],
161
- "features": model_features,
162
- "links": links,
163
- # TODO: we also need to get previous schema versions here if we support
164
- # multiple version of the same schema at the same time
165
- "content_types": self._get_model_content_types(
166
- service, resource_config_class, model_data
167
- ),
168
- "metadata": model_data.get("properties", {}).get("metadata", None)
169
- is not None,
170
- }
171
- )
172
- self.call_components("model", data=data)
173
- data.sort(key=lambda x: x["type"])
174
- return data
175
-
176
- @cached_property
177
- def vocabulary_data(self):
178
- ret = []
179
- try:
180
- from invenio_vocabularies.contrib.affiliations.api import Affiliation
181
- from invenio_vocabularies.contrib.awards.api import Award
182
- from invenio_vocabularies.contrib.funders.api import Funder
183
- from invenio_vocabularies.contrib.names.api import Name
184
- from invenio_vocabularies.contrib.subjects.api import Subject
185
- from invenio_vocabularies.records.api import Vocabulary
186
- from invenio_vocabularies.records.models import VocabularyType
187
- except ImportError:
188
- return ret
189
-
190
- def _generate_rdm_vocabulary(
191
- base_url: str,
192
- record: type[Record],
193
- vocabulary_type: str,
194
- vocabulary_name: str,
195
- vocabulary_description: str,
196
- special: bool,
197
- can_export: bool = True,
198
- can_deposit: bool = False,
199
- ) -> dict:
200
- if not base_url.endswith("/"):
201
- base_url += "/"
202
- url_prefix = base_url + "api" if special else base_url + "api/vocabularies"
203
- schema_path = base_url + record.schema.value.replace("local://", "schemas/")
204
- links = dict(
205
- records=f"{url_prefix}/{vocabulary_type}",
206
- )
207
- if can_deposit:
208
- links["deposit"] = f"{url_prefix}/{vocabulary_type}"
209
-
210
- return dict(
211
- schema=record.schema.value,
212
- type=vocabulary_type,
213
- name=vocabulary_name,
214
- description="Vocabulary for " + vocabulary_name,
215
- version="unknown",
216
- features=["rdm", "vocabulary"],
217
- links=links,
218
- content_types=[
219
- dict(
220
- content_type="application/json",
221
- name="Invenio RDM JSON",
222
- description="Vocabulary JSON",
223
- schema=schema_path,
224
- can_export=can_export,
225
- can_deposit=can_deposit,
226
- )
227
- ],
228
- metadata=False,
229
- )
230
-
231
- base_url = api_url_for("vocabularies.search", type="languages", _external=True)
232
- base_url = replace_path_in_url(base_url, "/")
233
- ret = [
234
- _generate_rdm_vocabulary(
235
- base_url, Affiliation, "affiliations", "Affiliations", "", special=True
236
- ),
237
- _generate_rdm_vocabulary(
238
- base_url, Award, "awards", "Awards", "", special=True
239
- ),
240
- _generate_rdm_vocabulary(
241
- base_url, Funder, "funders", "Funders", "", special=True
242
- ),
243
- _generate_rdm_vocabulary(
244
- base_url, Subject, "subjects", "Subjects", "", special=True
245
- ),
246
- _generate_rdm_vocabulary(
247
- base_url, Name, "names", "Names", "", special=True
248
- ),
249
- _generate_rdm_vocabulary(
250
- base_url,
251
- Affiliation,
252
- "affiliations-vocab",
253
- "Writable Affiliations",
254
- "Write endpoint for affiliations",
255
- special=False,
256
- can_deposit=True,
257
- ),
258
- _generate_rdm_vocabulary(
259
- base_url,
260
- Award,
261
- "awards-vocab",
262
- "Writable Awards",
263
- "Write endpoint for awards",
264
- special=False,
265
- can_deposit=True,
266
- ),
267
- _generate_rdm_vocabulary(
268
- base_url,
269
- Funder,
270
- "funders-vocab",
271
- "Writable Funders",
272
- "Write endpoint for funders",
273
- special=False,
274
- can_deposit=True,
275
- ),
276
- _generate_rdm_vocabulary(
277
- base_url,
278
- Subject,
279
- "subjects-vocab",
280
- "Writable Subjects",
281
- "Write endpoint for subjects",
282
- special=False,
283
- can_deposit=True,
284
- ),
285
- _generate_rdm_vocabulary(
286
- base_url,
287
- Name,
288
- "names-vocab",
289
- "Writable Names",
290
- "Write endpoint for names",
291
- special=False,
292
- can_deposit=True,
293
- ),
294
- ]
295
-
296
- vc_types = {vc.id for vc in VocabularyType.query.all()}
297
- vocab_type_metadata = current_app.config.get(
298
- "INVENIO_VOCABULARY_TYPE_METADATA", {}
299
- )
300
- vc_types.update(vocab_type_metadata.keys())
301
-
302
- for vc in sorted(vc_types):
303
- vc_metadata = vocab_type_metadata.get(vc, {})
304
- ret.append(
305
- _generate_rdm_vocabulary(
306
- base_url,
307
- Vocabulary,
308
- vc,
309
- to_current_language(vc_metadata.get("name")) or vc,
310
- to_current_language(vc_metadata.get("description")) or "",
311
- special=False,
312
- can_export=True,
313
- can_deposit=True,
314
- )
315
- )
316
-
317
- return ret
318
-
319
- @response_handler(many=True)
320
- def models(self):
321
- return self.model_data + self.vocabulary_data, 200
322
-
323
- @schema_view_args
324
- @response_handler()
325
- def schema(self):
326
- schema = resource_requestctx.view_args["schema"]
327
- return current_jsonschemas.get_schema(schema, resolved=True), 200
328
-
329
- @model_view_args
330
- @response_handler()
331
- def model(self):
332
- model = resource_requestctx.view_args["model"]
333
- for _model in importlib_metadata.entry_points().select(
334
- group="oarepo.models", name=model
335
- ):
336
- package_name, file_name = _model.value.split(":")
337
- model_data = json.loads(
338
- importlib_resources.files(package_name).joinpath(file_name).read_text()
339
- )
340
- return self._remove_implementation_details_from_model(model_data), 200
341
- abort(404)
342
-
343
- IMPLEMENTATION_DETAILS = re.compile(
344
- r"""
345
- ^(
346
- class |
347
- .*-class |
348
- base-classes |
349
- .*-base-classes |
350
- module |
351
- generate |
352
- imports |
353
- extra-code |
354
- components |
355
- .*-args
356
- )$
357
- """,
358
- re.VERBOSE,
359
- )
360
-
361
- def _remove_implementation_details_from_model(self, model):
362
- if isinstance(model, dict):
363
- return self._remove_implementation_details_from_model_dict(model)
364
- elif isinstance(model, list):
365
- return self._remove_implementation_details_from_model_list(model)
366
- else:
367
- return model
368
-
369
- def _remove_implementation_details_from_model_dict(self, model):
370
- ret = {}
371
- for k, v in model.items():
372
- if not self.IMPLEMENTATION_DETAILS.match(k):
373
- new_value = self._remove_implementation_details_from_model(v)
374
- if new_value is not None and new_value != {} and new_value != []:
375
- ret[k] = new_value
376
- return ret
377
-
378
- def _remove_implementation_details_from_model_list(self, model):
379
- ret = []
380
- for v in model:
381
- new_value = self._remove_implementation_details_from_model(v)
382
- if new_value is not None and new_value != {} and new_value != []:
383
- ret.append(new_value)
384
- return ret
385
-
386
- def call_components(self, method_name, **kwargs):
387
- for component in self.components:
388
- if hasattr(component, method_name):
389
- getattr(component, method_name)(**kwargs)
390
-
391
- def _get_model_features(self, model):
392
- features = []
393
- if model.get("requests", {}):
394
- features.append("requests")
395
- if model.get("draft", {}):
396
- features.append("drafts")
397
- if model.get("files", {}):
398
- features.append("files")
399
- return features
400
-
401
- def _get_model_api_endpoint(self, model):
402
- try:
403
- alias = model["api-blueprint"]["alias"]
404
- return api_url_for(f"{alias}.search", _external=True)
405
- except: # NOSONAR noqa
406
- logger.exception("Failed to get model api endpoint")
407
- return None
408
-
409
- def _get_model_draft_endpoint(self, model):
410
- try:
411
- alias = model["api-blueprint"]["alias"]
412
- return api_url_for(f"{alias}.search_user_records", _external=True)
413
- except: # NOSONAR noqa
414
- logger.exception("Failed to get model draft endpoint")
415
- return None
416
-
417
- def _get_model_html_endpoint(self, model):
418
- try:
419
- return urljoin(
420
- self._get_model_api_endpoint(model),
421
- model["resource-config"]["base-html-url"],
422
- )
423
- except: # NOSONAR noqa
424
- logger.exception("Failed to get model html endpoint")
425
- return None
426
-
427
- def _get_model_model_endpoint(self, model):
428
- try:
429
- return url_for("oarepo_runtime_info.model", model=model, _external=True)
430
- except: # NOSONAR noqa
431
- logger.exception("Failed to get model model endpoint")
432
- return None
433
-
434
- def _get_model_schema_endpoints(self, model):
435
- try:
436
- return {
437
- "application/json": url_for(
438
- "oarepo_runtime_info.schema",
439
- schema=model["json-schema-settings"]["name"],
440
- _external=True,
441
- )
442
- }
443
- except: # NOSONAR noqa
444
- logger.exception("Failed to get model schema endpoint")
445
- return None
446
-
447
- def _get_model_content_types(self, service, resource_config, model):
448
- """Get the content types supported by the model. Returns a list of:
449
-
450
- content_type="application/json",
451
- name="Invenio RDM JSON",
452
- description="Invenio RDM JSON as described in",
453
- schema=url / "schemas" / "records" / "record-v6.0.0.json",
454
- can_export=True,
455
- can_deposit=True,
456
- """
457
-
458
- content_types = []
459
- # implicit content type
460
- content_types.append(
461
- {
462
- "content_type": "application/json",
463
- "name": f"Internal json serialization of {model['model-name']}",
464
- "description": "This content type is serving this model's native format as described on model link.",
465
- "schema": url_for(
466
- "oarepo_runtime_info.schema",
467
- schema=model["json-schema-settings"]["name"],
468
- _external=True,
469
- ),
470
- "can_export": True,
471
- "can_deposit": True,
472
- }
473
- )
474
-
475
- # export content types
476
- try:
477
- for accept_type, handler in resource_config.response_handlers.items():
478
- if accept_type == "application/json":
479
- continue
480
- curr_item = {
481
- "content_type": accept_type,
482
- "name": getattr(handler, "name", accept_type),
483
- "description": getattr(handler, "description", ""),
484
- "can_export": True,
485
- "can_deposit": False,
486
- }
487
- if handler.serializer is not None:
488
- if hasattr(handler.serializer, "name"):
489
- curr_item["name"] = handler.serializer.name
490
- if hasattr(handler.serializer, "description"):
491
- curr_item["description"] = handler.serializer.description
492
- if hasattr(handler.serializer, "info"):
493
- curr_item.update(handler.serializer.info(service))
494
- content_types.append(curr_item)
495
- except: # NOSONAR noqa
496
- logger.exception("Failed to get model schemas")
497
- return content_types
498
-
499
- def _get_resource_config_class(self, model_data):
500
- model_class = model_data["resource-config"]["class"]
501
- return obj_or_import_string(model_class)()
502
-
503
- def _get_service(self, model_data):
504
- service_id = model_data["service-config"]["service-id"]
505
- try:
506
- service = current_service_registry.get(service_id)
507
- except KeyError:
508
- return None
509
- return service
510
-
511
- def _get_service_class(self, model_data):
512
- service_id = model_data["service"]["class"]
513
- return obj_or_import_string(service_id)
514
-
515
-
516
- def create_wellknown_blueprint(app):
517
- """Create blueprint."""
518
- config_class = obj_or_import_string(
519
- app.config.get("INFO_ENDPOINT_CONFIG", InfoConfig)
520
- )
521
- return InfoResource(config=config_class(app)).as_blueprint()
522
-
523
-
524
- def get_package_version(package_name):
525
- """Get package version."""
526
- from pkg_resources import get_distribution
527
-
528
- try:
529
- return re.sub(r"\+.*", "", get_distribution(package_name).version)
530
- except Exception: # NOSONAR noqa
531
- logger.exception(f"Failed to get package version for {package_name}")
532
- return None
533
-
534
-
535
- def api_url_for(endpoint, _external=True, **values):
536
- """API url_for."""
537
- try:
538
- api_app = current_app.wsgi_app.mounts["/api"]
539
- except:
540
- api_app = current_app
541
-
542
- site_api_url = current_app.config["SITE_API_URL"]
543
- site_url = current_app.config["SITE_UI_URL"]
544
- current_request_context = _cv_request.get()
545
- try:
546
- new_context = RequestContext(app=api_app, environ=request.environ)
547
- _cv_request.set(new_context)
548
- base_url = api_app.url_for(endpoint, **values, _external=_external)
549
- if base_url.startswith(site_api_url):
550
- return base_url
551
- if base_url.startswith(site_url):
552
- return base_url.replace(site_url, site_api_url)
553
- raise ValueError(
554
- f"URL {base_url} does not start with {site_url} or {site_api_url}"
555
- )
556
- finally:
557
- _cv_request.set(current_request_context)
558
-
559
-
560
- def replace_path_in_url(url, path):
561
- # Parse the URL into its components
562
- parsed_url = urlparse(url)
563
-
564
- # Replace the path with '/api'
565
- new_parsed_url = parsed_url._replace(path=path)
566
-
567
- # Reconstruct the URL with the new path
568
- new_url = urlunparse(new_parsed_url)
569
-
570
- return new_url
571
-
572
-
573
- def _add_feature_if_can_import(feature, module):
574
- try:
575
- importlib.import_module(module)
576
- return [feature]
577
- except ImportError:
578
- return []
579
-
580
-
581
- def to_current_language(data):
582
- if isinstance(data, dict):
583
- from flask_babel import get_locale
584
-
585
- return data.get(get_locale().language)
586
- return data
oarepo_runtime/profile.py DELETED
@@ -1,60 +0,0 @@
1
- # profiling support
2
- import atexit
3
- import contextlib
4
- import functools
5
- import math
6
- import time
7
- from collections import Counter
8
-
9
-
10
- class ProfilingTimer:
11
- def __init__(self):
12
- self.counts = Counter()
13
- self.sums = Counter()
14
- self.sums_squared = Counter()
15
-
16
- def time(self, function):
17
- @functools.wraps(function)
18
- def inner(*args, **kwargs):
19
- start = time.time()
20
- try:
21
- return function(*args, **kwargs)
22
- finally:
23
- stop = time.time()
24
- self.register(function, start, stop)
25
-
26
- return inner
27
-
28
- def register(self, function, start, stop):
29
- self.counts[function] += 1
30
- duration = stop - start
31
- self.sums[function] += duration
32
- self.sums_squared[function] += duration * duration
33
-
34
- @contextlib.contextmanager
35
- def time_block(self, name):
36
- start = time.time()
37
- try:
38
- yield
39
- finally:
40
- stop = time.time()
41
- self.register(name, start, stop)
42
-
43
- def display(self):
44
- for f in self.counts:
45
- print(f)
46
- print(f"Call count : {self.counts[f]}")
47
- print(f"Total time : {self.sums[f]}")
48
- print(f"Avg time : {self.sums[f] / self.counts[f]}")
49
- std_deviation = (
50
- math.sqrt(
51
- self.counts[f] * self.sums_squared[f] - self.sums[f] * self.sums[f]
52
- )
53
- / self.counts[f]
54
- )
55
- print(f"Std deviation : {std_deviation}")
56
- print()
57
-
58
-
59
- timer = ProfilingTimer()
60
- atexit.register(timer.display)
@@ -1,8 +0,0 @@
1
- from invenio_records.dumpers import SearchDumper as InvenioSearchDumper
2
-
3
-
4
- class SearchDumper(InvenioSearchDumper):
5
- extensions = []
6
-
7
- def __init__(self, **kwargs):
8
- super().__init__(extensions=self.extensions, **kwargs)
@@ -1,38 +0,0 @@
1
- from invenio_records.dumpers import SearchDumperExt
2
- from sqlalchemy.util import classproperty
3
-
4
- from oarepo_runtime.utils.path import PathTraversal
5
-
6
-
7
- class EDTFIntervalDumperExt(SearchDumperExt):
8
- paths = []
9
- _path_traversal = None
10
-
11
- @classproperty
12
- def path_traversal(cls):
13
- if cls._path_traversal is None:
14
- cls._path_traversal = PathTraversal(cls.paths)
15
- return cls._path_traversal
16
-
17
- def dump(self, record, data):
18
- for path in self.path_traversal.iter(data):
19
- rec = path[-1].current
20
- rec = rec.split("/")
21
- search_range = {}
22
- if rec[0]:
23
- search_range["gte"] = rec[0].strip()
24
- if len(rec) > 1 and rec[1]:
25
- search_range["lte"] = rec[1].strip()
26
- path[-1].parent_data[path[-1].key] = search_range
27
- return data
28
-
29
- def load(self, data, record_cls):
30
- for path in self.path_traversal.iter(data):
31
- rec = path[-1].current
32
- if rec:
33
- path[-1].parent_data[
34
- path[-1].key
35
- ] = f"{rec.get('gte', '')}/{rec.get('lte', '')}"
36
- else:
37
- del path[-1].parent_data[path[-1].key]
38
- return data