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.
- {gedcom_x-0.5.7.dist-info → gedcom_x-0.5.9.dist-info}/METADATA +1 -1
- gedcom_x-0.5.9.dist-info/RECORD +56 -0
- gedcomx/Extensions/rs10/rsLink.py +110 -60
- gedcomx/TopLevelTypeCollection.py +1 -1
- gedcomx/__init__.py +43 -42
- gedcomx/address.py +217 -0
- gedcomx/{Agent.py → agent.py} +107 -34
- gedcomx/attribution.py +115 -0
- gedcomx/{Conclusion.py → conclusion.py} +120 -51
- gedcomx/{Converter.py → converter.py} +261 -116
- gedcomx/coverage.py +64 -0
- gedcomx/{Date.py → date.py} +43 -9
- gedcomx/{Document.py → document.py} +60 -12
- gedcomx/{Event.py → event.py} +88 -31
- gedcomx/evidence_reference.py +20 -0
- gedcomx/{Fact.py → fact.py} +81 -74
- gedcomx/{Gedcom.py → gedcom.py} +10 -0
- gedcomx/{Gedcom5x.py → gedcom5x.py} +31 -21
- gedcomx/gedcom7/Exceptions.py +9 -0
- gedcomx/gedcom7/GedcomStructure.py +94 -0
- gedcomx/gedcom7/Specification.py +347 -0
- gedcomx/gedcom7/__init__.py +26 -0
- gedcomx/gedcom7/g7interop.py +205 -0
- gedcomx/gedcom7/gedcom7.py +160 -0
- gedcomx/gedcom7/logger.py +19 -0
- gedcomx/{GedcomX.py → gedcomx.py} +109 -106
- gedcomx/gender.py +91 -0
- gedcomx/group.py +72 -0
- gedcomx/{Identifier.py → identifier.py} +48 -21
- gedcomx/{LoggingHub.py → logging_hub.py} +19 -0
- gedcomx/{Mutations.py → mutations.py} +59 -30
- gedcomx/{Name.py → name.py} +88 -47
- gedcomx/note.py +105 -0
- gedcomx/online_account.py +19 -0
- gedcomx/{Person.py → person.py} +61 -41
- gedcomx/{PlaceDescription.py → place_description.py} +71 -23
- gedcomx/{PlaceReference.py → place_reference.py} +32 -10
- gedcomx/{Qualifier.py → qualifier.py} +20 -4
- gedcomx/relationship.py +156 -0
- gedcomx/resource.py +112 -0
- gedcomx/serialization.py +794 -0
- gedcomx/source_citation.py +37 -0
- gedcomx/source_description.py +401 -0
- gedcomx/{SourceReference.py → source_reference.py} +56 -21
- gedcomx/subject.py +122 -0
- gedcomx/textvalue.py +89 -0
- gedcomx/{Translation.py → translation.py} +4 -4
- gedcomx/uri.py +273 -0
- gedcom_x-0.5.7.dist-info/RECORD +0 -49
- gedcomx/Address.py +0 -131
- gedcomx/Attribution.py +0 -91
- gedcomx/Coverage.py +0 -37
- gedcomx/EvidenceReference.py +0 -11
- gedcomx/Gender.py +0 -65
- gedcomx/Group.py +0 -37
- gedcomx/Note.py +0 -73
- gedcomx/OnlineAccount.py +0 -10
- gedcomx/Relationship.py +0 -97
- gedcomx/Resource.py +0 -85
- gedcomx/Serialization.py +0 -816
- gedcomx/SourceCitation.py +0 -25
- gedcomx/SourceDescription.py +0 -314
- gedcomx/Subject.py +0 -59
- gedcomx/TextValue.py +0 -35
- gedcomx/URI.py +0 -105
- {gedcom_x-0.5.7.dist-info → gedcom_x-0.5.9.dist-info}/WHEEL +0 -0
- {gedcom_x-0.5.7.dist-info → gedcom_x-0.5.9.dist-info}/top_level.txt +0 -0
- /gedcomx/{Exceptions.py → exceptions.py} +0 -0
- /gedcomx/{ExtensibleEnum.py → extensible_enum.py} +0 -0
gedcomx/{Date.py → date.py}
RENAMED
@@ -1,9 +1,34 @@
|
|
1
|
-
from typing import Optional
|
1
|
+
from typing import Any, Optional, Dict
|
2
2
|
from datetime import datetime, timezone
|
3
3
|
from dateutil import parser
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
"""
|
5
|
+
======================================================================
|
6
|
+
Project: Gedcom-X
|
7
|
+
File: date.py
|
8
|
+
Author: David J. Cartwright
|
9
|
+
Purpose:
|
10
|
+
|
11
|
+
Created: 2025-08-25
|
12
|
+
Updated:
|
13
|
+
- 2025-09-03: _from_json refactored
|
14
|
+
|
15
|
+
======================================================================
|
16
|
+
"""
|
17
|
+
|
18
|
+
"""
|
19
|
+
======================================================================
|
20
|
+
GEDCOM Module Types
|
21
|
+
======================================================================
|
22
|
+
"""
|
23
|
+
from .logging_hub import hub, logging
|
24
|
+
"""
|
25
|
+
======================================================================
|
26
|
+
Logging
|
27
|
+
======================================================================
|
28
|
+
"""
|
29
|
+
log = logging.getLogger("gedcomx")
|
30
|
+
serial_log = "gedcomx.serialization"
|
31
|
+
#=====================================================================
|
7
32
|
|
8
33
|
|
9
34
|
class DateFormat:
|
@@ -25,20 +50,29 @@ class Date:
|
|
25
50
|
|
26
51
|
@property
|
27
52
|
def _as_dict_(self):
|
28
|
-
from .
|
53
|
+
from .serialization import Serialization
|
29
54
|
type_as_dict = {}
|
30
55
|
if self.original:
|
31
56
|
type_as_dict['original'] = self.original
|
32
57
|
if self.formal:
|
33
58
|
type_as_dict['formal'] = self.formal
|
59
|
+
return type_as_dict if type_as_dict != {} else None
|
34
60
|
return Serialization.serialize_dict(type_as_dict)
|
35
61
|
|
36
62
|
@classmethod
|
37
|
-
def _from_json_(cls,data):
|
38
|
-
|
39
|
-
|
63
|
+
def _from_json_(cls,data: Any, context=None):
|
64
|
+
if not isinstance(data, dict):
|
65
|
+
raise TypeError(f"{cls.__name__}._from_json_ expected dict or str, got {type(data)} data:{data}")
|
66
|
+
|
67
|
+
date_data: Dict[str, Any] = {}
|
68
|
+
|
69
|
+
# Scalars
|
70
|
+
if (orig := data.get("original")) is not None:
|
71
|
+
date_data["original"] = orig
|
72
|
+
if (formal := data.get("formal")) is not None:
|
73
|
+
date_data["formal"] = formal
|
40
74
|
|
41
|
-
return
|
75
|
+
return cls(**date_data)
|
42
76
|
|
43
77
|
|
44
78
|
|
@@ -1,12 +1,38 @@
|
|
1
1
|
from enum import Enum
|
2
|
-
from typing import
|
2
|
+
from typing import Any, Dict, List, Optional
|
3
|
+
"""
|
4
|
+
======================================================================
|
5
|
+
Project: Gedcom-X
|
6
|
+
File: document.py
|
7
|
+
Author: David J. Cartwright
|
8
|
+
Purpose:
|
3
9
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
10
|
+
Created: 2025-08-25
|
11
|
+
Updated:
|
12
|
+
- 2025-09-03: _from_json_ refactored
|
13
|
+
|
14
|
+
======================================================================
|
15
|
+
"""
|
8
16
|
|
9
|
-
|
17
|
+
"""
|
18
|
+
======================================================================
|
19
|
+
GEDCOM Module Types
|
20
|
+
======================================================================
|
21
|
+
"""
|
22
|
+
from .attribution import Attribution
|
23
|
+
from .conclusion import Conclusion, ConfidenceLevel
|
24
|
+
from .note import Note
|
25
|
+
from .resource import Resource
|
26
|
+
from .source_reference import SourceReference
|
27
|
+
from .logging_hub import hub, logging
|
28
|
+
"""
|
29
|
+
======================================================================
|
30
|
+
Logging
|
31
|
+
======================================================================
|
32
|
+
"""
|
33
|
+
log = logging.getLogger("gedcomx")
|
34
|
+
serial_log = "gedcomx.serialization"
|
35
|
+
#=====================================================================
|
10
36
|
|
11
37
|
|
12
38
|
class DocumentType(Enum):
|
@@ -38,7 +64,7 @@ class Document(Conclusion):
|
|
38
64
|
sources: Optional[List[SourceReference]] = None,
|
39
65
|
analysis: Optional[Resource] = None,
|
40
66
|
notes: Optional[List[Note]] = None,
|
41
|
-
confidence: Optional[
|
67
|
+
confidence: Optional[ConfidenceLevel] = None, # ConfidenceLevel
|
42
68
|
attribution: Optional[Attribution] = None,
|
43
69
|
type: Optional[DocumentType] = None,
|
44
70
|
extracted: Optional[bool] = None, # Default to False
|
@@ -53,7 +79,7 @@ class Document(Conclusion):
|
|
53
79
|
|
54
80
|
@property
|
55
81
|
def _as_dict(self):
|
56
|
-
from .
|
82
|
+
from .serialization import Serialization
|
57
83
|
type_as_dict = super()._as_dict_
|
58
84
|
if self.type:
|
59
85
|
type_as_dict['type'] = self.type.value
|
@@ -66,9 +92,31 @@ class Document(Conclusion):
|
|
66
92
|
return Serialization.serialize_dict(type_as_dict)
|
67
93
|
|
68
94
|
@classmethod
|
69
|
-
def _from_json_(cls, data:
|
95
|
+
def _from_json_(cls, data: Any, context: Any = None) -> "Document":
|
70
96
|
"""
|
71
|
-
|
97
|
+
Build a Document from JSON.
|
98
|
+
Shorthand: a bare string becomes {'text': <string>}.
|
72
99
|
"""
|
73
|
-
|
74
|
-
|
100
|
+
if not isinstance(data, dict):
|
101
|
+
raise TypeError(f"{cls.__name__}._from_json_ expected dict or str, got {type(data)}")
|
102
|
+
|
103
|
+
obj: Dict[str, Any] = Conclusion._dict_from_json_(data,context)
|
104
|
+
|
105
|
+
# type (enum)
|
106
|
+
if (typ := data.get("type")) is not None:
|
107
|
+
obj["type"] = DocumentType(typ)
|
108
|
+
|
109
|
+
|
110
|
+
# extracted (bool; accept common string forms)
|
111
|
+
if (ex := data.get("extracted")) is not None:
|
112
|
+
obj["extracted"] = bool(ex)
|
113
|
+
|
114
|
+
# textType (enum)
|
115
|
+
if (tt := data.get("textType")) is not None:
|
116
|
+
obj["textType"] = TextType(tt)
|
117
|
+
|
118
|
+
# text (string)
|
119
|
+
if (tx := data.get("text")) is not None:
|
120
|
+
obj["text"] = str(tx)
|
121
|
+
|
122
|
+
return cls(**obj)
|
gedcomx/{Event.py → event.py}
RENAMED
@@ -1,5 +1,5 @@
|
|
1
1
|
from enum import Enum
|
2
|
-
from typing import List, Optional
|
2
|
+
from typing import Any, Dict, List, Optional
|
3
3
|
|
4
4
|
"""
|
5
5
|
======================================================================
|
@@ -11,6 +11,8 @@ from typing import List, Optional
|
|
11
11
|
Created: 2025-08-25
|
12
12
|
Updated:
|
13
13
|
- 2025-08-31: fixed mutible [] in init, replaced List[Identifer] with IdentifierList
|
14
|
+
- 2025-09-03: _from_json_ refactor
|
15
|
+
- 2025-09-04: changed _as_dict_ to std dict creation and removed call to serailization
|
14
16
|
|
15
17
|
======================================================================
|
16
18
|
"""
|
@@ -20,17 +22,24 @@ from typing import List, Optional
|
|
20
22
|
GEDCOM Module Type Imports
|
21
23
|
======================================================================
|
22
24
|
"""
|
23
|
-
from .
|
24
|
-
from .
|
25
|
-
from .
|
26
|
-
from .
|
27
|
-
from .
|
28
|
-
from .
|
29
|
-
from .
|
30
|
-
from .
|
31
|
-
from .
|
32
|
-
from .
|
33
|
-
|
25
|
+
from .attribution import Attribution
|
26
|
+
from .conclusion import ConfidenceLevel, Conclusion
|
27
|
+
from .date import Date
|
28
|
+
from .evidence_reference import EvidenceReference
|
29
|
+
from .identifier import IdentifierList
|
30
|
+
from .note import Note
|
31
|
+
from .place_reference import PlaceReference
|
32
|
+
from .resource import Resource
|
33
|
+
from .source_reference import SourceReference
|
34
|
+
from .subject import Subject
|
35
|
+
from .logging_hub import hub, logging
|
36
|
+
"""
|
37
|
+
======================================================================
|
38
|
+
Logging
|
39
|
+
======================================================================
|
40
|
+
"""
|
41
|
+
log = logging.getLogger("gedcomx")
|
42
|
+
serial_log = "gedcomx.serialization"
|
34
43
|
#=====================================================================
|
35
44
|
|
36
45
|
class EventRoleType(Enum):
|
@@ -103,7 +112,6 @@ class EventRole(Conclusion):
|
|
103
112
|
|
104
113
|
@property
|
105
114
|
def _as_dict_(self):
|
106
|
-
from .Serialization import Serialization
|
107
115
|
type_as_dict = super()._as_dict_
|
108
116
|
if self.person:
|
109
117
|
type_as_dict['person'] = Resource(target=self.person)._as_dict_
|
@@ -112,8 +120,34 @@ class EventRole(Conclusion):
|
|
112
120
|
if self.details:
|
113
121
|
type_as_dict['details'] = self.details
|
114
122
|
|
115
|
-
return
|
123
|
+
return type_as_dict if type_as_dict != {} else None
|
124
|
+
|
125
|
+
|
126
|
+
@classmethod
|
127
|
+
def _from_json_(cls,data,context):
|
128
|
+
|
129
|
+
if not isinstance(data, dict):
|
130
|
+
print("Event: from:",data)
|
131
|
+
raise TypeError(f"{cls.__name__}._from_json_ expected dict or str, got {type(data)}")
|
132
|
+
event_role_data = Conclusion._dict_from_json_(data,context)
|
133
|
+
event_role_data: Dict[str, Any] = {}
|
134
|
+
|
135
|
+
# person: Person | Resource | URI string
|
136
|
+
if (p := data.get("person")) is not None:
|
137
|
+
event_role_data["person"] = Resource._from_json_(p, context)
|
138
|
+
|
139
|
+
|
140
|
+
# type: EventRoleType (enum-ish)
|
141
|
+
if (typ := data.get("type")) is not None:
|
142
|
+
event_role_data["type"] = EventRoleType(typ)
|
143
|
+
|
116
144
|
|
145
|
+
# details: TextValue | str
|
146
|
+
if (det := data.get("details")) is not None:
|
147
|
+
event_role_data["details"] = det # str or passthrough
|
148
|
+
|
149
|
+
return cls(**event_role_data)
|
150
|
+
|
117
151
|
class EventType(Enum):
|
118
152
|
Adoption = "http://gedcomx.org/Adoption"
|
119
153
|
AdultChristening = "http://gedcomx.org/AdultChristening"
|
@@ -268,22 +302,45 @@ class Event(Subject):
|
|
268
302
|
|
269
303
|
@property
|
270
304
|
def _as_dict_(self):
|
271
|
-
from .
|
272
|
-
type_as_dict =
|
273
|
-
|
274
|
-
'type'
|
275
|
-
|
276
|
-
'
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
305
|
+
from .serialization import Serialization
|
306
|
+
type_as_dict = {}
|
307
|
+
if self.type:
|
308
|
+
type_as_dict['type'] = self.type.value
|
309
|
+
if self.date:
|
310
|
+
type_as_dict['date'] = self.date._as_dict_
|
311
|
+
if self.place:
|
312
|
+
type_as_dict['place'] = self.place._as_dict_
|
313
|
+
if self.roles:
|
314
|
+
#print(self.roles)
|
315
|
+
for role in self.roles:
|
316
|
+
if isinstance(role,list):
|
317
|
+
assert False
|
318
|
+
type_as_dict['roles'] = [role._as_dict_ for role in self.roles]
|
319
|
+
|
320
|
+
return type_as_dict if type_as_dict != {} else None
|
321
|
+
|
281
322
|
|
282
323
|
@classmethod
|
283
|
-
def _from_json_(cls, data:
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
324
|
+
def _from_json_(cls, data: Dict[str, Any], context: Any = None) -> "Event":
|
325
|
+
if not isinstance(data, dict):
|
326
|
+
raise TypeError(f"{cls.__name__}._from_json_ expected dict, got {type(data)}")
|
327
|
+
|
328
|
+
event_data: Dict[str, Any] = Subject._dict_from_json_(data,context)
|
329
|
+
|
330
|
+
# Enum / type
|
331
|
+
if (typ := data.get("type")) is not None:
|
332
|
+
event_data["type"] = EventType(typ)
|
333
|
+
|
334
|
+
|
335
|
+
# Objects
|
336
|
+
if (dt := data.get("date")) is not None:
|
337
|
+
event_data["date"] = Date._from_json_(dt, context)
|
338
|
+
|
339
|
+
if (pl := data.get("place")) is not None:
|
340
|
+
event_data["place"] = PlaceReference._from_json_(pl, context)
|
341
|
+
|
342
|
+
# Lists
|
343
|
+
if (rls := data.get("roles")) is not None:
|
344
|
+
event_data["roles"] = [EventRole._from_json_(r, context) for r in rls]
|
345
|
+
|
346
|
+
return cls(**event_data)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from .attribution import Attribution
|
4
|
+
from .resource import Resource
|
5
|
+
from .logging_hub import hub, logging
|
6
|
+
"""
|
7
|
+
======================================================================
|
8
|
+
Logging
|
9
|
+
======================================================================
|
10
|
+
"""
|
11
|
+
log = logging.getLogger("gedcomx")
|
12
|
+
serial_log = "gedcomx.serialization"
|
13
|
+
#=====================================================================
|
14
|
+
|
15
|
+
class EvidenceReference:
|
16
|
+
identifier = 'http://gedcomx.org/v1/EvidenceReference'
|
17
|
+
version = 'http://gedcomx.org/conceptual-model/v1'
|
18
|
+
|
19
|
+
def __init__(self, resource: Resource, attribution: Optional[Attribution]) -> None:
|
20
|
+
pass
|
gedcomx/{Fact.py → fact.py}
RENAMED
@@ -1,28 +1,46 @@
|
|
1
1
|
import difflib
|
2
2
|
import re
|
3
3
|
|
4
|
-
from datetime import datetime
|
5
4
|
from enum import Enum
|
6
5
|
from typing import List, Optional, Dict, Any
|
6
|
+
"""
|
7
|
+
======================================================================
|
8
|
+
Project: Gedcom-X
|
9
|
+
File: fact.py
|
10
|
+
Author: David J. Cartwright
|
11
|
+
Purpose:
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
from .SourceReference import SourceReference
|
13
|
+
Created: 2025-08-25
|
14
|
+
Updated:
|
15
|
+
- 2025-09-03: _from_json_ refactor
|
16
|
+
|
17
|
+
======================================================================
|
18
|
+
"""
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
from
|
22
|
-
|
23
|
-
from
|
24
|
-
|
25
|
-
from .Extensions.rs10.rsLink import
|
20
|
+
"""
|
21
|
+
======================================================================
|
22
|
+
GEDCOM Module Types
|
23
|
+
======================================================================
|
24
|
+
"""
|
25
|
+
from .attribution import Attribution
|
26
|
+
from .conclusion import Conclusion, ConfidenceLevel
|
27
|
+
from .date import Date
|
28
|
+
from .document import Document
|
29
|
+
from .Extensions.rs10.rsLink import _rsLinks
|
30
|
+
from .note import Note
|
31
|
+
from .place_reference import PlaceReference
|
32
|
+
from .qualifier import Qualifier
|
33
|
+
from .resource import Resource
|
34
|
+
from .source_reference import SourceReference
|
35
|
+
from .logging_hub import hub, logging
|
36
|
+
"""
|
37
|
+
======================================================================
|
38
|
+
Logging
|
39
|
+
======================================================================
|
40
|
+
"""
|
41
|
+
log = logging.getLogger("gedcomx")
|
42
|
+
serial_log = "gedcomx.serialization"
|
43
|
+
#=====================================================================
|
26
44
|
|
27
45
|
|
28
46
|
class FactType(Enum):
|
@@ -370,7 +388,6 @@ class FactType(Enum):
|
|
370
388
|
return keywords_to_fact_type[matches[0]]
|
371
389
|
return None
|
372
390
|
|
373
|
-
|
374
391
|
class FactQualifier(Enum):
|
375
392
|
Age = "http://gedcomx.org/Age"
|
376
393
|
Cause = "http://gedcomx.org/Cause"
|
@@ -389,7 +406,6 @@ class FactQualifier(Enum):
|
|
389
406
|
}
|
390
407
|
return descriptions.get(self, "No description available.")
|
391
408
|
|
392
|
-
|
393
409
|
class Fact(Conclusion):
|
394
410
|
identifier = 'http://gedcomx.org/v1/Fact'
|
395
411
|
version = 'http://gedcomx.org/conceptual-model/v1'
|
@@ -397,9 +413,9 @@ class Fact(Conclusion):
|
|
397
413
|
def __init__(self,
|
398
414
|
id: Optional[str] = None,
|
399
415
|
lang: Optional[str] = None,
|
400
|
-
sources: Optional[List[SourceReference]] =
|
416
|
+
sources: Optional[List[SourceReference]] = None,
|
401
417
|
analysis: Optional[Resource | Document] = None,
|
402
|
-
notes: Optional[List[Note]] =
|
418
|
+
notes: Optional[List[Note]] = None,
|
403
419
|
confidence: Optional[ConfidenceLevel] = None,
|
404
420
|
attribution: Optional[Attribution] = None,
|
405
421
|
type: Optional[FactType] = None,
|
@@ -407,7 +423,7 @@ class Fact(Conclusion):
|
|
407
423
|
place: Optional[PlaceReference] = None,
|
408
424
|
value: Optional[str] = None,
|
409
425
|
qualifiers: Optional[List[FactQualifier]] = None,
|
410
|
-
links: Optional[
|
426
|
+
links: Optional[_rsLinks] = None):
|
411
427
|
super().__init__(id, lang, sources, analysis, notes, confidence, attribution, links=links)
|
412
428
|
self.type = type
|
413
429
|
self.date = date
|
@@ -428,60 +444,51 @@ class Fact(Conclusion):
|
|
428
444
|
|
429
445
|
@property
|
430
446
|
def _as_dict_(self):
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
447
|
+
'''
|
448
|
+
Standard GedcomX Type JSON Serialization
|
449
|
+
Returns: dict that contains only field for which the object has data in
|
450
|
+
'''
|
451
|
+
with hub.use(serial_log):
|
452
|
+
log.debug(f"Serializing 'Fact' with id: {self.id}")
|
453
|
+
type_as_dict = super()._as_dict_
|
454
|
+
if type_as_dict is None:
|
455
|
+
log.debug(f"Subject had no fields, creating new dict")
|
456
|
+
type_as_dict ={}
|
457
|
+
# Only add Relationship-specific fields
|
458
|
+
if self.type:
|
459
|
+
type_as_dict['type'] = getattr(self.type, 'value', self.type)
|
460
|
+
if self.date:
|
461
|
+
type_as_dict['date'] = self.date._as_dict_
|
462
|
+
if self.place:
|
463
|
+
type_as_dict['place'] = self.place._as_dict_
|
464
|
+
if self.value:
|
465
|
+
type_as_dict['value'] = self.value
|
466
|
+
if self.qualifiers and self.qualifiers != []:
|
467
|
+
type_as_dict['qualifiers'] = [getattr(q, 'value', q) for q in self.qualifiers]
|
468
|
+
log.debug(f"'Fact' serialized with fields: {type_as_dict.keys()}")
|
469
|
+
if type_as_dict == {}: log.warning("serializing and empty 'Fact'")
|
444
470
|
|
445
|
-
return
|
446
|
-
|
447
|
-
@classmethod
|
448
|
-
def _from_json_(cls, data: Dict[str, Any]) -> 'Fact':
|
471
|
+
return type_as_dict if type_as_dict != {} else None
|
449
472
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
qualifiers = [Qualifier._from_json_(q) for q in data.get('qualifiers', [])]
|
468
|
-
links = _rsLinkList._from_json_(data.get('links')) if data.get('links') else None
|
473
|
+
@classmethod
|
474
|
+
def _from_json_(cls, data: Dict[str, Any], context: Any = None) -> "Fact":
|
475
|
+
if not isinstance(data, dict):
|
476
|
+
raise TypeError(f"{cls.__name__}._from_json_ expected dict, got {type(data)}")
|
477
|
+
fact_data = Conclusion._dict_from_json_(data,context)
|
478
|
+
if (val := data.get("value")) is not None:
|
479
|
+
fact_data["value"] = val
|
480
|
+
if (date := data.get("date")) is not None:
|
481
|
+
fact_data["date"] = Date._from_json_(date, context)
|
482
|
+
if (place := data.get("place")) is not None:
|
483
|
+
fact_data["place"] = PlaceReference._from_json_(place, context)
|
484
|
+
if (ft := data.get("type")) is not None:
|
485
|
+
fact_data["type"] = FactType(ft)
|
486
|
+
if (quals := data.get("qualifiers")) is not None:
|
487
|
+
fact_data["qualifiers"] = [Qualifier._from_json_(q) for q in quals if q is not None]
|
488
|
+
|
489
|
+
return cls(**fact_data)
|
469
490
|
|
470
|
-
|
471
|
-
id=id_,
|
472
|
-
lang=lang,
|
473
|
-
sources=sources,
|
474
|
-
analysis=analysis,
|
475
|
-
notes=notes,
|
476
|
-
confidence=confidence,
|
477
|
-
attribution=attribution,
|
478
|
-
type=fact_type,
|
479
|
-
date=date,
|
480
|
-
place=place,
|
481
|
-
value=value,
|
482
|
-
qualifiers=qualifiers,
|
483
|
-
links=links
|
484
|
-
)
|
491
|
+
|
485
492
|
|
486
493
|
|
487
494
|
|
gedcomx/{Gedcom.py → gedcom.py}
RENAMED
@@ -1,5 +1,15 @@
|
|
1
1
|
import re
|
2
2
|
|
3
|
+
from .logging_hub import hub, logging
|
4
|
+
"""
|
5
|
+
======================================================================
|
6
|
+
Logging
|
7
|
+
======================================================================
|
8
|
+
"""
|
9
|
+
log = logging.getLogger("gedcomx")
|
10
|
+
serial_log = "gedcomx.serialization"
|
11
|
+
#=====================================================================
|
12
|
+
|
3
13
|
class Gedcom():
|
4
14
|
def __init__(self) -> None:
|
5
15
|
pass
|
@@ -9,7 +9,16 @@ from collections import defaultdict
|
|
9
9
|
from typing import Iterable, Iterator, List, Optional, Tuple, Union
|
10
10
|
|
11
11
|
import logging
|
12
|
-
from .
|
12
|
+
from .logging_hub import hub, ChannelConfig
|
13
|
+
from .logging_hub import hub, logging
|
14
|
+
"""
|
15
|
+
======================================================================
|
16
|
+
Logging
|
17
|
+
======================================================================
|
18
|
+
"""
|
19
|
+
log = logging.getLogger("gedcomx")
|
20
|
+
serial_log = "gedcomx.serialization"
|
21
|
+
#=====================================================================
|
13
22
|
|
14
23
|
job_id = "gedcomx.parsing.GEDCOM5x"
|
15
24
|
|
@@ -64,18 +73,17 @@ from typing import List, Optional, Iterator, Union
|
|
64
73
|
|
65
74
|
|
66
75
|
class Gedcom5xRecord():
|
67
|
-
def __init__(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
) -> None:
|
76
|
+
def __init__(self,
|
77
|
+
line_num: Optional[int] = None,
|
78
|
+
level: int = -1,
|
79
|
+
tag: str | None = "NONR",
|
80
|
+
xref: Optional[str] = None,
|
81
|
+
value: Optional[str] = None,
|
82
|
+
) -> None:
|
75
83
|
self.line = line_num
|
76
84
|
self._subRecords: List[Gedcom5xRecord] = []
|
77
85
|
self.level = int(level)
|
78
|
-
self.xref = xref
|
86
|
+
self.xref = xref.replace('@','') if xref else ''
|
79
87
|
self.pointer: bool = False
|
80
88
|
self.tag = str(tag).strip()
|
81
89
|
self.value = value
|
@@ -144,7 +152,7 @@ class Gedcom5xRecord():
|
|
144
152
|
# ───────────────────────────────
|
145
153
|
def subRecord(self, tag: str):
|
146
154
|
result = [r for r in self._subRecords if r.tag == tag]
|
147
|
-
return
|
155
|
+
return None if not result else result
|
148
156
|
|
149
157
|
def subRecords(self, tag: str | None = None) -> List['Gedcom5xRecord']:
|
150
158
|
if not tag:
|
@@ -367,7 +375,8 @@ class Gedcom5x():
|
|
367
375
|
import json
|
368
376
|
return json.dumps({'Individuals': [indi._as_dict_ for indi in self._individuals]},indent=4)
|
369
377
|
|
370
|
-
|
378
|
+
@property
|
379
|
+
def contents(self):
|
371
380
|
def print_table(pairs):
|
372
381
|
|
373
382
|
# Calculate the width of the columns
|
@@ -385,16 +394,16 @@ class Gedcom5x():
|
|
385
394
|
for name, value in pairs:
|
386
395
|
print(f"{name.ljust(name_width)} | {str(value).ljust(value_width)}")
|
387
396
|
|
388
|
-
imports_stats =
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
397
|
+
imports_stats = {
|
398
|
+
'Top Level Records': len(self.records),
|
399
|
+
'Individuals': len(self.individuals),
|
400
|
+
'Family Group Records': len(self.families),
|
401
|
+
'Repositories': len(self.repositories),
|
402
|
+
'Sources': len(self.sources),
|
403
|
+
'Objects': len(self.objects)
|
404
|
+
}
|
396
405
|
|
397
|
-
|
406
|
+
return imports_stats
|
398
407
|
|
399
408
|
@property
|
400
409
|
def sources(self) -> List[Gedcom5xRecord]:
|
@@ -475,6 +484,7 @@ class Gedcom5x():
|
|
475
484
|
|
476
485
|
level = int(match.group("level"))
|
477
486
|
xref_id = match.group("xref")
|
487
|
+
xref_id = xref_id.strip('@') if xref_id else None
|
478
488
|
tag = match.group("tag")
|
479
489
|
value = match.group("value")
|
480
490
|
if value == 'None': value = None
|