gedcom-x 0.5.6__py3-none-any.whl → 0.5.8__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 (64) hide show
  1. {gedcom_x-0.5.6.dist-info → gedcom_x-0.5.8.dist-info}/METADATA +1 -1
  2. gedcom_x-0.5.8.dist-info/RECORD +56 -0
  3. gedcomx/Extensions/__init__.py +1 -0
  4. gedcomx/Extensions/rs10/__init__.py +1 -0
  5. gedcomx/Extensions/rs10/rsLink.py +116 -0
  6. gedcomx/TopLevelTypeCollection.py +1 -1
  7. gedcomx/__init__.py +43 -41
  8. gedcomx/{Address.py → address.py} +13 -13
  9. gedcomx/{Agent.py → agent.py} +52 -24
  10. gedcomx/{Attribution.py → attribution.py} +36 -9
  11. gedcomx/{Conclusion.py → conclusion.py} +49 -21
  12. gedcomx/converter.py +1049 -0
  13. gedcomx/coverage.py +55 -0
  14. gedcomx/{Date.py → date.py} +11 -4
  15. gedcomx/{Document.py → document.py} +27 -8
  16. gedcomx/{Event.py → event.py} +102 -27
  17. gedcomx/{EvidenceReference.py → evidence_reference.py} +2 -2
  18. gedcomx/{Fact.py → fact.py} +45 -34
  19. gedcomx/{Gedcom5x.py → gedcom5x.py} +78 -61
  20. gedcomx/gedcom7/Exceptions.py +9 -0
  21. gedcomx/gedcom7/Gedcom7.py +160 -0
  22. gedcomx/gedcom7/GedcomStructure.py +94 -0
  23. gedcomx/gedcom7/Specification.py +347 -0
  24. gedcomx/gedcom7/__init__.py +26 -0
  25. gedcomx/gedcom7/g7interop.py +205 -0
  26. gedcomx/gedcom7/logger.py +19 -0
  27. gedcomx/gedcomx.py +501 -0
  28. gedcomx/{Gender.py → gender.py} +29 -17
  29. gedcomx/group.py +63 -0
  30. gedcomx/{Identifier.py → identifier.py} +13 -16
  31. gedcomx/{LoggingHub.py → logging_hub.py} +21 -0
  32. gedcomx/{Mutations.py → mutations.py} +50 -26
  33. gedcomx/name.py +396 -0
  34. gedcomx/{Note.py → note.py} +17 -10
  35. gedcomx/{OnlineAccount.py → online_account.py} +1 -1
  36. gedcomx/{Person.py → person.py} +52 -29
  37. gedcomx/place_description.py +123 -0
  38. gedcomx/place_reference.py +62 -0
  39. gedcomx/qualifier.py +54 -0
  40. gedcomx/{Relationship.py → relationship.py} +33 -13
  41. gedcomx/resource.py +85 -0
  42. gedcomx/serialization.py +815 -0
  43. gedcomx/{SourceDescription.py → source_description.py} +144 -85
  44. gedcomx/{SourceReference.py → source_reference.py} +15 -14
  45. gedcomx/{Subject.py → subject.py} +30 -28
  46. gedcomx/{GedcomX.py → translation.py} +283 -446
  47. gedcomx/{URI.py → uri.py} +42 -26
  48. gedcom_x-0.5.6.dist-info/RECORD +0 -45
  49. gedcomx/Coverage.py +0 -36
  50. gedcomx/Group.py +0 -37
  51. gedcomx/Name.py +0 -276
  52. gedcomx/PlaceDescription.py +0 -70
  53. gedcomx/PlaceReference.py +0 -30
  54. gedcomx/Qualifier.py +0 -27
  55. gedcomx/Resource.py +0 -75
  56. gedcomx/Serialization.py +0 -401
  57. gedcomx/Translation.py +0 -219
  58. {gedcom_x-0.5.6.dist-info → gedcom_x-0.5.8.dist-info}/WHEEL +0 -0
  59. {gedcom_x-0.5.6.dist-info → gedcom_x-0.5.8.dist-info}/top_level.txt +0 -0
  60. /gedcomx/{Exceptions.py → exceptions.py} +0 -0
  61. /gedcomx/{ExtensibleEnum.py → extensible_enum.py} +0 -0
  62. /gedcomx/{Gedcom.py → gedcom.py} +0 -0
  63. /gedcomx/{SourceCitation.py → source_citation.py} +0 -0
  64. /gedcomx/{TextValue.py → textvalue.py} +0 -0
gedcomx/coverage.py ADDED
@@ -0,0 +1,55 @@
1
+ from typing import Optional
2
+ """
3
+ ======================================================================
4
+ Project: Gedcom-X
5
+ File: coverage.py
6
+ Author: David J. Cartwright
7
+ Purpose:
8
+
9
+ Created: 2025-08-25
10
+ Updated:
11
+ - 2025-08-31:
12
+
13
+ ======================================================================
14
+ """
15
+
16
+ """
17
+ ======================================================================
18
+ GEDCOM Module Types
19
+ ======================================================================
20
+ """
21
+ from .date import Date
22
+ from .place_reference import PlaceReference
23
+
24
+
25
+ class Coverage:
26
+ identifier = 'http://gedcomx.org/v1/Coverage'
27
+ version = 'http://gedcomx.org/conceptual-model/v1'
28
+
29
+ def __init__(self,spatial: Optional[PlaceReference], temporal: Optional[Date]) -> None:
30
+ self.spatial = spatial
31
+ self.temporal = temporal
32
+
33
+ # ...existing code...
34
+
35
+ @property
36
+ def _as_dict_(self):
37
+ from .serialization import Serialization
38
+ type_as_dict = {}
39
+ if self.spatial:
40
+ type_as_dict['spatial'] = getattr(self.spatial, '_as_dict_', self.spatial)
41
+ if self.temporal: # (fixed: no space after the dot)
42
+ type_as_dict['temporal'] = getattr(self.temporal, '_as_dict_', self.temporal)
43
+ return Serialization.serialize_dict(type_as_dict)
44
+
45
+ @classmethod
46
+ def _from_json_(cls, data: dict):
47
+ """
48
+ Create a Coverage instance from a JSON-dict (already parsed).
49
+ """
50
+ from .place_reference import PlaceReference
51
+ from .date import Date
52
+
53
+ spatial = PlaceReference._from_json_(data.get('spatial')) if data.get('spatial') else None
54
+ temporal = Date._from_json_(data.get('temporal')) if data.get('temporal') else None
55
+ return cls(spatial=spatial, temporal=temporal)
@@ -4,6 +4,8 @@ from dateutil import parser
4
4
  import time
5
5
 
6
6
 
7
+
8
+
7
9
  class DateFormat:
8
10
  def __init__(self) -> None:
9
11
  pass
@@ -16,18 +18,23 @@ class Date:
16
18
  version = 'http://gedcomx.org/conceptual-model/v1'
17
19
 
18
20
  def __init__(self, original: Optional[str],normalized: Optional[DateNormalization] = None ,formal: Optional[str | DateFormat] = None) -> None:
19
- self.orginal = original
21
+ self.original = original
20
22
  self.formal = formal
21
23
 
22
24
  self.normalized: DateNormalization | None = normalized if normalized else None
23
25
 
24
26
  @property
25
27
  def _as_dict_(self):
26
- return {'original': self.orginal,
27
- 'formal': self.formal}
28
+ from .serialization import Serialization
29
+ type_as_dict = {}
30
+ if self.original:
31
+ type_as_dict['original'] = self.original
32
+ if self.formal:
33
+ type_as_dict['formal'] = self.formal
34
+ return Serialization.serialize_dict(type_as_dict)
28
35
 
29
36
  @classmethod
30
- def _from_json_(obj,data):
37
+ def _from_json_(cls,data):
31
38
  original = data.get('original',None)
32
39
  formal = data.get('formal',None)
33
40
 
@@ -1,13 +1,30 @@
1
1
  from enum import Enum
2
2
  from typing import Optional, List
3
+ """
4
+ ======================================================================
5
+ Project: Gedcom-X
6
+ File: document.py
7
+ Author: David J. Cartwright
8
+ Purpose:
3
9
 
4
- from .Attribution import Attribution
5
- from .Note import Note
6
- from .SourceReference import SourceReference
7
- from .Resource import Resource
10
+ Created: 2025-08-25
11
+ Updated:
12
+ - 2025-08-31:
13
+
14
+ ======================================================================
15
+ """
16
+
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
8
27
 
9
- from .Conclusion import Conclusion
10
- from .Serialization import Serialization
11
28
 
12
29
  class DocumentType(Enum):
13
30
  Abstract = "http://gedcomx.org/Abstract"
@@ -38,7 +55,7 @@ class Document(Conclusion):
38
55
  sources: Optional[List[SourceReference]] = None,
39
56
  analysis: Optional[Resource] = None,
40
57
  notes: Optional[List[Note]] = None,
41
- confidence: Optional[object] = None, # ConfidenceLevel
58
+ confidence: Optional[ConfidenceLevel] = None, # ConfidenceLevel
42
59
  attribution: Optional[Attribution] = None,
43
60
  type: Optional[DocumentType] = None,
44
61
  extracted: Optional[bool] = None, # Default to False
@@ -53,6 +70,7 @@ class Document(Conclusion):
53
70
 
54
71
  @property
55
72
  def _as_dict(self):
73
+ from .serialization import Serialization
56
74
  type_as_dict = super()._as_dict_
57
75
  if self.type:
58
76
  type_as_dict['type'] = self.type.value
@@ -69,5 +87,6 @@ class Document(Conclusion):
69
87
  """
70
88
  Create a Person instance from a JSON-dict (already parsed).
71
89
  """
90
+ from .serialization import Serialization
72
91
  type_as_dict = Serialization.get_class_fields('Document')
73
- return Serialization.deserialize(data, type_as_dict)
92
+ return Serialization.deserialize(type_as_dict,Document)
@@ -1,18 +1,37 @@
1
1
  from enum import Enum
2
2
  from typing import List, Optional
3
3
 
4
- from gedcomx.EvidenceReference import EvidenceReference
5
- from gedcomx.Identifier import Identifier
6
-
7
- from .Attribution import Attribution
8
- from .Conclusion import Conclusion, ConfidenceLevel
9
- from .Date import Date
10
- from .Note import Note
11
- from .PlaceReference import PlaceReference
12
- from .Serialization import Serialization
13
- from .SourceReference import SourceReference
14
- from .Subject import Subject
15
- from .Resource import Resource
4
+ """
5
+ ======================================================================
6
+ Project: Gedcom-X
7
+ File: Event.py
8
+ Author: David J. Cartwright
9
+ Purpose: Python Object representation of GedcomX Event Type, EventType, EventRole, EventRoleType Types
10
+
11
+ Created: 2025-08-25
12
+ Updated:
13
+ - 2025-08-31: fixed mutible [] in init, replaced List[Identifer] with IdentifierList
14
+
15
+ ======================================================================
16
+ """
17
+
18
+ """
19
+ ======================================================================
20
+ GEDCOM Module Type Imports
21
+ ======================================================================
22
+ """
23
+ from .attribution import Attribution
24
+ from .conclusion import ConfidenceLevel, Conclusion
25
+ from .date import Date
26
+ from .evidence_reference import EvidenceReference
27
+ from .identifier import IdentifierList
28
+ from .note import Note
29
+ from .place_reference import PlaceReference
30
+ from .resource import Resource
31
+ from .source_reference import SourceReference
32
+ from .subject import Subject
33
+
34
+ #=====================================================================
16
35
 
17
36
  class EventRoleType(Enum):
18
37
  Principal = "http://gedcomx.org/Principal"
@@ -23,10 +42,10 @@ class EventRoleType(Enum):
23
42
  @property
24
43
  def description(self):
25
44
  descriptions = {
26
- EventRole.Principal: "The person is the principal person of the event. For example, the principal of a birth event is the person that was born.",
27
- EventRole.Participant: "A participant in the event.",
28
- EventRole.Official: "A person officiating the event.",
29
- EventRole.Witness: "A witness of the event."
45
+ EventRoleType.Principal: "The person is the principal person of the event. For example, the principal of a birth event is the person that was born.",
46
+ EventRoleType.Participant: "A participant in the event.",
47
+ EventRoleType.Official: "A person officiating the event.",
48
+ EventRoleType.Witness: "A witness of the event."
30
49
  }
31
50
  return descriptions.get(self, "No description available.")
32
51
 
@@ -36,19 +55,64 @@ class EventRole(Conclusion):
36
55
 
37
56
  def __init__(self,
38
57
  id: Optional[str] = None,
39
- lang: Optional[str] = 'en',
58
+ lang: Optional[str] = None,
40
59
  sources: Optional[List[SourceReference]] = [],
41
60
  analysis: Optional[Resource] = None,
42
61
  notes: Optional[List[Note]] = [],
43
62
  confidence: Optional[ConfidenceLevel] = None,
44
63
  attribution: Optional[Attribution] = None,
45
- person: Resource = None,
64
+ person: Optional[Resource] = None,
46
65
  type: Optional[EventRoleType] = None,
47
66
  details: Optional[str] = None) -> None:
48
67
  super().__init__(id, lang, sources, analysis, notes, confidence, attribution)
49
68
  self.person = person
50
69
  self.type = type
51
70
  self.details = details
71
+
72
+ def __str__(self) -> str:
73
+ parts = []
74
+ if self.type is not None:
75
+ # assume enums expose .name
76
+ parts.append(f"type={getattr(self.type, 'name', str(self.type))}")
77
+ if self.person is not None:
78
+ # assume classes have meaningful __str__
79
+ parts.append(f"person={self.person}")
80
+ if self.details:
81
+ parts.append(f"details={self.details!r}")
82
+ if getattr(self, "id", None):
83
+ parts.append(f"id={self.id!r}")
84
+ return f"EventRole({', '.join(parts)})" if parts else "EventRole()"
85
+
86
+ def __repr__(self) -> str:
87
+ # assume enums expose .name and .value
88
+ if self.type is not None:
89
+ tcls = self.type.__class__.__name__
90
+ tname = getattr(self.type, "name", str(self.type))
91
+ tval = getattr(self.type, "value", self.type)
92
+ type_repr = f"<{tcls}.{tname}: {tval!r}>"
93
+ else:
94
+ type_repr = "None"
95
+ return (
96
+ f"{self.__class__.__name__}("
97
+ f"id={getattr(self, 'id', None)!r}, "
98
+ f"lang={getattr(self, 'lang', None)!r}, "
99
+ f"type={type_repr}, "
100
+ f"person={self.person!r}, "
101
+ f"details={self.details!r})"
102
+ )
103
+
104
+ @property
105
+ def _as_dict_(self):
106
+ from .serialization import Serialization
107
+ type_as_dict = super()._as_dict_
108
+ if self.person:
109
+ type_as_dict['person'] = Resource(target=self.person)._as_dict_
110
+ if self.type is not None:
111
+ type_as_dict['type'] = getattr(self.type, 'value', self.type)
112
+ if self.details:
113
+ type_as_dict['details'] = self.details
114
+
115
+ return Serialization.serialize_dict(type_as_dict)
52
116
 
53
117
  class EventType(Enum):
54
118
  Adoption = "http://gedcomx.org/Adoption"
@@ -180,16 +244,17 @@ class Event(Subject):
180
244
 
181
245
  def __init__(self,
182
246
  id: Optional[str] = None,
183
- lang: Optional[str] = 'en',
184
- sources: Optional[List[SourceReference]] = [],
247
+ lang: Optional[str] = None,
248
+ sources: Optional[List[SourceReference]] = None,
185
249
  analysis: Optional[Resource] = None,
186
- notes: Optional[List[Note]] = [],
250
+ notes: Optional[List[Note]] = None,
187
251
  confidence: Optional[ConfidenceLevel] = None,
188
252
  attribution: Optional[Attribution] = None,
189
253
  extracted: Optional[bool] = False,
190
- evidence: Optional[List[EvidenceReference]] = [],
191
- media: Optional[List[SourceReference]] = [],
192
- identifiers: Optional[List[Identifier]] = [],
254
+ evidence: Optional[List[EvidenceReference]] = None,
255
+ media: Optional[List[SourceReference]] = None,
256
+ #identifiers: Optional[List[Identifier]] = [],
257
+ identifiers: Optional[IdentifierList] = None,
193
258
  type: Optional[EventType] = None,
194
259
  date: Optional[Date] = None,
195
260
  place: Optional[PlaceReference] = None,
@@ -203,12 +268,22 @@ class Event(Subject):
203
268
 
204
269
  @property
205
270
  def _as_dict_(self):
206
- raise NotImplementedError("Not implemented yet")
271
+ from .serialization import Serialization
272
+ type_as_dict = super()._as_dict_
273
+ type_as_dict.update({
274
+ 'type': self.type.value if self.type else None,
275
+ 'date': self.date,
276
+ 'place': self.place._as_dict_ if self.place else None,
277
+ 'roles': [role._as_dict_ for role in self.roles],
278
+ })
279
+
280
+ return Serialization.serialize_dict(type_as_dict)
207
281
 
208
282
  @classmethod
209
283
  def _from_json_(cls, data: dict):
210
284
  """
211
285
  Create a Person instance from a JSON-dict (already parsed).
212
286
  """
213
- type_as_dict = Serialization.get_class_fields('Event')
214
- return Serialization.deserialize(data, type_as_dict)
287
+ #type_as_dict = Serialization.get_class_fields('Event')
288
+ from .serialization import Serialization
289
+ return Serialization.deserialize(data, Event)
@@ -1,7 +1,7 @@
1
1
  from typing import Optional
2
2
 
3
- from .Attribution import Attribution
4
- from .Resource import Resource
3
+ from .attribution import Attribution
4
+ from .resource import Resource
5
5
 
6
6
  class EvidenceReference:
7
7
  identifier = 'http://gedcomx.org/v1/EvidenceReference'
@@ -1,28 +1,38 @@
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
- from .Attribution import Attribution
9
- from .Conclusion import ConfidenceLevel
10
- from .Document import Document
11
- from .Date import Date
12
- from .Note import Note
13
- from .PlaceReference import PlaceReference
14
- from .SourceReference import SourceReference
15
- from .Serialization import Serialization
16
- from .Resource import Resource
13
+ Created: 2025-08-25
14
+ Updated:
15
+ - 2025-08-31:
16
+
17
+ ======================================================================
18
+ """
17
19
 
18
- from .Conclusion import Conclusion
19
- from .Qualifier import Qualifier
20
-
21
- from enum import Enum
22
-
23
- from collections.abc import Sized
24
-
25
- from .Extensions.rs10.rsLink import rsLink, _rsLinkList
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 _rsLinkList
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
+ #=====================================================================
26
36
 
27
37
 
28
38
  class FactType(Enum):
@@ -367,11 +377,9 @@ class FactType(Enum):
367
377
  for word in words:
368
378
  matches = difflib.get_close_matches(word, keywords_to_fact_type.keys(), n=1, cutoff=0.8)
369
379
  if matches:
370
- print(f"Guessed '{description} to be of fact type: {keywords_to_fact_type[matches[0]]}")
371
380
  return keywords_to_fact_type[matches[0]]
372
381
  return None
373
382
 
374
-
375
383
  class FactQualifier(Enum):
376
384
  Age = "http://gedcomx.org/Age"
377
385
  Cause = "http://gedcomx.org/Cause"
@@ -390,17 +398,16 @@ class FactQualifier(Enum):
390
398
  }
391
399
  return descriptions.get(self, "No description available.")
392
400
 
393
-
394
401
  class Fact(Conclusion):
395
402
  identifier = 'http://gedcomx.org/v1/Fact'
396
403
  version = 'http://gedcomx.org/conceptual-model/v1'
397
404
 
398
405
  def __init__(self,
399
406
  id: Optional[str] = None,
400
- lang: str = 'en',
401
- sources: Optional[List[SourceReference]] = [],
407
+ lang: Optional[str] = None,
408
+ sources: Optional[List[SourceReference]] = None,
402
409
  analysis: Optional[Resource | Document] = None,
403
- notes: Optional[List[Note]] = [],
410
+ notes: Optional[List[Note]] = None,
404
411
  confidence: Optional[ConfidenceLevel] = None,
405
412
  attribution: Optional[Attribution] = None,
406
413
  type: Optional[FactType] = None,
@@ -429,24 +436,28 @@ class Fact(Conclusion):
429
436
 
430
437
  @property
431
438
  def _as_dict_(self):
432
- fact_dict = super()._as_dict_
439
+ from .serialization import Serialization
440
+ type_as_dcit = super()._as_dict_
433
441
  # Only add Relationship-specific fields
434
- fact_dict.update( {
435
- 'type': self.type.value if self.type else None,
436
- 'date': self.date._as_dict_ if self.date else None,
437
- 'place': self.place._as_dict_ if self.place else None,
438
- 'value': self.value,
439
- 'qualifiers': [q.value for q in self.qualifiers] if self.qualifiers else []
440
- })
442
+ if self.type:
443
+ type_as_dcit['type'] = getattr(self.type, 'value', self.type)
444
+ if self.date:
445
+ type_as_dcit['date'] = self.date._as_dict_
446
+ if self.place:
447
+ type_as_dcit['place'] = self.place._as_dict_
448
+ if self.value:
449
+ type_as_dcit['value'] = self.value
450
+ if self.qualifiers:
451
+ type_as_dcit['qualifiers'] = [getattr(q, 'value', q) for q in self.qualifiers]
441
452
 
442
- return Serialization.serialize_dict(fact_dict)
453
+ return Serialization.serialize_dict(type_as_dcit)
443
454
 
444
455
  @classmethod
445
456
  def _from_json_(cls, data: Dict[str, Any]) -> 'Fact':
446
457
 
447
458
  # Extract fields, no trailing commas!
448
459
  id_ = data.get('id')
449
- lang = data.get('lang', 'en')
460
+ lang = data.get('lang', None)
450
461
  sources = [SourceReference._from_json_(s) for s in data.get('sources',[])]
451
462
  analysis = (Resource._from_json_(data['analysis'])
452
463
  if data.get('analysis') else None)