Skip to content

dataverse_schema

Pydantic models for the Dataverse '/api/metadatablocks' schema response.

This models the schema definition JSON itself (block -> fields -> optional recursive childFields), not an individual dataset's metadata values. Use it to parse, validate, and query the schema (e.g. "what fields exist in the citation block?", "is authorAffiliation required?", "what controlled vocab values does subject accept?").

DataverseSchemaResponse

Bases: BaseModel

Top-level wrapper matching the raw JSON returned by /api/metadatablocks.

Source code in src/dv_schema_models/dataverse_schema.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
class DataverseSchemaResponse(BaseModel):
    """Top-level wrapper matching the raw JSON returned by /api/metadatablocks."""

    model_config = ConfigDict(extra="ignore")

    status: str
    data: list[MetadataBlock]

    def get_block(self, block_name: str) -> MetadataBlock | None:
        """Look up a metadata block by its short name (e.g. 'citation', 'geospatial')."""
        return next((b for b in self.data if b.name == block_name), None)

    def block_names(self) -> list[str]:
        """List the short names of every block in the response."""
        return [b.name for b in self.data]

block_names()

List the short names of every block in the response.

Source code in src/dv_schema_models/dataverse_schema.py
102
103
104
def block_names(self) -> list[str]:
    """List the short names of every block in the response."""
    return [b.name for b in self.data]

get_block(block_name)

Look up a metadata block by its short name (e.g. 'citation', 'geospatial').

Source code in src/dv_schema_models/dataverse_schema.py
 98
 99
100
def get_block(self, block_name: str) -> MetadataBlock | None:
    """Look up a metadata block by its short name (e.g. 'citation', 'geospatial')."""
    return next((b for b in self.data if b.name == block_name), None)

MetadataBlock

Bases: BaseModel

A single metadata block (e.g. citation, geospatial, astrophysics).

Source code in src/dv_schema_models/dataverse_schema.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
class MetadataBlock(BaseModel):
    """A single metadata block (e.g. citation, geospatial, astrophysics)."""

    model_config = ConfigDict(extra="ignore")

    id: int
    name: str
    displayName: str
    displayOnCreate: bool
    fields: dict[str, MetadataField]

    def get_field(self, field_name: str) -> MetadataField | None:
        """Look up a top-level field in this block by its key name."""
        return self.fields.get(field_name)

    def all_leaf_fields(self) -> dict[str, MetadataField]:
        """Flatten every leaf field in this block (including nested ones) into a single dict."""
        flat: dict[str, MetadataField] = {}
        for field in self.fields.values():
            for leaf in field.iter_leaf_fields():
                flat[leaf.name] = leaf
        return flat

    def required_fields(self) -> list[str]:
        """Return the names of all leaf fields marked isRequired = True."""
        return [name for name, field in self.all_leaf_fields().items() if field.isRequired]

all_leaf_fields()

Flatten every leaf field in this block (including nested ones) into a single dict.

Source code in src/dv_schema_models/dataverse_schema.py
77
78
79
80
81
82
83
def all_leaf_fields(self) -> dict[str, MetadataField]:
    """Flatten every leaf field in this block (including nested ones) into a single dict."""
    flat: dict[str, MetadataField] = {}
    for field in self.fields.values():
        for leaf in field.iter_leaf_fields():
            flat[leaf.name] = leaf
    return flat

get_field(field_name)

Look up a top-level field in this block by its key name.

Source code in src/dv_schema_models/dataverse_schema.py
73
74
75
def get_field(self, field_name: str) -> MetadataField | None:
    """Look up a top-level field in this block by its key name."""
    return self.fields.get(field_name)

required_fields()

Return the names of all leaf fields marked isRequired = True.

Source code in src/dv_schema_models/dataverse_schema.py
85
86
87
def required_fields(self) -> list[str]:
    """Return the names of all leaf fields marked isRequired = True."""
    return [name for name, field in self.all_leaf_fields().items() if field.isRequired]

MetadataField

Bases: BaseModel

A single metadata field definition.

For compound fields (typeClass == 'compound'), childFields holds the nested sub-fields, keyed by field name, recursively using this same model. Leaf fields (primitive or controlledVocabulary) have childFields = None.

Source code in src/dv_schema_models/dataverse_schema.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class MetadataField(BaseModel):
    """A single metadata field definition.

    For compound fields (typeClass == 'compound'), `childFields` holds the
    nested sub-fields, keyed by field name, recursively using this same model.
    Leaf fields (primitive or controlledVocabulary) have `childFields = None`.
    """

    model_config = ConfigDict(extra="ignore")  # tolerate any schema fields we did not model

    name: str
    displayName: str
    displayOnCreate: bool
    title: str
    type: str  # e.g. 'TEXT', 'TEXTBOX', 'DATE', 'INT', 'FLOAT', 'URL', 'EMAIL', 'NONE'
    typeClass: str  # 'primitive', 'compound', or 'controlledVocabulary'
    watermark: str = ""
    description: str = ""
    multiple: bool
    isControlledVocabulary: bool
    isAdvancedSearchFieldType: bool
    displayFormat: str = ""
    displayOrder: int
    isRequired: bool
    controlledVocabularyValues: list[str] | None = None
    childFields: dict[str, MetadataField] | None = None

    def is_compound(self) -> bool:
        """Return True if this field wraps nested childFields rather than holding a value directly."""
        return self.childFields is not None

    def iter_leaf_fields(self) -> list[MetadataField]:
        """Recursively collect every leaf (non-compound) field reachable from this field."""
        if self.childFields:
            leaves: list[MetadataField] = []
            for child in self.childFields.values():
                leaves.extend(child.iter_leaf_fields())
            return leaves
        return [self]

is_compound()

Return True if this field wraps nested childFields rather than holding a value directly.

Source code in src/dv_schema_models/dataverse_schema.py
44
45
46
def is_compound(self) -> bool:
    """Return True if this field wraps nested childFields rather than holding a value directly."""
    return self.childFields is not None

iter_leaf_fields()

Recursively collect every leaf (non-compound) field reachable from this field.

Source code in src/dv_schema_models/dataverse_schema.py
48
49
50
51
52
53
54
55
def iter_leaf_fields(self) -> list[MetadataField]:
    """Recursively collect every leaf (non-compound) field reachable from this field."""
    if self.childFields:
        leaves: list[MetadataField] = []
        for child in self.childFields.values():
            leaves.extend(child.iter_leaf_fields())
        return leaves
    return [self]

load_schema(metadata)

Parse a metadatablocks JSON payload (already loaded as a dict) into a DataverseSchemaResponse.

Source code in src/dv_schema_models/dataverse_schema.py
107
108
109
def load_schema(metadata: dict) -> DataverseSchemaResponse:
    """Parse a metadatablocks JSON payload (already loaded as a dict) into a DataverseSchemaResponse."""
    return DataverseSchemaResponse.model_validate(metadata)