gedcom-x 0.5.1__py3-none-any.whl → 0.5.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.1.dist-info → gedcom_x-0.5.5.dist-info}/METADATA +1 -1
- gedcom_x-0.5.5.dist-info/RECORD +43 -0
- gedcomx/Address.py +42 -11
- gedcomx/Agent.py +136 -23
- gedcomx/Attribution.py +39 -91
- gedcomx/Conclusion.py +132 -53
- gedcomx/Coverage.py +10 -0
- gedcomx/Date.py +47 -11
- gedcomx/Document.py +43 -12
- gedcomx/Event.py +24 -5
- gedcomx/EvidenceReference.py +2 -2
- gedcomx/Exceptions.py +16 -0
- gedcomx/Fact.py +73 -50
- gedcomx/Gedcom.py +40 -333
- gedcomx/Gedcom5x.py +558 -0
- gedcomx/GedcomX.py +439 -194
- gedcomx/Gender.py +27 -8
- gedcomx/Group.py +3 -3
- gedcomx/Identifier.py +192 -55
- gedcomx/Logging.py +19 -0
- gedcomx/Mutations.py +228 -0
- gedcomx/Name.py +73 -38
- gedcomx/Note.py +5 -4
- gedcomx/OnlineAccount.py +2 -2
- gedcomx/Person.py +106 -92
- gedcomx/PlaceDescription.py +39 -16
- gedcomx/PlaceReference.py +14 -15
- gedcomx/Relationship.py +35 -56
- gedcomx/Resource.py +75 -0
- gedcomx/Serialization.py +394 -30
- gedcomx/SourceCitation.py +6 -1
- gedcomx/SourceDescription.py +89 -75
- gedcomx/SourceReference.py +33 -88
- gedcomx/Subject.py +12 -10
- gedcomx/TextValue.py +2 -1
- gedcomx/Translation.py +219 -0
- gedcomx/URI.py +96 -61
- gedcomx/Zip.py +1 -0
- gedcomx/__init__.py +11 -3
- gedcom_x-0.5.1.dist-info/RECORD +0 -37
- gedcomx/_Resource.py +0 -11
- {gedcom_x-0.5.1.dist-info → gedcom_x-0.5.5.dist-info}/WHEEL +0 -0
- {gedcom_x-0.5.1.dist-info → gedcom_x-0.5.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
gedcomx/Address.py,sha256=FDBic6oQB30eKMWM7-6_YVPHaJdPhziU5LybwE5TY5Q,4855
|
2
|
+
gedcomx/Agent.py,sha256=C-tzfqcjuU22iJ2LjoatKdCbI_i0xskpmZsuj58K6WY,8555
|
3
|
+
gedcomx/Attribution.py,sha256=2bcl2UNsMPn10kDrA080qFRzxK-KYqZBgmPGNBZ2M4Y,2608
|
4
|
+
gedcomx/Conclusion.py,sha256=t8n8FuWwzinFTPHp9D2Umu93-4A12I9L5fCx510mfqA,8414
|
5
|
+
gedcomx/Coverage.py,sha256=BVlB3kWDoOP2j86j67hNJLC4LqoLwqs3N93z0ZbXYTw,1227
|
6
|
+
gedcomx/Date.py,sha256=cv2UeyOcTHuH2CVHq9EjTnj3FR-r4_OVuPiuc8sbOPc,2130
|
7
|
+
gedcomx/Document.py,sha256=32nWfDNVWkPK2_I0-hhcNQkrjH3ssdbtw-II3QMMelw,2957
|
8
|
+
gedcomx/Event.py,sha256=BHhmO2UlxbkSzB5htdMRf2h-WNuJQsWfrSC8tNGQ6Mg,10375
|
9
|
+
gedcomx/EvidenceReference.py,sha256=WXZpmcKzwb3lYQmGVf-TY2IsbNG3fIInPY1khRjtOSg,348
|
10
|
+
gedcomx/Exceptions.py,sha256=0OdPM3euhBMgX8o61ZwPuKeN8zPuSuuDcSBFflVGFqk,587
|
11
|
+
gedcomx/Fact.py,sha256=-Zz321xeFd93riaX4C4i7gIPwpqdArAYZDlWRoXA1Uk,24444
|
12
|
+
gedcomx/Gedcom.py,sha256=l_BuLBynQacDtpLjhs2Afrabfiqt2Opoo_5_7myI7Z4,1709
|
13
|
+
gedcomx/Gedcom5x.py,sha256=qkRmOI99N3SJEtxuzhL_IiICQIm5OyJwBkLEQIkNjUA,21223
|
14
|
+
gedcomx/GedcomX.py,sha256=u95GeBQGRgyEp_wBl7y-RjPnhF8wTciH8Wlief99g_8,63258
|
15
|
+
gedcomx/Gender.py,sha256=AV125vECC5JSgvNJRmotjDEt-A3cFzth6pcSLFwJBEE,2328
|
16
|
+
gedcomx/Group.py,sha256=VNI_cI_-YnJ9cHzwMmHD8qwDNMe89kEocPuQ67rwStA,1606
|
17
|
+
gedcomx/Identifier.py,sha256=MePkMgx0o2wzzSPGv4AJ6JklIWniEgl8XZSWKTLHXhs,8515
|
18
|
+
gedcomx/Logging.py,sha256=vBDOjawVXc4tCge1laYjy6_2Ves-fnGzG0m6NnLZejE,624
|
19
|
+
gedcomx/Mutations.py,sha256=idhQsnikCTovmNEGAhDsOe97V0L9AnFTRaufzUPm64w,6298
|
20
|
+
gedcomx/Name.py,sha256=en_VkGjpZPP_Dbl9HSq2h2JCtLS2NMzmLvis5RdBPeM,12913
|
21
|
+
gedcomx/Note.py,sha256=cvV4-fCZ0oh2zXfzD-YYoIM_WTox-fk2_bfl3i4CoNc,2251
|
22
|
+
gedcomx/OnlineAccount.py,sha256=P24o98IXo_8XQoICYZPgALjdzS0q8t2l4DU3Od9KxyI,291
|
23
|
+
gedcomx/Person.py,sha256=LyGPCZh6rZU_dE3GCJE92x1lLk41c_Edr_Po9smhPLc,7321
|
24
|
+
gedcomx/PlaceDescription.py,sha256=TRHIkDiErHa_mlx_x8gYCF6UnQ-XgT08uSmYmFNa4u0,3255
|
25
|
+
gedcomx/PlaceReference.py,sha256=3NyEYq0FaMI8m3l4H6-Ov-n9NUq_m751iYVxofqtv30,870
|
26
|
+
gedcomx/Qualifier.py,sha256=mZ_GWT3gca8g9nWidlXIRTN5dEtf_rmnLHYl1jJkQYs,728
|
27
|
+
gedcomx/Relationship.py,sha256=oyT501vR5jvWxqEYy3KvW9egD4CPL5JaAYWJmlNy9Ig,3599
|
28
|
+
gedcomx/Resource.py,sha256=bZ2dV-OdpvmDRCppyfHJXiarIKL7-OcofwvYRnpOJW0,2324
|
29
|
+
gedcomx/Serialization.py,sha256=ubtmrvi-nKmVUCK1XGwuLijrPMggNJe--kkCIC-87Ds,18580
|
30
|
+
gedcomx/SourceCitation.py,sha256=aW-lEb7bT9QU49GiBjJppFMBvtisR6fhVVuXjr5y4vQ,742
|
31
|
+
gedcomx/SourceDescription.py,sha256=zOkXo-fy-uCl_EGU8B-c6pzhlMk3nYNHn13ln1AkYk0,11914
|
32
|
+
gedcomx/SourceReference.py,sha256=swVzZ5A0jt5yFYJNJvMnQZtb7d-2YEAQPxp2a4lEY1k,5071
|
33
|
+
gedcomx/Subject.py,sha256=znee3SxYKk99JLP6KmZHkXs5hIOGu_jeLwxagENNfXs,3298
|
34
|
+
gedcomx/TextValue.py,sha256=6B0wMxL0nigFNzhXZDhbTONvFGbnM2t2NcDZiZuu4Zw,1112
|
35
|
+
gedcomx/TopLevelTypeCollection.py,sha256=nvTO6GwFwEZk9jX4fVqhy75ygsshomNb20tnlExKqyY,1495
|
36
|
+
gedcomx/Translation.py,sha256=NWa1NtTOC_VgQ-EGwWG06zUpddRxdKFSLPP6066JFaA,12485
|
37
|
+
gedcomx/URI.py,sha256=S2pFsu_VyKgOsRdHIj8pjnh6_tdA3OjAYiIugoEd70k,4271
|
38
|
+
gedcomx/Zip.py,sha256=lBxcv-Vip45884EHj56wZJJ5I36Q38UuHUidDxQBoS8,14
|
39
|
+
gedcomx/__init__.py,sha256=Et3E0lBdtrMjyposrQ0MeoaRilg0ShSDqXg0y15pPf4,1616
|
40
|
+
gedcom_x-0.5.5.dist-info/METADATA,sha256=cTARXUhB_6HIix2ih1I9ThdwN1OYGn4gQA0jF9pKepM,633
|
41
|
+
gedcom_x-0.5.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
42
|
+
gedcom_x-0.5.5.dist-info/top_level.txt,sha256=smVBF4nxSU-mzCd6idtRYTbYjPICMMi8pTqewEmqF8Y,8
|
43
|
+
gedcom_x-0.5.5.dist-info/RECORD,,
|
gedcomx/Address.py
CHANGED
@@ -1,7 +1,28 @@
|
|
1
1
|
from typing import Optional
|
2
2
|
import json
|
3
3
|
|
4
|
+
from .Serialization import Serialization
|
5
|
+
|
4
6
|
class Address:
|
7
|
+
"""A GedcomX Address Data Type
|
8
|
+
A GedcomX Address Data Type.
|
9
|
+
|
10
|
+
Represents a postal address according to the GedcomX conceptual model.
|
11
|
+
|
12
|
+
Args:
|
13
|
+
value (str, optional): A complete address as a single string.
|
14
|
+
city (str, optional): Name of the city or town.
|
15
|
+
country (str, optional): Name of the country.
|
16
|
+
postalCode (str, optional): Postal or ZIP code.
|
17
|
+
stateOrProvince (str, optional): Name of the state, province, or region.
|
18
|
+
street (str, optional): First street address line.
|
19
|
+
street2 (str, optional): Second street address line.
|
20
|
+
street3 (str, optional): Third street address line.
|
21
|
+
street4 (str, optional): Fourth street address line.
|
22
|
+
street5 (str, optional): Fifth street address line.
|
23
|
+
street6 (str, optional): Sixth street address line.
|
24
|
+
"""
|
25
|
+
|
5
26
|
identifier = "http://gedcomx.org/v1/Address"
|
6
27
|
version = 'http://gedcomx.org/conceptual-model/v1'
|
7
28
|
|
@@ -30,17 +51,26 @@ class Address:
|
|
30
51
|
self.street6 = street6
|
31
52
|
|
32
53
|
@property
|
33
|
-
def value(self) ->
|
34
|
-
if self._value:
|
35
|
-
return self._value
|
54
|
+
def value(self) -> str:
|
36
55
|
return ', '.join(filter(None, [
|
37
|
-
self.
|
38
|
-
self.
|
39
|
-
self.
|
40
|
-
self.
|
56
|
+
self.street, self.street2, self.street3,
|
57
|
+
self.street4, self.street5, self.street6,
|
58
|
+
self.city, self.stateOrProvince,
|
59
|
+
self.postalCode, self.country
|
41
60
|
]))
|
42
61
|
|
43
|
-
|
62
|
+
@value.setter
|
63
|
+
def value(self,value: str):
|
64
|
+
self._value = value
|
65
|
+
return
|
66
|
+
raise NotImplementedError("Parsing of a full address is not implimented.")
|
67
|
+
|
68
|
+
def _append(self,value):
|
69
|
+
if self._value:
|
70
|
+
self._value = self._value + ' ' + value
|
71
|
+
else:
|
72
|
+
self._value = value
|
73
|
+
|
44
74
|
def __eq__(self, other):
|
45
75
|
if not isinstance(other, self.__class__):
|
46
76
|
return False
|
@@ -82,9 +112,8 @@ class Address:
|
|
82
112
|
return ', '.join(filtered_parts)
|
83
113
|
|
84
114
|
@property
|
85
|
-
def
|
86
|
-
|
87
|
-
#"value": self._value if self._value else None,
|
115
|
+
def _as_dict_(self):
|
116
|
+
type_as_dict = {
|
88
117
|
"city": self.city if self.city else None,
|
89
118
|
"country": self.country if self.country else None,
|
90
119
|
"postalCode": self.postalCode if self.postalCode else None,
|
@@ -97,4 +126,6 @@ class Address:
|
|
97
126
|
"street6": self.street6 if self.street6 else None
|
98
127
|
}
|
99
128
|
|
129
|
+
return Serialization.serialize_dict(type_as_dict)
|
130
|
+
|
100
131
|
|
gedcomx/Agent.py
CHANGED
@@ -4,12 +4,49 @@ import uuid
|
|
4
4
|
from typing import List, Optional
|
5
5
|
|
6
6
|
from .Address import Address
|
7
|
-
from .
|
7
|
+
#from .Attribution import Attribution
|
8
|
+
from .Identifier import Identifier, IdentifierList
|
9
|
+
|
8
10
|
from .OnlineAccount import OnlineAccount
|
9
11
|
from .TextValue import TextValue
|
12
|
+
from .Resource import Resource
|
10
13
|
from .URI import URI
|
14
|
+
from .Serialization import Serialization
|
15
|
+
|
11
16
|
|
12
17
|
class Agent:
|
18
|
+
"""A GedcomX Agent Data Type.
|
19
|
+
|
20
|
+
Represents an agent entity such as a person, organization, or software
|
21
|
+
responsible for creating or modifying genealogical data, as defined in
|
22
|
+
the GedcomX conceptual model.
|
23
|
+
|
24
|
+
Static Methods:
|
25
|
+
default_id_generator(): Generates a short, URL-safe Base64-encoded UUID
|
26
|
+
for use as a default agent identifier.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
id (str, optional): A unique identifier for this agent. If not provided,
|
30
|
+
one may be generated automatically using `default_id_generator()`.
|
31
|
+
identifiers (IdentifierList, optional): A list of alternate identifiers for this agent.
|
32
|
+
names (List[TextValue], optional): Names associated with the agent. Defaults to an empty list.
|
33
|
+
homepage (URI, optional): A link to the agent's homepage or primary website.
|
34
|
+
openid (URI, optional): The OpenID identifier for the agent.
|
35
|
+
accounts (List[OnlineAccount], optional): Online accounts associated with the agent.
|
36
|
+
Defaults to an empty list.
|
37
|
+
emails (List[URI], optional): Email addresses associated with the agent.
|
38
|
+
Defaults to an empty list.
|
39
|
+
phones (List[Resource], optional): Phone numbers associated with the agent.
|
40
|
+
Defaults to an empty list.
|
41
|
+
addresses (List[Address], optional): Postal addresses associated with the agent.
|
42
|
+
Defaults to an empty list.
|
43
|
+
person (Person, optional): A reference to the person represented
|
44
|
+
by the agent. Accepts a `Person` object or a `Resource` reference.
|
45
|
+
Declared as `object` to avoid circular imports.
|
46
|
+
attribution (Attribution, optional): Attribution information related to the agent.
|
47
|
+
uri (Resource, optional): A URI reference for this agent.
|
48
|
+
"""
|
49
|
+
|
13
50
|
@staticmethod
|
14
51
|
def default_id_generator():
|
15
52
|
# Generate a standard UUID
|
@@ -21,7 +58,7 @@ class Agent:
|
|
21
58
|
return short_uuid
|
22
59
|
|
23
60
|
def __init__(self, id: Optional[str] = None,
|
24
|
-
identifiers: Optional[
|
61
|
+
identifiers: Optional[IdentifierList] = None,
|
25
62
|
names: Optional[List[TextValue]] = [],
|
26
63
|
homepage: Optional[URI] = None,
|
27
64
|
openid: Optional[URI] = None,
|
@@ -29,25 +66,33 @@ class Agent:
|
|
29
66
|
emails: Optional[List[URI]] = [],
|
30
67
|
phones: Optional[List[URI]] = [],
|
31
68
|
addresses: Optional[List[Address]] = [],
|
32
|
-
person: Optional[object] | Optional[
|
33
|
-
|
69
|
+
person: Optional[object] | Optional[Resource] = None, # should be of Type 'Person', 'object' to avoid circular imports
|
70
|
+
#xnotes: Optional[List[Note]] = None,
|
71
|
+
attribution: Optional[object] = None, # Added for compatibility with GEDCOM5/7 Imports
|
72
|
+
uri: Optional[URI | Resource] = None):
|
34
73
|
|
35
74
|
self._id_generator = Agent.default_id_generator
|
36
75
|
|
37
|
-
self.id = id if id else self._id_generator()
|
38
|
-
self.identifiers = identifiers
|
39
|
-
self.names = names
|
40
|
-
self.homepage = homepage
|
41
|
-
self.openid = openid
|
42
|
-
self.accounts = accounts
|
43
|
-
self.emails = emails
|
44
|
-
self.phones = phones
|
45
|
-
self.addresses = addresses
|
46
|
-
|
47
|
-
self.
|
48
|
-
|
76
|
+
self.id = id if id else None #TODO self._id_generator()
|
77
|
+
self.identifiers = identifiers or IdentifierList()
|
78
|
+
self.names = names if names else []
|
79
|
+
self.homepage = homepage or None
|
80
|
+
self.openid = openid or None
|
81
|
+
self.accounts = accounts or []
|
82
|
+
self.emails = emails or []
|
83
|
+
self.phones = phones or []
|
84
|
+
self.addresses = addresses if addresses else []
|
85
|
+
self.xnotes = []
|
86
|
+
self.attribution = attribution or None
|
87
|
+
self.uri = URI(fragment=self.id)
|
88
|
+
|
49
89
|
def _append_to_name(self, text_to_append: str):
|
50
|
-
self.names[0]
|
90
|
+
if self.names and self.names[0] and self.names[0].value:
|
91
|
+
self.names[0].value = self.names[0].value + text_to_append
|
92
|
+
elif self.names and self.names[0]:
|
93
|
+
self.names[0].value = text_to_append
|
94
|
+
else:
|
95
|
+
raise ValueError() #TODO
|
51
96
|
|
52
97
|
def add_address(self, address_to_add: Address):
|
53
98
|
if address_to_add and isinstance(address_to_add, Address):
|
@@ -68,16 +113,84 @@ class Agent:
|
|
68
113
|
else:
|
69
114
|
raise ValueError(f'name must be of type str or TextValue, recived {type(name_to_add)}')
|
70
115
|
|
116
|
+
def add_note(self, note_to_add: 'Note'):
|
117
|
+
from .Note import Note
|
118
|
+
if note_to_add and isinstance(note_to_add,Note):
|
119
|
+
self.xnotes.append(note_to_add)
|
120
|
+
else:
|
121
|
+
raise ValueError(f'note must be of type Note, recived {type(note_to_add)}')
|
122
|
+
|
123
|
+
def add_identifier(self, identifier_to_add: Identifier):
|
124
|
+
self.identifiers.append(identifier_to_add)
|
125
|
+
|
71
126
|
@property
|
72
|
-
def
|
73
|
-
|
127
|
+
def _as_dict_(self):
|
128
|
+
type_as_dict = {
|
74
129
|
"id": self.id if self.id else None,
|
75
|
-
"identifiers":
|
76
|
-
"names": [name.
|
130
|
+
"identifiers": self.identifiers._as_dict_ if self.identifiers else None,
|
131
|
+
"names": [name._as_dict_ for name in self.names],
|
77
132
|
"homepage": self.homepage if self.homepage else None,
|
78
133
|
"openid": self.openid if self.openid else None,
|
79
134
|
"accounts": self.accounts if self.accounts else None,
|
80
135
|
"emails": self.emails if self.emails else None,
|
81
136
|
"phones": self.phones if self.phones else None,
|
82
|
-
"addresses": [address.
|
83
|
-
|
137
|
+
"addresses": [address._as_dict_ for address in self.addresses],
|
138
|
+
"notes": [note._as_dict_ for note in self.xnotes]
|
139
|
+
}
|
140
|
+
return Serialization.serialize_dict(type_as_dict)
|
141
|
+
|
142
|
+
@classmethod
|
143
|
+
def _from_json_(cls, data: dict):
|
144
|
+
"""
|
145
|
+
Create a Person instance from a JSON-dict (already parsed).
|
146
|
+
"""
|
147
|
+
type_as_dict = Serialization.get_class_fields('Agent')
|
148
|
+
return Serialization.deserialize(data, type_as_dict)
|
149
|
+
|
150
|
+
def __str__(self):
|
151
|
+
"""
|
152
|
+
Return a human-readable string representation of the Agent.
|
153
|
+
|
154
|
+
Returns:
|
155
|
+
str: A concise description including ID, primary name (if any), and type of agent.
|
156
|
+
"""
|
157
|
+
primary_name = self.names[0].value if self.names else "Unnamed Agent"
|
158
|
+
homepage_str = f", homepage={self.homepage}" if self.homepage else ""
|
159
|
+
return f"Agent(id={self.id}, name='{primary_name}'{homepage_str})"
|
160
|
+
|
161
|
+
def __eq__(self, other):
|
162
|
+
"""
|
163
|
+
Determine equality between two Agent instances.
|
164
|
+
|
165
|
+
Args:
|
166
|
+
other (Agent): The other object to compare against.
|
167
|
+
|
168
|
+
Returns:
|
169
|
+
bool: True if both objects represent the same agent, False otherwise.
|
170
|
+
"""
|
171
|
+
'''
|
172
|
+
if not isinstance(other, Agent):
|
173
|
+
return NotImplemented
|
174
|
+
|
175
|
+
return (
|
176
|
+
self.id == other.id and
|
177
|
+
self.identifiers == other.identifiers and
|
178
|
+
self.names == other.names and
|
179
|
+
self.homepage == other.homepage and
|
180
|
+
self.openid == other.openid and
|
181
|
+
self.accounts == other.accounts and
|
182
|
+
self.emails == other.emails and
|
183
|
+
self.phones == other.phones and
|
184
|
+
self.addresses == other.addresses and
|
185
|
+
self.person == other.person and
|
186
|
+
self.attribution == other.attribution and
|
187
|
+
self.uri == other.uri
|
188
|
+
)
|
189
|
+
'''
|
190
|
+
|
191
|
+
self_names = {n.value for n in self.names if hasattr(n, "value")}
|
192
|
+
other_names = {n.value for n in other.names if hasattr(n, "value")}
|
193
|
+
if self_names & other_names: # intersection not empty
|
194
|
+
return True
|
195
|
+
|
196
|
+
return False
|
gedcomx/Attribution.py
CHANGED
@@ -1,67 +1,52 @@
|
|
1
|
+
|
1
2
|
from datetime import datetime
|
2
3
|
from typing import Optional, Dict, Any
|
3
4
|
|
4
|
-
from .
|
5
|
+
from .Agent import Agent
|
6
|
+
from .Resource import Resource, get_resource_as_dict
|
7
|
+
from .Serialization import Serialization
|
5
8
|
|
6
9
|
class Attribution:
|
7
|
-
|
8
|
-
version = 'http://gedcomx.org/conceptual-model/v1'
|
10
|
+
"""Attribution Information for a Genealogy, Conclusion, Subject and child classes
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
Args:
|
13
|
+
contributor (Agent, optional): Contributor to object being attributed.
|
14
|
+
modified (timestamp, optional): timestamp for when this record was modified.
|
15
|
+
changeMessage (str, optional): Birth date (YYYY-MM-DD).
|
16
|
+
creator (Agent, optional): Creator of object being attributed.
|
17
|
+
created (timestamp, optional): timestamp for when this record was created
|
18
|
+
|
19
|
+
Raises:
|
15
20
|
|
21
|
+
"""
|
22
|
+
identifier = 'http://gedcomx.org/v1/Attribution'
|
23
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
16
24
|
|
17
|
-
|
18
|
-
|
25
|
+
def __init__(self,contributor: Optional[Agent | Resource] = None,
|
26
|
+
modified: Optional[datetime] = None,
|
27
|
+
changeMessage: Optional[str] = None,
|
28
|
+
creator: Optional[Agent | Resource] = None,
|
29
|
+
created: Optional[datetime] = None) -> None:
|
30
|
+
|
31
|
+
self.contributor = contributor
|
19
32
|
self.modified = modified
|
20
33
|
self.changeMessage = changeMessage
|
21
34
|
self.creator = creator
|
22
35
|
self.created = created
|
23
|
-
|
24
|
-
|
25
|
-
if isinstance(contributor,URI):
|
26
|
-
# TODO DEAL WITH URI <------------------------------------------------------------------------------------------------------------------
|
27
|
-
self._contributor_object = contributor
|
28
|
-
elif isinstance(contributor,Agent):
|
29
|
-
self._contributor_object = contributor
|
30
|
-
if hasattr(contributor,'_uri'):
|
31
|
-
self.contributor = contributor._uri
|
32
|
-
else:
|
33
|
-
assert False
|
34
|
-
self.description = URI(object=description)
|
35
|
-
description._uri = self.description
|
36
|
-
description._object = description
|
37
|
-
else:
|
38
|
-
raise ValueError(f"'description' must be of type 'SourceDescription' or 'URI', type: {type(contributor)} was provided, with value: {contributor}")
|
39
|
-
|
36
|
+
|
40
37
|
@property
|
41
38
|
def _as_dict_(self) -> Dict[str, Any]:
|
42
39
|
"""
|
43
40
|
Serialize Attribution to a JSON-ready dict, skipping None values.
|
44
41
|
"""
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
if self.
|
51
|
-
|
52
|
-
|
53
|
-
None)
|
54
|
-
if self.created:
|
55
|
-
data['created'] = _fmt_dt(self.created)
|
56
|
-
if self.creator:
|
57
|
-
data['creator'] = (self.creator._prop_dict()
|
58
|
-
if hasattr(self.creator, '_prop_dict') else
|
59
|
-
self.creator._prop_dict())
|
60
|
-
if self.modified:
|
61
|
-
data['modified'] = _fmt_dt(self.modified)
|
62
|
-
if self.changeMessage is not None:
|
63
|
-
data['changeMessage'] = self.changeMessage
|
64
|
-
return data
|
42
|
+
type_as_dict: Dict[str, Any] = {}
|
43
|
+
type_as_dict['contributor'] = get_resource_as_dict(self.contributor)
|
44
|
+
type_as_dict['modified'] = self.modified if self.modified else None
|
45
|
+
type_as_dict['changeMessage'] = self.changeMessage if self.changeMessage else None
|
46
|
+
type_as_dict['creator'] = get_resource_as_dict(self.creator)
|
47
|
+
type_as_dict['created'] = self.created if self.created else None
|
48
|
+
|
49
|
+
return Serialization.serialize_dict(type_as_dict)
|
65
50
|
|
66
51
|
@classmethod
|
67
52
|
def _from_json_(cls, data: Dict[str, Any]) -> 'Attribution':
|
@@ -70,47 +55,10 @@ class Attribution:
|
|
70
55
|
Handles 'created' and 'modified' as ISO strings or epoch ms ints.
|
71
56
|
"""
|
72
57
|
# contributor
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
# creator
|
82
|
-
creat = None
|
83
|
-
if 'creator' in data:
|
84
|
-
raw = data['creator']
|
85
|
-
if isinstance(raw, dict):
|
86
|
-
creat = URI._from_json_(raw)
|
87
|
-
elif isinstance(raw, str):
|
88
|
-
creat = URI(uri=raw)
|
89
|
-
|
90
|
-
# parse created date
|
91
|
-
raw_created = data.get('created')
|
92
|
-
if isinstance(raw_created, (int, float)):
|
93
|
-
created_dt = datetime.fromtimestamp(raw_created / 1000.0)
|
94
|
-
elif isinstance(raw_created, str):
|
95
|
-
created_dt = datetime.fromisoformat(raw_created)
|
96
|
-
else:
|
97
|
-
created_dt = None
|
98
|
-
|
99
|
-
# parse modified date
|
100
|
-
raw_modified = data.get('modified')
|
101
|
-
if isinstance(raw_modified, (int, float)):
|
102
|
-
modified_dt = datetime.fromtimestamp(raw_modified / 1000.0)
|
103
|
-
elif isinstance(raw_modified, str):
|
104
|
-
modified_dt = datetime.fromisoformat(raw_modified)
|
105
|
-
else:
|
106
|
-
modified_dt = None
|
107
|
-
|
108
|
-
change_msg = data.get('changeMessage')
|
109
|
-
|
110
|
-
return cls(
|
111
|
-
contributor=contrib,
|
112
|
-
created=created_dt,
|
113
|
-
creator=creat,
|
114
|
-
modified=modified_dt,
|
115
|
-
changeMessage=change_msg
|
116
|
-
)
|
58
|
+
|
59
|
+
"""
|
60
|
+
Create a Person instance from a JSON-dict (already parsed).
|
61
|
+
"""
|
62
|
+
from .Serialization import Serialization
|
63
|
+
|
64
|
+
return Serialization.deserialize(data, Attribution)
|