gedcom-x 0.5.9__py3-none-any.whl → 0.5.11__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 (48) hide show
  1. {gedcom_x-0.5.9.dist-info → gedcom_x-0.5.11.dist-info}/METADATA +1 -1
  2. gedcom_x-0.5.11.dist-info/RECORD +57 -0
  3. gedcomx/Extensions/rs10/rsLink.py +2 -1
  4. gedcomx/__init__.py +8 -3
  5. gedcomx/address.py +3 -0
  6. gedcomx/agent.py +11 -6
  7. gedcomx/attribution.py +3 -1
  8. gedcomx/conclusion.py +10 -6
  9. gedcomx/converter.py +92 -27
  10. gedcomx/coverage.py +3 -1
  11. gedcomx/date.py +3 -0
  12. gedcomx/document.py +3 -1
  13. gedcomx/event.py +3 -0
  14. gedcomx/evidence_reference.py +30 -3
  15. gedcomx/extensible.py +86 -0
  16. gedcomx/fact.py +6 -2
  17. gedcomx/gedcom5x.py +21 -3
  18. gedcomx/gedcom7/GedcomStructure.py +1 -3
  19. gedcomx/gedcom7/__init__.py +1 -1
  20. gedcomx/gedcom7/gedcom7.py +3 -3
  21. gedcomx/gedcom7/specification.py +4817 -0
  22. gedcomx/gedcomx.py +3 -0
  23. gedcomx/gender.py +5 -1
  24. gedcomx/group.py +11 -2
  25. gedcomx/identifier.py +5 -2
  26. gedcomx/logging_hub.py +132 -22
  27. gedcomx/name.py +15 -6
  28. gedcomx/note.py +25 -10
  29. gedcomx/online_account.py +20 -0
  30. gedcomx/person.py +8 -6
  31. gedcomx/place_description.py +3 -1
  32. gedcomx/place_reference.py +5 -2
  33. gedcomx/qualifier.py +2 -0
  34. gedcomx/relationship.py +8 -5
  35. gedcomx/resource.py +20 -6
  36. gedcomx/schemas.py +530 -0
  37. gedcomx/serialization.py +36 -16
  38. gedcomx/source_citation.py +22 -0
  39. gedcomx/source_description.py +22 -18
  40. gedcomx/source_reference.py +25 -3
  41. gedcomx/subject.py +2 -3
  42. gedcomx/textvalue.py +19 -4
  43. gedcomx/uri.py +8 -6
  44. gedcom_x-0.5.9.dist-info/RECORD +0 -56
  45. gedcomx/Logging.py +0 -19
  46. gedcomx/gedcom7/Specification.py +0 -347
  47. {gedcom_x-0.5.9.dist-info → gedcom_x-0.5.11.dist-info}/WHEEL +0 -0
  48. {gedcom_x-0.5.9.dist-info → gedcom_x-0.5.11.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,8 @@
1
+ from __future__ import annotations
1
2
  import warnings
2
3
 
3
4
  from enum import Enum
4
- from typing import Any, Dict, List, Optional, TYPE_CHECKING
5
+ from typing import Any, Dict, List, Optional, Union, TYPE_CHECKING
5
6
  if TYPE_CHECKING:
6
7
  from .document import Document
7
8
 
@@ -17,6 +18,7 @@ if TYPE_CHECKING:
17
18
  Updated:
18
19
  - 2025-08-31: _as_dict_ refactored to ignore empty fields, changed id creation to make_uid()
19
20
  - 2025-09-01: filename PEP8 standard, imports changed accordingly
21
+ - 2025-09-09: added schema_class
20
22
 
21
23
 
22
24
  ======================================================================
@@ -35,6 +37,7 @@ from .identifier import Identifier, IdentifierList, make_uid
35
37
  from .logging_hub import hub, logging
36
38
  from .note import Note
37
39
  from .resource import Resource
40
+ from .schemas import schema_class
38
41
  from .source_citation import SourceCitation
39
42
  from .source_reference import SourceReference
40
43
  from .textvalue import TextValue
@@ -66,7 +69,8 @@ class ResourceType(Enum):
66
69
  ResourceType.Record: "A historical record, such as a census record or a vital record."
67
70
  }
68
71
  return descriptions.get(self, "No description available.")
69
-
72
+
73
+ @schema_class(toplevel=True)
70
74
  class SourceDescription:
71
75
  """Description of a genealogical information source.
72
76
 
@@ -123,11 +127,11 @@ class SourceDescription:
123
127
  citations: Optional[List[SourceCitation]] = [],
124
128
  mediaType: Optional[str] = None,
125
129
  about: Optional[URI] = None,
126
- mediator: Optional[Agent|Resource] = None,
127
- publisher: Optional[Agent|Resource] = None,
130
+ mediator: Optional[Union[Resource,Agent]] = None,
131
+ publisher: Optional[Union[Resource,Agent]] = None,
128
132
  authors: Optional[List[Resource]] = None,
129
133
  sources: Optional[List[SourceReference]] = None, # SourceReference
130
- analysis: Optional["Document|Resource"] = None, #TODO add type checker so its a document
134
+ analysis: Optional[Union[Resource,Document]] = None, #TODO add type checker so its a document
131
135
  componentOf: Optional[SourceReference] = None, # SourceReference
132
136
  titles: Optional[List[TextValue]] = None,
133
137
  notes: Optional[List[Note]] = None,
@@ -140,7 +144,7 @@ class SourceDescription:
140
144
  modified: Optional[Date] = None,
141
145
  published: Optional[Date] = None,
142
146
  repository: Optional[Agent] = None,
143
- max_note_count: int = 20):
147
+ ):
144
148
 
145
149
  self.id = id if id else make_uid()
146
150
  self.resourceType = resourceType
@@ -164,19 +168,19 @@ class SourceDescription:
164
168
  self.modified = modified
165
169
  self.published = published
166
170
  self.repository = repository
167
- self.max_note_count = max_note_count
171
+
168
172
 
169
173
  self.uri = URI(fragment=id) if id else None #TODO Should i take care of this in the collections?
170
174
 
171
175
  self._place_holder = False
172
176
 
173
177
  @property
174
- def publisher(self) -> Resource | Agent | None:
178
+ def publisher(self) -> Union[Resource, Agent, None]:
175
179
  return self._publisher
176
180
 
177
-
178
181
  @publisher.setter
179
- def publisher(self, value: Resource | Agent):
182
+ def publisher(self,
183
+ value: Union[Resource, Agent]):
180
184
  if value is None:
181
185
  self._publisher = None
182
186
  elif isinstance(value,Resource):
@@ -198,14 +202,14 @@ class SourceDescription:
198
202
  self.identifiers.append(identifier_to_add)
199
203
 
200
204
  def add_note(self,note_to_add: Note):
201
- if len(self.notes) >= self.max_note_count:
202
- warnings.warn(f"Max not count of {self.max_note_count} reached for id: {self.id}")
203
- return False
204
- if note_to_add and isinstance(note_to_add,Note):
205
- for existing in self.notes:
206
- if note_to_add == existing:
207
- return False
208
- self.notes.append(note_to_add)
205
+ if note_to_add is not None and note_to_add.text is not None and note_to_add.text != '':
206
+ if note_to_add and isinstance(note_to_add,Note):
207
+ for existing in self.notes:
208
+ if note_to_add == existing:
209
+ return False
210
+ self.notes.append(note_to_add)
211
+ return
212
+
209
213
 
210
214
  def add_source_reference(self, source_to_add: SourceReference):
211
215
  if source_to_add and isinstance(object,SourceReference):
@@ -1,6 +1,26 @@
1
1
  from __future__ import annotations
2
- from typing import List, Optional, TYPE_CHECKING
2
+ from typing import List, Optional, Union, TYPE_CHECKING
3
+ """
4
+ ======================================================================
5
+ Project: Gedcom-X
6
+ File: Person.py
7
+ Author: David J. Cartwright
8
+ Purpose: Python Object representation of GedcomX Person Type
9
+
10
+ Created: 2025-08-25
11
+ Updated:
12
+ - 2025-08-31: _as_dict_ to only create entries in dict for fields that hold data
13
+ - 2025-09-03: _from_json_ refactor
14
+ - 2025-09-09: added schema_class
15
+
16
+ ======================================================================
17
+ """
3
18
 
19
+ """
20
+ ======================================================================
21
+ GEDCOM Module Types
22
+ ======================================================================
23
+ """
4
24
  if TYPE_CHECKING:
5
25
  from .source_description import SourceDescription
6
26
 
@@ -8,6 +28,7 @@ from .attribution import Attribution
8
28
  from .qualifier import Qualifier
9
29
 
10
30
  from .resource import Resource
31
+ from .schemas import schema_class
11
32
 
12
33
  from .uri import URI
13
34
  from .logging_hub import hub, logging
@@ -55,13 +76,14 @@ class KnownSourceReference(Qualifier):
55
76
  )
56
77
  }
57
78
  return descriptions.get(self, "No description available.")
58
-
79
+
80
+ @schema_class()
59
81
  class SourceReference:
60
82
  identifier = 'http://gedcomx.org/v1/SourceReference'
61
83
  version = 'http://gedcomx.org/conceptual-model/v1'
62
84
 
63
85
  def __init__(self,
64
- description: SourceDescription | URI | None = None,
86
+ description: Union[URI, SourceDescription] = None,
65
87
  descriptionId: Optional[str] = None,
66
88
  attribution: Optional[Attribution] = None,
67
89
  qualifiers: Optional[List[Qualifier]] = None
gedcomx/subject.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import warnings
2
- from typing import List, Optional
2
+ from typing import List, Optional
3
3
  """
4
4
  ======================================================================
5
5
  Project: Gedcom-X
@@ -55,14 +55,13 @@ class Subject(Conclusion):
55
55
  evidence: Optional[List[EvidenceReference]] = [],
56
56
  media: Optional[List[SourceReference]] = [],
57
57
  identifiers: Optional[IdentifierList] = None,
58
- uri: Optional[Resource] = None,
59
58
  links: Optional[_rsLinks] = None) -> None:
60
59
  super().__init__(id, lang, sources, analysis, notes, confidence, attribution,links=links)
61
60
  self.extracted = extracted
62
61
  self.evidence = evidence
63
62
  self.media = media
64
63
  self.identifiers = identifiers if identifiers else IdentifierList()
65
- self.uri = uri
64
+
66
65
 
67
66
  def add_identifier(self, identifier_to_add: Identifier):
68
67
  if identifier_to_add and isinstance(identifier_to_add,Identifier):
gedcomx/textvalue.py CHANGED
@@ -11,6 +11,7 @@ from typing import Any, Optional, Dict
11
11
  Updated:
12
12
  - 2025-09-03 _from_json_ refactor
13
13
  - 2025-09-04 added _str_ and _repr_ dunders
14
+ - 2025-09-09: added schema_class
14
15
 
15
16
  ======================================================================
16
17
  """
@@ -21,6 +22,7 @@ GEDCOM Module Types
21
22
  ======================================================================
22
23
  """
23
24
  from .logging_hub import hub, logging
25
+ from .schemas import schema_class
24
26
  """
25
27
  ======================================================================
26
28
  Logging
@@ -30,6 +32,7 @@ log = logging.getLogger("gedcomx")
30
32
  serial_log = "gedcomx.serialization"
31
33
  #=====================================================================
32
34
 
35
+ @schema_class()
33
36
  class TextValue:
34
37
  identifier = 'http://gedcomx.org/v1/TextValue'
35
38
  version = 'http://gedcomx.org/conceptual-model/v1'
@@ -37,6 +40,9 @@ class TextValue:
37
40
  def __init__(self, value: Optional[str] = None, lang: Optional[str] = None) -> None:
38
41
  self.lang = lang
39
42
  self.value = value
43
+ if value is None or value == '':
44
+ assert False
45
+
40
46
 
41
47
  def _append_to_value(self, value_to_append):
42
48
  if not isinstance(value_to_append, str):
@@ -56,11 +62,20 @@ class TextValue:
56
62
  def __str__(self):
57
63
  return f"{self.value} ({self.lang})"
58
64
 
65
+ # --- identity & hashing -------------------------------------------------
66
+ def _key(self) -> tuple[str, str]:
67
+ # Normalize for equality/hash:
68
+ # - treat missing lang as ""
69
+ # - casefold lang to compare 'EN' == 'en'
70
+ # - strip value to ignore surrounding whitespace
71
+ return ((self.lang or "").casefold(), (self.value or "").strip())
72
+
59
73
  def __eq__(self, other: object) -> bool:
60
- if isinstance(other,TextValue):
61
- if self.value.strip() == other.value.strip():
62
- return True
63
- return False
74
+ if not isinstance(other, TextValue):
75
+ return NotImplemented
76
+ return self._key() == other._key()
77
+
78
+
64
79
 
65
80
  # ...existing code...
66
81
 
gedcomx/uri.py CHANGED
@@ -24,6 +24,7 @@ GEDCOM Module Types
24
24
  ======================================================================
25
25
  """
26
26
  from .logging_hub import hub, logging
27
+ from .schemas import schema_class, SCHEMA
27
28
  """
28
29
  ======================================================================
29
30
  Logging
@@ -49,6 +50,9 @@ def _encode_query(q: QueryLike) -> str:
49
50
  return urlencode(list(q), doseq=True) # coerce iterable to a sequence
50
51
 
51
52
 
53
+
54
+
55
+ @schema_class()
52
56
  class URI():
53
57
  def __init__(self,
54
58
 
@@ -84,7 +88,7 @@ class URI():
84
88
  if self.target is not None:
85
89
  #log.debug(f"Creating URI from Target {target}, most likely for serialization")
86
90
  if hasattr(self.target,'id'):
87
- log.debug(f"'{target}.id' found {target.id}, using as fragment")
91
+ if hub.logEnabled:log.debug(f"'{type(target).__name__}.id' found {target.id}, using as fragment")
88
92
  self.fragment = self.target.id
89
93
  if hasattr(self.target,'uri'):
90
94
  #log.debug(f"'{target}.uri' found, copying")
@@ -156,10 +160,7 @@ class URI():
156
160
  def _as_dict_(self):
157
161
  return self.value or self._value
158
162
 
159
- @property
160
- def uri(self):
161
- return self
162
-
163
+
163
164
  @classmethod
164
165
  def from_url(cls,url):
165
166
  return cls(target=url)
@@ -167,7 +168,8 @@ class URI():
167
168
  @classmethod
168
169
  def _from_json_(cls,data,context=None):
169
170
  return cls(value=data)
170
-
171
+
172
+ #SCHEMA.set_uri_class(URI)
171
173
 
172
174
 
173
175
  @dataclass(slots=True)
@@ -1,56 +0,0 @@
1
- gedcomx/Logging.py,sha256=vBDOjawVXc4tCge1laYjy6_2Ves-fnGzG0m6NnLZejE,624
2
- gedcomx/TopLevelTypeCollection.py,sha256=p99i-O5LXiXe3GlC6jWuz4nH1TAcKxOLbe0VRxWbSFY,1495
3
- gedcomx/Zip.py,sha256=lBxcv-Vip45884EHj56wZJJ5I36Q38UuHUidDxQBoS8,14
4
- gedcomx/__init__.py,sha256=8qEa_oYCC1nMyeMt0zNmsqXnocfA2q6VNUlp0cCnMLI,1723
5
- gedcomx/address.py,sha256=7tGUPRItlSiUZ6-WaDNj4sbjvU8W_f2kw-I8s_nntTU,8049
6
- gedcomx/agent.py,sha256=HxDRB8axhReUmTDtn0XFNemG6znjJQezi-qxO2JRfCg,12803
7
- gedcomx/attribution.py,sha256=S648H7it_780WLA0c4dkBSrjeXIMz_YVMk1eJ6wZk6Q,4586
8
- gedcomx/conclusion.py,sha256=BpLFZY0p02yGa3H9Fis2eZz8NYBi7YsiLbaX6N7ZICM,11167
9
- gedcomx/converter.py,sha256=_VzdkjS52AVXrtKUAzgI6VGDaw7Wysa76B1Vt1XnNEs,57637
10
- gedcomx/coverage.py,sha256=XmBiTGxuH9WoeXumrgu03EMWtccHe982hFJu2Coxceo,2206
11
- gedcomx/date.py,sha256=xiAatY25DXTW8usmhbyx_6rmEae3FJnmR5FriGkCN80,3560
12
- gedcomx/document.py,sha256=quaa1N1XcqhMdpTwCzpvnZfRgygK1mRhFPWyX09ZrWw,4555
13
- gedcomx/event.py,sha256=7Iogi3eVmR4_-qg6seIo7orAmVS1ENvUQcJO3_tZGlc,15417
14
- gedcomx/evidence_reference.py,sha256=vtP0rYpehfuu4Jugf1V9u5V_wgPu-2EPb7mqPLS_9cI,696
15
- gedcomx/exceptions.py,sha256=0OdPM3euhBMgX8o61ZwPuKeN8zPuSuuDcSBFflVGFqk,587
16
- gedcomx/extensible_enum.py,sha256=DftCZLMBNul3C9hwh-rf0GE3SVdvylvyd5mt7bX_l6o,6535
17
- gedcomx/fact.py,sha256=bEAUKvLpn7ZAJjyOE57dcvOnvkdzZ63GqF3yb2nGhX0,24972
18
- gedcomx/gedcom.py,sha256=A8GQ670E6_knfP37kOGHdVl_cC9RXQoc4Dk6D_qlnuQ,2059
19
- gedcomx/gedcom5x.py,sha256=ajjLeTlncrSgw3JSBRo8Ip9aZik2NHnUt1iDhjc9-mE,23645
20
- gedcomx/gedcomx.py,sha256=PunMwjHIE4fp7O7sjuNrI8p44_4Y3pI43FQSCh7pyqE,19329
21
- gedcomx/gender.py,sha256=d2AEvTSa28sfQ1910X-Ysfi7MNDRMQ35EA7jcBYsLck,3178
22
- gedcomx/group.py,sha256=I4vdBBsdMdqAMigkzGg4mRxrCAjvsJJ-bIa_aR6CDhA,2879
23
- gedcomx/identifier.py,sha256=hCLfBuHVTVwa2VGD_2NFsiftFkqS3-7W8XMnyjmPZbM,9603
24
- gedcomx/logging_hub.py,sha256=DbYGwMdVD_nEj0xpVzHjsMVTi_WjttLLRexiebezfzM,8307
25
- gedcomx/mutations.py,sha256=ugQgfQh0o9r8FIB_dz5s6KqPyIDMHn2YSP7DvAHsDv0,7236
26
- gedcomx/name.py,sha256=5UpNgFPBfTfzC5yLQDqmeSJ-Fg1T6Nio9vEa6f5kA2Y,19501
27
- gedcomx/note.py,sha256=joDgKrDS9pbOEEve9LGopP2Gz48kFKqMeHYR72Z7bA0,3813
28
- gedcomx/online_account.py,sha256=EYMW-CepfwppaJu5RiPQOK63YKxnjE8bVOPUNQqbrMM,639
29
- gedcomx/person.py,sha256=QALVxY2NlZ93BU0QR9Q4Ykm4kZ-7j4j4QTVXo4hpO60,8993
30
- gedcomx/place_description.py,sha256=vFCVW37tKBosYCGttkXppR7yDXA-L8YVLpixSN-8b4E,7564
31
- gedcomx/place_reference.py,sha256=XE-tyRsvfXVK--vdiA_Pvj0ZrUecl72JldbV-c-k_PU,2939
32
- gedcomx/qualifier.py,sha256=Lg5D_CRLKxaUHcCGLzXhKmpMkmdOeQso0V-XN3yH2n4,2352
33
- gedcomx/relationship.py,sha256=_wA1NujEqQO0HzSfjlfLcl-yCFWBcOsRyxs3klr0HfE,5852
34
- gedcomx/resource.py,sha256=ShK3sQOaNI4ZlrIUcepL7_uLd_QX4zMx-A1SU2In_m4,3608
35
- gedcomx/serialization.py,sha256=Pg_tDO5wUXDgyMqVGPwAlm2WdBBNUA0L-TBaRSWhaNo,30308
36
- gedcomx/source_citation.py,sha256=QSh1zHK9DsgjQu6oHPDTCReLVs2HP8YDR-NlLAG-pek,1237
37
- gedcomx/source_description.py,sha256=A2R1T26HYqpk8Q4W8BYp7zlvHYqycHkUMX94uQRpwV8,19258
38
- gedcomx/source_reference.py,sha256=iakI-vLMXbSMuZLDU2c4J5s-XDanOCUJvV2Mz8uRP_8,6895
39
- gedcomx/subject.py,sha256=dgStcWiI3a3VX2QEgUIQNbo8HELD2sFUhYT-VI46ND8,5117
40
- gedcomx/textvalue.py,sha256=Y-SDRpHR2gGpWIyaOvTYrM5EbfOUeX7Tnh_7iOITAbk,3135
41
- gedcomx/translation.py,sha256=4REL68WaWqcC5f3XcBCZ1dn0gtaZftQJTCkvl1Sf-NA,61395
42
- gedcomx/uri.py,sha256=ceCcbbrx99QekivhQ_xfMvkmaUKiW_IF21WKTOFBtJg,9693
43
- gedcomx/Extensions/__init__.py,sha256=MQzi_whzlxiLiknUNh10hG8OVrNqJE38l6n-AwCssx8,24
44
- gedcomx/Extensions/rs10/__init__.py,sha256=nSHoZiD8hsCAyE-KyRTuWSLqSJSFh12kSz7hqilAMps,26
45
- gedcomx/Extensions/rs10/rsLink.py,sha256=IdmcG1pVicxX91ZMu9fUPwKYoXCl0Q60inGwiThDAVE,6004
46
- gedcomx/gedcom7/Exceptions.py,sha256=xeKr4x8b7r8pOqJ9yMpsCVTyxPeOlREDGgKoM5rX4U0,149
47
- gedcomx/gedcom7/GedcomStructure.py,sha256=ZKNoEcXc41KdrCLPx-A8ohOU9VYmXAkFc4xuZExsBPw,3435
48
- gedcomx/gedcom7/Specification.py,sha256=qIBe9wzL1GB0l0NyetS1ncbhz5C44b9nMyjAxHuqMt8,9245
49
- gedcomx/gedcom7/__init__.py,sha256=tPHWW9kchPFEZ5sfURWPPzK8ZBimsQn7SRDULAW1Yc4,679
50
- gedcomx/gedcom7/g7interop.py,sha256=hSzwqeok2n7xziEvN2QiJY7bVCWrOnZIZWXubnkrv7w,9945
51
- gedcomx/gedcom7/gedcom7.py,sha256=i_g9W0qsZQYLMoD2sBCA13ibKRYFnSf4uj9-ix_tE4Q,5614
52
- gedcomx/gedcom7/logger.py,sha256=QM1SySyh91UEhs90d2DMhH-s9qGF8XS8I8gr1eOcmfw,617
53
- gedcom_x-0.5.9.dist-info/METADATA,sha256=Wn8DcPMkZvmTZRrnNlo4GzUlwRYGSRbKJABN7oVYTaw,4332
54
- gedcom_x-0.5.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
- gedcom_x-0.5.9.dist-info/top_level.txt,sha256=smVBF4nxSU-mzCd6idtRYTbYjPICMMi8pTqewEmqF8Y,8
56
- gedcom_x-0.5.9.dist-info/RECORD,,
gedcomx/Logging.py DELETED
@@ -1,19 +0,0 @@
1
- import logging
2
-
3
- def get_logger(name='gedcomx.log'):
4
- logger = logging.getLogger(name)
5
- if not logger.handlers:
6
- logger.setLevel(logging.DEBUG)
7
-
8
- formatter = logging.Formatter('[%(asctime)s] %(levelname)s - %(name)s - %(message)s')
9
-
10
- console_handler = logging.StreamHandler()
11
- console_handler.setFormatter(formatter)
12
- logger.addHandler(console_handler)
13
-
14
- # Optional: file logging
15
- file_handler = logging.FileHandler(f"{name}.log", encoding="utf-8")
16
- file_handler.setFormatter(formatter)
17
- logger.addHandler(file_handler)
18
-
19
- return logger