gedcom-x 0.5.5__py3-none-any.whl → 0.5.7__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.
gedcomx/Name.py CHANGED
@@ -2,13 +2,33 @@ from enum import Enum
2
2
  from typing import List,Optional
3
3
  from typing_extensions import Self
4
4
 
5
+ """
6
+ ======================================================================
7
+ Project: Gedcom-X
8
+ File: Name.py
9
+ Author: David J. Cartwright
10
+ Purpose: Python Object representation of GedcomX Name, NameType, NameForm, NamePart Types
11
+
12
+ Created: 2025-08-25
13
+ Updated:
14
+ - 2025-08-31: _as_dict_ to only create entries in dict for fields that hold data
15
+
16
+ ======================================================================
17
+ """
18
+
19
+ """
20
+ ======================================================================
21
+ GEDCOM Module Types
22
+ ======================================================================
23
+ """
24
+ #======================================================================
5
25
  from .Attribution import Attribution
6
26
  from .Conclusion import Conclusion, ConfidenceLevel
7
27
  from .Date import Date
8
28
  from .Note import Note
9
- from .Serialization import Serialization
10
- from .SourceReference import SourceReference
11
29
  from .Resource import Resource
30
+ from .SourceReference import SourceReference
31
+ #======================================================================
12
32
 
13
33
 
14
34
  class NameType(Enum):
@@ -90,22 +110,57 @@ class NamePartType(Enum):
90
110
  return descriptions.get(self, "No description available.")
91
111
 
92
112
  class NamePart:
113
+ """Used to model a portion of a full name
114
+ including the terms that make up that portion. Some name parts may have qualifiers
115
+ to provide additional semantic meaning to the name part (e.g., "given name" or "surname").
116
+
117
+ Args:
118
+ type (NamePartType | None): Classification of this component of the name
119
+ (e.g., ``Given``, ``Surname``, ``Prefix``, ``Suffix``, ``Title``, ``Particle``).
120
+ value (str): The textual value for this part, without surrounding
121
+ punctuation (e.g., ``"John"``, ``"van"``, ``"III"``).
122
+ qualifiers (list[NamePartQualifier] | None): Optional qualifiers that refine
123
+ the meaning or usage of this part (e.g., language/script variants, initials).
124
+
125
+ Examples:
126
+ >>> from gedcomx.Name import *
127
+ >>> typ = NamePartType.Given
128
+ >>> given = "Moses"
129
+ >>> q = NamePartQualifier.Primary
130
+ >>> name = NamePart(type=typ,value=given,qualifiers=[q])
131
+ >>> print(name)
132
+ NamePart(type=Given, value='Moses', qualifiers=1)
133
+
134
+ """
93
135
  identifier = 'http://gedcomx.org/v1/NamePart'
94
136
  version = 'http://gedcomx.org/conceptual-model/v1'
95
137
 
96
138
  def __init__(self,
97
139
  type: Optional[NamePartType] = None,
98
140
  value: Optional[str] = None,
99
- qualifiers: Optional[List[NamePartQualifier]] = []) -> None:
141
+ qualifiers: Optional[List[NamePartQualifier]] = None) -> None:
100
142
  self.type = type
101
143
  self.value = value
102
- self.qualifiers = qualifiers
144
+ self.qualifiers = qualifiers if qualifiers else []
103
145
 
146
+ @property
104
147
  def _as_dict_(self):
105
- return Serialization.serialize_dict(
106
- {'type': self.type.value if self.type else None,
107
- 'value': self.value if self.value else None,
108
- 'qualifiers': [qualifier.value for qualifier in self.qualifiers] if self.qualifiers else None})
148
+ from .Serialization import Serialization
149
+ type_as_dict = {}
150
+ if self.type:
151
+ type_as_dict['type'] = self.type.value
152
+ if self.value:
153
+ type_as_dict['value'] = self.value
154
+ if self.qualifiers:
155
+ type_as_dict['qualifiers'] = [q.value for q in self.qualifiers]
156
+ Serialization.serialize_dict(type_as_dict)
157
+
158
+ @classmethod
159
+ def _from_json_(cls,data):
160
+ name_part =NamePart(type=NamePartType(data['type']) if 'type' in data else None,
161
+ value=data.get('value'),
162
+ qualifiers=[NamePartQualifier(q) for q in data.get('qualifiers')])
163
+ return name_part
109
164
 
110
165
  def __eq__(self, other):
111
166
  if not isinstance(other, NamePart):
@@ -114,26 +169,114 @@ class NamePart:
114
169
  self.value == other.value and
115
170
  self.qualifiers == other.qualifiers)
116
171
 
172
+ def __str__(self) -> str:
173
+ parts = []
174
+ if self.type is not None:
175
+ parts.append(f"type={getattr(self.type, 'name', str(self.type))}")
176
+ if self.value is not None:
177
+ parts.append(f"value={self.value!r}")
178
+ if self.qualifiers:
179
+ parts.append(f"qualifiers={len(self.qualifiers)}")
180
+ return f"NamePart({', '.join(parts)})" if parts else "NamePart()"
181
+
182
+ def __repr__(self) -> str:
183
+ if self.type is not None:
184
+ tcls = self.type.__class__.__name__
185
+ tname = getattr(self.type, "name", str(self.type))
186
+ tval = getattr(self.type, "value", self.type)
187
+ type_repr = f"<{tcls}.{tname}: {tval!r}>"
188
+ else:
189
+ type_repr = "None"
190
+ return (
191
+ f"{self.__class__.__name__}("
192
+ f"type={type_repr}, "
193
+ f"value={self.value!r}, "
194
+ f"qualifiers={self.qualifiers!r})"
195
+ )
196
+
117
197
  class NameForm:
198
+ """A representation of a name (a "name form")
199
+ within a given cultural context, such as a given language and script.
200
+ As names are captured (both in records or in applications), the terms
201
+ in the name are sometimes classified by type. For example, a certificate
202
+ of death might prompt for **"given name(s)"** and **"surname"**. The parts
203
+ list can be used to represent the terms in the name that have been classified.
204
+
205
+ Args:
206
+ lang (str | None): BCP-47 language tag for this name form (e.g., "en").
207
+ fullText (str | None): The full, unparsed name string as written in the source.
208
+ If provided, the name SHOULD be rendered as it would normally be spoken in
209
+ the applicable cultural context.
210
+ parts (list[NamePart] | None): Ordered structured components of the name
211
+ (e.g., Given, Surname). If provided, ``fullText`` may be omitted. If
212
+ provided, the list SHOULD be ordered such that the parts are in the order
213
+ they would normally be spoken in the applicable cultural context.
214
+
215
+ """
118
216
  identifier = 'http://gedcomx.org/v1/NameForm'
119
217
  version = 'http://gedcomx.org/conceptual-model/v1'
120
218
 
121
- def __init__(self, lang: Optional[str] = 'en', fullText: Optional[str] = None,parts: Optional[List[NamePart]] = []) -> None:
219
+ def __init__(self, lang: Optional[str] = None,
220
+ fullText: Optional[str] = None,
221
+ parts: Optional[List[NamePart]] = None) -> None:
222
+
122
223
  self.lang = lang
123
224
  self.fullText = fullText
124
- self.parts = parts
225
+ self.parts = parts if parts else []
125
226
 
126
227
  @property
127
228
  def _as_dict_(self):
128
- return Serialization.serialize_dict(
129
- {'lang': self.lang,
130
- 'fullText': self.fullText,
131
- 'parts': [part._as_dict_() for part in self.parts] if self.parts else None})
229
+ from .Serialization import Serialization
230
+ type_as_dict = {}
231
+ if self.lang:
232
+ type_as_dict['lang'] = self.lang
233
+ if self.fullText:
234
+ type_as_dict['fullText'] = self.fullText
235
+ if self.parts:
236
+ type_as_dict['parts'] = [part._as_dict_ for part in self.parts if part]
237
+ return Serialization.serialize_dict(type_as_dict)
238
+
239
+ @classmethod
240
+ def _from_json_(cls, data: dict) -> "NameForm":
241
+ """Build a NameForm from JSON-like dict."""
242
+ return cls(
243
+ lang=data.get("lang", "en"),
244
+ fullText=data.get("fullText"),
245
+ parts=[NamePart._from_json_(p) for p in ensure_list(data.get("parts"))],
246
+ )
132
247
 
133
248
  def _fulltext_parts(self):
134
249
  pass
135
250
 
136
251
  class Name(Conclusion):
252
+ """**Defines a name of a person.**
253
+
254
+ A Name is intended to represent a single variant of a person's name.
255
+ This means that nicknames, spelling variations, or other names
256
+ (often distinguishable by a name type) should be modeled with
257
+ separate instances of Name.
258
+
259
+ .. admonition:: Advanced details
260
+ :class: toggle
261
+
262
+ The name forms of a name contain alternate representations of the name.
263
+ A Name MUST contain at least one name form, presumably a representation
264
+ of the name that is considered proper and well formed in the person's native,
265
+ historical cultural context. Other name forms MAY be included, which can be
266
+ used to represent this name in contexts where the native name form is not easily
267
+ recognized and interpreted. Alternate forms are more likely in situations where
268
+ conclusions are being analyzed across cultural context boundaries that have both
269
+ language and writing script differences.
270
+
271
+
272
+ Attributes:
273
+ type (Optional[:class:`~gedcomx.NameType`]): Classification of the name
274
+ (e.g., BirthName, AlsoKnownAs).
275
+ nameForms (List[:class:`~gedcomx.NameForm`]): One or more structured
276
+ representations of the name (full text and parts).
277
+ date (Optional[:class:`~gedcomx.Date`]): Date context for this name
278
+ (e.g., when the name was used or recorded).
279
+ """
137
280
  identifier = 'http://gedcomx.org/v1/Name'
138
281
  version = 'http://gedcomx.org/conceptual-model/v1'
139
282
 
@@ -163,8 +306,8 @@ class Name(Conclusion):
163
306
  name = Name()
164
307
  return name
165
308
 
166
- def __init__(self, id: str = None,
167
- lang: str = 'en',
309
+ def __init__(self, id: Optional[str] = None,
310
+ lang: Optional[str] = None,
168
311
  sources: Optional[List[SourceReference]] = None,
169
312
  analysis: Resource = None,
170
313
  notes: Optional[List[Note]] = None,
@@ -187,39 +330,52 @@ class Name(Conclusion):
187
330
 
188
331
  @property
189
332
  def _as_dict_(self):
190
- def _serialize(value):
191
- if isinstance(value, (str, int, float, bool, type(None))):
192
- return value
193
- elif isinstance(value, dict):
194
- return {k: _serialize(v) for k, v in value.items()}
195
- elif isinstance(value, (list, tuple, set)):
196
- return [_serialize(v) for v in value]
197
- elif hasattr(value, "_as_dict_"):
198
- return value._as_dict_
199
- else:
200
- return str(value) # fallback for unknown objects
201
-
202
- name_as_dict = super()._as_dict_
203
-
204
- name_as_dict.update( {
205
- 'type':self.type.value if self.type else None,
206
- 'nameForms': [nameForm._as_dict_ for nameForm in self.nameForms],
207
- 'date': self.date._as_dict_ if self.date else None})
333
+ from .Serialization import Serialization
334
+ type_as_dict = super()._as_dict_
335
+ if self.type:
336
+ type_as_dict['type'] = getattr(self.type, 'value', self.type)
337
+ if self.nameForms:
338
+ type_as_dict['nameForms'] = [nf._as_dict_ for nf in self.nameForms if nf]
339
+ if self.date:
340
+ type_as_dict['date'] = self.date._as_dict_
208
341
 
209
- #del name_as_dict['id']
210
- # Serialize and exclude None values
211
- for key, value in name_as_dict.items():
212
- if value is not None:
213
- name_as_dict[key] = _serialize(value)
214
-
215
- # 3) merge and filter out None *at the top level*
216
- return {
217
- k: v
218
- for k, v in name_as_dict.items()
219
- if v is not None
220
- }
342
+ return Serialization.serialize_dict(type_as_dict)
343
+
344
+ @classmethod
345
+ def _from_json_(cls, data: dict) -> "Name":
346
+ """Build a Name from JSON-like dict."""
347
+ return cls(
348
+ id=data.get("id"),
349
+ lang=data.get("lang", "en"),
350
+ sources=[SourceReference._from_json_(s) for s in ensure_list(data.get("sources"))],
351
+ analysis=Resource._from_json_(data["analysis"]) if data.get("analysis") else None,
352
+ notes=[Note._from_json_(n) for n in ensure_list(data.get("notes"))],
353
+ confidence=ConfidenceLevel._from_json_(data["confidence"]) if data.get("confidence") else None,
354
+ attribution=Attribution._from_json_(data["attribution"]) if data.get("attribution") else None,
355
+ type=NameType(data["type"]) if data.get("type") else None,
356
+ nameForms=[NameForm._from_json_(nf) for nf in ensure_list(data.get("nameForms"))],
357
+ date=Date._from_json_(data["date"]) if data.get("date") else None,
358
+ )
221
359
 
222
- return name_as_dict
360
+ def __str__(self) -> str:
361
+ """Return a human-readable string for the Name-like object."""
362
+ return f"Name(id={self.id}, type={self.type}, forms={len(self.nameForms)}, date={self.date})"
363
+
364
+ def __repr__(self) -> str:
365
+ """Return an unambiguous string representation of the Name-like object."""
366
+ return (
367
+ f"{self.__class__.__name__}("
368
+ f"id={self.id!r}, "
369
+ f"lang={self.lang!r}, "
370
+ f"sources={self.sources!r}, "
371
+ f"analysis={self.analysis!r}, "
372
+ f"notes={self.notes!r}, "
373
+ f"confidence={self.confidence!r}, "
374
+ f"attribution={self.attribution!r}, "
375
+ f"type={self.type!r}, "
376
+ f"nameForms={self.nameForms!r}, "
377
+ f"date={self.date!r})"
378
+ )
223
379
 
224
380
  class QuickName():
225
381
  def __new__(cls,name: str) -> Name:
@@ -231,46 +387,10 @@ def ensure_list(val):
231
387
  return []
232
388
  return val if isinstance(val, list) else [val]
233
389
 
234
- NamePart._from_json_ = classmethod(lambda cls, data: NamePart(
235
- type=NamePartType(data['type']) if 'type' in data else None,
236
- value=data.get('value'),
237
- qualifiers=[NamePartQualifier(q) for q in ensure_list(data.get('qualifiers'))]
238
- ))
239
-
240
- NamePart._to_dict_ = lambda self: {
241
- 'type': self.type.value if self.type else None,
242
- 'value': self.value,
243
- 'qualifiers': [q.value for q in self.qualifiers] if self.qualifiers else []
244
- }
245
-
246
-
247
- # NameForm
248
- NameForm._from_json_ = classmethod(lambda cls, data: NameForm(
249
- lang=data.get('lang', 'en'),
250
- fullText=data.get('fullText'),
251
- parts=[NamePart._from_json_(p) for p in ensure_list(data.get('parts'))]
252
- ))
253
-
254
- NameForm._to_dict_ = lambda self: {
255
- 'lang': self.lang,
256
- 'fullText': self.fullText,
257
- 'parts': [p._to_dict_() for p in self.parts] if self.parts else []
258
- }
259
-
260
-
261
- # Name
262
- Name._from_json_ = classmethod(lambda cls, data: cls(
263
- id=data.get('id'),
264
- lang=data.get('lang', 'en'),
265
- sources=[SourceReference._from_json_(s) for s in ensure_list(data.get('sources'))],
266
- analysis=Resource._from_json_(data['analysis']) if data.get('analysis') else None,
267
- notes=[Note._from_json_(n) for n in ensure_list(data.get('notes'))],
268
- confidence=ConfidenceLevel._from_json_(data['confidence']) if data.get('confidence') else None,
269
- attribution=Attribution._from_json_(data['attribution']) if data.get('attribution') else None,
270
- type=NameType(data['type']) if data.get('type') else None,
271
- nameForms=[NameForm._from_json_(nf) for nf in ensure_list(data.get('nameForms'))],
272
- date=Date._from_json_(data['date']) if data.get('date') else None
273
- ))
390
+
391
+
392
+
393
+
274
394
 
275
395
 
276
396
 
gedcomx/Note.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
3
  from .Attribution import Attribution
4
- from .Serialization import Serialization
5
4
 
6
5
  class Note:
7
6
  identifier = 'http://gedcomx.org/v1/Note'
@@ -15,20 +14,28 @@ class Note:
15
14
 
16
15
  def append(self, text_to_add: str):
17
16
  if text_to_add and isinstance(text_to_add, str):
18
- self.text = self.text + text_to_add
17
+ if self.text:
18
+ self.text = self.text + text_to_add
19
+ else:
20
+ self.text = text_to_add
19
21
  else:
20
22
  return #TODO
21
23
  raise ValueError("The text to add must be a non-empty string.")
22
24
 
23
25
  @property
24
26
  def _as_dict_(self):
25
- note_dict = {
26
- "lang":self.lang if self.lang else None,
27
- "subject":self.subject if self.subject else None,
28
- "text":self.text if self.text else None,
29
- "attribution": self.attribution if self.attribution else None
30
- }
31
- return Serialization.serialize_dict(note_dict)
27
+ from .Serialization import Serialization
28
+ type_as_dict = {}
29
+ if self.lang:
30
+ type_as_dict["lang"] = self.lang
31
+ if self.subject:
32
+ type_as_dict["subject"] = self.subject
33
+ if self.text:
34
+ type_as_dict["text"] = self.text
35
+ if self.attribution:
36
+ # If attribution exposes `_as_dict_` as a property, use it; otherwise include as-is
37
+ type_as_dict["attribution"] = getattr(self.attribution, "_as_dict_", self.attribution)
38
+ return Serialization.serialize_dict(type_as_dict)
32
39
 
33
40
  def __eq__(self, other):
34
41
  if not isinstance(other, Note):
gedcomx/Person.py CHANGED
@@ -1,22 +1,38 @@
1
- from enum import Enum
2
1
  from typing import List, Optional
3
2
  from urllib.parse import urljoin
4
3
 
4
+ """
5
+ ======================================================================
6
+ Project: Gedcom-X
7
+ File: Person.py
8
+ Author: David J. Cartwright
9
+ Purpose: Python Object representation of GedcomX Person Type
10
+
11
+ Created: 2025-08-25
12
+ Updated:
13
+ - 2025-08-31: _as_dict_ to only create entries in dict for fields that hold data
14
+
15
+ ======================================================================
16
+ """
17
+
18
+ """
19
+ ======================================================================
20
+ GEDCOM Module Types
21
+ ======================================================================
22
+ """
5
23
  from .Attribution import Attribution
6
24
  from .Conclusion import ConfidenceLevel
7
25
  from .Date import Date
8
26
  from .EvidenceReference import EvidenceReference
27
+ from .Extensions.rs10.rsLink import _rsLinkList
9
28
  from .Fact import Fact, FactType
10
29
  from .Gender import Gender, GenderType
11
30
  from .Identifier import IdentifierList
12
31
  from .Name import Name, QuickName
13
32
  from .Note import Note
33
+ from .Resource import Resource
14
34
  from .SourceReference import SourceReference
15
- from .Serialization import Serialization
16
35
  from .Subject import Subject
17
- from .Resource import Resource
18
- from collections.abc import Sized
19
- from .Extensions.rs10.rsLink import _rsLinkList
20
36
 
21
37
  class Person(Subject):
22
38
  """A person in the system.
@@ -40,7 +56,7 @@ class Person(Subject):
40
56
  notes: Optional[List[Note]] = None,
41
57
  confidence: Optional[ConfidenceLevel] = None,
42
58
  attribution: Optional[Attribution] = None,
43
- extracted: bool = None,
59
+ extracted: Optional[bool] = None,
44
60
  evidence: Optional[List[EvidenceReference]] = None,
45
61
  media: Optional[List[SourceReference]] = None,
46
62
  identifiers: Optional[IdentifierList] = None,
@@ -102,7 +118,7 @@ class Person(Subject):
102
118
  "ascendancyNumber": "1",
103
119
  "deathDate": "from 2001 to 2005",
104
120
  "descendancyNumber": "1",
105
- "gender": self.gender.type,
121
+ "gender": self.gender.type if self.gender else 'Unknown',
106
122
  "lifespan": "-2005",
107
123
  "name": self.names[0].nameForms[0].fullText
108
124
  }
@@ -111,17 +127,20 @@ class Person(Subject):
111
127
 
112
128
  @property
113
129
  def _as_dict_(self):
114
- type_as_dict = super()._as_dict_ # Start with base class fields
115
- # Only add Relationship-specific fields
116
- type_as_dict.update({
117
- 'private': self.private,
118
- 'living': self.living,
119
- 'gender': self.gender._as_dict_ if self.gender else None,
120
- 'names': [name._as_dict_ for name in self.names],
121
- 'facts': [fact._as_dict_ for fact in self.facts],
122
- 'uri': self.uri._as_dict_ if self.uri else None
123
-
124
- })
130
+ from .Serialization import Serialization
131
+ type_as_dict = super()._as_dict_
132
+ if self.private is not None:
133
+ type_as_dict['private'] = self.private
134
+ if self.living is not None:
135
+ type_as_dict['living'] = self.living
136
+ if self.gender:
137
+ type_as_dict['gender'] = self.gender._as_dict_
138
+ if self.names:
139
+ type_as_dict['names'] = [n._as_dict_ for n in self.names if n]
140
+ if self.facts:
141
+ type_as_dict['facts'] = [f._as_dict_ for f in self.facts if f]
142
+ if self.uri:
143
+ type_as_dict['uri'] = self.uri._as_dict_
125
144
 
126
145
  return Serialization.serialize_dict(type_as_dict)
127
146
 
@@ -130,10 +149,12 @@ class Person(Subject):
130
149
  """
131
150
  Create a Person instance from a JSON-dict (already parsed).
132
151
  """
152
+ from .Serialization import Serialization
133
153
  return Serialization.deserialize(data, Person)
134
154
 
135
155
  @classmethod
136
156
  def from_familysearch(cls, pid: str, token: str, *, base_url: Optional[str] = None):
157
+ from .Serialization import Serialization
137
158
  """
138
159
  Fetch a single person by PID from FamilySearch and return a Person.
139
160
  - pid: e.g. "KPHP-4B4"
@@ -1,24 +1,65 @@
1
1
  from typing import List, Optional
2
2
 
3
+ """
4
+ ======================================================================
5
+ Project: Gedcom-X
6
+ File: PlaceDescription.py
7
+ Author: David J. Cartwright
8
+ Purpose: Python Object representation of GedcomX PlaceDescription 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
+
14
+ ======================================================================
15
+ """
16
+
17
+ """
18
+ ======================================================================
19
+ GEDCOM Module Types
20
+ ======================================================================
21
+ """
3
22
  from .Attribution import Attribution
4
23
  from .Conclusion import ConfidenceLevel
5
24
  from .Date import Date
6
25
  from .EvidenceReference import EvidenceReference
7
26
  from .Identifier import IdentifierList
8
27
  from .Note import Note
9
- from .SourceReference import SourceReference
10
- from .TextValue import TextValue
11
28
  from .Resource import Resource
12
- from .Serialization import Serialization
29
+ from .SourceReference import SourceReference
13
30
  from .Subject import Subject
31
+ from .TextValue import TextValue
14
32
  from .URI import URI
15
33
 
16
34
  class PlaceDescription(Subject):
35
+ """PlaceDescription describes the details of a place in terms of
36
+ its name and possibly its type, time period, and/or a geospatial description
37
+ functioning as a description of a place as a snapshot in time.
38
+
39
+ Encapsulates textual names, geospatial coordinates, jurisdictional context,
40
+ temporal coverage, and related resources (media, sources, evidence, etc.).
41
+
42
+
43
+ Attributes:
44
+ names (Optional[List[TextValue]]): Human-readable names or labels for
45
+ the place (e.g., “Boston, Suffolk, Massachusetts, United States”).
46
+ type (Optional[str]): A place type identifier (e.g., a URI). **TODO:**
47
+ replace with an enumeration when finalized.
48
+ place (Optional[URI]): Canonical identifier (URI) for the place.
49
+ jurisdiction (Optional[Resource|PlaceDescription]): The governing or
50
+ containing jurisdiction of this place (e.g., county for a town).
51
+ latitude (Optional[float]): Latitude in decimal degrees (WGS84).
52
+ longitude (Optional[float]): Longitude in decimal degrees (WGS84).
53
+ temporalDescription (Optional[Date]): Temporal coverage/validity window
54
+ for this description (e.g., when a jurisdictional boundary applied).
55
+ spatialDescription (Optional[Resource]): A resource describing spatial
56
+ geometry or a link to an external gazetteer/shape definition.
57
+ """
17
58
  identifier = "http://gedcomx.org/v1/PlaceDescription"
18
59
  version = 'http://gedcomx.org/conceptual-model/v1'
19
60
 
20
61
  def __init__(self, id: Optional[str] =None,
21
- lang: str = 'en',
62
+ lang: Optional[str] = None,
22
63
  sources: Optional[List[SourceReference]] = None,
23
64
  analysis: Optional[Resource] = None,
24
65
  notes: Optional[List[Note]] =None,
@@ -29,9 +70,9 @@ class PlaceDescription(Subject):
29
70
  media: Optional[List[SourceReference]] = None,
30
71
  identifiers: Optional[IdentifierList] = None,
31
72
  names: Optional[List[TextValue]] = None,
32
- type: Optional[str] = None,
73
+ type: Optional[str] = None, #TODO This needs to be an enumerated value, work out details
33
74
  place: Optional[URI] = None,
34
- jurisdiction: Optional["Resource | PlaceDescription"] = None, # PlaceDescription
75
+ jurisdiction: Optional["Resource | PlaceDescription"] = None,
35
76
  latitude: Optional[float] = None,
36
77
  longitude: Optional[float] = None,
37
78
  temporalDescription: Optional[Date] = None,
@@ -42,24 +83,33 @@ class PlaceDescription(Subject):
42
83
  self.type = type
43
84
  self.place = place
44
85
  self.jurisdiction = jurisdiction
45
- self.latitide = latitude
46
- self.longitute = longitude
86
+ self.latitude = latitude
87
+ self.longitude = longitude
47
88
  self.temporalDescription = temporalDescription
48
- self.spacialDescription = spatialDescription
89
+ self.spatialDescription = spatialDescription
49
90
 
50
91
  @property
51
92
  def _as_dict_(self):
93
+ from .Serialization import Serialization
52
94
  type_as_dict = super()._as_dict_
53
- type_as_dict.update({
54
- "names": [n for n in self.names] if self.names else None,
55
- "type": self.type if self.type else None,
56
- "place": self.place._as_dict_ if self.place else None,
57
- "jurisdiction": self.jurisdiction._as_dict_ if self.jurisdiction else None,
58
- "latitude": float(self.latitide) if self.latitide else None,
59
- "longitude": float(self.longitute) if self.longitute else None,
60
- "temporalDescription": self.temporalDescription if self.temporalDescription else None,
61
- "spatialDescription": self.spacialDescription._as_dict_ if self.spacialDescription else None
62
- })
95
+
96
+ if self.names:
97
+ type_as_dict["names"] = [n._as_dict_ for n in self.names if n]
98
+ if self.type:
99
+ type_as_dict["type"] = self.type #TODO
100
+ if self.place:
101
+ type_as_dict["place"] = self.place._as_dict_
102
+ if self.jurisdiction:
103
+ type_as_dict["jurisdiction"] = self.jurisdiction._as_dict_
104
+ if self.latitude is not None: # include 0.0; exclude only None
105
+ type_as_dict["latitude"] = float(self.latitude)
106
+ if self.longitude is not None: # include 0.0; exclude only None
107
+ type_as_dict["longitude"] = float(self.longitude)
108
+ if self.temporalDescription:
109
+ type_as_dict["temporalDescription"] = self.temporalDescription._as_dict_
110
+ if self.spatialDescription:
111
+ type_as_dict["spatialDescription"] = self.spatialDescription._as_dict_
112
+
63
113
  return Serialization.serialize_dict(type_as_dict)
64
114
 
65
115
  @classmethod
@@ -67,4 +117,5 @@ class PlaceDescription(Subject):
67
117
  """
68
118
  Create a PlaceDescription instance from a JSON-dict (already parsed).
69
119
  """
120
+ from .Serialization import Serialization
70
121
  return Serialization.deserialize(data, PlaceDescription)