Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow extra fields other than "@context" #266

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
62 changes: 60 additions & 2 deletions dandischema/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
Type,
TypeVar,
Union,
cast,
)
from warnings import warn

Expand Down Expand Up @@ -76,6 +77,51 @@
print(f"{field} is different")


def get_dict_without_context(d: Any) -> Any:
"""
If a given object is a dictionary, return a copy of it without the
`@context` key. Otherwise, return the input object as is.

:param d: The given object
:return: If the object is a dictionary, a copy of it without the `@context` key;
otherwise, the input object as is.
"""
if isinstance(d, dict):
return {k: v for k, v in d.items() if k != "@context"}
return d

Check warning on line 91 in dandischema/models.py

View check run for this annotation

Codecov / codecov/patch

dandischema/models.py#L91

Added line #L91 was not covered by tests


def add_context(json_schema: dict) -> None:
"""
Add the `@context` key to the given JSON schema

:param json_schema: The dictionary representing the JSON schema

raises: ValueError if the `@context` key is already present in the given schema
"""
context_key = "@context"
context_key_title = "@Context"
properties = cast(dict, json_schema.get("properties", {}))
required = cast(list, json_schema.get("required", []))

if context_key in properties or context_key in required:
msg = f"The '{context_key}' key is already present in the given JSON schema."
raise ValueError(msg)

Check warning on line 109 in dandischema/models.py

View check run for this annotation

Codecov / codecov/patch

dandischema/models.py#L108-L109

Added lines #L108 - L109 were not covered by tests

properties[context_key] = {
"format": "uri",
"minLength": 1,
"title": context_key_title,
"type": "string",
}
# required.append(context_key) # Uncomment this line to make `@context` required

# Update the schema
# This is needed to handle the case in which the keys are newly created
json_schema["properties"] = properties
json_schema["required"] = required


class AccessType(Enum):
"""An enumeration of access status options"""

Expand Down Expand Up @@ -608,6 +654,8 @@

return schema

model_config = ConfigDict(extra="forbid")


class PropertyValue(DandiBaseModel):
maxValue: Optional[float] = Field(None, json_schema_extra={"nskey": "schema"})
Expand Down Expand Up @@ -1588,8 +1636,6 @@
class Dandiset(CommonModel):
"""A body of structured information describing a DANDI dataset."""

model_config = ConfigDict(extra="allow")

@field_validator("contributor")
@classmethod
def contributor_musthave_contact(
Expand Down Expand Up @@ -1684,6 +1730,12 @@
"nskey": "dandi",
}

# Model validator to remove the `"@context"` key from data instance before
# "base" validation is performed.
_remove_context_key = model_validator(mode="before")(get_dict_without_context)

model_config = ConfigDict(json_schema_extra=add_context)


class BareAsset(CommonModel):
"""Metadata used to describe an asset anywhere (local or server).
Expand Down Expand Up @@ -1816,6 +1868,12 @@
json_schema_extra={"readOnly": True, "nskey": "schema"}
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

look here for an example on how we add extra to json schema.

May be you could add extra for your @context which would state something like "includeInUI": False


# Model validator to remove the `"@context"` key from data instance before
# "base" validation is performed.
_remove_context_key = model_validator(mode="before")(get_dict_without_context)

model_config = ConfigDict(json_schema_extra=add_context)


class Publishable(DandiBaseModel):
publishedBy: Union[AnyHttpUrl, PublishActivity] = Field(
Expand Down
Loading