invenio-vocabularies 9.1.2__py2.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.
- invenio_vocabularies/__init__.py +16 -0
- invenio_vocabularies/administration/__init__.py +10 -0
- invenio_vocabularies/administration/views/__init__.py +10 -0
- invenio_vocabularies/administration/views/vocabularies.py +43 -0
- invenio_vocabularies/alembic/17c703ce1eb7_create_names_table.py +54 -0
- invenio_vocabularies/alembic/3ba812d80559_add_internal_name_id.py +36 -0
- invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py +37 -0
- invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py +92 -0
- invenio_vocabularies/alembic/55a700f897b6_add_names_and_afiliations_pid_column.py +96 -0
- invenio_vocabularies/alembic/6312f33645c1_create_affiliations_table.py +54 -0
- invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py +58 -0
- invenio_vocabularies/alembic/8ff82dfb0be8_create_vocabularies_branch.py +28 -0
- invenio_vocabularies/alembic/__init__.py +9 -0
- invenio_vocabularies/alembic/af2457652217_drop_unique_constraint_from_internal_id.py +37 -0
- invenio_vocabularies/alembic/e1146238edd3_create_awards_table.py +56 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/.eslintrc.yml +11 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/.prettierrc +1 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/index.js +7 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/package.json +25 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/AwardResults.js +95 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/CustomAwardForm.js +139 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FunderDropdown.js +87 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingField.js +244 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingField.test.js +1 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingFieldItem.js +152 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingModal.js +246 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/NoAwardResults.js +37 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/index.js +8 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/index.js +7 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/index.js +7 -0
- invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/index.js +7 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/i18next.js +36 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/_generatedTranslations.js +66 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ar/messages.po +96 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ar/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/bg/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/bg/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ca/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ca/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/cs/messages.po +97 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/cs/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/da/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/da/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/de/messages.po +98 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/de/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/el/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/el/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/en/messages.po +88 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/en/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/es/messages.po +96 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/es/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/et/messages.po +95 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/et/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fa/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fa/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fr/messages.po +96 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fr/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hr/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hr/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hu/messages.po +96 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hu/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/index.js +24 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/it/messages.po +96 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/it/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ja/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ja/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ka/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ka/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ko/messages.po +90 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ko/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/lt/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/lt/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/no/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/no/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pl/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pl/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pt/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pt/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ro/messages.po +95 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ro/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ru/messages.po +95 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ru/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sk/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sk/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sv/messages.po +98 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sv/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/tr/messages.po +96 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/tr/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/uk/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/uk/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_CN/messages.po +96 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_CN/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_TW/messages.po +94 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_TW/translations.json +28 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/package.json +19 -0
- invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/translations.pot +88 -0
- invenio_vocabularies/cli.py +175 -0
- invenio_vocabularies/config.py +231 -0
- invenio_vocabularies/contrib/__init__.py +9 -0
- invenio_vocabularies/contrib/affiliations/__init__.py +20 -0
- invenio_vocabularies/contrib/affiliations/affiliations.py +61 -0
- invenio_vocabularies/contrib/affiliations/api.py +13 -0
- invenio_vocabularies/contrib/affiliations/config.py +79 -0
- invenio_vocabularies/contrib/affiliations/datastreams.py +301 -0
- invenio_vocabularies/contrib/affiliations/facets.py +36 -0
- invenio_vocabularies/contrib/affiliations/jsonschemas/__init__.py +9 -0
- invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json +63 -0
- invenio_vocabularies/contrib/affiliations/mappings/__init__.py +10 -0
- invenio_vocabularies/contrib/affiliations/mappings/os-v1/__init__.py +9 -0
- invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v1.0.0.json +112 -0
- invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v2.0.0.json +171 -0
- invenio_vocabularies/contrib/affiliations/mappings/os-v2/__init__.py +9 -0
- invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v1.0.0.json +112 -0
- invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v2.0.0.json +171 -0
- invenio_vocabularies/contrib/affiliations/mappings/v7/__init__.py +9 -0
- invenio_vocabularies/contrib/affiliations/mappings/v7/affiliations/affiliation-v1.0.0.json +112 -0
- invenio_vocabularies/contrib/affiliations/models.py +13 -0
- invenio_vocabularies/contrib/affiliations/resources.py +16 -0
- invenio_vocabularies/contrib/affiliations/schema.py +71 -0
- invenio_vocabularies/contrib/affiliations/services.py +15 -0
- invenio_vocabularies/contrib/awards/__init__.py +19 -0
- invenio_vocabularies/contrib/awards/api.py +13 -0
- invenio_vocabularies/contrib/awards/awards.py +96 -0
- invenio_vocabularies/contrib/awards/config.py +59 -0
- invenio_vocabularies/contrib/awards/datastreams.py +372 -0
- invenio_vocabularies/contrib/awards/jsonschemas/__init__.py +9 -0
- invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json +91 -0
- invenio_vocabularies/contrib/awards/mappings/__init__.py +9 -0
- invenio_vocabularies/contrib/awards/mappings/os-v1/__init__.py +9 -0
- invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json +147 -0
- invenio_vocabularies/contrib/awards/mappings/os-v2/__init__.py +9 -0
- invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json +147 -0
- invenio_vocabularies/contrib/awards/mappings/v7/__init__.py +9 -0
- invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json +147 -0
- invenio_vocabularies/contrib/awards/models.py +13 -0
- invenio_vocabularies/contrib/awards/resources.py +16 -0
- invenio_vocabularies/contrib/awards/schema.py +119 -0
- invenio_vocabularies/contrib/awards/serializer.py +47 -0
- invenio_vocabularies/contrib/awards/services.py +15 -0
- invenio_vocabularies/contrib/common/__init__.py +9 -0
- invenio_vocabularies/contrib/common/openaire/__init__.py +9 -0
- invenio_vocabularies/contrib/common/openaire/datastreams.py +84 -0
- invenio_vocabularies/contrib/common/ror/__init__.py +9 -0
- invenio_vocabularies/contrib/common/ror/datastreams.py +230 -0
- invenio_vocabularies/contrib/funders/__init__.py +19 -0
- invenio_vocabularies/contrib/funders/api.py +13 -0
- invenio_vocabularies/contrib/funders/config.py +78 -0
- invenio_vocabularies/contrib/funders/datastreams.py +97 -0
- invenio_vocabularies/contrib/funders/facets.py +36 -0
- invenio_vocabularies/contrib/funders/funders.py +72 -0
- invenio_vocabularies/contrib/funders/jsonschemas/__init__.py +9 -0
- invenio_vocabularies/contrib/funders/jsonschemas/funders/funder-v1.0.0.json +65 -0
- invenio_vocabularies/contrib/funders/mappings/__init__.py +9 -0
- invenio_vocabularies/contrib/funders/mappings/os-v1/__init__.py +9 -0
- invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v1.0.0.json +90 -0
- invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v2.0.0.json +156 -0
- invenio_vocabularies/contrib/funders/mappings/os-v2/__init__.py +9 -0
- invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v1.0.0.json +90 -0
- invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v2.0.0.json +156 -0
- invenio_vocabularies/contrib/funders/mappings/v7/__init__.py +9 -0
- invenio_vocabularies/contrib/funders/mappings/v7/funders/funder-v1.0.0.json +90 -0
- invenio_vocabularies/contrib/funders/models.py +13 -0
- invenio_vocabularies/contrib/funders/resources.py +16 -0
- invenio_vocabularies/contrib/funders/schema.py +88 -0
- invenio_vocabularies/contrib/funders/serializer.py +33 -0
- invenio_vocabularies/contrib/funders/services.py +15 -0
- invenio_vocabularies/contrib/names/__init__.py +19 -0
- invenio_vocabularies/contrib/names/api.py +13 -0
- invenio_vocabularies/contrib/names/components.py +24 -0
- invenio_vocabularies/contrib/names/config.py +75 -0
- invenio_vocabularies/contrib/names/datastreams.py +483 -0
- invenio_vocabularies/contrib/names/jsonschemas/__init__.py +9 -0
- invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json +68 -0
- invenio_vocabularies/contrib/names/mappings/__init__.py +9 -0
- invenio_vocabularies/contrib/names/mappings/os-v1/__init__.py +9 -0
- invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v1.0.0.json +101 -0
- invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v2.0.0.json +165 -0
- invenio_vocabularies/contrib/names/mappings/os-v2/__init__.py +9 -0
- invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v1.0.0.json +101 -0
- invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v2.0.0.json +165 -0
- invenio_vocabularies/contrib/names/mappings/v7/__init__.py +9 -0
- invenio_vocabularies/contrib/names/mappings/v7/names/name-v1.0.0.json +101 -0
- invenio_vocabularies/contrib/names/models.py +13 -0
- invenio_vocabularies/contrib/names/names.py +80 -0
- invenio_vocabularies/contrib/names/permissions.py +30 -0
- invenio_vocabularies/contrib/names/resources.py +54 -0
- invenio_vocabularies/contrib/names/s3client.py +50 -0
- invenio_vocabularies/contrib/names/schema.py +121 -0
- invenio_vocabularies/contrib/names/services.py +64 -0
- invenio_vocabularies/contrib/subjects/__init__.py +22 -0
- invenio_vocabularies/contrib/subjects/api.py +14 -0
- invenio_vocabularies/contrib/subjects/config.py +90 -0
- invenio_vocabularies/contrib/subjects/datastreams.py +63 -0
- invenio_vocabularies/contrib/subjects/euroscivoc/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/euroscivoc/datastreams.py +101 -0
- invenio_vocabularies/contrib/subjects/facets.py +23 -0
- invenio_vocabularies/contrib/subjects/gemet/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/gemet/datastreams.py +140 -0
- invenio_vocabularies/contrib/subjects/jsonschemas/__init__.py +10 -0
- invenio_vocabularies/contrib/subjects/jsonschemas/subjects/subject-v1.0.0.json +69 -0
- invenio_vocabularies/contrib/subjects/mappings/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/mappings/os-v1/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/mappings/os-v1/subjects/subject-v1.0.0.json +96 -0
- invenio_vocabularies/contrib/subjects/mappings/os-v2/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/mappings/os-v2/subjects/subject-v1.0.0.json +96 -0
- invenio_vocabularies/contrib/subjects/mappings/v7/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/mappings/v7/subjects/subject-v1.0.0.json +96 -0
- invenio_vocabularies/contrib/subjects/mesh/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/mesh/datastreams.py +48 -0
- invenio_vocabularies/contrib/subjects/models.py +14 -0
- invenio_vocabularies/contrib/subjects/nvs/__init__.py +9 -0
- invenio_vocabularies/contrib/subjects/nvs/datastreams.py +114 -0
- invenio_vocabularies/contrib/subjects/resources.py +17 -0
- invenio_vocabularies/contrib/subjects/schema.py +101 -0
- invenio_vocabularies/contrib/subjects/services.py +30 -0
- invenio_vocabularies/contrib/subjects/subjects.py +55 -0
- invenio_vocabularies/datastreams/__init__.py +18 -0
- invenio_vocabularies/datastreams/datastreams.py +239 -0
- invenio_vocabularies/datastreams/errors.py +29 -0
- invenio_vocabularies/datastreams/factories.py +86 -0
- invenio_vocabularies/datastreams/readers.py +448 -0
- invenio_vocabularies/datastreams/tasks.py +115 -0
- invenio_vocabularies/datastreams/transformers.py +130 -0
- invenio_vocabularies/datastreams/writers.py +222 -0
- invenio_vocabularies/datastreams/xml.py +34 -0
- invenio_vocabularies/ext.py +179 -0
- invenio_vocabularies/factories.py +193 -0
- invenio_vocabularies/fixtures.py +52 -0
- invenio_vocabularies/jobs.py +207 -0
- invenio_vocabularies/proxies.py +27 -0
- invenio_vocabularies/records/__init__.py +9 -0
- invenio_vocabularies/records/api.py +53 -0
- invenio_vocabularies/records/jsonschemas/__init__.py +9 -0
- invenio_vocabularies/records/jsonschemas/vocabularies/definitions-v1.0.0.json +30 -0
- invenio_vocabularies/records/jsonschemas/vocabularies/vocabulary-v1.0.0.json +55 -0
- invenio_vocabularies/records/mappings/__init__.py +9 -0
- invenio_vocabularies/records/mappings/os-v1/__init__.py +9 -0
- invenio_vocabularies/records/mappings/os-v1/vocabularies/vocabulary-v1.0.0.json +109 -0
- invenio_vocabularies/records/mappings/os-v2/__init__.py +9 -0
- invenio_vocabularies/records/mappings/os-v2/vocabularies/vocabulary-v1.0.0.json +109 -0
- invenio_vocabularies/records/mappings/v7/__init__.py +9 -0
- invenio_vocabularies/records/mappings/v7/vocabularies/vocabulary-v1.0.0.json +109 -0
- invenio_vocabularies/records/models.py +90 -0
- invenio_vocabularies/records/pidprovider.py +118 -0
- invenio_vocabularies/records/systemfields/__init__.py +16 -0
- invenio_vocabularies/records/systemfields/pid.py +125 -0
- invenio_vocabularies/records/systemfields/relations.py +51 -0
- invenio_vocabularies/resources/__init__.py +23 -0
- invenio_vocabularies/resources/config.py +105 -0
- invenio_vocabularies/resources/resource.py +156 -0
- invenio_vocabularies/resources/schema.py +21 -0
- invenio_vocabularies/resources/serializer.py +39 -0
- invenio_vocabularies/services/__init__.py +19 -0
- invenio_vocabularies/services/components.py +58 -0
- invenio_vocabularies/services/config.py +173 -0
- invenio_vocabularies/services/custom_fields/__init__.py +17 -0
- invenio_vocabularies/services/custom_fields/subject.py +82 -0
- invenio_vocabularies/services/custom_fields/vocabulary.py +96 -0
- invenio_vocabularies/services/facets.py +114 -0
- invenio_vocabularies/services/generators.py +38 -0
- invenio_vocabularies/services/permissions.py +30 -0
- invenio_vocabularies/services/querystr.py +57 -0
- invenio_vocabularies/services/results.py +110 -0
- invenio_vocabularies/services/schema.py +163 -0
- invenio_vocabularies/services/service.py +189 -0
- invenio_vocabularies/services/tasks.py +38 -0
- invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/subjects.html +23 -0
- invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabularies-list.html +12 -0
- invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabulary-details.html +71 -0
- invenio_vocabularies/translations/ar/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/ar/LC_MESSAGES/messages.po +277 -0
- invenio_vocabularies/translations/bg/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/bg/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/ca/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/ca/LC_MESSAGES/messages.po +276 -0
- invenio_vocabularies/translations/cs/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/cs/LC_MESSAGES/messages.po +281 -0
- invenio_vocabularies/translations/da/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/da/LC_MESSAGES/messages.po +271 -0
- invenio_vocabularies/translations/de/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/de/LC_MESSAGES/messages.po +293 -0
- invenio_vocabularies/translations/el/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/el/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/es/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/es/LC_MESSAGES/messages.po +281 -0
- invenio_vocabularies/translations/et/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/et/LC_MESSAGES/messages.po +276 -0
- invenio_vocabularies/translations/fa/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/fa/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/fr/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/fr/LC_MESSAGES/messages.po +279 -0
- invenio_vocabularies/translations/hr/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/hr/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/hu/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/hu/LC_MESSAGES/messages.po +280 -0
- invenio_vocabularies/translations/it/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/it/LC_MESSAGES/messages.po +277 -0
- invenio_vocabularies/translations/ja/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/ja/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/ka/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/ka/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/ko/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/ko/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/lt/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/lt/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/messages.pot +270 -0
- invenio_vocabularies/translations/no/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/no/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/pl/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/pl/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/pt/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/pt/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/ro/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/ro/LC_MESSAGES/messages.po +280 -0
- invenio_vocabularies/translations/ru/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/ru/LC_MESSAGES/messages.po +276 -0
- invenio_vocabularies/translations/sk/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/sk/LC_MESSAGES/messages.po +276 -0
- invenio_vocabularies/translations/sv/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/sv/LC_MESSAGES/messages.po +280 -0
- invenio_vocabularies/translations/tr/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/tr/LC_MESSAGES/messages.po +277 -0
- invenio_vocabularies/translations/uk/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/uk/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.po +276 -0
- invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.mo +0 -0
- invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.po +275 -0
- invenio_vocabularies/views.py +53 -0
- invenio_vocabularies/webpack.py +51 -0
- invenio_vocabularies-9.1.2.dist-info/METADATA +517 -0
- invenio_vocabularies-9.1.2.dist-info/RECORD +337 -0
- invenio_vocabularies-9.1.2.dist-info/WHEEL +6 -0
- invenio_vocabularies-9.1.2.dist-info/entry_points.txt +73 -0
- invenio_vocabularies-9.1.2.dist-info/licenses/AUTHORS.rst +13 -0
- invenio_vocabularies-9.1.2.dist-info/licenses/LICENSE +21 -0
- invenio_vocabularies-9.1.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2021-2024 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Vocabularies is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the MIT License; see LICENSE file for more
|
|
7
|
+
# details.
|
|
8
|
+
|
|
9
|
+
"""Transformers module."""
|
|
10
|
+
|
|
11
|
+
from abc import ABC, abstractmethod
|
|
12
|
+
from urllib.parse import urlparse
|
|
13
|
+
|
|
14
|
+
from lxml import etree
|
|
15
|
+
|
|
16
|
+
from .errors import TransformerError
|
|
17
|
+
from .xml import etree_to_dict
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import rdflib
|
|
21
|
+
except ImportError:
|
|
22
|
+
rdflib = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class BaseTransformer(ABC):
|
|
26
|
+
"""Base transformer."""
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def apply(self, stream_entry, *args, **kwargs):
|
|
30
|
+
"""Applies the transformation to the entry.
|
|
31
|
+
|
|
32
|
+
:returns: A StreamEntry. The transformed entry.
|
|
33
|
+
Raises TransformerError in case of errors.
|
|
34
|
+
"""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class XMLTransformer(BaseTransformer):
|
|
39
|
+
"""XML transformer."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, root_element=None, *args, **kwargs):
|
|
42
|
+
"""Initializes the transformer."""
|
|
43
|
+
self.root_element = root_element
|
|
44
|
+
super().__init__(*args, **kwargs)
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def _xml_to_etree(cls, xml):
|
|
48
|
+
"""Converts XML to a lxml etree."""
|
|
49
|
+
return etree.HTML(xml)
|
|
50
|
+
|
|
51
|
+
def apply(self, stream_entry, **kwargs):
|
|
52
|
+
"""Applies the transformation to the stream entry.
|
|
53
|
+
|
|
54
|
+
Requires the root element to be named "record".
|
|
55
|
+
"""
|
|
56
|
+
xml_tree = self._xml_to_etree(stream_entry.entry)
|
|
57
|
+
xml_dict = etree_to_dict(xml_tree)["html"]["body"]
|
|
58
|
+
|
|
59
|
+
if self.root_element:
|
|
60
|
+
record = xml_dict.get(self.root_element)
|
|
61
|
+
if not record:
|
|
62
|
+
raise TransformerError(
|
|
63
|
+
f"Root element '{self.root_element}' not found in XML entry."
|
|
64
|
+
)
|
|
65
|
+
else:
|
|
66
|
+
record = xml_dict
|
|
67
|
+
|
|
68
|
+
stream_entry.entry = record
|
|
69
|
+
return stream_entry
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class RDFTransformer(BaseTransformer):
|
|
73
|
+
"""Base Transformer class for RDF data to dictionary format."""
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def skos_core(self):
|
|
77
|
+
"""Get the SKOS core namespace."""
|
|
78
|
+
return rdflib.Namespace("http://www.w3.org/2004/02/skos/core#")
|
|
79
|
+
|
|
80
|
+
def _validate_subject_url(self, subject):
|
|
81
|
+
"""Check if the subject is a valid URL."""
|
|
82
|
+
parsed = urlparse(str(subject))
|
|
83
|
+
return bool(parsed.netloc and parsed.scheme)
|
|
84
|
+
|
|
85
|
+
def _get_identifiers(self, subject):
|
|
86
|
+
"""Generate identifiers field for a valid subject URL."""
|
|
87
|
+
if self._validate_subject_url(subject):
|
|
88
|
+
return [{"scheme": "url", "identifier": str(subject)}]
|
|
89
|
+
return []
|
|
90
|
+
|
|
91
|
+
def _get_labels(self, subject, rdf_graph):
|
|
92
|
+
"""Extract labels (prefLabel or altLabel) for a subject."""
|
|
93
|
+
labels = {
|
|
94
|
+
label.language: label.value.capitalize()
|
|
95
|
+
for _, _, label in rdf_graph.triples(
|
|
96
|
+
(subject, self.skos_core.prefLabel, None)
|
|
97
|
+
)
|
|
98
|
+
if label.language and "-" not in label.language
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if "en" not in labels:
|
|
102
|
+
for _, _, label in rdf_graph.triples(
|
|
103
|
+
(subject, self.skos_core.altLabel, None)
|
|
104
|
+
):
|
|
105
|
+
labels.setdefault(label.language, label.value.capitalize())
|
|
106
|
+
|
|
107
|
+
return labels
|
|
108
|
+
|
|
109
|
+
def _find_parents(self, subject, rdf_graph):
|
|
110
|
+
"""Find parent notations."""
|
|
111
|
+
return [
|
|
112
|
+
self._get_parent_notation(broader, rdf_graph)
|
|
113
|
+
for broader in rdf_graph.transitive_objects(subject, self.skos_core.broader)
|
|
114
|
+
if broader != subject
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
def _get_parent_notation(self, broader, rdf_graph):
|
|
118
|
+
"""Extract notation for a parent."""
|
|
119
|
+
raise NotImplementedError("This method should be implemented in a subclass.")
|
|
120
|
+
|
|
121
|
+
def _transform_entry(self, subject, rdf_graph):
|
|
122
|
+
"""Transform an RDF subject entry into the desired dictionary format."""
|
|
123
|
+
raise NotImplementedError("This method should be implemented in a subclass.")
|
|
124
|
+
|
|
125
|
+
def apply(self, stream_entry, *args, **kwargs):
|
|
126
|
+
"""Apply transformation to a stream entry."""
|
|
127
|
+
stream_entry.entry = self._transform_entry(
|
|
128
|
+
stream_entry.entry["subject"], stream_entry.entry["rdf_graph"]
|
|
129
|
+
)
|
|
130
|
+
return stream_entry
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2021-2024 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Vocabularies is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the MIT License; see LICENSE file for more
|
|
7
|
+
# details.
|
|
8
|
+
|
|
9
|
+
"""Writers module."""
|
|
10
|
+
|
|
11
|
+
from abc import ABC, abstractmethod
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import yaml
|
|
15
|
+
from flask import current_app
|
|
16
|
+
from invenio_access.permissions import system_identity
|
|
17
|
+
from invenio_pidstore.errors import PIDAlreadyExists, PIDDoesNotExistError
|
|
18
|
+
from invenio_records.systemfields.relations.errors import InvalidRelationValue
|
|
19
|
+
from invenio_records_resources.proxies import current_service_registry
|
|
20
|
+
from marshmallow import ValidationError
|
|
21
|
+
from sqlalchemy.exc import NoResultFound
|
|
22
|
+
|
|
23
|
+
from .datastreams import StreamEntry
|
|
24
|
+
from .errors import WriterError
|
|
25
|
+
from .tasks import write_entry, write_many_entry
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class BaseWriter(ABC):
|
|
29
|
+
"""Base writer."""
|
|
30
|
+
|
|
31
|
+
is_async = False
|
|
32
|
+
|
|
33
|
+
def __init__(self, *args, **kwargs):
|
|
34
|
+
"""Base initialization logic."""
|
|
35
|
+
# Add any base initialization here if needed
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def write(self, stream_entry, *args, **kwargs):
|
|
40
|
+
"""Writes the input stream entry to the target output.
|
|
41
|
+
|
|
42
|
+
:returns: A StreamEntry. The result of writing the entry.
|
|
43
|
+
Raises WriterException in case of errors.
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def write_many(self, stream_entries, *args, **kwargs):
|
|
50
|
+
"""Writes the input streams entry to the target output.
|
|
51
|
+
|
|
52
|
+
:returns: A List of StreamEntry. The result of writing the entry.
|
|
53
|
+
Raises WriterException in case of errors.
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ServiceWriter(BaseWriter):
|
|
60
|
+
"""Writes the entries to an RDM instance using a Service object."""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self, service_or_name, *args, identity=None, insert=True, update=False, **kwargs
|
|
64
|
+
):
|
|
65
|
+
"""Constructor.
|
|
66
|
+
|
|
67
|
+
:param service_or_name: a service instance or a key of the
|
|
68
|
+
service registry.
|
|
69
|
+
:param identity: access identity.
|
|
70
|
+
:param insert: if True it will insert records which do not exist.
|
|
71
|
+
:param update: if True it will update records if they exist.
|
|
72
|
+
"""
|
|
73
|
+
if isinstance(service_or_name, str):
|
|
74
|
+
service_or_name = current_service_registry.get(service_or_name)
|
|
75
|
+
|
|
76
|
+
self._service = service_or_name
|
|
77
|
+
self._identity = identity or system_identity
|
|
78
|
+
self._insert = insert
|
|
79
|
+
self._update = update
|
|
80
|
+
|
|
81
|
+
super().__init__(*args, **kwargs)
|
|
82
|
+
|
|
83
|
+
def _entry_id(self, entry):
|
|
84
|
+
"""Get the id from an entry."""
|
|
85
|
+
return (entry["type"], entry["id"])
|
|
86
|
+
|
|
87
|
+
def _resolve(self, id_):
|
|
88
|
+
return self._service.read(self._identity, id_)
|
|
89
|
+
|
|
90
|
+
def _do_update(self, entry):
|
|
91
|
+
vocab_id = self._entry_id(entry)
|
|
92
|
+
current_app.logger.debug(f"Resolving entry with ID: {vocab_id}")
|
|
93
|
+
current = self._resolve(vocab_id)
|
|
94
|
+
updated = dict(current.to_dict(), **entry)
|
|
95
|
+
current_app.logger.debug(f"Updating entry with ID: {vocab_id}")
|
|
96
|
+
return StreamEntry(
|
|
97
|
+
self._service.update(self._identity, vocab_id, updated), op_type="update"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def write(self, stream_entry, *args, **kwargs):
|
|
101
|
+
"""Writes the input entry using a given service."""
|
|
102
|
+
entry = stream_entry.entry
|
|
103
|
+
current_app.logger.debug(f"Writing entry: {entry}")
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
if self._insert:
|
|
107
|
+
try:
|
|
108
|
+
current_app.logger.debug("Inserting entry.")
|
|
109
|
+
return StreamEntry(
|
|
110
|
+
self._service.create(self._identity, entry), op_type="create"
|
|
111
|
+
)
|
|
112
|
+
except PIDAlreadyExists:
|
|
113
|
+
if not self._update:
|
|
114
|
+
raise WriterError([f"Vocabulary entry already exists: {entry}"])
|
|
115
|
+
return self._do_update(entry)
|
|
116
|
+
elif self._update:
|
|
117
|
+
try:
|
|
118
|
+
current_app.logger.debug("Attempting to update entry.")
|
|
119
|
+
return self._do_update(entry)
|
|
120
|
+
except (NoResultFound, PIDDoesNotExistError):
|
|
121
|
+
raise WriterError([f"Vocabulary entry does not exist: {entry}"])
|
|
122
|
+
else:
|
|
123
|
+
raise WriterError(
|
|
124
|
+
["Writer wrongly configured to not insert and to not update"]
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
except ValidationError as err:
|
|
128
|
+
raise WriterError([{"ValidationError": err.messages}])
|
|
129
|
+
except InvalidRelationValue as err:
|
|
130
|
+
# TODO: Check if we can get the error message easier
|
|
131
|
+
raise WriterError([{"InvalidRelationValue": err.args[0]}])
|
|
132
|
+
|
|
133
|
+
def write_many(self, stream_entries, *args, **kwargs):
|
|
134
|
+
"""Writes the input entries using a given service."""
|
|
135
|
+
current_app.logger.info(f"Writing {len(stream_entries)} entries")
|
|
136
|
+
entries = [entry.entry for entry in stream_entries]
|
|
137
|
+
entries_with_id = [(self._entry_id(entry), entry) for entry in entries]
|
|
138
|
+
result_list = self._service.create_or_update_many(
|
|
139
|
+
self._identity, entries_with_id
|
|
140
|
+
)
|
|
141
|
+
stream_entries_processed = []
|
|
142
|
+
for entry, result in zip(entries, result_list.results):
|
|
143
|
+
processed_stream_entry = StreamEntry(
|
|
144
|
+
entry=entry,
|
|
145
|
+
record=result.record,
|
|
146
|
+
errors=result.errors,
|
|
147
|
+
op_type=result.op_type,
|
|
148
|
+
exc=result.exc,
|
|
149
|
+
)
|
|
150
|
+
processed_stream_entry.log_errors()
|
|
151
|
+
stream_entries_processed.append(processed_stream_entry)
|
|
152
|
+
|
|
153
|
+
current_app.logger.debug(f"Finished writing {len(stream_entries)} entries")
|
|
154
|
+
return stream_entries_processed
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class YamlWriter(BaseWriter):
|
|
158
|
+
"""Writes the entries to a YAML file."""
|
|
159
|
+
|
|
160
|
+
def __init__(self, filepath, *args, **kwargs):
|
|
161
|
+
"""Constructor.
|
|
162
|
+
|
|
163
|
+
:param filepath: path of the output file.
|
|
164
|
+
"""
|
|
165
|
+
self._filepath = Path(filepath)
|
|
166
|
+
|
|
167
|
+
super().__init__(*args, **kwargs)
|
|
168
|
+
|
|
169
|
+
def write(self, stream_entry, *args, **kwargs):
|
|
170
|
+
"""Writes the input stream entry using a given service."""
|
|
171
|
+
with open(self._filepath, "a") as file:
|
|
172
|
+
# made into array for safer append
|
|
173
|
+
# will always read array (good for reader)
|
|
174
|
+
yaml.safe_dump([stream_entry.entry], file, allow_unicode=True)
|
|
175
|
+
|
|
176
|
+
return stream_entry
|
|
177
|
+
|
|
178
|
+
def write_many(self, stream_entries, *args, **kwargs):
|
|
179
|
+
"""Writes the yaml input entries."""
|
|
180
|
+
with open(self._filepath, "a") as file:
|
|
181
|
+
yaml.safe_dump(
|
|
182
|
+
[stream_entry.entry for stream_entry in stream_entries],
|
|
183
|
+
file,
|
|
184
|
+
allow_unicode=True,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class AsyncWriter(BaseWriter):
|
|
189
|
+
"""Writes the entries asynchronously (celery task)."""
|
|
190
|
+
|
|
191
|
+
is_async = True
|
|
192
|
+
|
|
193
|
+
def __init__(self, writer, *args, **kwargs):
|
|
194
|
+
"""Constructor.
|
|
195
|
+
|
|
196
|
+
:param writer: writer to use.
|
|
197
|
+
"""
|
|
198
|
+
super().__init__(*args, **kwargs)
|
|
199
|
+
self._writer = writer
|
|
200
|
+
|
|
201
|
+
def write(self, stream_entry, subtask_run_id=None, *args, **kwargs):
|
|
202
|
+
"""Launches a celery task to write an entry with a delay."""
|
|
203
|
+
# Add some delay to avoid processing the tasks too fast
|
|
204
|
+
write_entry.apply_async(
|
|
205
|
+
args=(self._writer, stream_entry.entry, subtask_run_id), countdown=1
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
return stream_entry
|
|
209
|
+
|
|
210
|
+
def write_many(self, stream_entries, subtask_run_id=None, *args, **kwargs):
|
|
211
|
+
"""Launches a celery task to write entries with a delay."""
|
|
212
|
+
# Add some delay to avoid processing the tasks too fast
|
|
213
|
+
write_many_entry.apply_async(
|
|
214
|
+
args=(
|
|
215
|
+
self._writer,
|
|
216
|
+
[stream_entry.entry for stream_entry in stream_entries],
|
|
217
|
+
subtask_run_id,
|
|
218
|
+
),
|
|
219
|
+
countdown=1,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return stream_entries
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2021-2024 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Vocabularies is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the MIT License; see LICENSE file for more
|
|
7
|
+
# details.
|
|
8
|
+
|
|
9
|
+
"""XML utils."""
|
|
10
|
+
|
|
11
|
+
from collections import defaultdict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def etree_to_dict(tree):
|
|
15
|
+
"""Convert an ElementTree to a dictionary."""
|
|
16
|
+
tag = tree.tag.split(":")[-1] # strip namespace
|
|
17
|
+
d = {tag: {} if tree.attrib else None}
|
|
18
|
+
children = list(tree)
|
|
19
|
+
if children:
|
|
20
|
+
dd = defaultdict(list)
|
|
21
|
+
for dc in map(etree_to_dict, children):
|
|
22
|
+
for k, v in dc.items():
|
|
23
|
+
dd[k].append(v)
|
|
24
|
+
d = {tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}}
|
|
25
|
+
if tree.attrib:
|
|
26
|
+
d[tag].update(("@" + k, v) for k, v in tree.attrib.items())
|
|
27
|
+
if tree.text:
|
|
28
|
+
text = tree.text.strip()
|
|
29
|
+
if children or tree.attrib:
|
|
30
|
+
if text:
|
|
31
|
+
d[tag]["#text"] = text
|
|
32
|
+
else:
|
|
33
|
+
d[tag] = text
|
|
34
|
+
return d
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2020-2024 CERN.
|
|
4
|
+
# Copyright (C) 2023 Graz University of Technology.
|
|
5
|
+
#
|
|
6
|
+
# Invenio-Vocabularies is free software; you can redistribute it and/or
|
|
7
|
+
# modify it under the terms of the MIT License; see LICENSE file for more
|
|
8
|
+
# details.
|
|
9
|
+
|
|
10
|
+
"""Invenio module for managing vocabularies."""
|
|
11
|
+
|
|
12
|
+
from . import config
|
|
13
|
+
from .contrib.affiliations import (
|
|
14
|
+
AffiliationsResource,
|
|
15
|
+
AffiliationsResourceConfig,
|
|
16
|
+
AffiliationsService,
|
|
17
|
+
AffiliationsServiceConfig,
|
|
18
|
+
)
|
|
19
|
+
from .contrib.awards import (
|
|
20
|
+
AwardsResource,
|
|
21
|
+
AwardsResourceConfig,
|
|
22
|
+
AwardsService,
|
|
23
|
+
AwardsServiceConfig,
|
|
24
|
+
)
|
|
25
|
+
from .contrib.funders import (
|
|
26
|
+
FundersResource,
|
|
27
|
+
FundersResourceConfig,
|
|
28
|
+
FundersService,
|
|
29
|
+
FundersServiceConfig,
|
|
30
|
+
)
|
|
31
|
+
from .contrib.names import (
|
|
32
|
+
NamesResource,
|
|
33
|
+
NamesResourceConfig,
|
|
34
|
+
NamesService,
|
|
35
|
+
NamesServiceConfig,
|
|
36
|
+
)
|
|
37
|
+
from .contrib.subjects import (
|
|
38
|
+
SubjectsResource,
|
|
39
|
+
SubjectsResourceConfig,
|
|
40
|
+
SubjectsService,
|
|
41
|
+
SubjectsServiceConfig,
|
|
42
|
+
)
|
|
43
|
+
from .resources import (
|
|
44
|
+
VocabulariesAdminResource,
|
|
45
|
+
VocabulariesResource,
|
|
46
|
+
VocabulariesResourceConfig,
|
|
47
|
+
VocabularyTypeResourceConfig,
|
|
48
|
+
)
|
|
49
|
+
from .services.config import VocabularyTypesServiceConfig
|
|
50
|
+
from .services.service import VocabulariesService, VocabularyTypeService
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class InvenioVocabularies(object):
|
|
54
|
+
"""Invenio-Vocabularies extension."""
|
|
55
|
+
|
|
56
|
+
def __init__(self, app=None):
|
|
57
|
+
"""Extension initialization."""
|
|
58
|
+
self.resource = None
|
|
59
|
+
self.service = None
|
|
60
|
+
if app:
|
|
61
|
+
self.init_app(app)
|
|
62
|
+
|
|
63
|
+
def init_app(self, app):
|
|
64
|
+
"""Flask application initialization."""
|
|
65
|
+
self.init_config(app)
|
|
66
|
+
self.init_services(app)
|
|
67
|
+
self.init_resource(app)
|
|
68
|
+
app.extensions["invenio-vocabularies"] = self
|
|
69
|
+
|
|
70
|
+
def init_config(self, app):
|
|
71
|
+
"""Initialize configuration."""
|
|
72
|
+
for k in dir(config):
|
|
73
|
+
if k.startswith("VOCABULARIES_"):
|
|
74
|
+
app.config.setdefault(k, getattr(config, k))
|
|
75
|
+
|
|
76
|
+
def service_configs(self, app):
|
|
77
|
+
"""Customized service configs."""
|
|
78
|
+
|
|
79
|
+
class ServiceConfigs:
|
|
80
|
+
affiliations = AffiliationsServiceConfig
|
|
81
|
+
awards = AwardsServiceConfig
|
|
82
|
+
funders = FundersServiceConfig
|
|
83
|
+
names = NamesServiceConfig
|
|
84
|
+
subjects = SubjectsServiceConfig
|
|
85
|
+
vocabulary_types = VocabularyTypesServiceConfig
|
|
86
|
+
|
|
87
|
+
return ServiceConfigs
|
|
88
|
+
|
|
89
|
+
def init_services(self, app):
|
|
90
|
+
"""Initialize vocabulary resources."""
|
|
91
|
+
service_configs = self.service_configs(app)
|
|
92
|
+
|
|
93
|
+
# Services
|
|
94
|
+
self.affiliations_service = AffiliationsService(
|
|
95
|
+
config=service_configs.affiliations,
|
|
96
|
+
)
|
|
97
|
+
self.awards_service = AwardsService(
|
|
98
|
+
config=service_configs.awards,
|
|
99
|
+
)
|
|
100
|
+
self.funders_service = FundersService(config=service_configs.funders)
|
|
101
|
+
self.names_service = NamesService(config=service_configs.names)
|
|
102
|
+
self.subjects_service = SubjectsService(config=service_configs.subjects)
|
|
103
|
+
self.vocabularies_service = VocabulariesService(
|
|
104
|
+
config=app.config["VOCABULARIES_SERVICE_CONFIG"],
|
|
105
|
+
)
|
|
106
|
+
self.vocabulary_types_service = VocabularyTypeService(
|
|
107
|
+
config=service_configs.vocabulary_types
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def init_resource(self, app):
|
|
111
|
+
"""Initialize vocabulary resources."""
|
|
112
|
+
# Generic Vocabularies
|
|
113
|
+
self.affiliations_resource = AffiliationsResource(
|
|
114
|
+
service=self.affiliations_service,
|
|
115
|
+
config=AffiliationsResourceConfig,
|
|
116
|
+
)
|
|
117
|
+
self.funders_resource = FundersResource(
|
|
118
|
+
service=self.funders_service,
|
|
119
|
+
config=FundersResourceConfig,
|
|
120
|
+
)
|
|
121
|
+
self.names_resource = NamesResource(
|
|
122
|
+
service=self.names_service,
|
|
123
|
+
config=NamesResourceConfig,
|
|
124
|
+
)
|
|
125
|
+
self.awards_resource = AwardsResource(
|
|
126
|
+
service=self.awards_service,
|
|
127
|
+
config=AwardsResourceConfig,
|
|
128
|
+
)
|
|
129
|
+
self.subjects_resource = SubjectsResource(
|
|
130
|
+
service=self.subjects_service,
|
|
131
|
+
config=SubjectsResourceConfig,
|
|
132
|
+
)
|
|
133
|
+
self.resource = VocabulariesResource(
|
|
134
|
+
service=self.vocabularies_service,
|
|
135
|
+
config=app.config["VOCABULARIES_RESOURCE_CONFIG"],
|
|
136
|
+
)
|
|
137
|
+
self.vocabulary_admin_resource = VocabulariesAdminResource(
|
|
138
|
+
service=self.vocabulary_types_service,
|
|
139
|
+
config=VocabularyTypeResourceConfig,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def finalize_app(app):
|
|
144
|
+
"""Finalize app.
|
|
145
|
+
|
|
146
|
+
NOTE: replace former @record_once decorator
|
|
147
|
+
"""
|
|
148
|
+
init(app)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def api_finalize_app(app):
|
|
152
|
+
"""Api Finalize app.
|
|
153
|
+
|
|
154
|
+
NOTE: replace former @record_once decorator
|
|
155
|
+
"""
|
|
156
|
+
init(app)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def init(app):
|
|
160
|
+
"""Init app."""
|
|
161
|
+
# Register services - cannot be done in extension because
|
|
162
|
+
# Invenio-Records-Resources might not have been initialized.
|
|
163
|
+
sregistry = app.extensions["invenio-records-resources"].registry
|
|
164
|
+
ext = app.extensions["invenio-vocabularies"]
|
|
165
|
+
sregistry.register(ext.affiliations_service, service_id="affiliations")
|
|
166
|
+
sregistry.register(ext.awards_service, service_id="awards")
|
|
167
|
+
sregistry.register(ext.funders_service, service_id="funders")
|
|
168
|
+
sregistry.register(ext.names_service, service_id="names")
|
|
169
|
+
sregistry.register(ext.subjects_service, service_id="subjects")
|
|
170
|
+
sregistry.register(ext.vocabularies_service, service_id="vocabularies")
|
|
171
|
+
sregistry.register(ext.vocabulary_types_service, service_id="vocabulary-types")
|
|
172
|
+
# Register indexers
|
|
173
|
+
iregistry = app.extensions["invenio-indexer"].registry
|
|
174
|
+
iregistry.register(ext.affiliations_service.indexer, indexer_id="affiliations")
|
|
175
|
+
iregistry.register(ext.awards_service.indexer, indexer_id="awards")
|
|
176
|
+
iregistry.register(ext.funders_service.indexer, indexer_id="funders")
|
|
177
|
+
iregistry.register(ext.names_service.indexer, indexer_id="names")
|
|
178
|
+
iregistry.register(ext.subjects_service.indexer, indexer_id="subjects")
|
|
179
|
+
iregistry.register(ext.vocabularies_service.indexer, indexer_id="vocabularies")
|