gedcom-x 0.5.7__py3-none-any.whl → 0.5.9__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.
Files changed (69) hide show
  1. {gedcom_x-0.5.7.dist-info → gedcom_x-0.5.9.dist-info}/METADATA +1 -1
  2. gedcom_x-0.5.9.dist-info/RECORD +56 -0
  3. gedcomx/Extensions/rs10/rsLink.py +110 -60
  4. gedcomx/TopLevelTypeCollection.py +1 -1
  5. gedcomx/__init__.py +43 -42
  6. gedcomx/address.py +217 -0
  7. gedcomx/{Agent.py → agent.py} +107 -34
  8. gedcomx/attribution.py +115 -0
  9. gedcomx/{Conclusion.py → conclusion.py} +120 -51
  10. gedcomx/{Converter.py → converter.py} +261 -116
  11. gedcomx/coverage.py +64 -0
  12. gedcomx/{Date.py → date.py} +43 -9
  13. gedcomx/{Document.py → document.py} +60 -12
  14. gedcomx/{Event.py → event.py} +88 -31
  15. gedcomx/evidence_reference.py +20 -0
  16. gedcomx/{Fact.py → fact.py} +81 -74
  17. gedcomx/{Gedcom.py → gedcom.py} +10 -0
  18. gedcomx/{Gedcom5x.py → gedcom5x.py} +31 -21
  19. gedcomx/gedcom7/Exceptions.py +9 -0
  20. gedcomx/gedcom7/GedcomStructure.py +94 -0
  21. gedcomx/gedcom7/Specification.py +347 -0
  22. gedcomx/gedcom7/__init__.py +26 -0
  23. gedcomx/gedcom7/g7interop.py +205 -0
  24. gedcomx/gedcom7/gedcom7.py +160 -0
  25. gedcomx/gedcom7/logger.py +19 -0
  26. gedcomx/{GedcomX.py → gedcomx.py} +109 -106
  27. gedcomx/gender.py +91 -0
  28. gedcomx/group.py +72 -0
  29. gedcomx/{Identifier.py → identifier.py} +48 -21
  30. gedcomx/{LoggingHub.py → logging_hub.py} +19 -0
  31. gedcomx/{Mutations.py → mutations.py} +59 -30
  32. gedcomx/{Name.py → name.py} +88 -47
  33. gedcomx/note.py +105 -0
  34. gedcomx/online_account.py +19 -0
  35. gedcomx/{Person.py → person.py} +61 -41
  36. gedcomx/{PlaceDescription.py → place_description.py} +71 -23
  37. gedcomx/{PlaceReference.py → place_reference.py} +32 -10
  38. gedcomx/{Qualifier.py → qualifier.py} +20 -4
  39. gedcomx/relationship.py +156 -0
  40. gedcomx/resource.py +112 -0
  41. gedcomx/serialization.py +794 -0
  42. gedcomx/source_citation.py +37 -0
  43. gedcomx/source_description.py +401 -0
  44. gedcomx/{SourceReference.py → source_reference.py} +56 -21
  45. gedcomx/subject.py +122 -0
  46. gedcomx/textvalue.py +89 -0
  47. gedcomx/{Translation.py → translation.py} +4 -4
  48. gedcomx/uri.py +273 -0
  49. gedcom_x-0.5.7.dist-info/RECORD +0 -49
  50. gedcomx/Address.py +0 -131
  51. gedcomx/Attribution.py +0 -91
  52. gedcomx/Coverage.py +0 -37
  53. gedcomx/EvidenceReference.py +0 -11
  54. gedcomx/Gender.py +0 -65
  55. gedcomx/Group.py +0 -37
  56. gedcomx/Note.py +0 -73
  57. gedcomx/OnlineAccount.py +0 -10
  58. gedcomx/Relationship.py +0 -97
  59. gedcomx/Resource.py +0 -85
  60. gedcomx/Serialization.py +0 -816
  61. gedcomx/SourceCitation.py +0 -25
  62. gedcomx/SourceDescription.py +0 -314
  63. gedcomx/Subject.py +0 -59
  64. gedcomx/TextValue.py +0 -35
  65. gedcomx/URI.py +0 -105
  66. {gedcom_x-0.5.7.dist-info → gedcom_x-0.5.9.dist-info}/WHEEL +0 -0
  67. {gedcom_x-0.5.7.dist-info → gedcom_x-0.5.9.dist-info}/top_level.txt +0 -0
  68. /gedcomx/{Exceptions.py → exceptions.py} +0 -0
  69. /gedcomx/{ExtensibleEnum.py → extensible_enum.py} +0 -0
@@ -1,17 +1,41 @@
1
1
  import base64
2
2
  import uuid
3
3
 
4
- from typing import List, Optional
4
+ from typing import Any, Dict, List, Optional
5
+ """
6
+ ======================================================================
7
+ Project: Gedcom-X
8
+ File: agent.py
9
+ Author: David J. Cartwright
10
+ Purpose:
5
11
 
6
- from .Address import Address
7
- #from .Attribution import Attribution
8
- from .Identifier import Identifier, IdentifierList
9
-
10
- from .OnlineAccount import OnlineAccount
11
- from .TextValue import TextValue
12
- from .Resource import Resource
13
- from .URI import URI
12
+ Created: 2025-08-25
13
+ Updated:
14
+ - 2025-09-03: _from_json_ refactor
15
+
16
+ ======================================================================
17
+ """
14
18
 
19
+ """
20
+ ======================================================================
21
+ GEDCOM Module Type Imports
22
+ ======================================================================
23
+ """
24
+ from .address import Address
25
+ from .identifier import Identifier, IdentifierList, make_uid
26
+ from .online_account import OnlineAccount
27
+ from .resource import Resource
28
+ from .textvalue import TextValue
29
+ from .uri import URI
30
+ from .logging_hub import hub, logging
31
+ """
32
+ ======================================================================
33
+ Logging
34
+ ======================================================================
35
+ """
36
+ log = logging.getLogger("gedcomx")
37
+ serial_log = "gedcomx.serialization"
38
+ #=====================================================================
15
39
 
16
40
 
17
41
  class Agent:
@@ -46,17 +70,7 @@ class Agent:
46
70
  attribution (Attribution, optional): Attribution information related to the agent.
47
71
  uri (Resource, optional): A URI reference for this agent.
48
72
  """
49
-
50
- @staticmethod
51
- def default_id_generator():
52
- # Generate a standard UUID
53
- standard_uuid = uuid.uuid4()
54
- # Convert UUID to bytes
55
- uuid_bytes = standard_uuid.bytes
56
- # Encode bytes to a Base64 string
57
- short_uuid = base64.urlsafe_b64encode(uuid_bytes).rstrip(b'=').decode('utf-8')
58
- return short_uuid
59
-
73
+
60
74
  def __init__(self, id: Optional[str] = None,
61
75
  identifiers: Optional[IdentifierList] = None,
62
76
  names: Optional[List[TextValue]] = [],
@@ -71,9 +85,8 @@ class Agent:
71
85
  attribution: Optional[object] = None, # Added for compatibility with GEDCOM5/7 Imports
72
86
  uri: Optional[URI | Resource] = None):
73
87
 
74
- self._id_generator = Agent.default_id_generator
75
-
76
- self.id = id if id else None #TODO self._id_generator()
88
+
89
+ self.id = id if id else make_uid()
77
90
  self.identifiers = identifiers or IdentifierList()
78
91
  self.names = names if names else []
79
92
  self.homepage = homepage or None
@@ -83,7 +96,7 @@ class Agent:
83
96
  self.phones = phones or []
84
97
  self.addresses = addresses if addresses else []
85
98
  self.person = person
86
- self.notes = []
99
+ self.xnotes = []
87
100
  self.attribution = attribution or None
88
101
  self.uri = URI(fragment=self.id) if self.id else None
89
102
 
@@ -115,7 +128,7 @@ class Agent:
115
128
  raise ValueError(f'name must be of type str or TextValue, recived {type(name_to_add)}')
116
129
 
117
130
  def add_note(self, note_to_add):
118
- from .Note import Note
131
+ from .note import Note
119
132
  if note_to_add and isinstance(note_to_add,Note):
120
133
  self.xnotes.append(note_to_add)
121
134
  else:
@@ -126,7 +139,7 @@ class Agent:
126
139
 
127
140
  @property
128
141
  def _as_dict_(self):
129
- from .Serialization import Serialization
142
+ from .serialization import Serialization
130
143
  type_as_dict = {}
131
144
 
132
145
  if self.id:
@@ -147,17 +160,77 @@ class Agent:
147
160
  type_as_dict["phones"] = self.phones
148
161
  if self.addresses:
149
162
  type_as_dict["addresses"] = [address._as_dict_ for address in self.addresses if address]
150
- if self.notes:
151
- type_as_dict["notes"] = [note._as_dict_() for note in self.notes if note]
163
+ if self.xnotes:
164
+ type_as_dict["notes"] = [note._as_dict_() for note in self.xnotes if note]
165
+ return type_as_dict if type_as_dict != {} else None
152
166
  return Serialization.serialize_dict(type_as_dict)
153
167
 
154
168
  @classmethod
155
- def _from_json_(cls, data: dict):
156
- """
157
- Create a Person instance from a JSON-dict (already parsed).
158
- """
159
- type_as_dict = Serialization.get_class_fields('Agent')
160
- return Serialization.deserialize(data, type_as_dict)
169
+ def _from_json_(cls, data: Any, context: Any = None) -> "Agent":
170
+
171
+ if not isinstance(data, dict):
172
+ raise TypeError(f"{cls.__name__}._from_json_ expected dict or str, got {type(data)}")
173
+
174
+ agent_data: Dict[str, Any] = {}
175
+
176
+ # ── Scalars ──────────────────────────────────────────────────────────────
177
+ if (id_ := data.get("id")) is not None:
178
+ agent_data["id"] = id_
179
+
180
+ # ── Objects ─────────────────────────────────────────────────────────────
181
+ if (identifiers := data.get("identifiers")) is not None:
182
+ agent_data["identifiers"] = IdentifierList._from_json_(identifiers, context)
183
+
184
+ # homepage / openid / uri: accept string or dict
185
+ if (homepage := data.get("homepage")) is not None:
186
+ agent_data["homepage"] = URI.from_url_(homepage) if isinstance(homepage, str) else URI._from_json_(homepage, context)
187
+
188
+ if (openid := data.get("openid")) is not None:
189
+ agent_data["openid"] = URI.from_url_(openid) if isinstance(openid, str) else URI._from_json_(openid, context)
190
+
191
+ if (uri := data.get("uri")) is not None:
192
+ if isinstance(uri, str):
193
+ agent_data["uri"] = URI.from_url_(uri)
194
+ else: raise ValueError()
195
+
196
+ # person can be a full Person object or a Resource/URI reference
197
+ if (person := data.get("person")) is not None:
198
+ if isinstance(person, dict):
199
+ agent_data["person"] = Resource._from_json_(person, context)
200
+ else:
201
+ raise ValueError()
202
+
203
+ # attribution (GEDCOM5/7 compatibility): try Attribution if shape matches; otherwise store as-is
204
+ if (attr := data.get("attribution")) is not None:
205
+ """
206
+ ======================================================================
207
+ GEDCOM Module Type Imports
208
+ ======================================================================
209
+ """
210
+ from .attribution import Attribution
211
+ #======================================================================
212
+ if isinstance(attr, dict) and any(k in attr for k in ("contributor", "created", "modified")):
213
+ agent_data["attribution"] = Attribution._from_json_(attr, context)
214
+ else:
215
+ raise ValueError()
216
+
217
+ # ── Lists ───────────────────────────────────────────────────────────────
218
+ if (names := data.get("names")) is not None:
219
+ agent_data["names"] = [TextValue._from_json_(n, context) if isinstance(n, (dict,)) else TextValue(n) for n in names]
220
+
221
+ if (accounts := data.get("accounts")) is not None:
222
+ agent_data["accounts"] = [OnlineAccount._from_json_(a, context) for a in accounts]
223
+
224
+ if (emails := data.get("emails")) is not None:
225
+ agent_data["emails"] = [URI.from_url_(e) if isinstance(e, str) else URI._from_json_(e, context) for e in emails]
226
+
227
+ if (phones := data.get("phones")) is not None:
228
+ agent_data["phones"] = [URI.from_url_(p) if isinstance(p, str) else URI._from_json_(p, context) for p in phones]
229
+
230
+ if (addresses := data.get("addresses")) is not None:
231
+ agent_data["addresses"] = [Address._from_json_(a, context) for a in addresses]
232
+
233
+ return cls(**agent_data)
161
234
 
162
235
  def __str__(self):
163
236
  """
gedcomx/attribution.py ADDED
@@ -0,0 +1,115 @@
1
+
2
+ from datetime import datetime
3
+ from typing import Optional, Dict, Any
4
+
5
+ """
6
+ ======================================================================
7
+ Project: Gedcom-X
8
+ File: Attribution.py
9
+ Author: David J. Cartwright
10
+ Purpose:
11
+
12
+ Created: 2025-08-25
13
+ Updated:
14
+ - 2025-08-31: fixed _as_dict_ to deal with Resources and ignore empty fields
15
+ - 2025-09-03: _from_json_ refactor
16
+
17
+
18
+ ======================================================================
19
+ """
20
+
21
+ """
22
+ ======================================================================
23
+ GEDCOM Module Types
24
+ ======================================================================
25
+ """
26
+ from .agent import Agent
27
+ from .resource import Resource
28
+ from .logging_hub import hub, logging
29
+ """
30
+ ======================================================================
31
+ Logging
32
+ ======================================================================
33
+ """
34
+ log = logging.getLogger("gedcomx")
35
+ serial_log = "gedcomx.serialization"
36
+ #=====================================================================
37
+
38
+
39
+ class Attribution:
40
+ """Attribution Information for a Genealogy, Conclusion, Subject and child classes
41
+
42
+ Args:
43
+ contributor (Agent, optional): Contributor to object being attributed.
44
+ modified (timestamp, optional): timestamp for when this record was modified.
45
+ changeMessage (str, optional): Birth date (YYYY-MM-DD).
46
+ creator (Agent, optional): Creator of object being attributed.
47
+ created (timestamp, optional): timestamp for when this record was created
48
+
49
+ Raises:
50
+
51
+ """
52
+ identifier = 'http://gedcomx.org/v1/Attribution'
53
+ version = 'http://gedcomx.org/conceptual-model/v1'
54
+
55
+ def __init__(self,contributor: Optional[Agent | Resource] = None,
56
+ modified: Optional[datetime] = None,
57
+ changeMessage: Optional[str] = None,
58
+ creator: Optional[Agent | Resource] = None,
59
+ created: Optional[datetime] = None) -> None:
60
+
61
+ self.contributor = contributor
62
+ self.modified = modified
63
+ self.changeMessage = changeMessage
64
+ self.creator = creator
65
+ self.created = created
66
+
67
+ @property
68
+ def _as_dict_(self) -> Dict[str, Any] | None:
69
+ """
70
+ Serialize Attribution to a JSON-ready dict, skipping None values.
71
+ """
72
+ with hub.use(serial_log):
73
+ log.debug(f"Serializing 'Attribution'")
74
+ type_as_dict: Dict[str, Any] = {}
75
+ if self.contributor:
76
+ type_as_dict['contributor'] = Resource(target=self.contributor)._as_dict_
77
+ if self.modified:
78
+ type_as_dict['modified'] = self.modified if self.modified else None
79
+ if self.changeMessage:
80
+ type_as_dict['changeMessage'] = self.changeMessage if self.changeMessage else None
81
+ if self.creator:
82
+ type_as_dict['creator'] = Resource(target=self.creator)._as_dict_
83
+ if self.created:
84
+ type_as_dict['created'] = self.created if self.created else None
85
+
86
+ log.debug(f"'Attribution' serialized with fields: {type_as_dict.keys()}")
87
+ if type_as_dict == {}: log.warning("serializing and empty 'Attribution'")
88
+ return type_as_dict if type_as_dict != {} else None
89
+
90
+ @classmethod
91
+ def _from_json_(cls, data: Dict[str, Any],context) -> 'Attribution':
92
+ if not isinstance(data, dict):
93
+ raise TypeError(f"{cls.__name__}._from_json_ expected dict or str, got {type(data)}")
94
+
95
+ attribution_data: Dict[str, Any] = {}
96
+
97
+ # contributor: Agent | Resource | URI string
98
+ if (contrib := data.get("contributor")) is not None:
99
+ attribution_data["contributor"] = Resource._from_json_(contrib, context)
100
+
101
+ # creator: Agent | Resource | URI string
102
+ if (creator := data.get("creator")) is not None:
103
+ attribution_data["creator"] = Resource._from_json_(creator, context)
104
+
105
+ # changeMessage: str
106
+ if (cm := data.get("changeMessage")) is not None:
107
+ attribution_data["changeMessage"] = cm
108
+
109
+ # created/modified: datetime
110
+ if (created := data.get("created")) is not None:
111
+ attribution_data["created"] = created
112
+ if (modified := data.get("modified")) is not None:
113
+ attribution_data["modified"] = modified
114
+
115
+ return cls(**attribution_data)
@@ -1,19 +1,46 @@
1
- import base64
2
- import uuid
1
+
3
2
  import warnings
4
3
 
5
- from typing import List, Optional
4
+ from typing import Any, Optional, List
5
+
6
+ """
7
+ ======================================================================
8
+ Project: Gedcom-X
9
+ File: conclusion.py
10
+ Author: David J. Cartwright
11
+ Purpose:
12
+
13
+ Created: 2025-08-25
14
+ Updated:
15
+ - 2025-09-03: _from_json_ refactor
16
+
17
+ ======================================================================
18
+ """
19
+
20
+ """
21
+ ======================================================================
22
+ GEDCOM Module Type Imports
23
+ ======================================================================
24
+ """
25
+ from .attribution import Attribution
26
+ from .Extensions.rs10.rsLink import _rsLinks, rsLink
27
+ from .identifier import make_uid
28
+ from .note import Note
29
+ from .qualifier import Qualifier
30
+ from .resource import Resource, URI
31
+ from .source_reference import SourceReference
32
+ from .logging_hub import hub, logging
33
+ """
34
+ ======================================================================
35
+ Logging
36
+ ======================================================================
37
+ """
38
+ log = logging.getLogger("gedcomx")
39
+ serial_log = "gedcomx.serialization"
40
+ #=====================================================================
6
41
 
7
- from .Attribution import Attribution
8
- #from .Document import Document
9
- from .Note import Note
10
- from .Qualifier import Qualifier
11
42
 
12
- from .SourceReference import SourceReference
13
- from .Resource import Resource, URI
14
- from .Extensions.rs10.rsLink import _rsLinkList, rsLink
15
43
 
16
- from collections.abc import Sized
17
44
 
18
45
  class ConfidenceLevel(Qualifier):
19
46
  High = "http://gedcomx.org/High"
@@ -114,17 +141,7 @@ class Conclusion:
114
141
  """
115
142
  identifier = 'http://gedcomx.org/v1/Conclusion'
116
143
  version = 'http://gedcomx.org/conceptual-model/v1'
117
-
118
- @staticmethod
119
- def default_id_generator():
120
- # Generate a standard UUID
121
- standard_uuid = uuid.uuid4()
122
- # Convert UUID to bytes
123
- uuid_bytes = standard_uuid.bytes
124
- # Encode bytes to a Base64 string
125
- short_uuid = base64.urlsafe_b64encode(uuid_bytes).rstrip(b'=').decode('utf-8')
126
- return short_uuid
127
-
144
+
128
145
  def __init__(self,
129
146
  id: Optional[str] = None,
130
147
  lang: Optional[str] = None,
@@ -135,11 +152,10 @@ class Conclusion:
135
152
  attribution: Optional[Attribution] = None,
136
153
  uri: Optional[Resource] = None,
137
154
  _max_note_count: int = 20,
138
- links: Optional[_rsLinkList] = None) -> None:
155
+ links: Optional[_rsLinks] = None) -> None:
139
156
 
140
- self._id_generator = Conclusion.default_id_generator
141
-
142
- self.id = id if id else None
157
+
158
+ self.id = id if id else make_uid()
143
159
  self.lang = lang
144
160
  self.sources = sources if sources else []
145
161
  self.analysis = analysis
@@ -147,8 +163,7 @@ class Conclusion:
147
163
  self.confidence = confidence
148
164
  self.attribution = attribution
149
165
  self.max_note_count = _max_note_count
150
- self.uri = uri if uri else URI(fragment=id if id else self.id)
151
- self.links = links if links else _rsLinkList() #NOTE This is not in specification, following FS format
166
+ self.links = links if links else _rsLinks() #NOTE This is not in specification, following FS format
152
167
 
153
168
  def add_note(self,note_to_add: Note):
154
169
  if self.notes and len(self.notes) >= self.max_note_count:
@@ -160,7 +175,7 @@ class Conclusion:
160
175
  return False
161
176
  self.notes.append(note_to_add)
162
177
 
163
- def add_source(self, source_to_add: SourceReference):
178
+ def add_source_reference(self, source_to_add: SourceReference):
164
179
  if source_to_add and isinstance(source_to_add,SourceReference):
165
180
  for current_source in self.sources:
166
181
  if source_to_add == current_source:
@@ -188,30 +203,84 @@ class Conclusion:
188
203
 
189
204
  @property
190
205
  def _as_dict_(self):
191
- from .Serialization import Serialization
192
- type_as_dict = {}
193
-
194
- if self.id:
195
- type_as_dict['id'] = self.id
196
- if self.lang:
197
- type_as_dict['lang'] = self.lang
198
- if self.sources:
199
- type_as_dict['sources'] = [s._as_dict_ for s in self.sources if s]
200
- if self.analysis:
201
- type_as_dict['analysis'] = getattr(self.analysis, '_as_dict_', self.analysis)
202
- if self.notes:
203
- type_as_dict['notes'] = [
204
- (n._as_dict_ if hasattr(n, '_as_dict_') else n) for n in self.notes if n
205
- ]
206
- if self.confidence is not None:
207
- type_as_dict['confidence'] = self.confidence
208
- if self.attribution:
209
- type_as_dict['attribution'] = getattr(self.attribution, '_as_dict_', self.attribution)
210
- if self.links:
211
- type_as_dict['links'] = self.links._as_dict_
206
+ with hub.use(serial_log):
207
+ log.debug(f"Serializing 'Conclusion' with id: {self.id}")
208
+ type_as_dict = {}
209
+
210
+ if self.id:
211
+ type_as_dict['id'] = self.id
212
+ if self.lang:
213
+ type_as_dict['lang'] = self.lang
214
+ if self.sources and self.sources != []:
215
+ type_as_dict['sources'] = [s._as_dict_ for s in self.sources if s]
216
+ if self.analysis:
217
+ type_as_dict['analysis'] = getattr(self.analysis, '_as_dict_', self.analysis)
218
+ if self.notes and self.notes != []:
219
+ type_as_dict['notes'] = [
220
+ (n._as_dict_ if hasattr(n, '_as_dict_') else n) for n in self.notes if n
221
+ ]
222
+ if self.confidence is not None:
223
+ type_as_dict['confidence'] = self.confidence
224
+ if self.attribution is not None:
225
+ type_as_dict['attribution'] = self.attribution._as_dict_
226
+ if self.links is not None:
227
+ print(self.links)
228
+ type_as_dict['links'] = self.links._as_dict_
229
+ log.debug(f"'Conclusion' serialized with fields: {type_as_dict.keys()}")
230
+ if type_as_dict == {}: log.warning("serializing and empty 'Conclusion'")
212
231
 
213
- return Serialization.serialize_dict(type_as_dict)
232
+ return type_as_dict if type_as_dict != {} else None
233
+
234
+
214
235
 
236
+
237
+ @classmethod
238
+ def _dict_from_json_(cls, data: dict, context=None) -> dict:
239
+ conclusion = {}
240
+
241
+ # Scalars
242
+ if (id_ := data.get("id")) is not None:
243
+ conclusion["id"] = id_
244
+
245
+ if (lang := data.get("lang")) is not None:
246
+ conclusion["lang"] = lang
247
+
248
+ # Lists
249
+ if (sources := data.get("sources")) is not None:
250
+ conclusion["sources"] = [
251
+ SourceReference._from_json_(x, context) for x in sources
252
+ ]
253
+
254
+ if (notes := data.get("notes")) is not None:
255
+ conclusion["notes"] = [
256
+ Note._from_json_(x, context) for x in notes
257
+ ]
258
+
259
+ # Objects
260
+ if (analysis := data.get("analysis")) is not None:
261
+ # depending on your model, analysis might be a Resource or Document
262
+ conclusion["analysis"] = Resource._from_json_(analysis, context)
263
+
264
+ if (confidence := data.get("confidence")) is not None:
265
+ conclusion["confidence"] = ConfidenceLevel._from_json_(confidence, context)
266
+
267
+ if (attribution := data.get("attribution")) is not None:
268
+ conclusion["attribution"] = Attribution._from_json_(attribution, context)
269
+
270
+ if (uri := data.get("uri")) is not None:
271
+ conclusion["uri"] = URI(uri)
272
+
273
+ if (links := data.get("links")) is not None:
274
+ conclusion["links"] = _rsLinks._from_json_(links, context)
275
+ if isinstance(conclusion["links"],dict): assert False
276
+
277
+ # Constant / defaults
278
+ #conclusion["_max_note_count"] = 20
279
+
280
+ #return cls(**conclusion)
281
+ return conclusion
282
+
283
+
215
284
  def __eq__(self, other):
216
285
  if not isinstance(other, self.__class__):
217
286
  return False