gedcom-x 0.5.8__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 (45) hide show
  1. {gedcom_x-0.5.8.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 +109 -59
  4. gedcomx/__init__.py +1 -1
  5. gedcomx/address.py +102 -16
  6. gedcomx/agent.py +81 -24
  7. gedcomx/attribution.py +52 -28
  8. gedcomx/conclusion.py +97 -45
  9. gedcomx/converter.py +209 -79
  10. gedcomx/coverage.py +10 -1
  11. gedcomx/date.py +42 -8
  12. gedcomx/document.py +37 -7
  13. gedcomx/event.py +77 -20
  14. gedcomx/evidence_reference.py +9 -0
  15. gedcomx/fact.py +53 -54
  16. gedcomx/gedcom.py +10 -0
  17. gedcomx/gedcom5x.py +30 -20
  18. gedcomx/gedcom7/__init__.py +1 -1
  19. gedcomx/gedcomx.py +95 -93
  20. gedcomx/gender.py +21 -9
  21. gedcomx/group.py +9 -0
  22. gedcomx/identifier.py +47 -20
  23. gedcomx/logging_hub.py +19 -0
  24. gedcomx/mutations.py +10 -5
  25. gedcomx/name.py +74 -33
  26. gedcomx/note.py +50 -18
  27. gedcomx/online_account.py +9 -0
  28. gedcomx/person.py +44 -26
  29. gedcomx/place_description.py +54 -8
  30. gedcomx/place_reference.py +30 -8
  31. gedcomx/qualifier.py +19 -3
  32. gedcomx/relationship.py +55 -14
  33. gedcomx/resource.py +45 -18
  34. gedcomx/serialization.py +400 -421
  35. gedcomx/source_citation.py +16 -4
  36. gedcomx/source_description.py +181 -94
  37. gedcomx/source_reference.py +51 -16
  38. gedcomx/subject.py +59 -14
  39. gedcomx/textvalue.py +66 -12
  40. gedcomx/translation.py +3 -3
  41. gedcomx/uri.py +155 -3
  42. gedcom_x-0.5.8.dist-info/RECORD +0 -56
  43. {gedcom_x-0.5.8.dist-info → gedcom_x-0.5.9.dist-info}/WHEEL +0 -0
  44. {gedcom_x-0.5.8.dist-info → gedcom_x-0.5.9.dist-info}/top_level.txt +0 -0
  45. /gedcomx/gedcom7/{Gedcom7.py → gedcom7.py} +0 -0
gedcomx/relationship.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from enum import Enum
2
- from typing import List, Optional
2
+ from typing import Any, Dict, Optional, List
3
3
  """
4
4
  ======================================================================
5
5
  Project: Gedcom-X
@@ -10,6 +10,7 @@ from typing import List, Optional
10
10
  Created: 2025-08-25
11
11
  Updated:
12
12
  - 2025-09-31: filename PEP8 standard
13
+ - 2025-09-03: _from_json_ refactor
13
14
 
14
15
  ======================================================================
15
16
  """
@@ -22,13 +23,22 @@ GEDCOM Module Types
22
23
  from .attribution import Attribution
23
24
  from .conclusion import ConfidenceLevel
24
25
  from .evidence_reference import EvidenceReference
26
+ from .Extensions.rs10.rsLink import _rsLinks #new
25
27
  from .fact import Fact
26
- from .identifier import Identifier
28
+ from .identifier import Identifier, make_uid
27
29
  from .note import Note
28
30
  from .person import Person
29
31
  from .resource import Resource
30
32
  from .source_reference import SourceReference
31
33
  from .subject import Subject
34
+ from .logging_hub import hub, logging
35
+ """
36
+ ======================================================================
37
+ Logging
38
+ ======================================================================
39
+ """
40
+ log = logging.getLogger("gedcomx")
41
+ serial_log = "gedcomx.serialization"
32
42
  #=====================================================================
33
43
 
34
44
 
@@ -74,18 +84,20 @@ class Relationship(Subject):
74
84
  media: Optional[List[SourceReference]] = None,
75
85
  identifiers: Optional[List[Identifier]] = None,
76
86
  type: Optional[RelationshipType] = None,
87
+ links: Optional[_rsLinks] = None,
77
88
  ) -> None:
78
89
 
79
90
  # Call superclass initializer if required
80
- super().__init__(id, lang, sources, analysis, notes, confidence, attribution, extracted, evidence, media, identifiers)
91
+ super().__init__(id, lang, sources, analysis, notes, confidence, attribution, extracted, evidence, media, identifiers,links=links)
81
92
 
93
+ self.id = id if id else make_uid()
82
94
  self.type = type
83
95
  self.person1 = person1
84
96
  self.person2 = person2
85
97
  self.facts = facts if facts else []
86
98
 
87
99
  def add_fact(self,fact: Fact):
88
- if fact is not None and isinstance(fact,Fact):
100
+ if (fact is not None) and isinstance(fact,Fact):
89
101
  for existing_fact in self.facts:
90
102
  if fact == existing_fact:
91
103
  return
@@ -96,20 +108,49 @@ class Relationship(Subject):
96
108
  @property
97
109
  def _as_dict_(self):
98
110
  from .serialization import Serialization
99
- type_as_dict = super()._as_dict_
100
- type_as_dict.update({
101
- "type": self.type.value if isinstance(self.type, RelationshipType) else self.type,
111
+ return Serialization.serialize(self)
112
+
113
+ type_as_dict = (super()._as_dict_ or {}).copy()
114
+
115
+ extras = {
116
+ "type": getattr(self.type, "value", None),
102
117
  "person1": Resource(target=self.person1)._as_dict_ if self.person1 else None,
103
- "person2": Resource(target=self.person1)._as_dict_ if self.person2 else None,
104
- "facts": [fact for fact in self.facts] if self.facts else None
105
- })
106
- return Serialization.serialize_dict(type_as_dict)
118
+ "person2": Resource(target=self.person2)._as_dict_ if self.person2 else None,
119
+ "facts": [f._as_dict_ for f in self.facts if f] if getattr(self, "facts", None) else None,
120
+ }
121
+
122
+ # only keep non-empty values
123
+ type_as_dict.update({k: v for k, v in extras.items() if v not in (None, [], {}, ())})
124
+
125
+ return type_as_dict or None
107
126
 
108
127
  @classmethod
109
- def _from_json_(cls, data: dict):
128
+ def _from_json_(cls, data: Dict[str, Any], context: Any = None) -> "Relationship":
110
129
  """
111
130
  Create a Person instance from a JSON-dict (already parsed).
112
131
  """
113
- from .serialization import Serialization
114
- return Serialization.deserialize(data, Relationship)
132
+ if not isinstance(data, dict):
133
+ raise TypeError(f"{cls.__name__}._from_json_ expected dict, got {type(data)}")
134
+
135
+ relationship_data: Dict[str, Any] = {}
136
+ relationship_data = Subject._dict_from_json_(data,context)
137
+
138
+ if (id_ := data.get("id")) is not None:
139
+ relationship_data["id"] = id_
140
+
141
+ if (type_ := data.get("type")) is not None:
142
+ relationship_data["type"] = RelationshipType(type_)
143
+
144
+ # person1 / person2
145
+ if (p1 := data.get("person1")) is not None:
146
+ relationship_data["person1"] = Resource._from_json_(p1,context)
147
+
148
+ if (p2 := data.get("person2")) is not None:
149
+ relationship_data["person2"] = Resource._from_json_(p2,context)
150
+
151
+ # facts
152
+ if (facts := data.get("facts")) is not None:
153
+ relationship_data["facts"] = [Fact._from_json_(f, context) for f in facts]
154
+
155
+ return cls(**relationship_data)
115
156
 
gedcomx/resource.py CHANGED
@@ -10,6 +10,7 @@ from typing import Optional
10
10
  Created: 2025-08-25
11
11
  Updated:
12
12
  - 2025-08-31: working on target=Resource and deserialization issues
13
+ - 2025-09-03: _from_json_ refactor, arguments changed
13
14
 
14
15
  ======================================================================
15
16
  """
@@ -21,6 +22,15 @@ GEDCOM Module Types
21
22
  """
22
23
 
23
24
  from .uri import URI
25
+ from .logging_hub import hub, logging
26
+ """
27
+ ======================================================================
28
+ Logging
29
+ ======================================================================
30
+ """
31
+ log = logging.getLogger("gedcomx")
32
+ serial_log = "gedcomx.serialization"
33
+ #=====================================================================
24
34
 
25
35
  class Resource:
26
36
  """
@@ -35,10 +45,14 @@ class Resource:
35
45
  If `id` is not a valid UUID.
36
46
  """
37
47
  # TODO, Deal with a resouce being passed, as it may be unresolved.
38
- def __init__(self,uri: Optional[URI|str] = None, id:Optional[str] = None,top_lvl_object: Optional[object] = None,target= None) -> None:
48
+ def __init__(self,resource: URI | None = None,resourceId: str | None = None, target: object = None) -> None:
39
49
 
40
- self.resource = URI.from_url(uri.value) if isinstance(uri,URI) else URI.from_url(uri) if isinstance(uri,str) else None
41
- self.Id = id
50
+ #if (resource is None) and (target is None): #TODO
51
+ # raise ValueError('Resource object must point to something.')
52
+
53
+ self.resource = resource
54
+ self.resourceId = resourceId
55
+ self.Id = None
42
56
 
43
57
  self.type = None
44
58
  self.resolved = False
@@ -48,12 +62,15 @@ class Resource:
48
62
  if target:
49
63
  if isinstance(target,Resource):
50
64
  self.resource = target.resource
51
- self.Id = target.Id
65
+ self.resourceId = target.resourceId
52
66
  self.target = target.target
53
67
  else:
54
- self.resource = target.uri
55
- self.Id = target.id
56
- self.type = type(target)
68
+ log.debug(f"Target of type: {type(target)}, {target}")
69
+ if hasattr(target,'uri'):
70
+ self.resource = target.uri
71
+ else:
72
+ self.resourceId = URI(fragment=target.id)
73
+ self.resourceId = target.id
57
74
 
58
75
  @property
59
76
  def uri(self):
@@ -62,24 +79,34 @@ class Resource:
62
79
  @property
63
80
  def _as_dict_(self):
64
81
  from .serialization import Serialization
82
+ return Serialization.serialize(self)
65
83
  typ_as_dict = {}
66
- if self.resource:
67
- typ_as_dict['resource'] = self.resource.value if self.resource else None
68
- if self.Id:
69
- typ_as_dict['resourceId'] = self.Id
70
- return Serialization.serialize_dict(typ_as_dict)
84
+ if self.resource is not None:
85
+ typ_as_dict["resource"] = self.resource
86
+ if self.resourceId is not None:
87
+ typ_as_dict["resourceId"] = self.resourceId,
88
+
89
+ return typ_as_dict or None
90
+
91
+
71
92
 
72
93
  @classmethod
73
- def _from_json_(cls,data):
74
- # TODO This is not used but taken care of in Serialization
75
- r = Resource(uri=data.get('resource'),id=data.get('resourceId',None))
76
- #return r
94
+ def _from_json_(cls, data: dict, context=None) -> "Resource":
95
+ if not isinstance(data, dict):
96
+ raise TypeError(f"{cls.__name__}._from_json_ expected dict, got {type(data)} {data}")
97
+ resource = {}
98
+
99
+ # Scalars
100
+ if (res := data.get("resource")) is not None:
101
+ resource["resource"] = res
102
+
103
+ return cls(**resource)
77
104
 
78
105
  def __repr__(self) -> str:
79
- return f"Resource(uri={self.resource}, id={self.Id}, target={self.target})"
106
+ return f"Resource(resource={self.resource}, resourceId={self.resourceId}, target={self.target})"
80
107
 
81
108
  def __str__(self) -> str:
82
- return f"{self.resource}{f', id={self.Id}' if self.Id else ''}"
109
+ return f"resource={self.resource}{f', resourceId={self.resourceId}' if self.resourceId else ''}"
83
110
 
84
111
 
85
112