gedcom-x 0.5__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.
- gedcom_x-0.5.dist-info/METADATA +17 -0
- gedcom_x-0.5.dist-info/RECORD +37 -0
- gedcom_x-0.5.dist-info/WHEEL +5 -0
- gedcom_x-0.5.dist-info/top_level.txt +1 -0
- gedcomx/Address.py +100 -0
- gedcomx/Agent.py +83 -0
- gedcomx/Attribution.py +116 -0
- gedcomx/Conclusion.py +137 -0
- gedcomx/Coverage.py +26 -0
- gedcomx/Date.py +29 -0
- gedcomx/Document.py +42 -0
- gedcomx/Event.py +195 -0
- gedcomx/EvidenceReference.py +11 -0
- gedcomx/Fact.py +462 -0
- gedcomx/Gedcom.py +345 -0
- gedcomx/GedcomX.py +1105 -0
- gedcomx/Gender.py +48 -0
- gedcomx/Group.py +37 -0
- gedcomx/Identifier.py +89 -0
- gedcomx/Name.py +241 -0
- gedcomx/Note.py +65 -0
- gedcomx/OnlineAccount.py +10 -0
- gedcomx/Person.py +178 -0
- gedcomx/PlaceDescription.py +47 -0
- gedcomx/PlaceReference.py +31 -0
- gedcomx/Qualifier.py +27 -0
- gedcomx/Relationship.py +116 -0
- gedcomx/Serialization.py +37 -0
- gedcomx/SourceCitation.py +20 -0
- gedcomx/SourceDescription.py +241 -0
- gedcomx/SourceReference.py +168 -0
- gedcomx/Subject.py +73 -0
- gedcomx/TextValue.py +34 -0
- gedcomx/TopLevelTypeCollection.py +47 -0
- gedcomx/URI.py +70 -0
- gedcomx/_Resource.py +11 -0
- gedcomx/__init__.py +39 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
from typing import List, Optional
|
2
|
+
|
3
|
+
from .Attribution import Attribution
|
4
|
+
from .Conclusion import ConfidenceLevel
|
5
|
+
from .Date import Date
|
6
|
+
from .EvidenceReference import EvidenceReference
|
7
|
+
from .Identifier import Identifier
|
8
|
+
from .Note import Note
|
9
|
+
from .SourceReference import SourceReference
|
10
|
+
from .TextValue import TextValue
|
11
|
+
from .URI import URI
|
12
|
+
|
13
|
+
from .Subject import Subject
|
14
|
+
|
15
|
+
class PlaceDescription(Subject):
|
16
|
+
identifier = "http://gedcomx.org/v1/PlaceDescription"
|
17
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
18
|
+
|
19
|
+
def __init__(self, id: str =None,
|
20
|
+
lang: str = 'en',
|
21
|
+
sources: Optional[List[SourceReference]] = [],
|
22
|
+
analysis: URI = None, notes: Optional[List[Note]] =[],
|
23
|
+
confidence: ConfidenceLevel = None,
|
24
|
+
attribution: Attribution = None,
|
25
|
+
extracted: bool = None,
|
26
|
+
evidence: List[EvidenceReference] = None,
|
27
|
+
media: List[SourceReference] = [],
|
28
|
+
identifiers: List[Identifier] = [],
|
29
|
+
names: List[TextValue] = [],
|
30
|
+
type: Optional[str] = None,
|
31
|
+
place: Optional[URI] = None,
|
32
|
+
jurisdiction: Optional["PlaceDescription"] = None, # PlaceDescription
|
33
|
+
latitude: Optional[float] = None,
|
34
|
+
longitude: Optional[float] = None,
|
35
|
+
temporalDescription: Optional[Date] = None,
|
36
|
+
spatialDescription: Optional[URI] = None,) -> None:
|
37
|
+
super().__init__(id, lang, sources, analysis, notes, confidence, attribution, extracted, evidence, media, identifiers)
|
38
|
+
self.names = names
|
39
|
+
self.type = type
|
40
|
+
self.place = place
|
41
|
+
self.jurisdiction = jurisdiction
|
42
|
+
self.latitide = latitude
|
43
|
+
self.longitute = longitude
|
44
|
+
self.temporalDescription = temporalDescription
|
45
|
+
self.spacialDescription = spatialDescription
|
46
|
+
|
47
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from .URI import URI
|
4
|
+
|
5
|
+
class PlaceReference:
|
6
|
+
identifier = 'http://gedcomx.org/v1/PlaceReference'
|
7
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
8
|
+
|
9
|
+
def __init__(self, original: Optional[str], descriptionRef: Optional[URI]) -> None:
|
10
|
+
self.original = original
|
11
|
+
self.descriptionRef = descriptionRef
|
12
|
+
|
13
|
+
@property
|
14
|
+
def _as_dict_(self):
|
15
|
+
return {
|
16
|
+
'original': self.original,
|
17
|
+
'descriptionRef': self.descriptionRef._as_dict_ if self.descriptionRef else None
|
18
|
+
}
|
19
|
+
|
20
|
+
def ensure_list(val):
|
21
|
+
if val is None:
|
22
|
+
return []
|
23
|
+
return val if isinstance(val, list) else [val]
|
24
|
+
|
25
|
+
# PlaceReference
|
26
|
+
PlaceReference._from_json_ = classmethod(lambda cls, data: PlaceReference(
|
27
|
+
original=data.get('original'),
|
28
|
+
descriptionRef=URI._from_json_(data['description']) if data.get('description') else None
|
29
|
+
))
|
30
|
+
|
31
|
+
|
gedcomx/Qualifier.py
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
class Qualifier:
|
4
|
+
identifier = 'http://gedcomx.org/v1/Qualifier'
|
5
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
6
|
+
|
7
|
+
def __init__(self, name: str, value: Optional[str]) -> None:
|
8
|
+
self.name = name
|
9
|
+
self.value = value
|
10
|
+
|
11
|
+
@property
|
12
|
+
def __as_dict__(self):
|
13
|
+
from .Serialization import serialize_to_dict
|
14
|
+
|
15
|
+
data = {
|
16
|
+
"name":self.name if self.name else None,
|
17
|
+
"value":self.value if self.value else None
|
18
|
+
}
|
19
|
+
|
20
|
+
return serialize_to_dict(data,False)
|
21
|
+
|
22
|
+
# Qualifier
|
23
|
+
Qualifier._from_json_ = classmethod(lambda cls, data: Qualifier(
|
24
|
+
name=data.get('name'),
|
25
|
+
value=data.get('value')
|
26
|
+
))
|
27
|
+
|
gedcomx/Relationship.py
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from typing import List, Optional
|
3
|
+
|
4
|
+
from .Attribution import Attribution
|
5
|
+
from .Conclusion import ConfidenceLevel
|
6
|
+
from .EvidenceReference import EvidenceReference
|
7
|
+
from .Fact import Fact
|
8
|
+
from .Identifier import Identifier
|
9
|
+
from .Note import Note
|
10
|
+
from .Person import Person
|
11
|
+
from .Serialization import serialize_to_dict
|
12
|
+
from .SourceReference import SourceReference
|
13
|
+
from .URI import URI
|
14
|
+
|
15
|
+
from .Subject import Subject
|
16
|
+
|
17
|
+
class RelationshipType(Enum):
|
18
|
+
Couple = "http://gedcomx.org/Couple"
|
19
|
+
ParentChild = "http://gedcomx.org/ParentChild"
|
20
|
+
|
21
|
+
@property
|
22
|
+
def description(self):
|
23
|
+
descriptions = {
|
24
|
+
RelationshipType.Couple: "A relationship of a pair of persons.",
|
25
|
+
RelationshipType.ParentChild: "A relationship from a parent to a child."
|
26
|
+
}
|
27
|
+
return descriptions.get(self, "No description available.")
|
28
|
+
|
29
|
+
class Relationship(Subject):
|
30
|
+
identifier = 'http://gedcomx.org/v1/Relationship'
|
31
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
32
|
+
|
33
|
+
def __init__(self,
|
34
|
+
id: Optional[str] = None,
|
35
|
+
lang: Optional[str] = None,
|
36
|
+
sources: Optional[List[SourceReference]] = None,
|
37
|
+
analysis: Optional[URI] = None,
|
38
|
+
notes: Optional[List[Note]] = None,
|
39
|
+
confidence: Optional[ConfidenceLevel] = None,
|
40
|
+
attribution: Optional[Attribution] = None,
|
41
|
+
extracted: Optional[bool] = None,
|
42
|
+
evidence: Optional[List[EvidenceReference]] = None,
|
43
|
+
media: Optional[List[SourceReference]] = None,
|
44
|
+
identifiers: Optional[List[Identifier]] = None,
|
45
|
+
type: Optional[RelationshipType] = None,
|
46
|
+
person1: Optional[URI] = None,
|
47
|
+
person2: Optional[URI] = None,
|
48
|
+
facts: Optional[List[Fact]] = None) -> None:
|
49
|
+
|
50
|
+
# Call superclass initializer if required
|
51
|
+
super().__init__(id, lang, sources, analysis, notes, confidence, attribution, extracted, evidence, media, identifiers)
|
52
|
+
|
53
|
+
# Initialize optional parameters with default empty lists if None
|
54
|
+
#self.sources = sources if sources is not None else []
|
55
|
+
#self.notes = notes if notes is not None else []
|
56
|
+
#self.evidence = evidence if evidence is not None else []
|
57
|
+
#self.media = media if media is not None else []
|
58
|
+
#self.identifiers = identifiers if identifiers is not None else []
|
59
|
+
#self.facts = facts if facts is not None else []
|
60
|
+
|
61
|
+
# Initialize other attributes
|
62
|
+
self.type = type
|
63
|
+
self.person1 = person1
|
64
|
+
self.person2 = person2
|
65
|
+
self.facts = facts if facts else None
|
66
|
+
|
67
|
+
@property
|
68
|
+
def _as_dict_(self):
|
69
|
+
return serialize_to_dict(self, {
|
70
|
+
"type": self.type.value if isinstance(self.type, RelationshipType) else self.type,
|
71
|
+
"person1": self.person1._uri,
|
72
|
+
"person2": self.person2._uri,
|
73
|
+
"facts": [fact for fact in self.facts] if self.facts else None
|
74
|
+
})
|
75
|
+
|
76
|
+
@classmethod
|
77
|
+
def _from_json_(cls, data: dict):
|
78
|
+
"""
|
79
|
+
Create a Relationship instance from a JSON-dict (already parsed).
|
80
|
+
"""
|
81
|
+
def ensure_list(value):
|
82
|
+
if value is None:
|
83
|
+
return []
|
84
|
+
if isinstance(value, list):
|
85
|
+
return value
|
86
|
+
return [value] # wrap single item in list
|
87
|
+
|
88
|
+
# Basic scalar fields (adjust as needed)
|
89
|
+
id_ = data.get('id')
|
90
|
+
type_ = data.get('type')
|
91
|
+
extracted = data.get('extracted', None)
|
92
|
+
private = data.get('private', None)
|
93
|
+
|
94
|
+
# Complex singletons (adjust as needed)
|
95
|
+
person1 = URI.from_url(data.get('person1')['resource']) if data.get('person1') else None
|
96
|
+
person2 = URI.from_url(data.get('person2')['resource']) if data.get('person2') else None
|
97
|
+
facts = [Fact._from_json_(o) for o in ensure_list(data.get('facts'))]
|
98
|
+
sources = [SourceReference._from_json_(o) for o in ensure_list(data.get('sources'))]
|
99
|
+
notes = [Note._from_json_(o) for o in ensure_list(data.get('notes'))]
|
100
|
+
|
101
|
+
# Build the instance
|
102
|
+
inst = cls(
|
103
|
+
id = id_,
|
104
|
+
type = type_,
|
105
|
+
extracted = extracted,
|
106
|
+
#private = private, #TODO Has this been added?
|
107
|
+
person1 = person1,
|
108
|
+
person2 = person2,
|
109
|
+
facts = facts,
|
110
|
+
sources = sources,
|
111
|
+
notes = notes
|
112
|
+
)
|
113
|
+
|
114
|
+
return inst
|
115
|
+
|
116
|
+
|
gedcomx/Serialization.py
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
from typing import Dict
|
2
|
+
|
3
|
+
|
4
|
+
def _has_parent_class(obj) -> bool:
|
5
|
+
return hasattr(obj, '__class__') and hasattr(obj.__class__, '__bases__') and len(obj.__class__.__bases__) > 0
|
6
|
+
|
7
|
+
def serialize_to_dict(obj,class_values:Dict,ignore_null=True):
|
8
|
+
def _serialize(value):
|
9
|
+
if isinstance(value, (str, int, float, bool, type(None))):
|
10
|
+
return value
|
11
|
+
elif isinstance(value, dict):
|
12
|
+
return {k: _serialize(v) for k, v in value.items()}
|
13
|
+
elif isinstance(value, (list, tuple, set)):
|
14
|
+
return [_serialize(v) for v in value]
|
15
|
+
elif hasattr(value, "_as_dict_"):
|
16
|
+
return value._as_dict_
|
17
|
+
else:
|
18
|
+
return str(value) # fallback for unknown objects
|
19
|
+
|
20
|
+
values_dict = {}
|
21
|
+
if _has_parent_class(obj):
|
22
|
+
values_dict.update(super(obj.__class__, obj)._as_dict_)
|
23
|
+
if class_values:
|
24
|
+
values_dict.update(class_values)
|
25
|
+
# Serialize and exclude None values
|
26
|
+
|
27
|
+
empty_fields = []
|
28
|
+
for key, value in values_dict.items():
|
29
|
+
if value is not None:
|
30
|
+
values_dict[key] = _serialize(value)
|
31
|
+
else:
|
32
|
+
empty_fields.append(key)
|
33
|
+
|
34
|
+
for key in empty_fields:
|
35
|
+
del values_dict[key]
|
36
|
+
|
37
|
+
return values_dict
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
class SourceCitation:
|
4
|
+
identifier = 'http://gedcomx.org/v1/SourceCitation'
|
5
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
6
|
+
|
7
|
+
def __init__(self, lang: Optional[str], value: str) -> None:
|
8
|
+
self.lang = lang if lang else 'en'
|
9
|
+
self.value = value
|
10
|
+
|
11
|
+
# ...existing code...
|
12
|
+
|
13
|
+
@classmethod
|
14
|
+
def _from_json_(cls, data: dict):
|
15
|
+
"""
|
16
|
+
Create a SourceCitation instance from a JSON-dict (already parsed).
|
17
|
+
"""
|
18
|
+
lang = data.get('lang', 'en')
|
19
|
+
value = data.get('value')
|
20
|
+
return cls(lang=lang, value=value)
|
@@ -0,0 +1,241 @@
|
|
1
|
+
import base64
|
2
|
+
import uuid
|
3
|
+
import warnings
|
4
|
+
|
5
|
+
from enum import Enum
|
6
|
+
from typing import List, Optional, Dict, Any
|
7
|
+
|
8
|
+
from .Agent import Agent
|
9
|
+
from .Attribution import Attribution
|
10
|
+
from .Coverage import Coverage
|
11
|
+
from .Date import Date
|
12
|
+
from .Identifier import Identifier
|
13
|
+
from .Note import Note
|
14
|
+
from .SourceCitation import SourceCitation
|
15
|
+
from .SourceReference import SourceReference
|
16
|
+
from .TextValue import TextValue
|
17
|
+
from .URI import URI
|
18
|
+
|
19
|
+
class ResourceType(Enum):
|
20
|
+
Collection = "http://gedcomx.org/Collection"
|
21
|
+
PhysicalArtifact = "http://gedcomx.org/PhysicalArtifact"
|
22
|
+
DigitalArtifact = "http://gedcomx.org/DigitalArtifact"
|
23
|
+
Record = "http://gedcomx.org/Record"
|
24
|
+
|
25
|
+
@property
|
26
|
+
def description(self):
|
27
|
+
descriptions = {
|
28
|
+
ResourceType.Collection: "A collection of genealogical resources. A collection may contain physical artifacts (such as a collection of books in a library), records (such as the 1940 U.S. Census), or digital artifacts (such as an online genealogical application).",
|
29
|
+
ResourceType.PhysicalArtifact: "A physical artifact, such as a book.",
|
30
|
+
ResourceType.DigitalArtifact: "A digital artifact, such as a digital image of a birth certificate or other record.",
|
31
|
+
ResourceType.Record: "A historical record, such as a census record or a vital record."
|
32
|
+
}
|
33
|
+
return descriptions.get(self, "No description available.")
|
34
|
+
|
35
|
+
class SourceDescription:
|
36
|
+
identifier = "http://gedcomx.org/v1/SourceDescription"
|
37
|
+
|
38
|
+
def __init__(self, id: Optional[str] = None,
|
39
|
+
resourceType: Optional[ResourceType] = None,
|
40
|
+
citations: Optional[List[SourceCitation]] = [],
|
41
|
+
mediaType: Optional[str] = None,
|
42
|
+
about: Optional[URI] = None,
|
43
|
+
mediator: Optional[URI] = None,
|
44
|
+
publisher: Optional[URI] = None,
|
45
|
+
authors: Optional[List[URI]] = [],
|
46
|
+
sources: List[SourceReference] = [], # SourceReference
|
47
|
+
analysis: Optional[URI] = None, # analysis should be of type 'Document', not specified to avoid circular import
|
48
|
+
componentOf: Optional[SourceReference] = None, # SourceReference
|
49
|
+
titles: Optional[List[TextValue]] = [],
|
50
|
+
notes: Optional[List[Note]] = [],
|
51
|
+
attribution: Optional[Attribution] = None,
|
52
|
+
rights: Optional[List[URI]] = [],
|
53
|
+
coverage: Optional[Coverage] = None, # Coverage
|
54
|
+
descriptions: Optional[List[TextValue]] = [],
|
55
|
+
identifiers: Optional[List[Identifier]] = [],
|
56
|
+
created: Optional[Date] = None,
|
57
|
+
modified: Optional[Date] = None,
|
58
|
+
published: Optional[Date] = None,
|
59
|
+
repository: Optional[Agent] = None,
|
60
|
+
max_note_count: int = 20):
|
61
|
+
|
62
|
+
self.id = id if id else SourceDescription.default_id_generator()
|
63
|
+
self.resourceType = resourceType
|
64
|
+
self.citations = citations or []
|
65
|
+
self.mediaType = mediaType
|
66
|
+
self.about = about
|
67
|
+
self.mediator = mediator
|
68
|
+
self.publisher = publisher
|
69
|
+
self.authors = authors or []
|
70
|
+
self.source_refs = sources or []
|
71
|
+
self.analysis = analysis
|
72
|
+
self.componentOf = componentOf
|
73
|
+
self.titles = titles or []
|
74
|
+
self.notes = notes or []
|
75
|
+
self.attribution = attribution
|
76
|
+
self.rights = rights or []
|
77
|
+
self.coverage = coverage or []
|
78
|
+
self.descriptions = descriptions or []
|
79
|
+
self.identifiers = identifiers or []
|
80
|
+
self.created = created
|
81
|
+
self.modified = modified
|
82
|
+
self.published = published
|
83
|
+
self.repository = repository
|
84
|
+
self.max_note_count = max_note_count
|
85
|
+
|
86
|
+
self._uri = URI(fragment=id)
|
87
|
+
|
88
|
+
def add_description(self, desccription_to_add: TextValue):
|
89
|
+
if desccription_to_add and isinstance(desccription_to_add,TextValue):
|
90
|
+
for current_description in self.descriptions:
|
91
|
+
if desccription_to_add == current_description:
|
92
|
+
return
|
93
|
+
self.descriptions.append(desccription_to_add)
|
94
|
+
|
95
|
+
def add_identifier(self, identifier_to_add: Identifier):
|
96
|
+
if identifier_to_add and isinstance(identifier_to_add,Identifier):
|
97
|
+
for current_identifier in self.identifiers:
|
98
|
+
if identifier_to_add == current_identifier:
|
99
|
+
return
|
100
|
+
self.identifiers.append(identifier_to_add)
|
101
|
+
|
102
|
+
def add_note(self,note_to_add: Note):
|
103
|
+
if len(self.notes) >= self.max_note_count:
|
104
|
+
warnings.warn(f"Max not count of {self.max_note_count} reached for id: {self.id}")
|
105
|
+
return False
|
106
|
+
if note_to_add and isinstance(note_to_add,Note):
|
107
|
+
for existing in self.notes:
|
108
|
+
if note_to_add == existing:
|
109
|
+
return False
|
110
|
+
self.notes.append(note_to_add)
|
111
|
+
|
112
|
+
def add_source(self, source_to_add: object):
|
113
|
+
#from .SourceReference import SourceReference
|
114
|
+
if source_to_add and isinstance(object,SourceReference):
|
115
|
+
for current_source in self.sources:
|
116
|
+
if current_source == source_to_add:
|
117
|
+
return
|
118
|
+
self.sources.append(source_to_add)
|
119
|
+
|
120
|
+
def add_title(self, title_to_add: TextValue):
|
121
|
+
if isinstance(title_to_add,str): title_to_add = TextValue(value=title_to_add)
|
122
|
+
if title_to_add and isinstance(title_to_add, TextValue):
|
123
|
+
for current_title in self.titles:
|
124
|
+
if title_to_add == current_title:
|
125
|
+
return False
|
126
|
+
self.titles.append(title_to_add)
|
127
|
+
else:
|
128
|
+
raise ValueError(f"Cannot add title of type {type(title_to_add)}")
|
129
|
+
|
130
|
+
@staticmethod
|
131
|
+
def default_id_generator():
|
132
|
+
# Generate a standard UUID
|
133
|
+
standard_uuid = uuid.uuid4()
|
134
|
+
# Convert UUID to bytes
|
135
|
+
uuid_bytes = standard_uuid.bytes
|
136
|
+
# Encode bytes to a Base64 string
|
137
|
+
short_uuid = base64.urlsafe_b64encode(uuid_bytes).rstrip(b'=').decode('utf-8')
|
138
|
+
return 'SD-' + str(short_uuid)
|
139
|
+
|
140
|
+
@property
|
141
|
+
def _as_dict_(self) -> Dict[str, Any]:
|
142
|
+
def _serialize(val: Any) -> Any:
|
143
|
+
if hasattr(val, '_as_dict_'):
|
144
|
+
return val._as_dict_
|
145
|
+
if isinstance(val, URI):
|
146
|
+
return val._prop_dict()
|
147
|
+
if isinstance(val, Enum):
|
148
|
+
return val.value
|
149
|
+
if isinstance(val, (str, int, float, bool)) or val is None:
|
150
|
+
return val
|
151
|
+
if isinstance(val, list):
|
152
|
+
return [_serialize(v) for v in val]
|
153
|
+
if isinstance(val, dict):
|
154
|
+
return {k: _serialize(v) for k, v in val.items()}
|
155
|
+
return str(val)
|
156
|
+
|
157
|
+
data = {
|
158
|
+
'id': self.id,
|
159
|
+
'resourceType': self.resourceType.value if self.resourceType else None,
|
160
|
+
'citations': [c._as_dict_ for c in self.citations] or None,
|
161
|
+
'mediaType': self.mediaType,
|
162
|
+
'about': self.about._prop_dict() if self.about else None,
|
163
|
+
'mediator': self.mediator._prop_dict() if self.mediator else None,
|
164
|
+
'publisher': self.publisher._prop_dict() if self.publisher else None,
|
165
|
+
'authors': [a._prop_dict() for a in self.authors] or None,
|
166
|
+
'sources': [s._as_dict_ for s in self.sources] or None,
|
167
|
+
'analysis': self.analysis._prop_dict() if self.analysis else None,
|
168
|
+
'componentOf': self.componentOf._as_dict_ if self.componentOf else None,
|
169
|
+
'titles': [t._prop_dict() for t in self.titles] or None,
|
170
|
+
'notes': [n._prop_dict() for n in self.notes] or None,
|
171
|
+
'attribution': self.attribution._as_dict_ if self.attribution else None,
|
172
|
+
'rights': [r._prop_dict() for r in self.rights] or None,
|
173
|
+
'coverage': self.coverage._as_dict_ if self.coverage else None,
|
174
|
+
'descriptions': [d._prop_dict() for d in self.descriptions] or None,
|
175
|
+
'identifiers': [i._as_dict_ for i in self.identifiers] or None,
|
176
|
+
'created': self.created._prop_dict() if self.created else None,
|
177
|
+
'modified': self.modified._prop_dict() if self.modified else None,
|
178
|
+
'published': self.published._prop_dict() if self.published else None,
|
179
|
+
'repository': self.repository._prop_dict() if self.repository else None
|
180
|
+
}
|
181
|
+
# Remove None values
|
182
|
+
return {k: v for k, v in data.items() if v is not None}
|
183
|
+
|
184
|
+
@classmethod
|
185
|
+
def _from_json_(cls, data: Dict[str, Any]) -> 'SourceDescription':
|
186
|
+
print(data,type(data))
|
187
|
+
# TODO Hande Resource/URI
|
188
|
+
|
189
|
+
# Basic fields
|
190
|
+
id_ = data.get('id')
|
191
|
+
rt = ResourceType(data['resourceType']) if data.get('resourceType') else None
|
192
|
+
|
193
|
+
# Sub-objects
|
194
|
+
citations = [SourceCitation._from_json_(c) for c in data.get('citations', [])]
|
195
|
+
about = URI._from_json_(data['about']) if data.get('about') else None
|
196
|
+
mediator = URI._from_json_(data['mediator']) if data.get('mediator') else None
|
197
|
+
publisher = Agent._from_json_(data['publisher']) if data.get('publisher') else None
|
198
|
+
authors = [URI._from_json_(a) for a in data.get('authors', [])]
|
199
|
+
sources = [SourceReference._from_json_(s) for s in data.get('sources', [])]
|
200
|
+
analysis = URI._from_json_(data['analysis']) if data.get('analysis') else None
|
201
|
+
component_of = SourceReference._from_json_(data['componentOf']) if data.get('componentOf') else None
|
202
|
+
titles = [TextValue._from_json_(t) for t in data.get('titles', [])]
|
203
|
+
notes = [Note._from_json_(n) for n in data.get('notes', [])]
|
204
|
+
attribution = Attribution._from_json_(data['attribution']) if data.get('attribution') else None
|
205
|
+
rights = [URI._from_json_(r) for r in data.get('rights', [])]
|
206
|
+
coverage = [Coverage._from_json_(cvg) for cvg in data.get('coverage',[])]
|
207
|
+
descriptions = [TextValue._from_json_(d) for d in data.get('descriptions', [])]
|
208
|
+
identifiers = [Identifier._from_json_(i) for i in data.get('identifiers', [])]
|
209
|
+
created = Date._from_json_(data['created']) if data.get('created') else None
|
210
|
+
modified = Date._from_json_(data['modified']) if data.get('modified') else None
|
211
|
+
published = Date._from_json_(data['published']) if data.get('published') else None
|
212
|
+
repository = Agent._from_json_(data['repository']) if data.get('repository') else None
|
213
|
+
|
214
|
+
return cls(
|
215
|
+
id=id_, resourceType=rt, citations=citations,
|
216
|
+
mediaType=data.get('mediaType'), about=about,
|
217
|
+
mediator=mediator, publisher=publisher,
|
218
|
+
authors=authors, sources=sources,
|
219
|
+
analysis=analysis, componentOf=component_of,
|
220
|
+
titles=titles, notes=notes, attribution=attribution,
|
221
|
+
rights=rights, coverage=coverage,
|
222
|
+
descriptions=descriptions, identifiers=identifiers,
|
223
|
+
created=created, modified=modified,
|
224
|
+
published=published, repository=repository
|
225
|
+
)
|
226
|
+
|
227
|
+
@property
|
228
|
+
def publisher(self) -> URI:
|
229
|
+
if not self._publisher is None or isinstance(self._publisher,URI): assert False
|
230
|
+
return self._publisher
|
231
|
+
|
232
|
+
@publisher.setter
|
233
|
+
def publisher(self, value: URI | Agent):
|
234
|
+
if value is None:
|
235
|
+
self._publisher = None
|
236
|
+
elif isinstance(value,URI):
|
237
|
+
assert False
|
238
|
+
elif isinstance(value,Agent):
|
239
|
+
self._publisher = value._uri
|
240
|
+
else:
|
241
|
+
raise ValueError(f"'publisher' must be of type 'URI' or 'Agent', type: {type(value)} was provided")
|