invenio-vocabularies 1.6.0__py2.py3-none-any.whl → 2.0.0__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.

Potentially problematic release.


This version of invenio-vocabularies might be problematic. Click here for more details.

Files changed (26) hide show
  1. invenio_vocabularies/__init__.py +1 -1
  2. invenio_vocabularies/alembic/55a700f897b6_add_names_and_afiliations_pid_column.py +96 -0
  3. invenio_vocabularies/config.py +6 -3
  4. invenio_vocabularies/contrib/affiliations/affiliations.py +11 -6
  5. invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json +0 -6
  6. invenio_vocabularies/contrib/affiliations/schema.py +6 -2
  7. invenio_vocabularies/contrib/awards/datastreams.py +9 -0
  8. invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json +3 -0
  9. invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json +3 -0
  10. invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json +3 -0
  11. invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json +3 -0
  12. invenio_vocabularies/contrib/awards/schema.py +10 -34
  13. invenio_vocabularies/contrib/awards/serializer.py +1 -0
  14. invenio_vocabularies/contrib/names/datastreams.py +5 -34
  15. invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json +0 -7
  16. invenio_vocabularies/contrib/names/names.py +14 -10
  17. invenio_vocabularies/contrib/names/schema.py +2 -2
  18. invenio_vocabularies/services/custom_fields/vocabulary.py +9 -1
  19. invenio_vocabularies/services/schema.py +28 -0
  20. {invenio_vocabularies-1.6.0.dist-info → invenio_vocabularies-2.0.0.dist-info}/METADATA +10 -1
  21. {invenio_vocabularies-1.6.0.dist-info → invenio_vocabularies-2.0.0.dist-info}/RECORD +26 -25
  22. {invenio_vocabularies-1.6.0.dist-info → invenio_vocabularies-2.0.0.dist-info}/AUTHORS.rst +0 -0
  23. {invenio_vocabularies-1.6.0.dist-info → invenio_vocabularies-2.0.0.dist-info}/LICENSE +0 -0
  24. {invenio_vocabularies-1.6.0.dist-info → invenio_vocabularies-2.0.0.dist-info}/WHEEL +0 -0
  25. {invenio_vocabularies-1.6.0.dist-info → invenio_vocabularies-2.0.0.dist-info}/entry_points.txt +0 -0
  26. {invenio_vocabularies-1.6.0.dist-info → invenio_vocabularies-2.0.0.dist-info}/top_level.txt +0 -0
@@ -10,6 +10,6 @@
10
10
 
11
11
  from .ext import InvenioVocabularies
12
12
 
13
- __version__ = "1.6.0"
13
+ __version__ = "2.0.0"
14
14
 
15
15
  __all__ = ("__version__", "InvenioVocabularies")
@@ -0,0 +1,96 @@
1
+ #
2
+ # This file is part of Invenio.
3
+ # Copyright (C) 2023 CERN.
4
+ #
5
+ # Invenio is free software; you can redistribute it and/or modify it
6
+ # under the terms of the MIT License; see LICENSE file for more details.
7
+
8
+ """Add "pid" column to names and affiliations tables."""
9
+
10
+ import sqlalchemy as sa
11
+ from alembic import op
12
+
13
+ # revision identifiers, used by Alembic.
14
+ revision = "55a700f897b6"
15
+ down_revision = "e1146238edd3"
16
+ branch_labels = ()
17
+ depends_on = None
18
+
19
+
20
+ pids_table = sa.sql.table(
21
+ "pidstore_pid",
22
+ sa.sql.column("pid_type"),
23
+ sa.sql.column("pid_value"),
24
+ sa.sql.column("object_uuid"),
25
+ sa.sql.column("object_type"),
26
+ )
27
+ names_table = sa.sql.table(
28
+ "name_metadata",
29
+ sa.sql.column("id"),
30
+ sa.sql.column("pid"),
31
+ )
32
+ affiliations_table = sa.sql.table(
33
+ "affiliation_metadata",
34
+ sa.sql.column("id"),
35
+ sa.sql.column("pid"),
36
+ )
37
+
38
+
39
+ def upgrade():
40
+ """Upgrade database."""
41
+ op.add_column(
42
+ "name_metadata",
43
+ sa.Column("pid", sa.String(255), nullable=True),
44
+ )
45
+ # populate from PIDStore
46
+ op.execute(
47
+ names_table.update()
48
+ .where(
49
+ names_table.c.id == pids_table.c.object_uuid,
50
+ pids_table.c.object_type == "rec",
51
+ pids_table.c.pid_type == "names",
52
+ )
53
+ .values(pid=pids_table.c.pid_value)
54
+ )
55
+ op.create_unique_constraint(
56
+ op.f("uq_name_metadata_pid"),
57
+ "name_metadata",
58
+ ["pid"],
59
+ )
60
+
61
+ op.add_column(
62
+ "affiliation_metadata",
63
+ sa.Column("pid", sa.String(255), nullable=True),
64
+ )
65
+ # populate from PIDStore
66
+ op.execute(
67
+ affiliations_table.update()
68
+ .where(
69
+ affiliations_table.c.id == pids_table.c.object_uuid,
70
+ pids_table.c.object_type == "rec",
71
+ pids_table.c.pid_type == "aff",
72
+ )
73
+ .values(pid=pids_table.c.pid_value)
74
+ )
75
+
76
+ op.create_unique_constraint(
77
+ op.f("uq_affiliation_metadata_pid"),
78
+ "affiliation_metadata",
79
+ ["pid"],
80
+ )
81
+
82
+
83
+ def downgrade():
84
+ """Downgrade database."""
85
+ op.drop_constraint(
86
+ op.f("uq_name_metadata_pid"),
87
+ "name_metadata",
88
+ type_="unique",
89
+ )
90
+ op.drop_constraint(
91
+ op.f("uq_affiliation_metadata_pid"),
92
+ "affiliation_metadata",
93
+ type_="unique",
94
+ )
95
+ op.drop_column("name_metadata", "pid")
96
+ op.drop_column("affiliation_metadata", "pid")
@@ -62,15 +62,18 @@ VOCABULARIES_AWARD_SCHEMES = {
62
62
  """Awards allowed identifier schemes."""
63
63
 
64
64
  VOCABULARIES_AWARDS_OPENAIRE_FUNDERS = {
65
- "anr_________": "00rbzpz17",
66
65
  "aka_________": "05k73zm37",
66
+ "anr_________": "00rbzpz17",
67
67
  "arc_________": "05mmh0f86",
68
+ "asap________": "03zj4c476",
68
69
  "cihr________": "01gavpb45",
69
70
  "corda_______": "00k4n6c32",
71
+ "corda_____he": "00k4n6c32",
70
72
  "corda__h2020": "00k4n6c32",
71
73
  "euenvagency_": "02k4b9v70",
72
74
  "fct_________": "00snfqn58",
73
75
  "fwf_________": "013tf3c58",
76
+ "inca________": "03m8vkq32",
74
77
  "irb_hr______": "03n51vw80",
75
78
  "mestd_______": "01znas443",
76
79
  "nhmrc_______": "011kf5r70",
@@ -78,12 +81,12 @@ VOCABULARIES_AWARDS_OPENAIRE_FUNDERS = {
78
81
  "nserc_______": "01h531d29",
79
82
  "nsf_________": "021nxhr62",
80
83
  "nwo_________": "04jsz6e67",
81
- "rcuk________": "10.13039/501100000690",
82
- "ukri________": "001aqnf71",
84
+ "rcuk________": "00dq2kk65", # deprecated funder org
83
85
  "sfi_________": "0271asj38",
84
86
  "snsf________": "00yjd3n13",
85
87
  "sshrc_______": "006cvnv84",
86
88
  "tubitakf____": "04w9kkr77",
89
+ "ukri________": "001aqnf71",
87
90
  "wt__________": "029chgv08",
88
91
  }
89
92
  """Mapping of OpenAIRE and ROR funder codes."""
@@ -8,12 +8,12 @@
8
8
 
9
9
  """Vocabulary affiliations."""
10
10
 
11
+ from invenio_db import db
11
12
  from invenio_records.dumpers import SearchDumper
12
13
  from invenio_records.dumpers.indexedat import IndexedAtDumperExt
13
14
  from invenio_records_resources.factories.factory import RecordTypeFactory
15
+ from invenio_records_resources.records.systemfields import ModelPIDField
14
16
 
15
- from ...records.pidprovider import PIDProviderFactory
16
- from ...records.systemfields import BaseVocabularyPIDFieldContext
17
17
  from ...services.permissions import PermissionPolicy
18
18
  from .config import AffiliationsSearchOptions, service_components
19
19
  from .schema import AffiliationSchema
@@ -21,17 +21,22 @@ from .schema import AffiliationSchema
21
21
  record_type = RecordTypeFactory(
22
22
  "Affiliation",
23
23
  # Data layer
24
+ pid_field_cls=ModelPIDField,
24
25
  pid_field_kwargs={
25
- "create": False,
26
- "provider": PIDProviderFactory.create(pid_type="aff"),
27
- "context_cls": BaseVocabularyPIDFieldContext,
26
+ "model_field_name": "pid",
27
+ },
28
+ model_cls_attrs={
29
+ # cannot set to nullable=False because it would fail at
30
+ # service level when create({}), see records-resources.
31
+ "pid": db.Column(db.String(255), unique=True),
28
32
  },
29
33
  schema_version="1.0.0",
30
34
  schema_path="local://affiliations/affiliation-v1.0.0.json",
31
35
  record_dumper=SearchDumper(
36
+ model_fields={"pid": ("id", str)},
32
37
  extensions=[
33
38
  IndexedAtDumperExt(),
34
- ]
39
+ ],
35
40
  ),
36
41
  # Service layer
37
42
  service_id="affiliations",
@@ -10,9 +10,6 @@
10
10
  "acronym": {
11
11
  "type": "string"
12
12
  },
13
- "id": {
14
- "$ref": "local://definitions-v1.0.0.json#/identifier"
15
- },
16
13
  "identifiers": {
17
14
  "description": "Alternate identifiers for the record.",
18
15
  "type": "array",
@@ -22,9 +19,6 @@
22
19
  "name": {
23
20
  "type": "string"
24
21
  },
25
- "pid": {
26
- "$ref": "local://definitions-v1.0.0.json#/internal-pid"
27
- },
28
22
  "title": {
29
23
  "$ref": "local://vocabularies/definitions-v1.0.0.json#/title"
30
24
  }
@@ -15,11 +15,15 @@ from marshmallow import fields
15
15
  from marshmallow_utils.fields import IdentifierSet, SanitizedUnicode
16
16
  from marshmallow_utils.schemas import IdentifierSchema
17
17
 
18
- from ...services.schema import BaseVocabularySchema, ContribVocabularyRelationSchema
18
+ from ...services.schema import (
19
+ BaseVocabularySchema,
20
+ ContribVocabularyRelationSchema,
21
+ ModePIDFieldVocabularyMixin,
22
+ )
19
23
  from .config import affiliation_schemes
20
24
 
21
25
 
22
- class AffiliationSchema(BaseVocabularySchema):
26
+ class AffiliationSchema(BaseVocabularySchema, ModePIDFieldVocabularyMixin):
23
27
  """Service schema for affiliations."""
24
28
 
25
29
  acronym = SanitizedUnicode()
@@ -52,6 +52,15 @@ class OpenAIREProjectTransformer(BaseTransformer):
52
52
 
53
53
  award["id"] = f"{funder_id}::{code}"
54
54
 
55
+ funding = next(iter(record.get("funding", [])), None)
56
+ if funding:
57
+ funding_stream_id = funding.get("funding_stream", {}).get("id", "")
58
+ # Example funding stream ID: `EC::HE::HORIZON-AG-UN`. We need the `EC`
59
+ # string, i.e. the second "part" of the identifier.
60
+ program = next(iter(funding_stream_id.split("::")[1:2]), "")
61
+ if program:
62
+ award["program"] = program
63
+
55
64
  identifiers = []
56
65
  if funder_id == awards_ec_ror_id:
57
66
  identifiers.append(
@@ -36,6 +36,9 @@
36
36
  },
37
37
  "acronym": {
38
38
  "type": "string"
39
+ },
40
+ "program": {
41
+ "type": "string"
39
42
  }
40
43
  }
41
44
  }
@@ -55,6 +55,9 @@
55
55
  "acronym": {
56
56
  "type": "keyword"
57
57
  },
58
+ "program": {
59
+ "type": "keyword"
60
+ },
58
61
  "funder": {
59
62
  "type": "object",
60
63
  "properties": {
@@ -55,6 +55,9 @@
55
55
  "acronym": {
56
56
  "type": "keyword"
57
57
  },
58
+ "program": {
59
+ "type": "keyword"
60
+ },
58
61
  "funder": {
59
62
  "type": "object",
60
63
  "properties": {
@@ -55,6 +55,9 @@
55
55
  "acronym": {
56
56
  "type": "keyword"
57
57
  },
58
+ "program": {
59
+ "type": "keyword"
60
+ },
58
61
  "funder": {
59
62
  "type": "object",
60
63
  "properties": {
@@ -10,26 +10,21 @@
10
10
 
11
11
  from functools import partial
12
12
 
13
- from attr import attr
14
13
  from invenio_i18n import lazy_gettext as _
15
- from marshmallow import (
16
- Schema,
17
- ValidationError,
18
- fields,
19
- post_load,
20
- pre_dump,
21
- validate,
22
- validates_schema,
23
- )
14
+ from marshmallow import Schema, ValidationError, fields, validate, validates_schema
24
15
  from marshmallow_utils.fields import IdentifierSet, SanitizedUnicode
25
16
  from marshmallow_utils.schemas import IdentifierSchema
26
17
 
27
- from ...services.schema import BaseVocabularySchema, i18n_strings
18
+ from ...services.schema import (
19
+ BaseVocabularySchema,
20
+ ModePIDFieldVocabularyMixin,
21
+ i18n_strings,
22
+ )
28
23
  from ..funders.schema import FunderRelationSchema
29
24
  from .config import award_schemes
30
25
 
31
26
 
32
- class AwardSchema(BaseVocabularySchema):
27
+ class AwardSchema(BaseVocabularySchema, ModePIDFieldVocabularyMixin):
33
28
  """Award schema."""
34
29
 
35
30
  identifiers = IdentifierSet(
@@ -49,32 +44,12 @@ class AwardSchema(BaseVocabularySchema):
49
44
 
50
45
  acronym = SanitizedUnicode()
51
46
 
47
+ program = SanitizedUnicode()
48
+
52
49
  id = SanitizedUnicode(
53
50
  validate=validate.Length(min=1, error=_("PID cannot be blank."))
54
51
  )
55
52
 
56
- @validates_schema
57
- def validate_id(self, data, **kwargs):
58
- """Validates ID."""
59
- is_create = "record" not in self.context
60
- if is_create and "id" not in data:
61
- raise ValidationError(_("Missing PID."), "id")
62
- if not is_create:
63
- data.pop("id", None)
64
-
65
- @post_load(pass_many=False)
66
- def move_id(self, data, **kwargs):
67
- """Moves id to pid."""
68
- if "id" in data:
69
- data["pid"] = data.pop("id")
70
- return data
71
-
72
- @pre_dump(pass_many=False)
73
- def extract_pid_value(self, data, **kwargs):
74
- """Extracts the PID value."""
75
- data["id"] = data.pid.pid_value
76
- return data
77
-
78
53
 
79
54
  class AwardRelationSchema(Schema):
80
55
  """Award relation schema."""
@@ -92,6 +67,7 @@ class AwardRelationSchema(Schema):
92
67
  )
93
68
  )
94
69
  acronym = SanitizedUnicode()
70
+ program = SanitizedUnicode()
95
71
 
96
72
  @validates_schema
97
73
  def validate_data(self, data, **kwargs):
@@ -35,5 +35,6 @@ class AwardL10NItemSchema(Schema):
35
35
  description = L10NString(data_key="description_l10n")
36
36
  number = fields.String(dump_only=True)
37
37
  acronym = fields.String(dump_only=True)
38
+ program = fields.String(dump_only=True)
38
39
  funder = fields.Nested(FunderRelationSchema, dump_only=True)
39
40
  identifiers = fields.List(fields.Nested(IdentifierSchema), dump_only=True)
@@ -9,12 +9,9 @@
9
9
  """Names datastreams, transformers, writers and readers."""
10
10
 
11
11
  from invenio_access.permissions import system_identity
12
- from invenio_pidstore.errors import PIDDoesNotExistError
13
12
  from invenio_records.dictutils import dict_lookup
14
- from marshmallow import ValidationError
15
13
 
16
- from ...datastreams import StreamEntry
17
- from ...datastreams.errors import TransformerError, WriterError
14
+ from ...datastreams.errors import TransformerError
18
15
  from ...datastreams.readers import SimpleHTTPReader
19
16
  from ...datastreams.transformers import BaseTransformer
20
17
  from ...datastreams.writers import ServiceWriter
@@ -40,13 +37,14 @@ class OrcidTransformer(BaseTransformer):
40
37
  """Applies the transformation to the stream entry."""
41
38
  record = stream_entry.entry
42
39
  person = record["person"]
43
- orcid_id = record["orcid-identifier"]["uri"]
40
+ orcid_id = record["orcid-identifier"]["path"]
44
41
 
45
42
  name = person.get("name")
46
43
  if name is None:
47
44
  raise TransformerError(f"Name not found in ORCiD entry.")
48
45
 
49
46
  entry = {
47
+ "id": orcid_id,
50
48
  "given_name": name.get("given-names"),
51
49
  "family_name": name.get("family-name"),
52
50
  "identifiers": [{"scheme": "orcid", "identifier": orcid_id}],
@@ -79,41 +77,14 @@ class OrcidTransformer(BaseTransformer):
79
77
  class NamesServiceWriter(ServiceWriter):
80
78
  """Names service writer."""
81
79
 
82
- def __init__(self, *args, scheme_id="orcid", **kwargs):
80
+ def __init__(self, *args, **kwargs):
83
81
  """Constructor."""
84
82
  service_or_name = kwargs.pop("service_or_name", "names")
85
83
  super().__init__(service_or_name=service_or_name, *args, **kwargs)
86
- self._scheme_id = scheme_id
87
84
 
88
85
  def _entry_id(self, entry):
89
86
  """Get the id from an entry."""
90
- for identifier in entry.get("identifiers"):
91
- if identifier.get("scheme") == self._scheme_id:
92
- return identifier["identifier"]
93
-
94
- def _resolve(self, id_):
95
- """Resolve an entry given an id."""
96
- return self._service.resolve(self._identity, id_=id_, id_type=self._scheme_id)
97
-
98
- def write(self, stream_entry, *args, **kwargs):
99
- """Writes the input entry using a given service."""
100
- entry = stream_entry.entry
101
- try:
102
- vocab_id = self._entry_id(entry)
103
- # it is resolved before creation to avoid duplicates since
104
- # the pid is recidv2 not e.g. the orcid
105
- current = self._resolve(vocab_id)
106
- if not self._update:
107
- raise WriterError([f"Vocabulary entry already exists: {entry}"])
108
- updated = dict(current.to_dict(), **entry)
109
- return StreamEntry(
110
- self._service.update(self._identity, current.id, updated)
111
- )
112
- except PIDDoesNotExistError:
113
- return StreamEntry(self._service.create(self._identity, entry))
114
-
115
- except ValidationError as err:
116
- raise WriterError([{"ValidationError": err.messages}])
87
+ return entry["id"]
117
88
 
118
89
 
119
90
  VOCABULARIES_DATASTREAM_READERS = {
@@ -8,13 +8,6 @@
8
8
  "$schema": {
9
9
  "$ref": "local://definitions-v1.0.0.json#/$schema"
10
10
  },
11
- "id": {
12
- "description": "URI or classification code as identifier - globally unique among all names schemes.",
13
- "$ref": "local://definitions-v1.0.0.json#/identifier"
14
- },
15
- "pid": {
16
- "$ref": "local://definitions-v1.0.0.json#/internal-pid"
17
- },
18
11
  "scheme": {
19
12
  "description": "Identifier of the name scheme.",
20
13
  "$ref": "local://definitions-v1.0.0.json#/identifier"
@@ -8,16 +8,17 @@
8
8
 
9
9
  """Vocabulary names."""
10
10
 
11
- from invenio_pidstore.providers.recordid_v2 import RecordIdProviderV2
11
+ from invenio_db import db
12
12
  from invenio_records.dumpers import SearchDumper
13
13
  from invenio_records.dumpers.indexedat import IndexedAtDumperExt
14
14
  from invenio_records.dumpers.relations import RelationDumperExt
15
15
  from invenio_records.systemfields import RelationsField
16
16
  from invenio_records_resources.factories.factory import RecordTypeFactory
17
- from invenio_records_resources.records.systemfields import PIDListRelation
17
+ from invenio_records_resources.records.systemfields import (
18
+ ModelPIDField,
19
+ PIDListRelation,
20
+ )
18
21
 
19
- from ...records.pidprovider import PIDProviderFactory
20
- from ...records.systemfields import BaseVocabularyPIDFieldContext
21
22
  from ...services.permissions import PermissionPolicy
22
23
  from ..affiliations.api import Affiliation
23
24
  from .config import NamesSearchOptions, service_components
@@ -35,21 +36,24 @@ name_relations = RelationsField(
35
36
  record_type = RecordTypeFactory(
36
37
  "Name",
37
38
  # Data layer
39
+ pid_field_cls=ModelPIDField,
38
40
  pid_field_kwargs={
39
- "create": False,
40
- "provider": PIDProviderFactory.create(
41
- pid_type="names", base_cls=RecordIdProviderV2
42
- ),
43
- "context_cls": BaseVocabularyPIDFieldContext,
41
+ "model_field_name": "pid",
42
+ },
43
+ model_cls_attrs={
44
+ # cannot set to nullable=False because it would fail at
45
+ # service level when create({}), see records-resources.
46
+ "pid": db.Column(db.String(255), unique=True),
44
47
  },
45
48
  schema_version="1.0.0",
46
49
  schema_path="local://names/name-v1.0.0.json",
47
50
  record_relations=name_relations,
48
51
  record_dumper=SearchDumper(
52
+ model_fields={"pid": ("id", str)},
49
53
  extensions=[
50
54
  RelationDumperExt("relations"),
51
55
  IndexedAtDumperExt(),
52
- ]
56
+ ],
53
57
  ),
54
58
  # Service layer
55
59
  service_id="names",
@@ -11,16 +11,16 @@
11
11
  from functools import partial
12
12
 
13
13
  from invenio_i18n import lazy_gettext as _
14
- from invenio_records_resources.services.records.schema import BaseRecordSchema
15
14
  from marshmallow import ValidationError, fields, post_load, validates_schema
16
15
  from marshmallow_utils.fields import IdentifierSet, SanitizedUnicode
17
16
  from marshmallow_utils.schemas import IdentifierSchema
18
17
 
18
+ from ...services.schema import BaseVocabularySchema, ModePIDFieldVocabularyMixin
19
19
  from ..affiliations.schema import AffiliationRelationSchema
20
20
  from .config import names_schemes
21
21
 
22
22
 
23
- class NameSchema(BaseRecordSchema):
23
+ class NameSchema(BaseVocabularySchema, ModePIDFieldVocabularyMixin):
24
24
  """Service schema for names.
25
25
 
26
26
  Note that this vocabulary is very different from the base vocabulary
@@ -30,7 +30,13 @@ class VocabularyCF(BaseCF):
30
30
  """
31
31
 
32
32
  def __init__(
33
- self, name, vocabulary_id, multiple=False, dump_options=True, **kwargs
33
+ self,
34
+ name,
35
+ vocabulary_id,
36
+ multiple=False,
37
+ dump_options=True,
38
+ sort_by=None,
39
+ **kwargs
34
40
  ):
35
41
  """Constructor."""
36
42
  super().__init__(name, **kwargs)
@@ -38,6 +44,7 @@ class VocabularyCF(BaseCF):
38
44
  self.vocabulary_id = vocabulary_id
39
45
  self.dump_options = dump_options
40
46
  self.multiple = multiple
47
+ self.sort_by = sort_by
41
48
 
42
49
  @property
43
50
  def mapping(self):
@@ -78,6 +85,7 @@ class VocabularyCF(BaseCF):
78
85
  identity,
79
86
  fields=self.field_keys,
80
87
  type=self.vocabulary_id,
88
+ sort=self.sort_by,
81
89
  )
82
90
  options = []
83
91
  for vocab in vocabs:
@@ -14,6 +14,8 @@ from marshmallow import (
14
14
  Schema,
15
15
  ValidationError,
16
16
  fields,
17
+ post_load,
18
+ pre_dump,
17
19
  pre_load,
18
20
  validate,
19
21
  validates_schema,
@@ -98,6 +100,32 @@ class VocabularySchema(BaseVocabularySchema):
98
100
  type = fields.Str(attribute="type.id", required=True)
99
101
 
100
102
 
103
+ class ModePIDFieldVocabularyMixin:
104
+ """Mixin for vocabularies using a model field for their PID."""
105
+
106
+ @validates_schema
107
+ def validate_id(self, data, **kwargs):
108
+ """Validates ID."""
109
+ is_create = "record" not in self.context
110
+ if is_create and "id" not in data:
111
+ raise ValidationError(_("Missing PID."), "id")
112
+ if not is_create:
113
+ data.pop("id", None)
114
+
115
+ @post_load(pass_many=False)
116
+ def move_id(self, data, **kwargs):
117
+ """Moves id to pid."""
118
+ if "id" in data:
119
+ data["pid"] = data.pop("id")
120
+ return data
121
+
122
+ @pre_dump(pass_many=False)
123
+ def extract_pid_value(self, data, **kwargs):
124
+ """Extracts the PID value."""
125
+ data["id"] = data.pid.pid_value
126
+ return data
127
+
128
+
101
129
  class DatastreamObject(Schema):
102
130
  """Datastream object (reader, transformer, writer)."""
103
131
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: invenio-vocabularies
3
- Version: 1.6.0
3
+ Version: 2.0.0
4
4
  Summary: "Invenio module for managing vocabularies."
5
5
  Home-page: https://github.com/inveniosoftware/invenio-vocabularies
6
6
  Author: CERN
@@ -74,6 +74,15 @@ https://invenio-vocabularies.readthedocs.io/
74
74
  Changes
75
75
  =======
76
76
 
77
+ Version 2.0.0 (2023-09-14)
78
+
79
+ - contrib-awards: add "program" to schema fields
80
+ - global: switch names and affiliations to model PID field
81
+ - ci: update matrix
82
+ - awards: add "program" field
83
+ - config: update awards funders mapping
84
+ - service: add sort option to load vocabs
85
+
77
86
  Version 1.6.0 (2023-09-12)
78
87
 
79
88
  - awards: add acronym to schema
@@ -1,6 +1,6 @@
1
- invenio_vocabularies/__init__.py,sha256=qQttzVKNd9Bm6YntCrVuzR3ONsgCEsxwVifPi1RN8Ls,377
1
+ invenio_vocabularies/__init__.py,sha256=cK-Bn52JUjx9MdWs9tU-GMpaoLRcnJVbB42lmI7DjdQ,377
2
2
  invenio_vocabularies/cli.py,sha256=Ymuy0l846eJXIA4UybunSqq7P9m2N0OdTtj6nEgd1-0,6355
3
- invenio_vocabularies/config.py,sha256=TAY5PJUe3NFlGGNSs43VhWgYPKnRym-zoUYttxVu6m4,3627
3
+ invenio_vocabularies/config.py,sha256=S6Ra5aIey9_K0Rw7qqGsV6TEi7t8iLzNoVu4R6hKuu4,3739
4
4
  invenio_vocabularies/ext.py,sha256=wMJfv3GG4ZOp-c4ePVrNhxi9KyWAb874b9_D23K1orU,3805
5
5
  invenio_vocabularies/fixtures.py,sha256=nNWwH04HFASjfj1oy5kMdcQGKmVjzUuA5wSw-ER1QAg,1585
6
6
  invenio_vocabularies/proxies.py,sha256=H_bcJXPTwGbErx-pF89ChayOZcXJXJGZW7O0xkJkYQ4,693
@@ -9,6 +9,7 @@ invenio_vocabularies/webpack.py,sha256=7A1DkwwTw0NRn-aZNvh_rBEx5o_Eyx6NiMXw31y2B
9
9
  invenio_vocabularies/alembic/17c703ce1eb7_create_names_table.py,sha256=2QGs0Ofi6yd93VzIBqghNi47hrZtuLf0DylKyvVzskI,1572
10
10
  invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py,sha256=Ywtp8qOFcI3PxUXemHdvy_VwdcUVtMFV1sFgNAmYrms,1054
11
11
  invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py,sha256=jSrr0CLRchYADjkFeod0L-oophq2woXtRwbUU5Vytiw,3039
12
+ invenio_vocabularies/alembic/55a700f897b6_add_names_and_afiliations_pid_column.py,sha256=IKV7IW84R-Rcy_53VFWN51NJlqUIbgHCSp-TQDj3KX4,2371
12
13
  invenio_vocabularies/alembic/6312f33645c1_create_affiliations_table.py,sha256=0rg7ODaMG4YoHOiOMXKOgPK7QryyLGfgrdJjtn6JPsY,1600
13
14
  invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py,sha256=4y0jihIQ1s93k7EoqC4vZFrR-tXvuxa678u9hKcu0z0,1791
14
15
  invenio_vocabularies/alembic/8ff82dfb0be8_create_vocabularies_branch.py,sha256=RnyKQ38Pkubf_DU2rH9pRdufoAvABdnaP9b9S4-y4Vw,586
@@ -38,15 +39,15 @@ invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/script
38
39
  invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/scripts/initCatalog.js,sha256=ghTi5iOIhT8AJoFGlxnBrHWiw2ts21dKwY_vWxmkiCE,682
39
40
  invenio_vocabularies/contrib/__init__.py,sha256=C5eDia6tAVBCrbb5hd_KnxmczyBoF87NIBUCLID-Tzc,240
40
41
  invenio_vocabularies/contrib/affiliations/__init__.py,sha256=rV8YAzBRoSKsBYcVjCNJh6j7ITuPRfurwj9HJHRjkN8,565
41
- invenio_vocabularies/contrib/affiliations/affiliations.py,sha256=n_0aCyo6cm-gVTDBSEONyorRJec9Ko-KolKiTHO95zQ,1430
42
+ invenio_vocabularies/contrib/affiliations/affiliations.py,sha256=Ph0z7bT_tudsWDKFaiksCBngsG-eO6Xpbe3KdejfLXI,1591
42
43
  invenio_vocabularies/contrib/affiliations/api.py,sha256=-NrA_aYxabvNMofYCnrDZ2bLP15HGDTvvhHTDuXNg-g,322
43
44
  invenio_vocabularies/contrib/affiliations/config.py,sha256=ZUVANL9oU0DS4QAObQlh3_ucAkxX-CrJyJI4o0Mt4zc,1683
44
45
  invenio_vocabularies/contrib/affiliations/models.py,sha256=JUcj-1ydc2Cw2Rsc24JwXE3TFBJ_6fivhUYhGq4rT8A,329
45
46
  invenio_vocabularies/contrib/affiliations/resources.py,sha256=DBEbRxQmp-o-PeZlgFG588Q4sGcruuwIL8L9O-SzCes,435
46
- invenio_vocabularies/contrib/affiliations/schema.py,sha256=07c-6VUDAKKuH4mWwST6QNobUfSmG0dchElYld18W_w,1247
47
+ invenio_vocabularies/contrib/affiliations/schema.py,sha256=cUlE_8NehMJnlC9nzQzoN6fyZS8xJ1GfWDMPMr1n2rY,1322
47
48
  invenio_vocabularies/contrib/affiliations/services.py,sha256=C_6cMnh3mnL3-xxdsb16Rvm2aK4FyiaQ_qUTGylCwjo,391
48
49
  invenio_vocabularies/contrib/affiliations/jsonschemas/__init__.py,sha256=ILyZ5kejTr0p50macMBPALQCTJSe4KEE3_cgf2p3zV4,252
49
- invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json,sha256=fplTNgJtZMFXKFPln-YhixlkHCYbqK7LVU0gF0ZZQDc,838
50
+ invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json,sha256=dNzPBRoEGD_xPznFzPW_mDGR0sk8zsmixiGmciHXEgQ,677
50
51
  invenio_vocabularies/contrib/affiliations/mappings/__init__.py,sha256=q7hb9lcT9KLRSGr6G7qpL8Top6wZfzj_E4uzGxnraTw,295
51
52
  invenio_vocabularies/contrib/affiliations/mappings/os-v1/__init__.py,sha256=uEiG5rFrjhpFxg5pD5j5E96_xrPojsla9PhtlOqSCw4,256
52
53
  invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v1.0.0.json,sha256=oHJiDYnfsJhb4HCbUeDm7FNfiisX_HBeyg5x-DLk83s,1723
@@ -58,21 +59,21 @@ invenio_vocabularies/contrib/awards/__init__.py,sha256=KwCmwFalz-3pDs9iTa5TKUidB
58
59
  invenio_vocabularies/contrib/awards/api.py,sha256=OXukE7PLXs45BTtqVrhvGBNqLmQaI-CgXmHTCi36LZk,303
59
60
  invenio_vocabularies/contrib/awards/awards.py,sha256=N-BNE2ffUu-IlfKFBjMjfYqxL0vmpO8YMPe4q4e-rTo,2695
60
61
  invenio_vocabularies/contrib/awards/config.py,sha256=ESVzPAOU5wMmAAEyUdOIK7hS9getJO200ri7HOw-CQY,1675
61
- invenio_vocabularies/contrib/awards/datastreams.py,sha256=JNtxgzBcME0BpZPuowfMbxqzfsyFJ6b7MTk5m9LQym0,3397
62
+ invenio_vocabularies/contrib/awards/datastreams.py,sha256=lJDokc72MA6s5YvfwExBVNdqVnnIVajFzagB9YitQxk,3847
62
63
  invenio_vocabularies/contrib/awards/models.py,sha256=mM-kSNf7kDH3oIbV8epxxbUi7muYqi4JreXxgWXlVzw,318
63
64
  invenio_vocabularies/contrib/awards/resources.py,sha256=_9YTqbhz8axFXGhG5y4WyjE27p9n-7e3c6HoBRditPA,411
64
- invenio_vocabularies/contrib/awards/schema.py,sha256=fdazc6vaE_ciY8tNUUXpY3veF1mNbFE3t1VcY6ye4DY,3392
65
- invenio_vocabularies/contrib/awards/serializer.py,sha256=z92SsjEf6vf6LX1egwGiRY1AHU2qRxCaWyWVUXPwqag,1095
65
+ invenio_vocabularies/contrib/awards/schema.py,sha256=bg-09nvhEn-ipzaztK1iNbKc59saAM8v8hAW9zpKDAc,2786
66
+ invenio_vocabularies/contrib/awards/serializer.py,sha256=MDnq41EJf_LFu-UT6qlB3-O2S7aEYePIzQ_immMnwag,1139
66
67
  invenio_vocabularies/contrib/awards/services.py,sha256=oExHPYgXgege9a7oLCK4LGb8FXCHfY0ekeS9HvTJLxs,367
67
68
  invenio_vocabularies/contrib/awards/jsonschemas/__init__.py,sha256=XB2l9hr53vqTk7o9lmy18FWGhHEUvNHu8D6nMF8Bz4k,246
68
- invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json,sha256=Vi_FM8yeqYWkfsk-HvuRIl8b2B7YN3pgGC2PicUQmmw,982
69
+ invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json,sha256=kNw4djIuqo7Ing9O5w4k3n_HIejX4f5hpApnmJpDt7A,1029
69
70
  invenio_vocabularies/contrib/awards/mappings/__init__.py,sha256=PbM5urjiSrJSx4Ak-H_lJrOOVKGT38MrGgRv61gIbAM,243
70
71
  invenio_vocabularies/contrib/awards/mappings/os-v1/__init__.py,sha256=r8IZvjorG9SVz32Hv1fncoqLfz-5Ml0Ph3jiYWCHBPk,250
71
- invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json,sha256=vAbmJnkr4By7VD6UdG-npE7rMIMs8-9Ukbd2_ue0IZo,1354
72
+ invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json,sha256=pjbqzEc2q0t7VQBqVjU5DjsKcLaFWd5f7xSA6B9_HZc,1408
72
73
  invenio_vocabularies/contrib/awards/mappings/os-v2/__init__.py,sha256=9gRLFRtjhNJcbop3qz8iRpQVEng_wudDTbOFsS-gxjk,250
73
- invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json,sha256=vAbmJnkr4By7VD6UdG-npE7rMIMs8-9Ukbd2_ue0IZo,1354
74
+ invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json,sha256=pjbqzEc2q0t7VQBqVjU5DjsKcLaFWd5f7xSA6B9_HZc,1408
74
75
  invenio_vocabularies/contrib/awards/mappings/v7/__init__.py,sha256=fERdPp7K7ajaoUu_4_HVLfF-WD_qcl7QgST6yGb68s4,253
75
- invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json,sha256=vAbmJnkr4By7VD6UdG-npE7rMIMs8-9Ukbd2_ue0IZo,1354
76
+ invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json,sha256=pjbqzEc2q0t7VQBqVjU5DjsKcLaFWd5f7xSA6B9_HZc,1408
76
77
  invenio_vocabularies/contrib/funders/__init__.py,sha256=YxFXBDnT7NM8rFwxT_Ge3xXR2n17EM0alknQq7r_Bt8,478
77
78
  invenio_vocabularies/contrib/funders/api.py,sha256=QKGGeSnPHSoBfucvpaVruXT_txYidofZ080G3IxFkIo,306
78
79
  invenio_vocabularies/contrib/funders/config.py,sha256=sJjnGpUmwhbPQ7fI2EyvzNdDrguBwlJeAORXBSZrILs,1748
@@ -96,14 +97,14 @@ invenio_vocabularies/contrib/funders/mappings/v7/funders/funder-v1.0.0.json,sha2
96
97
  invenio_vocabularies/contrib/names/__init__.py,sha256=DBfsM7JMETZGaV5QmXEwE7zhCaAXvc2SZN6uXnW_V-c,451
97
98
  invenio_vocabularies/contrib/names/api.py,sha256=sEPn_jFX3gyoxgbdEUSIvOoPCUI8pocI6qCZO6mzCgQ,300
98
99
  invenio_vocabularies/contrib/names/config.py,sha256=hKDTEEBYGYOY6sMOArZjjkq2HJ6MJtRZp1geGLAFgRg,1735
99
- invenio_vocabularies/contrib/names/datastreams.py,sha256=pXP_lMauUmJKB4008M8CKPd--ysqvk-xN0-_5y7nEZ8,5014
100
+ invenio_vocabularies/contrib/names/datastreams.py,sha256=qcNgCLT57M99IL2yZxyfEIdi5AbkBGOMmSoE0e4vEJM,3661
100
101
  invenio_vocabularies/contrib/names/models.py,sha256=SYdtDDG-y5Wq_d06YhiVO5n8gfxPW_mx-tECsIcv5H8,308
101
- invenio_vocabularies/contrib/names/names.py,sha256=gsvUfhOPRtVjvJNHc4xyhMDKc2smuLC0FR1tYFZ7-_4,1994
102
+ invenio_vocabularies/contrib/names/names.py,sha256=fRNZW3yTmIE3FBB8zAcTdt1CXH6O8p6Ggz_7k9e8QTk,1987
102
103
  invenio_vocabularies/contrib/names/resources.py,sha256=Z8XqLKfFKE69zdTTvcTDmpEZ6wqiqjIH5tp0LzXTSwQ,1588
103
- invenio_vocabularies/contrib/names/schema.py,sha256=LxnoEFTzMGpAtlNopmBO6LYJeZ5mScQJqcfd9O7gwdk,2283
104
+ invenio_vocabularies/contrib/names/schema.py,sha256=3PKji7JYl0BNPPjoaY6YjrkbrdMctphrNNmdeqNKYPE,2318
104
105
  invenio_vocabularies/contrib/names/services.py,sha256=1viM-L8VEojmQWMisIOhDyl8KInPPCZEIf6tU8G07As,1763
105
106
  invenio_vocabularies/contrib/names/jsonschemas/__init__.py,sha256=pdDZdyoxqWbAQ6ngiclhYoDUsGKgRDRPXlIDy0U5Jzg,241
106
- invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json,sha256=eKmfHVRXKG6FnLIApqg6cdoGwz_g2gq_9iaLlwNVWo0,1439
107
+ invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json,sha256=vAqnz9LbRuhRg2Vdg9Ygc_s07VqZh_gdQP4Ch5Eztsw,1170
107
108
  invenio_vocabularies/contrib/names/mappings/__init__.py,sha256=l5hYJmrj83lds5GupnwCcwQn7cdJo6_4H4YYzrnBa54,242
108
109
  invenio_vocabularies/contrib/names/mappings/os-v1/__init__.py,sha256=CKtF-xflE4QGF5P82Lj1ifEP1c7ekR24fc3SiTAkhsY,249
109
110
  invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v1.0.0.json,sha256=XtrCBgvEwlhu_kyitiZ-ZRVn8ImK17rFuRVSV4gjHvw,1892
@@ -162,11 +163,11 @@ invenio_vocabularies/services/components.py,sha256=d9C-24dEDM63gFm75nU-dXrrjS2zZ
162
163
  invenio_vocabularies/services/facets.py,sha256=9v8lYSPL_aHMZelZhfVbLwrocD6XB8-pczyeCNDABjQ,2778
163
164
  invenio_vocabularies/services/permissions.py,sha256=one3NvNFYq-q15e6xxf85OkH1bWZ5OsvJqMnNbm3Qms,696
164
165
  invenio_vocabularies/services/querystr.py,sha256=X3JHVF9B0O0iLWrnW3ok_bf_8jA-Cs_oAcYYkGOm3Uw,1829
165
- invenio_vocabularies/services/schema.py,sha256=le29X8SO320cTepTNClTzaqyGgGT6cY9NryTKuO1MLo,3501
166
+ invenio_vocabularies/services/schema.py,sha256=ShnnH_ILHZGxE546J6Jsdwdeix6jLubSRomzf472DK8,4307
166
167
  invenio_vocabularies/services/service.py,sha256=W3wtKOttQjOr8Nkaus6m3KRuCMBqBsWUCAVv7Dj8bvM,7392
167
168
  invenio_vocabularies/services/tasks.py,sha256=zTAWdnI5celWBKrF986wQzCmkOTGOwTghtN7U5FMZ5Q,783
168
169
  invenio_vocabularies/services/custom_fields/__init__.py,sha256=1emONO3aiE7TanAoyUSkWE6gwZiBwjzzJ5y8jeomOLc,310
169
- invenio_vocabularies/services/custom_fields/vocabulary.py,sha256=p5e1_vSgI_RmO-kC6mNeC5lxNfu9fedSYSKoDyTWbf0,2690
170
+ invenio_vocabularies/services/custom_fields/vocabulary.py,sha256=zLh-igEVoPa4svCZPNsBuvoQ4a5CTFAKJzX8ndLVWE4,2818
170
171
  invenio_vocabularies/translations/messages.pot,sha256=IzTTWdWknzmKKtl1UNUxPOwHjfBB_iidm_eeEY2kV-M,3907
171
172
  invenio_vocabularies/translations/af/LC_MESSAGES/messages.mo,sha256=Tq2jiOLpIEsJN7K27mp4qfMU0Uih7fu_glHWMsYifBs,523
172
173
  invenio_vocabularies/translations/af/LC_MESSAGES/messages.po,sha256=XXoiqCtGELaxl6hxRj31D3DCdgBUrz0oD3MYJUpcklM,3976
@@ -262,10 +263,10 @@ invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.mo,sha256=B1ysk8DOW
262
263
  invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.po,sha256=vg8qC8ofpAdJ3mQz7mWM1ylKDpiNWXFs7rlMdSPkgKk,4629
263
264
  invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.mo,sha256=1fiYIHoTDv1OS_Y6_KHQ0tlogc6a4LsuAIWIWISGp58,600
264
265
  invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.po,sha256=9ACePz_EpB-LfcIJajZ2kp8Q04tcdrQLOtug162ZUss,4115
265
- invenio_vocabularies-1.6.0.dist-info/AUTHORS.rst,sha256=8d0p_WWE1r9DavvzMDi2D4YIGBHiMYcN3LYxqQOj8sY,291
266
- invenio_vocabularies-1.6.0.dist-info/LICENSE,sha256=UvI8pR8jGWqe0sTkb_hRG6eIrozzWwWzyCGEpuXX4KE,1062
267
- invenio_vocabularies-1.6.0.dist-info/METADATA,sha256=3spgWtuRiwJ0_l5zn32-ryIUf1XP7BeYVyndYbMprHU,4450
268
- invenio_vocabularies-1.6.0.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
269
- invenio_vocabularies-1.6.0.dist-info/entry_points.txt,sha256=cBazxlQQIn53RNdPI8edCL5v1k-6fE7UU4O0QssUoBE,2309
270
- invenio_vocabularies-1.6.0.dist-info/top_level.txt,sha256=x1gRNbaODF_bCD0SBLM3nVOFPGi06cmGX5X94WKrFKk,21
271
- invenio_vocabularies-1.6.0.dist-info/RECORD,,
266
+ invenio_vocabularies-2.0.0.dist-info/AUTHORS.rst,sha256=8d0p_WWE1r9DavvzMDi2D4YIGBHiMYcN3LYxqQOj8sY,291
267
+ invenio_vocabularies-2.0.0.dist-info/LICENSE,sha256=UvI8pR8jGWqe0sTkb_hRG6eIrozzWwWzyCGEpuXX4KE,1062
268
+ invenio_vocabularies-2.0.0.dist-info/METADATA,sha256=FzG_Md-zho3gUsBgYZw6XYljxUS8ZdgyHiVWCIxQxkI,4719
269
+ invenio_vocabularies-2.0.0.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
270
+ invenio_vocabularies-2.0.0.dist-info/entry_points.txt,sha256=cBazxlQQIn53RNdPI8edCL5v1k-6fE7UU4O0QssUoBE,2309
271
+ invenio_vocabularies-2.0.0.dist-info/top_level.txt,sha256=x1gRNbaODF_bCD0SBLM3nVOFPGi06cmGX5X94WKrFKk,21
272
+ invenio_vocabularies-2.0.0.dist-info/RECORD,,