Coverage for src/metador_core/schema/common/rocrate.py: 82%
66 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-08 10:29 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-08-08 10:29 +0000
1"""RO Crate compatible Metadata.
3Here we do impose certain constraints (make fields mandatory).
5See https://www.researchobject.org/ro-crate/1.1/
6"""
7from __future__ import annotations
9from typing import Set
11from pydantic import parse_obj_as, root_validator, validator
13from ..decorators import make_mandatory
14from ..ld import LDIdRef, ld_decorator
15from ..types import MimeTypeStr, NonEmptyStr
16from . import schemaorg
18CTX_URL_ROCRATE = "https://w3id.org/ro/crate/1.1/context"
21rocrate = ld_decorator(context=CTX_URL_ROCRATE)
24@make_mandatory("contentSize", "sha256")
25@rocrate(type="File")
26class FileMeta(schemaorg.MediaObject):
27 class Plugin:
28 name = "core.file"
29 version = (0, 1, 0)
31 # NOTE: We do not use `name` here because `name` is used semantically
32 # like a title in schema.org, which could also make sense for a file to have.
33 filename: NonEmptyStr
34 """Original name of the file in source directory."""
36 encodingFormat: MimeTypeStr
37 """MIME type of the file."""
40@rocrate(type="Dataset")
41class DirMeta(schemaorg.Dataset):
42 class Plugin:
43 name = "core.dir"
44 version = (0, 1, 0)
46 hasPart: Set[LDIdRef] = set()
47 """References to (a subset of) contained files and subdirectories."""
50@rocrate(type="Organization")
51class Organization(schemaorg.Organization):
52 @validator("id_")
53 def check_id(cls, v):
54 if not v:
55 return None
56 if not v.startswith("https://ror.org/"):
57 raise ValueError("Person @id must be a valid ROR URL!")
58 return parse_obj_as(schemaorg.URL, v)
61@rocrate(type="Person")
62class Person(schemaorg.Person):
63 @validator("id_")
64 def check_id(cls, v):
65 if not v:
66 return None
67 if not v.startswith("https://orcid.org/"):
68 raise ValueError("Person @id must be a valid ORCID URL!")
69 return parse_obj_as(schemaorg.URL, v)
71 @root_validator(pre=True)
72 def check_name(cls, values):
73 has_given_or_additional = values.get("givenName") or values.get(
74 "additionalName"
75 )
76 if has_given_or_additional and not values.get("familyName"):
77 msg = "givenName and additionalName require also familyName to be provided!"
78 raise ValueError(msg)
79 return values
81 @root_validator
82 def ensure_name(cls, values):
83 missing_name = values.get("name") is None
84 if missing_name:
85 parts = []
86 for k in ["givenName", "additionalName", "familyName"]:
87 if v := values.get(k):
88 parts.append(v)
89 fullname = " ".join(parts)
90 if not fullname:
91 msg = "A Person must have name or familyName set!"
92 raise ValueError(msg)
93 values["name"] = fullname
94 return values
97# required self-description of RO-Crate file
98rocrate_self_meta = {
99 "@type": "CreativeWork",
100 "@id": "ro-crate-metadata.json",
101 "conformsTo": {"@id": "https://w3id.org/ro/crate/1.1"},
102 "about": {"@id": "./"},
103}