gedcom-x 0.5__py3-none-any.whl → 0.5.2__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/GedcomX.py CHANGED
@@ -13,9 +13,10 @@ from .Agent import Agent
13
13
  from .Attribution import Attribution
14
14
  from .Conclusion import Conclusion
15
15
  from .Coverage import Coverage
16
- from .Date import Date
16
+ from .Date import Date, date_to_timestamp
17
17
  from .Document import Document
18
18
  from .EvidenceReference import EvidenceReference
19
+ from .Exceptions import TagConversionError
19
20
  from .Event import Event,EventType,EventRole,EventRoleType
20
21
  from .Fact import Fact, FactType, FactQualifier
21
22
  from .Gedcom import Gedcom
@@ -23,6 +24,7 @@ from .Gedcom import GedcomRecord
23
24
  from .Gender import Gender, GenderType
24
25
  from .Group import Group
25
26
  from .Identifier import Identifier, IdentifierType
27
+ from .Logging import get_logger
26
28
  from .Name import Name, NameType, NameForm, NamePart, NamePartType, NamePartQualifier
27
29
  from .Note import Note
28
30
  from .OnlineAccount import OnlineAccount
@@ -37,7 +39,10 @@ from .SourceReference import SourceReference, KnownSourceReference
37
39
  from .Subject import Subject
38
40
  from .TextValue import TextValue
39
41
  from .TopLevelTypeCollection import TopLevelTypeCollection
40
- from .URI import URI
42
+ from .Resource import Resource, URI
43
+
44
+ import_log = get_logger('import')
45
+ convert_log = get_logger('conversion')
41
46
 
42
47
  def TypeCollection(item_type):
43
48
  class Collection:
@@ -108,8 +113,10 @@ def TypeCollection(item_type):
108
113
 
109
114
  def byName(self, sname: str):
110
115
  # Use the name index for fast lookup
111
- sname = sname.strip()
112
- return self._name_index.get(sname, [])
116
+ if sname:
117
+ sname = sname.strip()
118
+ return self._name_index.get(sname, [])
119
+ return None
113
120
 
114
121
  def byId(self, id):
115
122
  # Use the id index for fast lookup
@@ -122,7 +129,9 @@ def TypeCollection(item_type):
122
129
  def append(self, item):
123
130
  if not isinstance(item, item_type):
124
131
  raise TypeError(f"Expected item of type {item_type.__name__}, got {type(item).__name__}")
125
- item._uri._path = f'{str(item_type.__name__)}s' if item._uri._path is None else item._uri._path
132
+ item.uri.path = f'{str(item_type.__name__)}s' if (item.uri.path is None or item.uri.path == "") else item.uri.path
133
+
134
+
126
135
  #if isinstance(item,Agent):
127
136
  # item._uri._path = 'Agents'
128
137
  # print(item._uri._as_dict_)
@@ -163,30 +172,49 @@ def TypeCollection(item_type):
163
172
 
164
173
  @property
165
174
  def _items_as_dict(self) -> dict:
166
- print(self.item_type)
167
-
168
- #return {f'{str(item_type.__name__)}s': [item._as_dict_ for item in self._items]}
169
- return {f'{str(item_type.__name__)}s': [item._as_dict_ for item in self._items]}
170
-
171
- @property
172
- def json(self):
173
- return json.dumps(self._as_dict, indent=4)
175
+ return {f'{str(item_type.__name__)}s': [item._as_dict_ for item in self._items]}
174
176
 
175
177
  @property
176
178
  def _as_dict_(self):
177
- return {"Collection": [item._as_dict_ for item in self._items]}
179
+ return {f'{str(item_type.__name__).lower()}s': [item._as_dict_ for item in self._items]}
180
+
181
+ @property
182
+ def json(self) -> str:
183
+
184
+ return json.dumps(self._as_dict_, indent=4)
178
185
 
179
186
  return Collection()
180
187
 
181
188
  class GedcomX:
189
+ """
190
+ Main GedcomX Object representing a Genealogy. Stores collections of Top Level Gedcom-X Types.
191
+ complies with GEDCOM X Conceptual Model V1 (http://gedcomx.org/conceptual-model/v1)
192
+
193
+ Parameters
194
+ ----------
195
+ id : str
196
+ Unique identifier for this Genealogy.
197
+ attribution : Attribution Object
198
+ Attribution information for the Genealogy
199
+ filepath : str
200
+ Not Implimented.
201
+ description : str
202
+ Description of the Genealogy: ex. 'My Family Tree'
203
+
204
+ Raises
205
+ ------
206
+ ValueError
207
+ If `id` is not a valid UUID.
208
+ """
182
209
  version = 'http://gedcomx.org/conceptual-model/v1'
183
210
 
184
- def __init__(self, id: str = None, attribution: Attribution = None, filepath: str = None) -> None:
211
+ def __init__(self, id: str = None, attribution: Attribution = None, filepath: str = None, description: str = None) -> None:
185
212
  self.id = id
186
213
  self.attribution = attribution
187
214
 
188
215
  self._filepath = None
189
216
 
217
+ self.description = description
190
218
  self.source_descriptions = TypeCollection(SourceDescription)
191
219
  self.persons = TypeCollection(Person)
192
220
  self.relationships = TypeCollection(Relationship)
@@ -199,7 +227,6 @@ class GedcomX:
199
227
  self.person_relationships_lookup = {}
200
228
 
201
229
  def _add(self,gedcomx_type_object):
202
- #print(type(gedcomx_type_object))
203
230
  if gedcomx_type_object:
204
231
  if isinstance(gedcomx_type_object,Person):
205
232
  self.add_person(gedcomx_type_object)
@@ -228,16 +255,27 @@ class GedcomX:
228
255
  raise ValueError(f"When adding a SourceDescription, value must be of type SourceDescription, type {type(sourceDescription)} was provided")
229
256
 
230
257
  def add_person(self,person: Person):
258
+ """Add a Person object to the Genealogy
259
+
260
+ Args:
261
+ person: Person Object
262
+
263
+ Returns:
264
+ None
265
+
266
+ Raises:
267
+ ValueError: If `person` is not of type Person.
268
+ """
231
269
  if person and isinstance(person,Person):
232
270
  if person.id is None:
233
271
  person.id =self.personURIgenerator()
234
272
  self.persons.append(item=person)
235
273
  else:
236
- raise ValueError()
274
+ raise ValueError(f'person must be a Person Object not type: {type(person)}')
237
275
 
238
276
  def add_relationship(self,relationship: Relationship):
239
277
  if relationship and isinstance(relationship,Relationship):
240
- if isinstance(relationship.person1,URI) and isinstance(relationship.person2,URI):
278
+ if isinstance(relationship.person1,Resource) and isinstance(relationship.person2,Resource):
241
279
  print("Adding unresolved Relationship")
242
280
  self.relationships.append(relationship)
243
281
  return
@@ -277,9 +315,21 @@ class GedcomX:
277
315
  self.places.append(placeDescription)
278
316
 
279
317
  def add_agent(self,agent: Agent):
318
+ """Add a Agent object to the Genealogy
319
+
320
+ Args:
321
+ agent: Agent Object
322
+
323
+ Returns:
324
+ None
325
+
326
+ Raises:
327
+ ValueError: If `agent` is not of type Agent.
328
+ """
280
329
  if agent and isinstance(agent,Agent):
330
+ if agent in self.agents:
331
+ return
281
332
  if agent.id is None:
282
- raise("Empty ID")
283
333
  agent.id = Agent.default_id_generator()
284
334
  if self.agents.byId(agent.id):
285
335
  raise ValueError
@@ -293,7 +343,7 @@ class GedcomX:
293
343
  return
294
344
  self.events.append(event_to_add)
295
345
 
296
- def person(self,id: str):
346
+ def get_person_by_id(self,id: str):
297
347
  filtered = [person for person in self.persons if getattr(person, 'id') == id]
298
348
  if filtered: return filtered[0]
299
349
  return None
@@ -303,11 +353,23 @@ class GedcomX:
303
353
  if filtered: return filtered[0]
304
354
  return None
305
355
 
356
+ def json(self):
357
+ """
358
+ JSON Representation of the GedcomX Genealogy.
359
+
360
+ Returns:
361
+ str: JSON Representation of the GedcomX Genealogy in the GEDCOM X JSON Serialization Format
362
+ """
363
+ gedcomx_json = {
364
+ 'persons': [person._as_dict_ for person in self.persons],
365
+ 'sourceDescriptions' : [sourceDescription._as_dict_ for sourceDescription in self.source_descriptions]
366
+ }
367
+ return json.dumps(gedcomx_json, indent=4)
306
368
 
307
369
  class Translater():
308
- def __init__(self,gedcom) -> None:
370
+ def __init__(self,gedcom: Gedcom) -> None:
309
371
  self.handlers = {}
310
- self.gedcom: Gedcom = gedcom if gedcom else None
372
+ self.gedcom: Gedcom = gedcom
311
373
  self.gedcomx = GedcomX()
312
374
 
313
375
  self.object_stack = []
@@ -316,6 +378,7 @@ class Translater():
316
378
 
317
379
  self.translate()
318
380
 
381
+
319
382
  gedcom_even_to_fact = {
320
383
  # Person Fact Types
321
384
  "ADOP": FactType.Adoption,
@@ -367,15 +430,55 @@ class Translater():
367
430
  "ADOP": FactType.AdoptiveParent
368
431
  }
369
432
 
433
+ gedcom_even_to_evnt = {
434
+ # Person Fact Types
435
+ "ADOP": EventType.Adoption,
436
+ "CHR": EventType.AdultChristening,
437
+ "BAPM": EventType.Baptism,
438
+ "BARM": EventType.BarMitzvah,
439
+ "BASM": EventType.BatMitzvah,
440
+ "BIRT": EventType.Birth,
441
+ "BIRT, CHR": EventType.Birth,
442
+ "BLES": EventType.Blessing,
443
+ "BURI": EventType.Burial,
444
+
445
+ "CENS": EventType.Census,
446
+ "CIRC": EventType.Circumcision,
447
+ "CONF": EventType.Confirmation,
448
+ "CREM": EventType.Cremation,
449
+ "DEAT": EventType.Death,
450
+ "EDUC": EventType.Education,
451
+ "EMIG": EventType.Emigration,
452
+ "FCOM": EventType.FirstCommunion,
370
453
 
454
+ "IMMI": EventType.Immigration,
455
+
456
+ "NATU": EventType.Naturalization,
457
+
458
+ "ORDN": EventType.Ordination,
459
+
460
+
461
+ # Couple Relationship Fact Types
462
+ "ANUL": EventType.Annulment,
463
+ "DIV": EventType.Divorce,
464
+ "DIVF": EventType.DivorceFiling,
465
+ "ENGA": EventType.Engagement,
466
+ "MARR": EventType.Marriage
467
+
468
+ }
469
+
470
+ @staticmethod
371
471
  def clean_str(text: str) -> str:
372
472
  # Regular expression to match HTML/XML tags
473
+ if text is None or text.strip() == '':
474
+ return None
373
475
  clean_text = re.sub(r'<[^>]+>', '', text)
374
476
 
375
477
  return clean_text
376
478
 
377
479
  def translate(self):
378
- for repository in self.gedcom.repositories:
480
+ for n, repository in enumerate(self.gedcom.repositories):
481
+ print(f"Parsing Repository {n}")
379
482
  self.parse_record(repository)
380
483
  print(f"Translated {len(self.gedcomx.agents)} 'REPO' records to Agents")
381
484
  for source in self.gedcom.sources:
@@ -402,7 +505,7 @@ class Translater():
402
505
 
403
506
  print(f"Translated {len(self.gedcomx.events)} 'EVEN' records to Events")
404
507
 
405
- def find_urls(sef,text: str):
508
+ def find_urls(self,text: str):
406
509
  # Regular expression pattern to match URLs
407
510
  url_pattern = re.compile(r'https?://[^\s]+')
408
511
  # Find all URLs using the pattern
@@ -411,37 +514,36 @@ class Translater():
411
514
 
412
515
  @property
413
516
  def event_type_conversion_table(self):
414
- return {'BIRT':EventType.BIRTH,
415
- 'OBIT':FactType.OBITUARY}
517
+ return {'BIRT':EventType.Birth,
518
+ 'OBIT':FactType.Obituary}
416
519
 
417
520
  def parse_record(self,record: GedcomRecord):
418
-
419
- if DEBUG: print(record.describe())
521
+
420
522
  handler_name = 'handle_' + record.tag.lower()
421
523
 
422
- if hasattr(self,handler_name):
423
-
424
- handler = getattr(self,handler_name)
524
+ if hasattr(self,handler_name):
525
+ convert_log.info(f'Parsing Record: {record.describe()}')
526
+ handler = getattr(self,handler_name)
425
527
  handler(record)
426
528
  else:
427
529
  if record.tag in self.missing_handler_count:
428
530
  self.missing_handler_count[record.tag] += 1
429
531
  else:
430
532
  self.missing_handler_count[record.tag] = 1
431
- if not record.tag.startswith("_"):
432
- print(f"\033[1;31mCould not find handler for GEDCOM tag {record.tag}\n{record.describe()}\033[0m")
533
+
534
+ convert_log.error(f'Failed Parsing Record: {record.describe()}')
433
535
  for sub_record in record.subRecords():
434
536
  self.parse_record(sub_record)
435
-
436
- def handle__apid(self, record):
537
+
538
+ def handle__apid(self, record: GedcomRecord):
437
539
  if isinstance(self.object_map[record.level-1], SourceReference):
438
- self.object_map[record.level-1]._description_object.add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
540
+ self.object_map[record.level-1].description.add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
439
541
  elif isinstance(self.object_map[record.level-1], SourceDescription):
440
542
  self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
441
543
  else:
442
544
  raise ValueError(f"Could not handle '_APID' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
443
545
 
444
- def handle__meta(self, record):
546
+ def handle__meta(self, record: GedcomRecord):
445
547
  if isinstance(self.object_map[record.level-1], SourceDescription):
446
548
  gxobject = Note(text=Translater.clean_str(record.value))
447
549
  self.object_map[record.level-1].add_note(gxobject)
@@ -450,14 +552,14 @@ class Translater():
450
552
  else:
451
553
  raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
452
554
 
453
- def handle__wlnk(self, record):
555
+ def handle__wlnk(self, record: GedcomRecord):
454
556
  return self.handle_sour(record)
455
557
 
456
- def handle_addr(self, record):
558
+ def handle_addr(self, record: GedcomRecord):
457
559
  if isinstance(self.object_map[record.level-1], Agent):
458
560
  # TODO CHeck if URL?
459
561
  if Translater.clean_str(record.value):
460
- gxobject = URI(value=Translater.clean_str(record.value))
562
+ gxobject = Address(value=Translater.clean_str(record.value))
461
563
  else:
462
564
  gxobject = Address()
463
565
  self.object_map[record.level-1].address = gxobject
@@ -466,26 +568,80 @@ class Translater():
466
568
  else:
467
569
  raise ValueError(f"I do not know how to handle an 'ADDR' tag for a {type(self.object_map[record.level-1])}")
468
570
 
469
- def handle_adr1(self, record):
571
+ def handle_adr1(self, record: GedcomRecord):
470
572
  if isinstance(self.object_map[record.level-1], Address):
471
573
  if Translater.clean_str(record.value):
472
- self.object_map[record.level-1].street = Translater.clean_str(record.value)
473
-
574
+ self.object_map[record.level-1].street = Translater.clean_str(record.value)
474
575
  else:
475
- raise ValueError(f"I do not know how to handle an 'ADDR' tag for a {type(self.object_map[record.level-1])}")
576
+ raise ValueError(f"I do not know how to handle an 'ADR1' tag for a {type(self.object_map[record.level-1])}")
577
+
578
+ def handle_adr2(self, record: GedcomRecord):
579
+ if isinstance(self.object_map[record.level-1], Address):
580
+ if Translater.clean_str(record.value):
581
+ self.object_map[record.level-1].street2 = Translater.clean_str(record.value)
582
+ else:
583
+ raise ValueError(f"I do not know how to handle an 'ADR2' tag for a {type(self.object_map[record.level-1])}")
584
+
585
+ def handle_adr3(self, record: GedcomRecord):
586
+ if isinstance(self.object_map[record.level-1], Address):
587
+ if Translater.clean_str(record.value):
588
+ self.object_map[record.level-1].street3 = Translater.clean_str(record.value)
589
+ else:
590
+ raise ValueError(f"I do not know how to handle an 'ADR3' tag for a {type(self.object_map[record.level-1])}")
591
+
592
+ def handle_adr4(self, record: GedcomRecord):
593
+ if isinstance(self.object_map[record.level-1], Address):
594
+ if Translater.clean_str(record.value):
595
+ self.object_map[record.level-1].street4 = Translater.clean_str(record.value)
596
+ else:
597
+ raise ValueError(f"I do not know how to handle an 'ADR4' tag for a {type(self.object_map[record.level-1])}")
598
+
599
+ def handle_adr5(self, record: GedcomRecord):
600
+ if isinstance(self.object_map[record.level-1], Address):
601
+ if Translater.clean_str(record.value):
602
+ self.object_map[record.level-1].street5 = Translater.clean_str(record.value)
603
+ else:
604
+ raise ValueError(f"I do not know how to handle an 'ADR5' tag for a {type(self.object_map[record.level-1])}")
605
+
606
+ def handle_adr6(self, record: GedcomRecord):
607
+ if isinstance(self.object_map[record.level-1], Address):
608
+ if Translater.clean_str(record.value):
609
+ self.object_map[record.level-1].street5 = Translater.clean_str(record.value)
610
+ else:
611
+ raise ValueError(f"I do not know how to handle an 'ADR6' tag for a {type(self.object_map[record.level-1])}")
612
+
613
+ def handle_phon(self, record: GedcomRecord):
614
+ if isinstance(self.object_map[record.level-1], Agent):
615
+ if Translater.clean_str(record.value):
616
+ self.object_map[record.level-1].phones.append(Translater.clean_str(record.value))
617
+ else:
618
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
619
+
620
+ def handle_email(self, record: GedcomRecord):
621
+ if isinstance(self.object_map[record.level-1], Agent):
622
+ if Translater.clean_str(record.value):
623
+ self.object_map[record.level-1].emails.append(Translater.clean_str(record.value))
624
+ else:
625
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
626
+
627
+ def handle_fax(self, record: GedcomRecord):
628
+ if isinstance(self.object_map[record.level-1], Agent):
629
+ if Translater.clean_str(record.value):
630
+ self.object_map[record.level-1].emails.append('FAX:' + Translater.clean_str(record.value))
631
+ else:
632
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
476
633
 
477
- def handle_adop(self, record):
634
+ def handle_adop(self, record: GedcomRecord):
478
635
  if isinstance(self.object_map[record.level-1], Person):
479
- gxobject = Fact(type=FactType.ADOPTION)
636
+ gxobject = Fact(type=FactType.Adoption)
480
637
  self.object_map[record.level-1].add_fact(gxobject)
481
638
 
482
639
  self.object_stack.append(gxobject)
483
640
  self.object_map[record.level] = gxobject
484
641
  else:
485
- print("Cannot translate 'BAPM")
486
- assert False
642
+ raise TagConversionError(record=record,levelstack=self.object_map)
487
643
 
488
- def handle_auth(self, record):
644
+ def handle_auth(self, record: GedcomRecord):
489
645
  if isinstance(self.object_map[record.level-1], SourceDescription):
490
646
  if self.gedcomx.agents.byName(record.value):
491
647
  gxobject = self.gedcomx.agents.byName(record.value)[0]
@@ -497,10 +653,9 @@ class Translater():
497
653
  self.object_stack.append(gxobject)
498
654
  self.object_map[record.level] = gxobject
499
655
  else:
500
- print("Cannot translate 'AUTH")
501
- assert False
656
+ raise TagConversionError(record=record,levelstack=self.object_map)
502
657
 
503
- def handle_bapm(self, record):
658
+ def handle_bapm(self, record: GedcomRecord):
504
659
  if isinstance(self.object_map[record.level-1], Person):
505
660
  gxobject = Fact(type=FactType.Baptism)
506
661
  self.object_map[record.level-1].add_fact(gxobject)
@@ -508,10 +663,9 @@ class Translater():
508
663
  self.object_stack.append(gxobject)
509
664
  self.object_map[record.level] = gxobject
510
665
  else:
511
- print("Cannot translate 'BAPM")
512
- assert False
666
+ raise TagConversionError(record=record,levelstack=self.object_map)
513
667
 
514
- def handle_birt(self, record):
668
+ def handle_birt(self, record: GedcomRecord):
515
669
  if isinstance(self.object_map[record.level-1], Person):
516
670
  #gxobject = Event(type=EventType.BIRTH, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
517
671
  gxobject = Fact(type=FactType.Birth)
@@ -521,10 +675,9 @@ class Translater():
521
675
  self.object_stack.append(gxobject)
522
676
  self.object_map[record.level] = gxobject
523
677
  else:
524
- print("Cannot translate 'AUTH")
525
- assert False
678
+ raise TagConversionError(record=record,levelstack=self.object_map)
526
679
 
527
- def handle_buri(self, record):
680
+ def handle_buri(self, record: GedcomRecord):
528
681
  if isinstance(self.object_map[record.level-1], Person):
529
682
  gxobject = Fact(type=FactType.Burial)
530
683
  self.object_map[record.level-1].add_fact(gxobject)
@@ -532,10 +685,9 @@ class Translater():
532
685
  self.object_stack.append(gxobject)
533
686
  self.object_map[record.level] = gxobject
534
687
  else:
535
- print("Cannot translate 'BURI")
536
- assert False
688
+ raise TagConversionError(record=record,levelstack=self.object_map)
537
689
 
538
- def handle_caln(self, record):
690
+ def handle_caln(self, record: GedcomRecord):
539
691
  if isinstance(self.object_map[record.level-1], SourceReference):
540
692
  self.object_map[record.level-1].description.add_identifier(Identifier(value=URI.from_url('Call Number:' + record.value)))
541
693
  elif isinstance(self.object_map[record.level-1], SourceDescription):
@@ -546,7 +698,19 @@ class Translater():
546
698
  else:
547
699
  raise ValueError(f"Could not handle 'CALN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
548
700
 
549
- def handle_chr(self, record):
701
+ def handle_chan(self, record: GedcomRecord):
702
+ if isinstance(self.object_map[record.level-1], SourceDescription):
703
+ self.object_map[record.level-1].created = Date(record.subRecord('DATE'))
704
+ elif isinstance(self.object_map[record.level-1], Agent):
705
+ if self.object_map[record.level-1].attribution is None:
706
+ gxobject = Attribution()
707
+ self.object_map[record.level-1].attribution = gxobject
708
+ self.object_stack.append(gxobject)
709
+ self.object_map[record.level] = gxobject
710
+ else:
711
+ raise ValueError()
712
+
713
+ def handle_chr(self, record: GedcomRecord):
550
714
  if isinstance(self.object_map[record.level-1], Person):
551
715
  gxobject = Fact(type=FactType.Christening)
552
716
  self.object_map[record.level-1].add_fact(gxobject)
@@ -554,16 +718,15 @@ class Translater():
554
718
  self.object_stack.append(gxobject)
555
719
  self.object_map[record.level] = gxobject
556
720
  else:
557
- print("Cannot translate 'CHR")
558
- assert False
721
+ raise TagConversionError(record=record,levelstack=self.object_map)
559
722
 
560
- def handle_city(self, record):
723
+ def handle_city(self, record: GedcomRecord):
561
724
  if isinstance(self.object_map[record.level-1], Address):
562
725
  self.object_map[record.level-1].city = Translater.clean_str(record.value)
563
726
  else:
564
727
  raise ValueError(f"I do not know how to handle an 'CITY' tag for a {type(self.object_map[record.level-1])}")
565
728
 
566
- def handle_conc(self, record):
729
+ def handle_conc(self, record: GedcomRecord):
567
730
  if isinstance(self.object_map[record.level-1], Note):
568
731
  gxobject = Translater.clean_str(str(record.value))
569
732
  self.object_map[record.level-1].append(gxobject)
@@ -582,69 +745,85 @@ class Translater():
582
745
  self.object_map[record.level-1].notes[0].text += record.value
583
746
 
584
747
  else:
585
- print(f"Cannot translate 'CONC', {self.object_map[record.level-1]}")
586
- assert False
748
+ raise TagConversionError(record=record,levelstack=self.object_map)
587
749
 
588
- def handle_cont(self, record):
750
+ def handle_cont(self, record: GedcomRecord):
589
751
  if isinstance(self.object_map[record.level-1], Note):
590
- gxobject = str("\n" + record.value)
752
+ gxobject = str("\n" + record.value if record.value else '')
591
753
  self.object_map[record.level-1].append(gxobject)
592
754
  elif isinstance(self.object_map[record.level-1], Agent):
593
- gxobject = str("\n" + record.value)
755
+ gxobject = str("\n" + record.value if record.value else '')
594
756
  elif isinstance(self.object_map[record.level-1], Qualifier):
595
- gxobject = str("\n" + record.value)
757
+ gxobject = str("\n" + record.value if record.value else '')
596
758
  self.object_map[record.level-1].append(gxobject)
597
759
  elif isinstance(self.object_map[record.level-1], TextValue):
598
760
  #gxobject = TextValue(value="\n" + record.value)
599
- self.object_map[record.level-1]._append_to_value(record.value)
761
+ self.object_map[record.level-1]._append_to_value(record.value if record.value else '\n')
600
762
  elif isinstance(self.object_map[record.level-1], SourceReference):
601
763
  self.object_map[record.level-1].append(record.value)
764
+ elif isinstance(self.object_map[record.level-1], Address):
765
+ self.object_map[record.level-1]._append(record.value)
602
766
  else:
603
- print(f"Cannot translate 'CONT', {type(self.object_map[record.level-1])}")
604
- assert False
767
+ raise TagConversionError(record=record,levelstack=self.object_map)
605
768
 
606
- def handle__crea(self, record):
769
+ def handle_crea(self, record: GedcomRecord):
607
770
  if isinstance(self.object_map[record.level-1], SourceDescription):
608
- self.object_map[record.level-1].created = Date(original=record.value)
771
+ self.object_map[record.level-1].created = Date(original=record.subRecord('DATE'))
772
+
773
+ elif isinstance(self.object_map[record.level-1], Agent):
774
+ if self.object_map[record.level-1].attribution is None:
775
+ gxobject = Attribution()
776
+ self.object_map[record.level-1].attribution = gxobject
777
+ self.object_stack.append(gxobject)
778
+ self.object_map[record.level] = gxobject
779
+ else:
780
+ convert_log.info(f"[{record.tag}] Attribution already exists for SourceDescription with id: {self.object_map[record.level-1].id}")
609
781
  else:
610
- raise ValueError(f"Could not handle '_URL' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
782
+ raise ValueError(f"Could not handle '{record.tag}' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
611
783
 
612
- def handle_ctry(self, record):
784
+ def handle_ctry(self, record: GedcomRecord):
613
785
  if isinstance(self.object_map[record.level-1], Address):
614
786
  self.object_map[record.level-1].country = Translater.clean_str(record.value)
615
787
  else:
616
- raise ValueError(f"I do not know how to handle an 'CTRY' tag for a {type(self.object_map[record.level-1])}")
788
+ raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
617
789
 
618
790
  def handle_data(self, record: GedcomRecord) -> None:
619
- if record.value != '':
791
+ if record.value != '' and record.value == 'None':
620
792
  assert False
621
- self.object_map[record.level] = None
793
+ self.object_map[record.level] = self.object_map[record.level-1]
622
794
 
623
795
  def handle_date(self, record: GedcomRecord):
624
796
  if record.parent.tag == 'PUBL':
625
- gxobject = Date(original=record.value)
626
- self.object_map[0].published = gxobject
627
-
628
- self.object_stack.append(gxobject)
629
- self.object_map[record.level] = gxobject
797
+ #gxobject = Date(original=record.value) #TODO Make a parser for solid timestamps
798
+ #self.object_map[0].published = gxobject
799
+ #self.object_map[0].published = date_to_timestamp(record.value) if record.value else None
800
+ self.object_map[0].published = record.value
801
+ #self.object_stack.append(gxobject)
802
+ #self.object_map[record.level] = gxobject
630
803
  elif isinstance(self.object_map[record.level-1], Event):
631
804
  self.object_map[record.level-1].date = Date(original=record.value)
632
805
  elif isinstance(self.object_map[record.level-1], Fact):
633
806
  self.object_map[record.level-1].date = Date(original=record.value)
634
807
  elif record.parent.tag == 'DATA' and isinstance(self.object_map[record.level-2], SourceReference):
635
808
  gxobject = Note(text='Date: ' + record.value)
636
- self.object_map[record.level-2]._description_object.add_note(gxobject)
809
+ self.object_map[record.level-2].description.add_note(gxobject)
637
810
  self.object_stack.append(gxobject)
638
811
  self.object_map[record.level] = gxobject
639
812
  elif isinstance(self.object_map[record.level-1], SourceDescription):
640
813
 
641
814
  self.object_map[record.level-1].ctreated = record.value #TODO String to timestamp
642
-
815
+ elif isinstance(self.object_map[record.level-1], Attribution):
816
+ if record.parent.tag == 'CREA':
817
+ self.object_map[record.level-1].created = record.value #TODO G7
818
+ elif record.parent.tag == "CHAN":
819
+ self.object_map[record.level-1].modified = record.value #TODO G7
820
+ elif record.parent.tag in ['CREA','CHAN']:
821
+ pass
822
+
643
823
  else:
644
- print(f"Cannot translate 'DATE {type(self.object_map[record.level-1])}")
645
- assert False
824
+ raise TagConversionError(record=record,levelstack=self.object_map)
646
825
 
647
- def handle_deat(self, record):
826
+ def handle_deat(self, record: GedcomRecord):
648
827
  if isinstance(self.object_map[record.level-1], Person):
649
828
  gxobject = Fact(type=FactType.Death)
650
829
  self.object_map[record.level-1].add_fact(gxobject)
@@ -652,12 +831,11 @@ class Translater():
652
831
  self.object_stack.append(gxobject)
653
832
  self.object_map[record.level] = gxobject
654
833
  else:
655
- print("Cannot translate 'DEAT")
656
- assert False
834
+ raise TagConversionError(record=record,levelstack=self.object_map)
657
835
 
658
836
  def handle_even(self, record: GedcomRecord):
659
837
  # TODO If events in a @S, check if only 1 person matches?
660
- if not record.value.strip() == '':
838
+ if record.value and (not record.value.strip() == ''):
661
839
  values = [value.strip() for value in record.value.split(",")]
662
840
  for value in values:
663
841
  if value in Translater.gedcom_even_to_fact.keys():
@@ -667,18 +845,21 @@ class Translater():
667
845
 
668
846
  self.object_stack.append(gxobject)
669
847
  self.object_map[record.level] = gxobject
670
- print(self.object_map)
848
+
849
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
850
+ gxobject = Event(type=Translater.gedcom_even_to_evnt[value],sources=[self.object_map[record.level-1]])
851
+ self.gedcomx.add_event(gxobject)
852
+ self.object_stack.append(gxobject)
853
+ self.object_map[record.level] = gxobject
671
854
  else:
672
- print(record.describe())
855
+ raise TagConversionError(record=record,levelstack=self.object_map)
673
856
  assert False
674
857
  # TODO: Fix, this. making an event to cacth subtags, why are these fact tied to a source? GEDCOM is horrible
675
858
  gxobject = Event(type=EventType.UNKNOWN)
676
859
  self.object_stack.append(gxobject)
677
860
  self.object_map[record.level] = gxobject
678
861
  else:
679
-
680
-
681
- print("This event does not look like a Fact")
862
+ raise TagConversionError(record=record,levelstack=self.object_map)
682
863
 
683
864
  else:
684
865
  possible_fact = FactType.guess(record.subRecord('TYPE')[0].value)
@@ -708,6 +889,13 @@ class Translater():
708
889
  else:
709
890
  assert False
710
891
 
892
+ def handle_exid(self,record: GedcomRecord):
893
+ gxobject = Identifier(type=IdentifierType.External,value=[record.value])
894
+ self.object_map[record.level-1].add_identifier(gxobject)
895
+
896
+ self.object_stack.append(gxobject)
897
+ self.object_map[record.level] = gxobject
898
+
711
899
  def handle_fam(self, record: GedcomRecord) -> None:
712
900
  if record.tag != 'FAM' or record.level != 0:
713
901
  raise ValueError("Invalid record: Must be a level 0 FAM record")
@@ -716,16 +904,16 @@ class Translater():
716
904
 
717
905
  husband_record = record.subRecords('HUSB')
718
906
  if husband_record:
719
- husband = self.gedcomx.person(husband_record[0].value.replace('@',''))
907
+ husband = self.gedcomx.get_person_by_id(husband_record[0].xref)
720
908
 
721
909
  wife_record = record.subRecords('WIFE')
722
910
  if wife_record:
723
- wife = self.gedcomx.person(wife_record[0].value.replace('@',''))
911
+ wife = self.gedcomx.get_person_by_id(wife_record[0].xref)
724
912
 
725
913
  children_records = record.subRecords('CHIL')
726
914
  if children_records:
727
915
  for child_record in children_records:
728
- child = self.gedcomx.person(child_record.value.replace('@',''))
916
+ child = self.gedcomx.get_person_by_id(child_record.xref)
729
917
  if child:
730
918
  children.append(child)
731
919
 
@@ -748,41 +936,43 @@ class Translater():
748
936
  return
749
937
 
750
938
  def handle_file(self, record: GedcomRecord):
751
- if record.value.strip() != '':
939
+ if record.value and record.value.strip() != '':
752
940
  #raise ValueError(f"I did not expect the 'FILE' tag to have a value: {record.value}")
753
941
  #TODO Handle files referenced here
754
942
  ...
755
943
  elif isinstance(self.object_map[record.level-1], SourceDescription):
756
944
  ...
757
945
  self.object_map[record.level-1].resourceType = ResourceType.DigitalArtifact
758
-
759
-
946
+
760
947
  def handle_form(self, record: GedcomRecord):
761
948
  if record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
762
- if record.value.strip() != '':
949
+ if record.value and record.value.strip() != '':
763
950
  mime_type, _ = mimetypes.guess_type('placehold.' + record.value)
764
951
  if mime_type:
765
952
  self.object_map[record.level-2].mediaType = mime_type
766
953
  else:
767
954
  print(f"Could not determing mime type from {record.value}")
955
+ elif isinstance(self.object_map[record.level-1], PlaceDescription):
956
+ self.object_map[record.level-1].names.append(TextValue(value=record.value))
957
+ elif record.parent.tag == 'TRAN':
958
+ pass #TODO
768
959
  else:
769
- raise ValueError(f"I do not know how to translate the 'FORM' tag with value '{record.value}' for a {type(self.object_map[record.level-1])}")
960
+ raise TagConversionError(record=record,levelstack=self.object_map)
770
961
 
771
- def handle_givn(self, record):
962
+ def handle_givn(self, record: GedcomRecord):
772
963
  if isinstance(self.object_map[record.level-1], Name):
773
964
  given_name = NamePart(value=record.value, type=NamePartType.Given)
774
965
  self.object_map[record.level-1]._add_name_part(given_name)
775
966
  else:
776
- print(f"{record.describe()}, Cannot translate 'NAME', {self.object_map[record.level-1]}")
777
- assert False
967
+ raise TagConversionError(record=record,levelstack=self.object_map)
778
968
 
779
- def handle_indi(self, record):
969
+ def handle_indi(self, record: GedcomRecord):
780
970
  person = Person(id=record.xref.replace('@',''))
781
971
  self.gedcomx.add_person(person)
782
972
  self.object_stack.append(person)
783
973
  self.object_map[record.level] = person
784
974
 
785
- def handle_immi(self, record):
975
+ def handle_immi(self, record: GedcomRecord):
786
976
  if isinstance(self.object_map[record.level-1], Person):
787
977
  gxobject = Fact(type=FactType.Immigration)
788
978
  self.object_map[record.level-1].add_fact(gxobject)
@@ -790,10 +980,9 @@ class Translater():
790
980
  self.object_stack.append(gxobject)
791
981
  self.object_map[record.level] = gxobject
792
982
  else:
793
- print("Cannot translate 'IMMI")
794
- assert False
983
+ raise TagConversionError(record=record,levelstack=self.object_map)
795
984
 
796
- def handle_marr(self, record):
985
+ def handle_marr(self, record: GedcomRecord):
797
986
  if isinstance(self.object_map[record.level-1], Person):
798
987
  gxobject = Fact(type=FactType.Marriage)
799
988
  self.object_map[record.level-1].add_fact(gxobject)
@@ -801,10 +990,9 @@ class Translater():
801
990
  self.object_stack.append(gxobject)
802
991
  self.object_map[record.level] = gxobject
803
992
  else:
804
- print("Cannot translate 'MARR")
805
- assert False
993
+ raise TagConversionError(record=record,levelstack=self.object_map)
806
994
 
807
- def handle_name(self, record):
995
+ def handle_name(self, record: GedcomRecord):
808
996
  if isinstance(self.object_map[record.level-1], Person):
809
997
  gxobject = Name.simple(record.value)
810
998
  #gxobject = Name(nameForms=[NameForm(fullText=record.value)], type=NameType.BirthName)
@@ -816,10 +1004,9 @@ class Translater():
816
1004
  gxobject = TextValue(value=record.value)
817
1005
  self.object_map[record.level-1].add_name(gxobject)
818
1006
  else:
819
- print(f"{record.describe()}, Cannot translate 'NAME', {self.object_map[record.level-1]}")
820
- assert False
1007
+ raise TagConversionError(record=record,levelstack=self.object_map)
821
1008
 
822
- def handle_note(self, record):
1009
+ def handle_note(self, record: GedcomRecord):
823
1010
  if isinstance(self.object_map[record.level-1], SourceDescription):
824
1011
  gxobject = Note(text=Translater.clean_str(record.value))
825
1012
  self.object_map[record.level-1].add_note(gxobject)
@@ -828,7 +1015,7 @@ class Translater():
828
1015
  self.object_map[record.level] = gxobject
829
1016
  elif isinstance(self.object_map[record.level-1], SourceReference):
830
1017
  gxobject = Note(text=Translater.clean_str(record.value))
831
- self.object_map[record.level-1]._description_object.add_note(gxobject)
1018
+ self.object_map[record.level-1].description.add_note(gxobject)
832
1019
 
833
1020
  self.object_stack.append(gxobject)
834
1021
  self.object_map[record.level] = gxobject
@@ -838,19 +1025,30 @@ class Translater():
838
1025
 
839
1026
  self.object_stack.append(gxobject)
840
1027
  self.object_map[record.level] = gxobject
1028
+ elif isinstance(self.object_map[record.level-1], Agent):
1029
+ gxobject = Note(text=record.value)
1030
+ self.object_map[record.level-1].add_note(gxobject)
1031
+
1032
+ self.object_stack.append(gxobject)
1033
+ self.object_map[record.level] = gxobject
1034
+ elif isinstance(self.object_map[record.level-1], Attribution):
1035
+ if self.object_map[record.level-1].changeMessage is None:
1036
+ self.object_map[record.level-1].changeMessage = record.value
1037
+ else:
1038
+ self.object_map[record.level-1].changeMessage = self.object_map[record.level-1].changeMessage + '' + record.value
1039
+
841
1040
  else:
842
1041
  raise ValueError(f"Could not handle 'NOTE' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
843
1042
  assert False
844
1043
 
845
- def handle_nsfx(self, record):
1044
+ def handle_nsfx(self, record: GedcomRecord):
846
1045
  if isinstance(self.object_map[record.level-1], Name):
847
1046
  surname = NamePart(value=record.value, type=NamePartType.Suffix)
848
1047
  self.object_map[record.level-1]._add_name_part(surname)
849
1048
  else:
850
- print(f"{record.describe()}, Cannot translate 'NSFX', {self.object_map[record.level-1]}")
851
- assert False
1049
+ raise TagConversionError(record=record,levelstack=self.object_map)
852
1050
 
853
- def handle_occu(self, record):
1051
+ def handle_occu(self, record: GedcomRecord):
854
1052
  if isinstance(self.object_map[record.level-1], Person):
855
1053
  gxobject = Fact(type=FactType.Occupation)
856
1054
  self.object_map[record.level-1].add_fact(gxobject)
@@ -858,13 +1056,12 @@ class Translater():
858
1056
  self.object_stack.append(gxobject)
859
1057
  self.object_map[record.level] = gxobject
860
1058
  else:
861
- print("Cannot translate 'OCCU")
862
- assert False
1059
+ raise TagConversionError(record=record,levelstack=self.object_map)
863
1060
 
864
1061
  def handle_obje(self, record: GedcomRecord):
865
1062
  self.handle_sour(record)
866
1063
 
867
- def handle_page(self, record):
1064
+ def handle_page(self, record: GedcomRecord):
868
1065
  if isinstance(self.object_map[record.level-1], SourceReference):
869
1066
  self.object_map[record.level-1].descriptionId = record.value
870
1067
  self.object_map[record.level-1].add_qualifier(KnownSourceReference.Page)
@@ -875,7 +1072,7 @@ class Translater():
875
1072
  else:
876
1073
  raise ValueError(f"Could not handle 'PAGE' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
877
1074
 
878
- def handle_plac(self, record):
1075
+ def handle_plac(self, record: GedcomRecord):
879
1076
  if isinstance(self.object_map[record.level-1], Agent):
880
1077
  gxobject = Address(value=record.value)
881
1078
  self.object_map[record.level-1].add_address(gxobject)
@@ -889,6 +1086,9 @@ class Translater():
889
1086
  place_des = PlaceDescription(names=[TextValue(value=record.value)])
890
1087
  self.gedcomx.add_place_description(place_des)
891
1088
  self.object_map[record.level-1].place = PlaceReference(original=record.value, descriptionRef=place_des)
1089
+ if len(record.subRecords()) > 0:
1090
+ self.object_map[record.level]= place_des
1091
+
892
1092
  elif isinstance(self.object_map[record.level-1], Fact):
893
1093
  if self.gedcomx.places.byName(record.value):
894
1094
  self.object_map[record.level-1].place = PlaceReference(original=record.value, descriptionRef=self.gedcomx.places.byName(record.value)[0])
@@ -902,18 +1102,17 @@ class Translater():
902
1102
  self.object_stack.append(gxobject)
903
1103
  self.object_map[record.level] = gxobject
904
1104
  else:
905
- print("Cannot translate 'PLACE")
906
- assert False
1105
+ raise TagConversionError(record=record,levelstack=self.object_map)
907
1106
 
908
- def handle_post(self, record):
1107
+ def handle_post(self, record: GedcomRecord):
909
1108
  if isinstance(self.object_map[record.level-1], Address):
910
1109
  self.object_map[record.level-1].postalCode = Translater.clean_str(record.value)
911
1110
  else:
912
1111
  raise ValueError(f"I do not know how to handle an 'POST' tag for a {type(self.object_map[record.level-1])}")
913
1112
 
914
- def handle_publ(self, record):
1113
+ def handle_publ(self, record: GedcomRecord):
915
1114
  if isinstance(self.object_map[record.level-1], SourceDescription):
916
- if self.gedcomx.agents.byName(record.value):
1115
+ if record.value and self.gedcomx.agents.byName(record.value):
917
1116
  gxobject = self.gedcomx.agents.byName(record.value)[0]
918
1117
  else:
919
1118
  gxobject = Agent(names=[TextValue(record.value)])
@@ -923,10 +1122,9 @@ class Translater():
923
1122
  self.object_stack.append(gxobject)
924
1123
  self.object_map[record.level] = gxobject
925
1124
  else:
926
- print("Cannot translate 'PUBL")
927
- assert False
1125
+ raise TagConversionError(record=record,levelstack=self.object_map)
928
1126
 
929
- def handle_prob(self, record):
1127
+ def handle_prob(self, record: GedcomRecord):
930
1128
  if isinstance(self.object_map[record.level-1], Person):
931
1129
  gxobject = Fact(type=FactType.Probate)
932
1130
  self.object_map[record.level-1].add_fact(gxobject)
@@ -934,28 +1132,46 @@ class Translater():
934
1132
  self.object_stack.append(gxobject)
935
1133
  self.object_map[record.level] = gxobject
936
1134
  else:
937
- print("Cannot translate 'PROB")
938
- assert False
1135
+ raise TagConversionError(record=record,levelstack=self.object_map)
939
1136
 
940
- def handle_refn(self, record):
1137
+ def handle_uid(self, record: GedcomRecord):
1138
+ if isinstance(self.object_map[record.level-1], Agent):
1139
+ gxobject = Identifier(value=['UID:' + record.value],type=IdentifierType.Primary)
1140
+ self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
1141
+ self.object_stack.append(gxobject)
1142
+ self.object_map[record.level] = gxobject
1143
+
1144
+ def handle_refn(self, record: GedcomRecord):
941
1145
  if isinstance(self.object_map[record.level-1], Person) or isinstance(self.object_map[record.level-1], SourceDescription):
942
- self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('Reference Number:' + record.value)))
1146
+ gxobject = Identifier(value=[URI.from_url('Reference Number:' + record.value)])
1147
+ self.object_map[record.level-1].add_identifier(gxobject)
1148
+ self.object_stack.append(gxobject)
1149
+ self.object_map[record.level] = gxobject
1150
+ elif isinstance(self.object_map[record.level-1], Agent):
1151
+ gxobject = Identifier(value=['Reference Number:' + record.value])
1152
+ self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
1153
+ self.object_stack.append(gxobject)
1154
+ self.object_map[record.level] = gxobject
943
1155
  else:
944
1156
  raise ValueError(f"Could not handle 'REFN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
945
1157
 
946
- def handle_repo(self, record):
1158
+ def handle_repo(self, record: GedcomRecord):
1159
+
947
1160
  if record.level == 0:
948
1161
 
949
- gxobject = Agent(id=record.value.replace('@',''))
1162
+ gxobject = Agent(id=record.xref)
950
1163
  self.gedcomx.add_agent(gxobject)
951
1164
  self.object_stack.append(gxobject)
952
1165
  self.object_map[record.level] = gxobject
953
1166
 
954
1167
  elif isinstance(self.object_map[record.level-1], SourceDescription):
955
- if self.gedcomx.agents.byId(record.value.replace('@','')):
1168
+ if self.gedcomx.agents.byId(record.xref) is not None:
1169
+
956
1170
  # TODO WHere and what to add this to?
957
- gxobject = self.gedcomx.agents.byId(record.value)
1171
+ gxobject = self.gedcomx.agents.byId(record.xref)
958
1172
  self.object_map[record.level-1].repository = gxobject
1173
+ self.object_map[record.level] = gxobject
1174
+
959
1175
  else:
960
1176
  print(record.describe())
961
1177
  raise ValueError()
@@ -967,20 +1183,19 @@ class Translater():
967
1183
  self.object_stack.append(gxobject)
968
1184
  self.object_map[record.level] = gxobject
969
1185
 
970
- def handle_resi(self, record):
1186
+ def handle_resi(self, record: GedcomRecord):
971
1187
  if isinstance(self.object_map[record.level-1], Person):
972
1188
  gxobject = Fact(type=FactType.Residence)
973
- if record.value.strip() != '':
1189
+ if record.value and record.value.strip() != '':
974
1190
  gxobject.add_note(Note(text=record.value))
975
1191
  self.object_map[record.level-1].add_fact(gxobject)
976
1192
 
977
1193
  self.object_stack.append(gxobject)
978
1194
  self.object_map[record.level] = gxobject
979
1195
  else:
980
- print("Cannot translate 'RESI")
981
- assert False
1196
+ raise TagConversionError(record=record,levelstack=self.object_map)
982
1197
 
983
- def handle_rin(self, record):
1198
+ def handle_rin(self, record: GedcomRecord):
984
1199
  if isinstance(self.object_map[record.level-1], SourceDescription):
985
1200
  self.object_map[record.level-1].id = record.value
986
1201
  self.object_map[record.level-1].add_note(Note(text=f"Source had RIN: of {record.value}"))
@@ -1004,51 +1219,59 @@ class Translater():
1004
1219
  else:
1005
1220
  assert False
1006
1221
 
1007
- def handle_sour(self, record):
1222
+ def handle_sour(self, record: GedcomRecord):
1008
1223
  if record.level == 0 or record.tag == '_WLNK' or (record.level == 0 and record.tag == 'OBJE'):
1009
- source_description = SourceDescription(id=record.xref)
1224
+ source_description = SourceDescription(id=record.xref.replace('@','') if record.xref else None)
1010
1225
  self.gedcomx.add_source_description(source_description)
1011
1226
  self.object_stack.append(source_description)
1012
1227
  self.object_map[record.level] = source_description
1013
1228
  else:
1229
+ # This 'SOUR' is a SourceReference
1230
+ if record.xref and record.xref.strip() == '':
1231
+ import_log.warning(f"SOUR points to nothing: {record.describe()}")
1232
+ return False
1014
1233
  if self.gedcomx.source_descriptions.byId(record.xref):
1015
1234
  gxobject = SourceReference(descriptionId=record.xref, description=self.gedcomx.source_descriptions.byId(record.xref))
1016
1235
  else:
1236
+ import_log.warning(f'Could not find source with id: {record.xref}')
1017
1237
  source_description = SourceDescription(id=record.xref)
1018
1238
  gxobject = SourceReference(descriptionId=record.value, description=source_description)
1019
- if isinstance(self.object_map[record.level-1],SourceReference):
1020
- self.object_map[record.level-1]._description_object.add_source(gxobject)
1021
- else:
1022
- self.object_map[record.level-1].add_source(gxobject)
1239
+ if isinstance(self.object_map[record.level-1],SourceReference):
1240
+ self.object_map[record.level-1].description.add_source(gxobject)
1241
+ elif record.parent.tag in ['NOTE']:
1242
+ pass
1243
+ else:
1244
+ self.object_map[record.level-1].add_source(gxobject)
1023
1245
  self.object_stack.append(gxobject)
1024
1246
  self.object_map[record.level] = gxobject
1025
-
1026
-
1027
- def handle_stae(self, record):
1247
+
1248
+ def handle_stae(self, record: GedcomRecord):
1028
1249
  if isinstance(self.object_map[record.level-1], Address):
1029
1250
  self.object_map[record.level-1].stateOrProvince = Translater.clean_str(record.value)
1030
1251
  else:
1031
1252
  raise ValueError(f"I do not know how to handle an 'STAE' tag for a {type(self.object_map[record.level-1])}")
1032
1253
 
1033
- def handle_surn(self, record):
1254
+ def handle_surn(self, record: GedcomRecord):
1034
1255
  if isinstance(self.object_map[record.level-1], Name):
1035
1256
  surname = NamePart(value=record.value, type=NamePartType.Surname)
1036
1257
  self.object_map[record.level-1]._add_name_part(surname)
1037
1258
  else:
1038
- print(f"{record.describe()}, Cannot translate 'NAME', {self.object_map[record.level-1]}")
1039
- assert False
1259
+ raise TagConversionError(record=record,levelstack=self.object_map)
1040
1260
 
1041
1261
  def handle_text(self, record: GedcomRecord):
1042
1262
  if record.parent.tag == 'DATA':
1043
1263
  if isinstance(self.object_map[record.level-2], SourceReference):
1044
1264
  gxobject = TextValue(value=record.value)
1045
- self.object_map[record.level-2]._description_object.add_description(gxobject)
1265
+ self.object_map[record.level-2].description.add_description(gxobject)
1046
1266
  self.object_stack.append(gxobject)
1047
1267
  self.object_map[record.level] = gxobject
1268
+ elif isinstance(self.object_map[record.level-1], SourceDescription):
1269
+ gxobject = Document(text=record.value)
1270
+ self.object_map[record.level-1].analysis = gxobject
1048
1271
  else:
1049
1272
  assert False
1050
1273
 
1051
- def handle_titl(self, record):
1274
+ def handle_titl(self, record: GedcomRecord):
1052
1275
  if isinstance(self.object_map[record.level-1], SourceDescription):
1053
1276
 
1054
1277
  gxobject = TextValue(value=Translater.clean_str(record.value))
@@ -1068,12 +1291,12 @@ class Translater():
1068
1291
 
1069
1292
  self.object_map[record.level]._add_name_part(gxobject)
1070
1293
  else:
1071
- print(self.object_map)
1072
- print(self.object_map[record.level])
1073
- raise ValueError(f"Could not handle 'TITL' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
1074
- assert False
1294
+ raise TagConversionError(record=record,levelstack=self.object_map)
1075
1295
 
1076
- def handle_type(self, record):
1296
+ def handle_tran(self, record: GedcomRecord):
1297
+ pass
1298
+
1299
+ def handle_type(self, record: GedcomRecord):
1077
1300
  # peek to see if event or fact
1078
1301
  if isinstance(self.object_map[record.level-1], Event):
1079
1302
  if EventType.guess(record.value):
@@ -1084,6 +1307,11 @@ class Translater():
1084
1307
  elif isinstance(self.object_map[record.level-1], Fact):
1085
1308
  if not self.object_map[record.level-1].type:
1086
1309
  self.object_map[0].type = FactType.guess(record.value)
1310
+ elif isinstance(self.object_map[record.level-1], Identifier):
1311
+
1312
+ self.object_map[record.level-1].values.append(Translater.clean_str(record.value))
1313
+ self.object_map[record.level-1].type = IdentifierType.Other
1314
+
1087
1315
  elif record.parent.tag == 'FORM':
1088
1316
  if not self.object_map[0].mediaType:
1089
1317
  self.object_map[0].mediaType = record.value
@@ -1091,15 +1319,17 @@ class Translater():
1091
1319
  else:
1092
1320
  raise ValueError(f"I do not know how to handle 'TYPE' tag for {type(self.object_map[record.level-1])}")
1093
1321
 
1094
- def handle__url(self, record):
1322
+ def handle__url(self, record: GedcomRecord):
1095
1323
  if isinstance(self.object_map[record.level-2], SourceDescription):
1096
1324
  self.object_map[record.level-2].about = URI.from_url(record.value)
1097
1325
  else:
1098
1326
  raise ValueError(f"Could not handle '_URL' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1099
1327
 
1100
- def handle_www(self, record):
1101
- if isinstance(self.object_map[record.level-2], SourceReference):
1102
- self.object_map[record.level-2]._description_object.add_identifier(Identifier(value=URI.from_url(record.value)))
1328
+ def handle_www(self, record: GedcomRecord):
1329
+ if isinstance(self.object_map[record.level-1], Agent):
1330
+ self.object_map[record.level-1].homepage = Translater.clean_str(record.value)
1331
+ elif isinstance(self.object_map[record.level-2], SourceReference):
1332
+ self.object_map[record.level-2].description.add_identifier(Identifier(value=URI.from_url(record.value)))
1103
1333
  else:
1104
1334
  raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1105
1335