Coverage for src/metador_core/schema/common/rocrate.py: 83%

72 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-11-02 09:33 +0000

1"""RO Crate compatible Metadata. 

2 

3Here we do impose certain constraints (make fields mandatory). 

4 

5See https://www.researchobject.org/ro-crate/1.1/ 

6""" 

7from __future__ import annotations 

8 

9from typing import Set 

10 

11from pydantic import parse_obj_as, root_validator, validator 

12 

13from ..decorators import make_mandatory 

14from ..ld import LDIdRef, ld_decorator 

15from ..types import MimeTypeStr, NonEmptyStr 

16from . import schemaorg 

17 

18CTX_URL_ROCRATE = "https://w3id.org/ro/crate/1.1/context" 

19 

20 

21rocrate = ld_decorator(context=CTX_URL_ROCRATE) 

22 

23 

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) 

30 

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.""" 

35 

36 encodingFormat: MimeTypeStr 

37 """MIME type of the file.""" 

38 

39 

40@rocrate(type="Dataset") 

41class DirMeta(schemaorg.Dataset): 

42 class Plugin: 

43 name = "core.dir" 

44 version = (0, 1, 0) 

45 

46 hasPart: Set[LDIdRef] = set() 

47 """References to (a subset of) contained files and subdirectories.""" 

48 

49 

50@rocrate(type="Organization") 

51class Organization(schemaorg.Organization): 

52 class Plugin: 

53 name = "core.org" 

54 version = (0, 1, 0) 

55 

56 @validator("id_") 

57 def check_id(cls, v): 

58 if not v: 

59 return None 

60 if not v.startswith("https://ror.org/"): 

61 raise ValueError("Person @id must be a valid ROR URL!") 

62 return parse_obj_as(schemaorg.URL, v) 

63 

64 

65@rocrate(type="Person") 

66class Person(schemaorg.Person): 

67 class Plugin: 

68 name = "core.person" 

69 version = (0, 1, 0) 

70 

71 @validator("id_") 

72 def check_id(cls, v): 

73 if not v: 

74 return None 

75 if not v.startswith("https://orcid.org/"): 

76 raise ValueError("Person @id must be a valid ORCID URL!") 

77 return parse_obj_as(schemaorg.URL, v) 

78 

79 @root_validator(pre=True) 

80 def check_name(cls, values): 

81 has_given_or_additional = values.get("givenName") or values.get( 

82 "additionalName" 

83 ) 

84 if has_given_or_additional and not values.get("familyName"): 

85 msg = "givenName and additionalName require also familyName to be provided!" 

86 raise ValueError(msg) 

87 return values 

88 

89 @root_validator 

90 def ensure_name(cls, values): 

91 missing_name = values.get("name") is None 

92 if missing_name: 

93 parts = [] 

94 for k in ["givenName", "additionalName", "familyName"]: 

95 if v := values.get(k): 

96 parts.append(v) 

97 fullname = " ".join(parts) 

98 if not fullname: 

99 msg = "A Person must have name or familyName set!" 

100 raise ValueError(msg) 

101 values["name"] = fullname 

102 return values 

103 

104 

105# required self-description of RO-Crate file 

106rocrate_self_meta = { 

107 "@type": "CreativeWork", 

108 "@id": "ro-crate-metadata.json", 

109 "conformsTo": {"@id": "https://w3id.org/ro/crate/1.1"}, 

110 "about": {"@id": "./"}, 

111}