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/GedcomX.py CHANGED
@@ -1,50 +1,72 @@
1
1
  DEBUG = False
2
- import base64
3
- import json
4
- import mimetypes
5
- import re
6
- import uuid
7
- import xml.etree.ElementTree as ET
8
2
 
9
- from typing import List, Optional
10
- from xml.dom import minidom
11
- from .Address import Address
3
+ import json
4
+ import random
5
+ import string
6
+
7
+ from typing import Any, Dict, Optional
8
+
9
+ """
10
+ ======================================================================
11
+ Project: Gedcom-X
12
+ File: GedcomX.py
13
+ Author: David J. Cartwright
14
+ Purpose: Object for working with Gedcom-X Data
15
+
16
+ Created: 2025-07-25
17
+ Updated:
18
+ - 2025-08-31: _as_dict_ to only create entries in dict for fields that hold data,
19
+ id_index functionality, will be used for resolution of Resources
20
+
21
+ ======================================================================
22
+ """
23
+
24
+ """
25
+ ======================================================================
26
+ GEDCOM Module Types
27
+ ======================================================================
28
+ """
12
29
  from .Agent import Agent
13
30
  from .Attribution import Attribution
14
- from .Conclusion import Conclusion
15
- from .Coverage import Coverage
16
- from .Date import Date, date_to_timestamp
17
31
  from .Document import Document
18
- from .EvidenceReference import EvidenceReference
19
- from .Exceptions import TagConversionError
20
- from .Event import Event,EventType,EventRole,EventRoleType
21
- from .Fact import Fact, FactType, FactQualifier
22
- from .Gedcom import Gedcom
23
- from .Gedcom5x import GedcomRecord
24
- from .Gender import Gender, GenderType
32
+ from .Event import Event
25
33
  from .Group import Group
26
- from .Identifier import Identifier, IdentifierType, make_uid, IdentifierList
34
+ from .Identifier import make_uid
27
35
  from .Logging import get_logger
28
- from .Name import Name, NameType, NameForm, NamePart, NamePartType, NamePartQualifier
29
- from .Note import Note
30
- from .OnlineAccount import OnlineAccount
31
36
  from .Person import Person
32
37
  from .PlaceDescription import PlaceDescription
33
- from .PlaceReference import PlaceReference
34
- from .Qualifier import Qualifier
35
38
  from .Relationship import Relationship, RelationshipType
36
- from .SourceCitation import SourceCitation
37
- from .SourceDescription import SourceDescription, ResourceType
38
- from .SourceReference import SourceReference, KnownSourceReference
39
- from .Subject import Subject
40
- from .TextValue import TextValue
41
- from .TopLevelTypeCollection import TopLevelTypeCollection
42
39
  from .Resource import Resource, URI
40
+ from .SourceDescription import ResourceType, SourceDescription
41
+ from .TextValue import TextValue
42
+ #=====================================================================
43
43
 
44
- import_log = get_logger('import')
45
- convert_log = get_logger('conversion')
46
44
 
47
45
  def TypeCollection(item_type):
46
+ """
47
+ Factory that creates a typed, indexable collection for a specific model class.
48
+
49
+ The returned object behaves like:
50
+ - a container (append/remove, __len__, __getitem__)
51
+ - an iterator (for item in collection)
52
+ - a simple query helper via __call__(**field_equals)
53
+ - a small in-memory index on id, name (see note), and uri
54
+
55
+ Parameters
56
+ ----------
57
+ item_type : type
58
+ The class/type that items in this collection must be instances of.
59
+
60
+ Returns
61
+ -------
62
+ Collection
63
+ A new, empty collection instance specialized for `item_type`.
64
+
65
+ Notes
66
+ -----
67
+ - Name indexing is currently disabled (see TODO in `_update_indexes`).
68
+ - The collection auto-assigns/normalizes an item's `uri.path` based on `item_type`.
69
+ """
48
70
  class Collection:
49
71
  def __init__(self):
50
72
  self._items = []
@@ -75,8 +97,8 @@ def TypeCollection(item_type):
75
97
  self._id_index[item.id] = item
76
98
 
77
99
  try:
78
- if hasattr(item, '_uri'):
79
- self._uri_index[item._uri.value] = item
100
+ if hasattr(item, 'uri'):
101
+ self._uri_index[item.uri.value] = item
80
102
  except AttributeError as e:
81
103
  print(f"type{item}")
82
104
  assert False
@@ -93,7 +115,10 @@ def TypeCollection(item_type):
93
115
  else:
94
116
  self._name_index[name_value] = [item]
95
117
  '''
96
-
118
+ @property
119
+ def id_index(self):
120
+ return self._id_index
121
+
97
122
  def _remove_from_indexes(self, item):
98
123
  # Remove from the id index
99
124
  if hasattr(item, 'id'):
@@ -111,12 +136,12 @@ def TypeCollection(item_type):
111
136
  if not self._name_index[name_value]:
112
137
  del self._name_index[name_value]
113
138
 
114
- def byName(self, sname: str):
139
+ def byName(self, sname: str | None):
115
140
  # Use the name index for fast lookup
116
141
  if sname:
117
142
  sname = sname.strip()
118
143
  return self._name_index.get(sname, [])
119
- return None
144
+ return []
120
145
 
121
146
  def byId(self, id):
122
147
  # Use the id index for fast lookup
@@ -132,12 +157,7 @@ def TypeCollection(item_type):
132
157
  if item.uri:
133
158
  item.uri.path = f'{str(item_type.__name__)}s' if (item.uri.path is None or item.uri.path == "") else item.uri.path
134
159
  else:
135
- item.uri = URI(path=f'/{item_type.__name__}s/')
136
-
137
-
138
- #if isinstance(item,Agent):
139
- # item._uri._path = 'Agents'
140
- # print(item._uri._as_dict_)
160
+ item.uri = URI(path=f'/{item_type.__name__}s/',fragment=item.id)
141
161
 
142
162
  self._items.append(item)
143
163
  self._update_indexes(item)
@@ -234,6 +254,19 @@ class GedcomX:
234
254
 
235
255
  self.default_id_generator = make_uid
236
256
 
257
+ @property
258
+ def contents(self):
259
+ return {
260
+ "source_descriptions": len(self.source_descriptions),
261
+ "persons": len(self.persons),
262
+ "relationships": len(self.relationships),
263
+ "agents": len(self.agents),
264
+ "events": len(self.events),
265
+ "documents": len(self.documents),
266
+ "places": len(self.places),
267
+ "groups": len(self.groups),
268
+ }
269
+
237
270
  def add(self,gedcomx_type_object):
238
271
  if gedcomx_type_object:
239
272
  if isinstance(gedcomx_type_object,Person):
@@ -276,7 +309,7 @@ class GedcomX:
276
309
  """
277
310
  if person and isinstance(person,Person):
278
311
  if person.id is None:
279
- person.id =self.personURIgenerator()
312
+ person.id =self.make_id()
280
313
  self.persons.append(item=person)
281
314
  else:
282
315
  raise ValueError(f'person must be a Person Object not type: {type(person)}')
@@ -287,32 +320,33 @@ class GedcomX:
287
320
  print("Adding unresolved Relationship")
288
321
  self.relationships.append(relationship)
289
322
  return
323
+ elif isinstance(relationship.person1,Person) and isinstance(relationship.person2,Person):
324
+
325
+ if relationship.person1:
326
+ if relationship.person1.id is None:
327
+ relationship.person1.id = self.make_id()
328
+ if not self.persons.byId(relationship.person1.id):
329
+ self.persons.append(relationship.person1)
330
+ if relationship.person1.id not in self.relationship_table:
331
+ self.relationship_table[relationship.person1.id] = []
332
+ self.relationship_table[relationship.person1.id].append(relationship)
333
+ relationship.person1._add_relationship(relationship)
334
+ else:
335
+ pass
336
+
337
+ if relationship.person2:
338
+ if relationship.person2.id is None:
339
+ relationship.person2.id = self.make_id() #TODO
340
+ if not self.persons.byId(relationship.person2.id):
341
+ self.persons.append(relationship.person2)
342
+ if relationship.person2.id not in self.relationship_table:
343
+ self.relationship_table[relationship.person2.id] = []
344
+ self.relationship_table[relationship.person2.id].append(relationship)
345
+ relationship.person2._add_relationship(relationship)
346
+ else:
347
+ pass
290
348
 
291
- if relationship.person1:
292
- if relationship.person1.id is None:
293
- relationship.person1.id = self.personURIgenerator()
294
- if not self.persons.byId(relationship.person1.id):
295
- self.persons.append(relationship.person1)
296
- if relationship.person1.id not in self.relationship_table:
297
- self.relationship_table[relationship.person1.id] = []
298
- self.relationship_table[relationship.person1.id].append(relationship)
299
- relationship.person1._add_relationship(relationship)
300
- else:
301
- pass
302
-
303
- if relationship.person2:
304
- if relationship.person2.id is None:
305
- relationship.person2.id = self.personURIgenerator() #TODO
306
- if not self.persons.byId(relationship.person2.id):
307
- self.persons.append(relationship.person2)
308
- if relationship.person2.id not in self.relationship_table:
309
- self.relationship_table[relationship.person2.id] = []
310
- self.relationship_table[relationship.person2.id].append(relationship)
311
- relationship.person2._add_relationship(relationship)
312
- else:
313
- pass
314
-
315
- self.relationships.append(relationship)
349
+ self.relationships.append(relationship)
316
350
  else:
317
351
  raise ValueError()
318
352
 
@@ -338,18 +372,24 @@ class GedcomX:
338
372
  if agent in self.agents:
339
373
  return
340
374
  if agent.id is None:
341
- agent.id = Agent.default_id_generator()
375
+ agent.id = make_uid()
342
376
  if self.agents.byId(agent.id):
343
- raise ValueError
344
- print(f'Added Agent with id: {agent.id}')
377
+ pass #TODO Deal with duplicates
378
+ #raise ValueError
345
379
  self.agents.append(agent)
346
380
 
347
381
  def add_event(self,event_to_add: Event):
348
382
  if event_to_add and isinstance(event_to_add,Event):
383
+ if event_to_add.id is None: event_to_add.id = make_uid()
349
384
  for current_event in self.events:
350
385
  if event_to_add == current_event:
386
+ print("DUPLICATE EVENT")
387
+ print(event_to_add._as_dict_)
388
+ print(current_event._as_dict_)
351
389
  return
352
390
  self.events.append(event_to_add)
391
+ else:
392
+ raise ValueError
353
393
 
354
394
  def get_person_by_id(self,id: str):
355
395
  filtered = [person for person in self.persons if getattr(person, 'id') == id]
@@ -361,6 +401,53 @@ class GedcomX:
361
401
  if filtered: return filtered[0]
362
402
  return None
363
403
 
404
+ @property
405
+ def id_index(self):
406
+ combined = {**self.source_descriptions.id_index,
407
+ **self.persons.id_index,
408
+ **self.relationships.id_index,
409
+ **self.agents.id_index,
410
+ **self.events.id_index,
411
+ **self.documents.id_index,
412
+ **self.places.id_index,
413
+ **self.groups.id_index
414
+ }
415
+ for i in combined.keys():
416
+ combined[i] = str(type(combined[i]).__name__)
417
+ return combined
418
+
419
+ @property
420
+ def _as_dict(self) -> dict[str, Any]:
421
+ type_as_dict: Dict[str, Any] = {}
422
+
423
+ if self.persons and len(self.persons) > 0:
424
+ type_as_dict["persons"] = [person._as_dict_ for person in self.persons]
425
+
426
+ if self.source_descriptions:
427
+ type_as_dict["sourceDescriptions"] = [
428
+ sd._as_dict_ for sd in self.source_descriptions
429
+ ]
430
+
431
+ if self.relationships:
432
+ type_as_dict["relationships"] = [
433
+ rel._as_dict_ for rel in self.relationships
434
+ ]
435
+
436
+ if self.agents:
437
+ type_as_dict["agents"] = [agent._as_dict_ for agent in self.agents]
438
+
439
+ if self.events:
440
+ type_as_dict["events"] = [event._as_dict_ for event in self.events]
441
+
442
+ if self.places:
443
+ type_as_dict["places"] = [place._as_dict_ for place in self.places]
444
+
445
+ if self.documents:
446
+ type_as_dict["documents"] = [doc._as_dict_ for doc in self.documents]
447
+
448
+ return type_as_dict
449
+
450
+ @property
364
451
  def json(self):
365
452
  """
366
453
  JSON Representation of the GedcomX Genealogy.
@@ -379,972 +466,35 @@ class GedcomX:
379
466
  }
380
467
  return json.dumps(gedcomx_json, indent=4)
381
468
 
382
- class Translater():
383
- def __init__(self,gedcom: Gedcom) -> None:
384
- self.handlers = {}
385
- self.gedcom: Gedcom = gedcom
386
- self.gedcomx = GedcomX()
387
-
388
- self.object_stack = []
389
- self.object_map = {}
390
- self.missing_handler_count = {}
391
-
392
- self.translate()
393
-
394
-
395
- gedcom_even_to_fact = {
396
- # Person Fact Types
397
- "ADOP": FactType.Adoption,
398
- "CHR": FactType.AdultChristening,
399
- "EVEN": FactType.Amnesty, # and other FactTypes with no direct GEDCOM tag
400
- "BAPM": FactType.Baptism,
401
- "BARM": FactType.BarMitzvah,
402
- "BASM": FactType.BatMitzvah,
403
- "BIRT": FactType.Birth,
404
- "BIRT, CHR": FactType.Birth,
405
- "BLES": FactType.Blessing,
406
- "BURI": FactType.Burial,
407
- "CAST": FactType.Caste,
408
- "CENS": FactType.Census,
409
- "CIRC": FactType.Circumcision,
410
- "CONF": FactType.Confirmation,
411
- "CREM": FactType.Cremation,
412
- "DEAT": FactType.Death,
413
- "EDUC": FactType.Education,
414
- "EMIG": FactType.Emigration,
415
- "FCOM": FactType.FirstCommunion,
416
- "GRAD": FactType.Graduation,
417
- "IMMI": FactType.Immigration,
418
- "MIL": FactType.MilitaryService,
419
- "NATI": FactType.Nationality,
420
- "NATU": FactType.Naturalization,
421
- "OCCU": FactType.Occupation,
422
- "ORDN": FactType.Ordination,
423
- "DSCR": FactType.PhysicalDescription,
424
- "PROB": FactType.Probate,
425
- "PROP": FactType.Property,
426
- "RELI": FactType.Religion,
427
- "RESI": FactType.Residence,
428
- "WILL": FactType.Will,
429
-
430
- # Couple Relationship Fact Types
431
- "ANUL": FactType.Annulment,
432
- "DIV": FactType.Divorce,
433
- "DIVF": FactType.DivorceFiling,
434
- "ENGA": FactType.Engagement,
435
- "MARR": FactType.Marriage,
436
- "MARB": FactType.MarriageBanns,
437
- "MARC": FactType.MarriageContract,
438
- "MARL": FactType.MarriageLicense,
439
- "SEPA": FactType.Separation,
440
-
441
- # Parent-Child Relationship Fact Types
442
- # (Note: Only ADOPTION has a direct GEDCOM tag, others are under "EVEN")
443
- "ADOP": FactType.AdoptiveParent
444
- }
445
-
446
- gedcom_even_to_evnt = {
447
- # Person Fact Types
448
- "ADOP": EventType.Adoption,
449
- "CHR": EventType.AdultChristening,
450
- "BAPM": EventType.Baptism,
451
- "BARM": EventType.BarMitzvah,
452
- "BASM": EventType.BatMitzvah,
453
- "BIRT": EventType.Birth,
454
- "BIRT, CHR": EventType.Birth,
455
- "BLES": EventType.Blessing,
456
- "BURI": EventType.Burial,
457
-
458
- "CENS": EventType.Census,
459
- "CIRC": EventType.Circumcision,
460
- "CONF": EventType.Confirmation,
461
- "CREM": EventType.Cremation,
462
- "DEAT": EventType.Death,
463
- "EDUC": EventType.Education,
464
- "EMIG": EventType.Emigration,
465
- "FCOM": EventType.FirstCommunion,
466
-
467
- "IMMI": EventType.Immigration,
468
-
469
- "NATU": EventType.Naturalization,
470
-
471
- "ORDN": EventType.Ordination,
472
-
473
-
474
- # Couple Relationship Fact Types
475
- "ANUL": EventType.Annulment,
476
- "DIV": EventType.Divorce,
477
- "DIVF": EventType.DivorceFiling,
478
- "ENGA": EventType.Engagement,
479
- "MARR": EventType.Marriage
480
-
481
- }
482
-
483
469
  @staticmethod
484
- def clean_str(text: str) -> str:
485
- # Regular expression to match HTML/XML tags
486
- if text is None or text.strip() == '':
487
- return None
488
- clean_text = re.sub(r'<[^>]+>', '', text)
489
-
490
- return clean_text
491
-
492
- def translate(self):
493
- for n, repository in enumerate(self.gedcom.repositories):
494
- print(f"Parsing Repository {n}")
495
- self.parse_record(repository)
496
- print(f"Translated {len(self.gedcomx.agents)} 'REPO' records to Agents")
497
- for source in self.gedcom.sources:
498
- self.parse_record(source)
499
- print(f"Translated {len(self.gedcomx.source_descriptions)} 'SOUR' records to SourceDescription")
500
-
501
- for object in self.gedcom.objects:
502
- self.parse_record(object)
503
- print(f"Translated {len(self.gedcom.objects)} 'OBJE' records to SourceDescriptions")
504
-
505
- for individual in self.gedcom.individuals:
506
- self.parse_record(individual)
507
- print(f"Translated {len(self.gedcomx.persons)} 'INDI' records to Persons")
508
-
509
- for key in self.missing_handler_count:
510
- print(f"{key}: {self.missing_handler_count[key]}")
511
-
470
+ def from_json(data: dict):
471
+ from .Serialization import Serialization
472
+ gx = GedcomX()
512
473
 
513
-
514
- fam_count = len(self.gedcom.families)
515
- for family in self.gedcom.families:
516
- self.handle_fam(family)
517
- print(f"Translated {fam_count} 'FAM' records to {len(self.gedcomx.relationships)} Relationship")
474
+ source_descriptions = data.get('sourceDescriptions', [])
475
+ for source in source_descriptions:
476
+ gx.add_source_description(Serialization.deserialize(source,SourceDescription))
518
477
 
519
- print(f"Translated {len(self.gedcomx.events)} 'EVEN' records to Events")
520
-
521
- def find_urls(self,text: str):
522
- # Regular expression pattern to match URLs
523
- url_pattern = re.compile(r'https?://[^\s]+')
524
- # Find all URLs using the pattern
525
- urls = url_pattern.findall(text)
526
- return urls
527
-
528
- @property
529
- def event_type_conversion_table(self):
530
- return {'BIRT':EventType.Birth,
531
- 'OBIT':FactType.Obituary}
532
-
533
- def parse_record(self,record: GedcomRecord):
534
-
535
- handler_name = 'handle_' + record.tag.lower()
536
-
537
- if hasattr(self,handler_name):
538
- convert_log.info(f'Parsing Record: {record.describe()}')
539
- handler = getattr(self,handler_name)
540
- handler(record)
541
- else:
542
- if record.tag in self.missing_handler_count:
543
- self.missing_handler_count[record.tag] += 1
544
- else:
545
- self.missing_handler_count[record.tag] = 1
546
-
547
- convert_log.error(f'Failed Parsing Record: {record.describe()}')
548
- for sub_record in record.subRecords():
549
- self.parse_record(sub_record)
550
-
551
- def handle__apid(self, record: GedcomRecord):
552
- if isinstance(self.object_map[record.level-1], SourceReference):
553
- self.object_map[record.level-1].description.add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
554
- elif isinstance(self.object_map[record.level-1], SourceDescription):
555
- self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
556
- else:
557
- raise ValueError(f"Could not handle '_APID' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
558
-
559
- def handle__meta(self, record: GedcomRecord):
560
- if isinstance(self.object_map[record.level-1], SourceDescription):
561
- gxobject = Note(text=Translater.clean_str(record.value))
562
- self.object_map[record.level-1].add_note(gxobject)
563
- self.object_stack.append(gxobject)
564
- self.object_map[record.level] = gxobject
565
- else:
566
- raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
567
-
568
- def handle__wlnk(self, record: GedcomRecord):
569
- return self.handle_sour(record)
570
-
571
- def handle_addr(self, record: GedcomRecord):
572
- if isinstance(self.object_map[record.level-1], Agent):
573
- # TODO CHeck if URL?
574
- if Translater.clean_str(record.value):
575
- gxobject = Address(value=Translater.clean_str(record.value))
576
- else:
577
- gxobject = Address()
578
- self.object_map[record.level-1].address = gxobject
579
- self.object_stack.append(gxobject)
580
- self.object_map[record.level] = gxobject
581
- else:
582
- raise ValueError(f"I do not know how to handle an 'ADDR' tag for a {type(self.object_map[record.level-1])}")
583
-
584
- def handle_adr1(self, record: GedcomRecord):
585
- if isinstance(self.object_map[record.level-1], Address):
586
- if Translater.clean_str(record.value):
587
- self.object_map[record.level-1].street = Translater.clean_str(record.value)
588
- else:
589
- raise ValueError(f"I do not know how to handle an 'ADR1' tag for a {type(self.object_map[record.level-1])}")
590
-
591
- def handle_adr2(self, record: GedcomRecord):
592
- if isinstance(self.object_map[record.level-1], Address):
593
- if Translater.clean_str(record.value):
594
- self.object_map[record.level-1].street2 = Translater.clean_str(record.value)
595
- else:
596
- raise ValueError(f"I do not know how to handle an 'ADR2' tag for a {type(self.object_map[record.level-1])}")
597
-
598
- def handle_adr3(self, record: GedcomRecord):
599
- if isinstance(self.object_map[record.level-1], Address):
600
- if Translater.clean_str(record.value):
601
- self.object_map[record.level-1].street3 = Translater.clean_str(record.value)
602
- else:
603
- raise ValueError(f"I do not know how to handle an 'ADR3' tag for a {type(self.object_map[record.level-1])}")
604
-
605
- def handle_adr4(self, record: GedcomRecord):
606
- if isinstance(self.object_map[record.level-1], Address):
607
- if Translater.clean_str(record.value):
608
- self.object_map[record.level-1].street4 = Translater.clean_str(record.value)
609
- else:
610
- raise ValueError(f"I do not know how to handle an 'ADR4' tag for a {type(self.object_map[record.level-1])}")
611
-
612
- def handle_adr5(self, record: GedcomRecord):
613
- if isinstance(self.object_map[record.level-1], Address):
614
- if Translater.clean_str(record.value):
615
- self.object_map[record.level-1].street5 = Translater.clean_str(record.value)
616
- else:
617
- raise ValueError(f"I do not know how to handle an 'ADR5' tag for a {type(self.object_map[record.level-1])}")
618
-
619
- def handle_adr6(self, record: GedcomRecord):
620
- if isinstance(self.object_map[record.level-1], Address):
621
- if Translater.clean_str(record.value):
622
- self.object_map[record.level-1].street5 = Translater.clean_str(record.value)
623
- else:
624
- raise ValueError(f"I do not know how to handle an 'ADR6' tag for a {type(self.object_map[record.level-1])}")
625
-
626
- def handle_phon(self, record: GedcomRecord):
627
- if isinstance(self.object_map[record.level-1], Agent):
628
- if Translater.clean_str(record.value):
629
- self.object_map[record.level-1].phones.append(Translater.clean_str(record.value))
630
- else:
631
- raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
632
-
633
- def handle_email(self, record: GedcomRecord):
634
- if isinstance(self.object_map[record.level-1], Agent):
635
- if Translater.clean_str(record.value):
636
- self.object_map[record.level-1].emails.append(Translater.clean_str(record.value))
637
- else:
638
- raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
639
-
640
- def handle_fax(self, record: GedcomRecord):
641
- if isinstance(self.object_map[record.level-1], Agent):
642
- if Translater.clean_str(record.value):
643
- self.object_map[record.level-1].emails.append('FAX:' + Translater.clean_str(record.value))
644
- else:
645
- raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
646
-
647
- def handle_adop(self, record: GedcomRecord):
648
- if isinstance(self.object_map[record.level-1], Person):
649
- gxobject = Fact(type=FactType.Adoption)
650
- self.object_map[record.level-1].add_fact(gxobject)
651
-
652
- self.object_stack.append(gxobject)
653
- self.object_map[record.level] = gxobject
654
- else:
655
- raise TagConversionError(record=record,levelstack=self.object_map)
656
-
657
- def handle_auth(self, record: GedcomRecord):
658
- if isinstance(self.object_map[record.level-1], SourceDescription):
659
- if self.gedcomx.agents.byName(record.value):
660
- gxobject = self.gedcomx.agents.byName(record.value)[0]
661
- else:
662
- gxobject = Agent(names=[TextValue(record.value)])
663
- self.gedcomx.add_agent(gxobject)
664
-
665
- self.object_map[record.level-1].author = gxobject
666
- self.object_stack.append(gxobject)
667
- self.object_map[record.level] = gxobject
668
- else:
669
- raise TagConversionError(record=record,levelstack=self.object_map)
670
-
671
- def handle_bapm(self, record: GedcomRecord):
672
- if isinstance(self.object_map[record.level-1], Person):
673
- gxobject = Fact(type=FactType.Baptism)
674
- self.object_map[record.level-1].add_fact(gxobject)
675
-
676
- self.object_stack.append(gxobject)
677
- self.object_map[record.level] = gxobject
678
- else:
679
- raise TagConversionError(record=record,levelstack=self.object_map)
680
-
681
- def handle_birt(self, record: GedcomRecord):
682
- if isinstance(self.object_map[record.level-1], Person):
683
- #gxobject = Event(type=EventType.BIRTH, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
684
- gxobject = Fact(type=FactType.Birth)
685
- #self.gedcomx.add_event(gxobject)
686
- self.object_map[record.level-1].add_fact(gxobject)
687
-
688
- self.object_stack.append(gxobject)
689
- self.object_map[record.level] = gxobject
690
- else:
691
- raise TagConversionError(record=record,levelstack=self.object_map)
692
-
693
- def handle_buri(self, record: GedcomRecord):
694
- if isinstance(self.object_map[record.level-1], Person):
695
- gxobject = Fact(type=FactType.Burial)
696
- self.object_map[record.level-1].add_fact(gxobject)
697
-
698
- self.object_stack.append(gxobject)
699
- self.object_map[record.level] = gxobject
700
- else:
701
- raise TagConversionError(record=record,levelstack=self.object_map)
702
-
703
- def handle_caln(self, record: GedcomRecord):
704
- if isinstance(self.object_map[record.level-1], SourceReference):
705
- self.object_map[record.level-1].description.add_identifier(Identifier(value=URI.from_url('Call Number:' + record.value)))
706
- elif isinstance(self.object_map[record.level-1], SourceDescription):
707
- self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('Call Number:' + record.value)))
708
- elif isinstance(self.object_map[record.level-1], Agent):
709
- pass
710
- # TODO Why is GEDCOM so shitty? A callnumber for a repository?
711
- else:
712
- raise ValueError(f"Could not handle 'CALN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
713
-
714
- def handle_chan(self, record: GedcomRecord):
715
- if isinstance(self.object_map[record.level-1], SourceDescription):
716
- self.object_map[record.level-1].created = Date(record.subRecord('DATE'))
717
- elif isinstance(self.object_map[record.level-1], Agent):
718
- if self.object_map[record.level-1].attribution is None:
719
- gxobject = Attribution()
720
- self.object_map[record.level-1].attribution = gxobject
721
- self.object_stack.append(gxobject)
722
- self.object_map[record.level] = gxobject
723
- else:
724
- raise ValueError()
725
-
726
- def handle_chr(self, record: GedcomRecord):
727
- if isinstance(self.object_map[record.level-1], Person):
728
- gxobject = Fact(type=FactType.Christening)
729
- self.object_map[record.level-1].add_fact(gxobject)
730
-
731
- self.object_stack.append(gxobject)
732
- self.object_map[record.level] = gxobject
733
- else:
734
- raise TagConversionError(record=record,levelstack=self.object_map)
735
-
736
- def handle_city(self, record: GedcomRecord):
737
- if isinstance(self.object_map[record.level-1], Address):
738
- self.object_map[record.level-1].city = Translater.clean_str(record.value)
739
- else:
740
- raise ValueError(f"I do not know how to handle an 'CITY' tag for a {type(self.object_map[record.level-1])}")
741
-
742
- def handle_conc(self, record: GedcomRecord):
743
- if isinstance(self.object_map[record.level-1], Note):
744
- gxobject = Translater.clean_str(str(record.value))
745
- self.object_map[record.level-1].append(gxobject)
746
- elif isinstance(self.object_map[record.level-1], Agent):
747
- gxobject = str(record.value)
748
- self.object_map[record.level-1]._append_to_name(gxobject)
749
- elif isinstance(self.object_map[record.level-1], Qualifier):
750
- gxobject = str(record.value)
751
- self.object_map[record.level-2].append(gxobject)
752
- elif isinstance(self.object_map[record.level-1], TextValue):
753
- #gxobject = TextValue(value=Translater.clean_str(record.value))
754
- self.object_map[record.level-1]._append_to_value(record.value)
755
- elif isinstance(self.object_map[record.level-1], SourceReference):
756
- self.object_map[record.level-1].append(record.value)
757
- elif isinstance(self.object_map[record.level-1], Fact):
758
- self.object_map[record.level-1].notes[0].text += record.value
759
-
760
- else:
761
- raise TagConversionError(record=record,levelstack=self.object_map)
762
-
763
- def handle_cont(self, record: GedcomRecord):
764
- if isinstance(self.object_map[record.level-1], Note):
765
- gxobject = str("\n" + record.value if record.value else '')
766
- self.object_map[record.level-1].append(gxobject)
767
- elif isinstance(self.object_map[record.level-1], Agent):
768
- gxobject = str("\n" + record.value if record.value else '')
769
- elif isinstance(self.object_map[record.level-1], Qualifier):
770
- gxobject = str("\n" + record.value if record.value else '')
771
- self.object_map[record.level-1].append(gxobject)
772
- elif isinstance(self.object_map[record.level-1], TextValue):
773
- #gxobject = TextValue(value="\n" + record.value)
774
- self.object_map[record.level-1]._append_to_value(record.value if record.value else '\n')
775
- elif isinstance(self.object_map[record.level-1], SourceReference):
776
- self.object_map[record.level-1].append(record.value)
777
- elif isinstance(self.object_map[record.level-1], Address):
778
- self.object_map[record.level-1]._append(record.value)
779
- else:
780
- raise TagConversionError(record=record,levelstack=self.object_map)
781
-
782
- def handle_crea(self, record: GedcomRecord):
783
- if isinstance(self.object_map[record.level-1], SourceDescription):
784
- self.object_map[record.level-1].created = Date(original=record.subRecord('DATE'))
785
-
786
- elif isinstance(self.object_map[record.level-1], Agent):
787
- if self.object_map[record.level-1].attribution is None:
788
- gxobject = Attribution()
789
- self.object_map[record.level-1].attribution = gxobject
790
- self.object_stack.append(gxobject)
791
- self.object_map[record.level] = gxobject
792
- else:
793
- convert_log.info(f"[{record.tag}] Attribution already exists for SourceDescription with id: {self.object_map[record.level-1].id}")
794
- else:
795
- raise ValueError(f"Could not handle '{record.tag}' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
796
-
797
- def handle_ctry(self, record: GedcomRecord):
798
- if isinstance(self.object_map[record.level-1], Address):
799
- self.object_map[record.level-1].country = Translater.clean_str(record.value)
800
- else:
801
- raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
802
-
803
- def handle_data(self, record: GedcomRecord) -> None:
804
- if record.value != '' and record.value == 'None':
805
- assert False
806
- self.object_map[record.level] = self.object_map[record.level-1]
807
-
808
- def handle_date(self, record: GedcomRecord):
809
- if record.parent.tag == 'PUBL':
810
- #gxobject = Date(original=record.value) #TODO Make a parser for solid timestamps
811
- #self.object_map[0].published = gxobject
812
- #self.object_map[0].published = date_to_timestamp(record.value) if record.value else None
813
- self.object_map[0].published = record.value
814
- #self.object_stack.append(gxobject)
815
- #self.object_map[record.level] = gxobject
816
- elif isinstance(self.object_map[record.level-1], Event):
817
- self.object_map[record.level-1].date = Date(original=record.value)
818
- elif isinstance(self.object_map[record.level-1], Fact):
819
- self.object_map[record.level-1].date = Date(original=record.value)
820
- elif record.parent.tag == 'DATA' and isinstance(self.object_map[record.level-2], SourceReference):
821
- gxobject = Note(text='Date: ' + record.value)
822
- self.object_map[record.level-2].description.add_note(gxobject)
823
- self.object_stack.append(gxobject)
824
- self.object_map[record.level] = gxobject
825
- elif isinstance(self.object_map[record.level-1], SourceDescription):
826
-
827
- self.object_map[record.level-1].ctreated = record.value #TODO String to timestamp
828
- elif isinstance(self.object_map[record.level-1], Attribution):
829
- if record.parent.tag == 'CREA':
830
- self.object_map[record.level-1].created = record.value #TODO G7
831
- elif record.parent.tag == "CHAN":
832
- self.object_map[record.level-1].modified = record.value #TODO G7
833
- elif record.parent.tag in ['CREA','CHAN']:
834
- pass
835
-
836
- else:
837
- raise TagConversionError(record=record,levelstack=self.object_map)
838
-
839
- def handle_deat(self, record: GedcomRecord):
840
- if isinstance(self.object_map[record.level-1], Person):
841
- gxobject = Fact(type=FactType.Death)
842
- self.object_map[record.level-1].add_fact(gxobject)
843
-
844
- self.object_stack.append(gxobject)
845
- self.object_map[record.level] = gxobject
846
- else:
847
- raise TagConversionError(record=record,levelstack=self.object_map)
848
-
849
- def handle_even(self, record: GedcomRecord):
850
- # TODO If events in a @S, check if only 1 person matches?
851
- if record.value and (not record.value.strip() == ''):
852
- values = [value.strip() for value in record.value.split(",")]
853
- for value in values:
854
- if value in Translater.gedcom_even_to_fact.keys():
855
- if isinstance(self.object_map[record.level-1], Person):
856
- gxobject = Fact(type=Translater.gedcom_even_to_fact[value])
857
- self.object_map[record.level-1].add_fact(gxobject)
858
-
859
- self.object_stack.append(gxobject)
860
- self.object_map[record.level] = gxobject
861
-
862
- elif isinstance(self.object_map[record.level-1], SourceDescription):
863
- gxobject = Event(type=Translater.gedcom_even_to_evnt[value],sources=[self.object_map[record.level-1]])
864
- self.gedcomx.add_event(gxobject)
865
- self.object_stack.append(gxobject)
866
- self.object_map[record.level] = gxobject
867
- else:
868
- convert_log.warning(f"Could not convert EVEN '{value}' for object of type {type(self.object_map[record.level-1])} in record {record.describe()}")
869
- return
870
- raise TagConversionError(record=record,levelstack=self.object_map)
871
- assert False
872
- # TODO: Fix, this. making an event to cacth subtags, why are these fact tied to a source? GEDCOM is horrible
873
- gxobject = Event(type=EventType.UNKNOWN)
874
- self.object_stack.append(gxobject)
875
- self.object_map[record.level] = gxobject
876
- else:
877
- raise TagConversionError(record=record,levelstack=self.object_map)
878
-
879
- else:
880
- possible_fact = FactType.guess(record.subRecord('TYPE')[0].value)
881
- if possible_fact:
882
- gxobject = Fact(type=possible_fact)
883
- self.object_map[record.level-1].add_fact(gxobject)
884
-
885
- self.object_stack.append(gxobject)
886
- self.object_map[record.level] = gxobject
887
- return
888
- elif EventType.guess(record.subRecord('TYPE')[0].value):
889
- if isinstance(self.object_map[record.level-1], Person):
890
- gxobject = Event(type=EventType.guess(record.subRecord('TYPE')[0].value), roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
891
- self.gedcomx.add_event(gxobject)
892
- self.object_stack.append(gxobject)
893
- self.object_map[record.level] = gxobject
894
- return
895
- else:
896
- if isinstance(self.object_map[record.level-1], Person):
897
- gxobject = Event(type=None, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
898
- gxobject.add_note(Note(subject='Event', text=record.value))
899
- self.gedcomx.add_event(gxobject)
900
- self.object_stack.append(gxobject)
901
- self.object_map[record.level] = gxobject
902
- return
903
-
904
- else:
905
- assert False
906
-
907
- def handle_exid(self,record: GedcomRecord):
908
- gxobject = Identifier(type=IdentifierType.External,value=[record.value])
909
- self.object_map[record.level-1].add_identifier(gxobject)
910
-
911
- self.object_stack.append(gxobject)
912
- self.object_map[record.level] = gxobject
913
-
914
- def handle_fam(self, record: GedcomRecord) -> None:
915
- if record.tag != 'FAM' or record.level != 0:
916
- raise ValueError("Invalid record: Must be a level 0 FAM record")
917
-
918
- husband, wife, children = None, None, []
919
-
920
- husband_record = record.subRecords('HUSB')
921
- if husband_record:
922
- husband = self.gedcomx.get_person_by_id(husband_record[0].xref)
923
-
924
- wife_record = record.subRecords('WIFE')
925
- if wife_record:
926
- wife = self.gedcomx.get_person_by_id(wife_record[0].xref)
927
-
928
- children_records = record.subRecords('CHIL')
929
- if children_records:
930
- for child_record in children_records:
931
- child = self.gedcomx.get_person_by_id(child_record.xref)
932
- if child:
933
- children.append(child)
934
-
935
- if husband:
936
- for child in children:
937
- relationship = Relationship(person1=husband, person2=child, type=RelationshipType.ParentChild)
938
- self.gedcomx.add_relationship(relationship)
939
- if wife:
940
- for child in children:
941
- relationship = Relationship(person1=wife, person2=child, type=RelationshipType.ParentChild)
942
- self.gedcomx.add_relationship(relationship)
943
- if husband and wife:
944
- relationship = Relationship(person1=husband, person2=wife, type=RelationshipType.Couple)
945
- self.gedcomx.add_relationship(relationship)
946
-
947
- def handle_famc(self, record: GedcomRecord) -> None:
948
- return
949
-
950
- def handle_fams(self, record: GedcomRecord) -> None:
951
- return
952
-
953
- def handle_file(self, record: GedcomRecord):
954
- if record.value and record.value.strip() != '':
955
- #raise ValueError(f"I did not expect the 'FILE' tag to have a value: {record.value}")
956
- #TODO Handle files referenced here
957
- ...
958
- elif isinstance(self.object_map[record.level-1], SourceDescription):
959
- ...
960
- self.object_map[record.level-1].resourceType = ResourceType.DigitalArtifact
961
-
962
- def handle_form(self, record: GedcomRecord):
963
- if record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
964
- if record.value and record.value.strip() != '':
965
- mime_type, _ = mimetypes.guess_type('placehold.' + record.value)
966
- if mime_type:
967
- self.object_map[record.level-2].mediaType = mime_type
968
- else:
969
- print(f"Could not determing mime type from {record.value}")
970
- elif isinstance(self.object_map[record.level-1], PlaceDescription):
971
- self.object_map[record.level-1].names.append(TextValue(value=record.value))
972
- elif record.parent.tag == 'TRAN':
973
- pass #TODO
974
- else:
975
- raise TagConversionError(record=record,levelstack=self.object_map)
976
-
977
- def handle_givn(self, record: GedcomRecord):
978
- if isinstance(self.object_map[record.level-1], Name):
979
- given_name = NamePart(value=record.value, type=NamePartType.Given)
980
- self.object_map[record.level-1]._add_name_part(given_name)
981
- else:
982
- raise TagConversionError(record=record,levelstack=self.object_map)
983
-
984
- def handle_indi(self, record: GedcomRecord):
985
- person = Person(id=record.xref.replace('@',''))
986
- self.gedcomx.add_person(person)
987
- self.object_stack.append(person)
988
- self.object_map[record.level] = person
989
-
990
- def handle_immi(self, record: GedcomRecord):
991
- if isinstance(self.object_map[record.level-1], Person):
992
- gxobject = Fact(type=FactType.Immigration)
993
- self.object_map[record.level-1].add_fact(gxobject)
994
-
995
- self.object_stack.append(gxobject)
996
- self.object_map[record.level] = gxobject
997
- else:
998
- raise TagConversionError(record=record,levelstack=self.object_map)
999
-
1000
- def handle_marr(self, record: GedcomRecord):
1001
- if isinstance(self.object_map[record.level-1], Person):
1002
- gxobject = Fact(type=FactType.Marriage)
1003
- self.object_map[record.level-1].add_fact(gxobject)
1004
-
1005
- self.object_stack.append(gxobject)
1006
- self.object_map[record.level] = gxobject
1007
- else:
1008
- raise TagConversionError(record=record,levelstack=self.object_map)
1009
-
1010
- def handle_name(self, record: GedcomRecord):
1011
- if isinstance(self.object_map[record.level-1], Person):
1012
- gxobject = Name.simple(record.value)
1013
- #gxobject = Name(nameForms=[NameForm(fullText=record.value)], type=NameType.BirthName)
1014
- self.object_map[record.level-1].add_name(gxobject)
1015
-
1016
- self.object_stack.append(gxobject)
1017
- self.object_map[record.level] = gxobject
1018
- elif isinstance(self.object_map[record.level-1], Agent):
1019
- gxobject = TextValue(value=record.value)
1020
- self.object_map[record.level-1].add_name(gxobject)
1021
- else:
1022
- raise TagConversionError(record=record,levelstack=self.object_map)
1023
-
1024
- def handle_note(self, record: GedcomRecord):
1025
- if isinstance(self.object_map[record.level-1], SourceDescription):
1026
- gxobject = Note(text=Translater.clean_str(record.value))
1027
- self.object_map[record.level-1].add_note(gxobject)
1028
-
1029
- self.object_stack.append(gxobject)
1030
- self.object_map[record.level] = gxobject
1031
- elif isinstance(self.object_map[record.level-1], SourceReference):
1032
- gxobject = Note(text=Translater.clean_str(record.value))
1033
- self.object_map[record.level-1].description.add_note(gxobject)
1034
-
1035
- self.object_stack.append(gxobject)
1036
- self.object_map[record.level] = gxobject
1037
- elif isinstance(self.object_map[record.level-1], Conclusion):
1038
- gxobject = Note(text=record.value)
1039
- self.object_map[record.level-1].add_note(gxobject)
1040
-
1041
- self.object_stack.append(gxobject)
1042
- self.object_map[record.level] = gxobject
1043
- elif isinstance(self.object_map[record.level-1], Agent):
1044
- gxobject = Note(text=record.value)
1045
- self.object_map[record.level-1].add_note(gxobject)
1046
-
1047
- self.object_stack.append(gxobject)
1048
- self.object_map[record.level] = gxobject
1049
- elif isinstance(self.object_map[record.level-1], Attribution):
1050
- if self.object_map[record.level-1].changeMessage is None:
1051
- self.object_map[record.level-1].changeMessage = record.value
1052
- else:
1053
- self.object_map[record.level-1].changeMessage = self.object_map[record.level-1].changeMessage + '' + record.value
1054
-
1055
- else:
1056
- raise ValueError(f"Could not handle 'NOTE' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
1057
- assert False
1058
-
1059
- def handle_nsfx(self, record: GedcomRecord):
1060
- if isinstance(self.object_map[record.level-1], Name):
1061
- surname = NamePart(value=record.value, type=NamePartType.Suffix)
1062
- self.object_map[record.level-1]._add_name_part(surname)
1063
- else:
1064
- raise TagConversionError(record=record,levelstack=self.object_map)
1065
-
1066
- def handle_occu(self, record: GedcomRecord):
1067
- if isinstance(self.object_map[record.level-1], Person):
1068
- gxobject = Fact(type=FactType.Occupation)
1069
- self.object_map[record.level-1].add_fact(gxobject)
1070
-
1071
- self.object_stack.append(gxobject)
1072
- self.object_map[record.level] = gxobject
1073
- else:
1074
- raise TagConversionError(record=record,levelstack=self.object_map)
1075
-
1076
- def handle_obje(self, record: GedcomRecord):
1077
- self.handle_sour(record)
1078
-
1079
- def handle_page(self, record: GedcomRecord):
1080
- if isinstance(self.object_map[record.level-1], SourceReference):
1081
- self.object_map[record.level-1].descriptionId = record.value
1082
- self.object_map[record.level-1].add_qualifier(KnownSourceReference(name=str(KnownSourceReference.Page),value=record.value))
1083
-
1084
- #self.object_stack.append(gxobject)
1085
- #self.object_map[record.level] = gxobject
1086
- self.object_map[record.level] = self.object_map[record.level-1]
1087
- else:
1088
- raise ValueError(f"Could not handle 'PAGE' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1089
-
1090
- def handle_plac(self, record: GedcomRecord):
1091
- if isinstance(self.object_map[record.level-1], Agent):
1092
- gxobject = Address(value=record.value)
1093
- self.object_map[record.level-1].add_address(gxobject)
1094
-
1095
- self.object_stack.append(gxobject)
1096
- self.object_map[record.level] = gxobject
1097
- elif isinstance(self.object_map[record.level-1], Event):
1098
- if self.gedcomx.places.byName(record.value):
1099
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=self.gedcomx.places.byName(record.value)[0])
1100
- else:
1101
- place_des = PlaceDescription(names=[TextValue(value=record.value)])
1102
- self.gedcomx.add_place_description(place_des)
1103
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=place_des)
1104
- if len(record.subRecords()) > 0:
1105
- self.object_map[record.level]= place_des
1106
-
1107
- elif isinstance(self.object_map[record.level-1], Fact):
1108
- if self.gedcomx.places.byName(record.value):
1109
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=self.gedcomx.places.byName(record.value)[0])
1110
- else:
1111
- place_des = PlaceDescription(names=[TextValue(value=record.value)])
1112
- self.gedcomx.add_place_description(place_des)
1113
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=place_des)
1114
- elif isinstance(self.object_map[record.level-1], SourceDescription):
1115
- gxobject = Note(text='Place: ' + record.value)
1116
- self.object_map[record.level-1].add_note(gxobject)
1117
- self.object_stack.append(gxobject)
1118
- self.object_map[record.level] = gxobject
1119
- else:
1120
- raise TagConversionError(record=record,levelstack=self.object_map)
1121
-
1122
- def handle_post(self, record: GedcomRecord):
1123
- if isinstance(self.object_map[record.level-1], Address):
1124
- self.object_map[record.level-1].postalCode = Translater.clean_str(record.value)
1125
- else:
1126
- raise ValueError(f"I do not know how to handle an 'POST' tag for a {type(self.object_map[record.level-1])}")
1127
-
1128
- def handle_publ(self, record: GedcomRecord):
1129
- if isinstance(self.object_map[record.level-1], SourceDescription):
1130
- if record.value and self.gedcomx.agents.byName(record.value):
1131
- gxobject = self.gedcomx.agents.byName(record.value)[0]
1132
- else:
1133
- gxobject = Agent(names=[TextValue(record.value)])
1134
- self.gedcomx.add_agent(gxobject)
1135
- self.object_map[record.level-1].publisher = gxobject
1136
-
1137
- self.object_stack.append(gxobject)
1138
- self.object_map[record.level] = gxobject
1139
- else:
1140
- raise TagConversionError(record=record,levelstack=self.object_map)
1141
-
1142
- def handle_prob(self, record: GedcomRecord):
1143
- if isinstance(self.object_map[record.level-1], Person):
1144
- gxobject = Fact(type=FactType.Probate)
1145
- self.object_map[record.level-1].add_fact(gxobject)
1146
-
1147
- self.object_stack.append(gxobject)
1148
- self.object_map[record.level] = gxobject
1149
- else:
1150
- raise TagConversionError(record=record,levelstack=self.object_map)
1151
-
1152
- def handle_uid(self, record: GedcomRecord):
1153
- if isinstance(self.object_map[record.level-1], Agent):
1154
- gxobject = Identifier(value=['UID:' + record.value],type=IdentifierType.Primary)
1155
- self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
1156
- self.object_stack.append(gxobject)
1157
- self.object_map[record.level] = gxobject
1158
-
1159
- def handle_refn(self, record: GedcomRecord):
1160
- if isinstance(self.object_map[record.level-1], Person) or isinstance(self.object_map[record.level-1], SourceDescription):
1161
- gxobject = Identifier(value=[URI.from_url('Reference Number:' + record.value)])
1162
- self.object_map[record.level-1].add_identifier(gxobject)
1163
- self.object_stack.append(gxobject)
1164
- self.object_map[record.level] = gxobject
1165
- elif isinstance(self.object_map[record.level-1], Agent):
1166
- gxobject = Identifier(value=['Reference Number:' + record.value])
1167
- self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
1168
- self.object_stack.append(gxobject)
1169
- self.object_map[record.level] = gxobject
1170
- else:
1171
- raise ValueError(f"Could not handle 'REFN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
1172
-
1173
- def handle_repo(self, record: GedcomRecord):
1174
-
1175
- if record.level == 0:
1176
-
1177
- gxobject = Agent(id=record.xref)
1178
- self.gedcomx.add_agent(gxobject)
1179
- self.object_stack.append(gxobject)
1180
- self.object_map[record.level] = gxobject
1181
-
1182
- elif isinstance(self.object_map[record.level-1], SourceDescription):
1183
- if self.gedcomx.agents.byId(record.xref) is not None:
1184
-
1185
- # TODO WHere and what to add this to?
1186
- gxobject = self.gedcomx.agents.byId(record.xref)
1187
- self.object_map[record.level-1].repository = gxobject
1188
- self.object_map[record.level] = gxobject
1189
-
1190
- else:
1191
- print(record.describe())
1192
- raise ValueError()
1193
- gxobject = Agent(names=[TextValue(record.value)])
1194
- else:
1195
- raise ValueError(f"I do not know how to handle 'REPO' tag that is not a top-level, or sub-tag of {type(self.object_map[record.level-1])}")
1196
-
1197
-
1198
- self.object_stack.append(gxobject)
1199
- self.object_map[record.level] = gxobject
1200
-
1201
- def handle_resi(self, record: GedcomRecord):
1202
- if isinstance(self.object_map[record.level-1], Person):
1203
- gxobject = Fact(type=FactType.Residence)
1204
- if record.value and record.value.strip() != '':
1205
- gxobject.add_note(Note(text=record.value))
1206
- self.object_map[record.level-1].add_fact(gxobject)
1207
-
1208
- self.object_stack.append(gxobject)
1209
- self.object_map[record.level] = gxobject
1210
- else:
1211
- raise TagConversionError(record=record,levelstack=self.object_map)
1212
-
1213
- def handle_rin(self, record: GedcomRecord):
1214
- if isinstance(self.object_map[record.level-1], SourceDescription):
1215
- self.object_map[record.level-1].id = record.value
1216
- self.object_map[record.level-1].add_note(Note(text=f"Source had RIN: of {record.value}"))
1217
-
1218
- else:
1219
- raise ValueError(f"Could not handle 'RIN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
478
+ persons = data.get('persons', [])
479
+ for person in persons:
480
+ gx.add_person(Serialization.deserialize(person,Person))
1220
481
 
1221
- def handle_sex(self, record: GedcomRecord):
482
+ relationships = data.get('relationships', [])
483
+ for relationship in relationships:
484
+ gx.add_relationship(Serialization.deserialize(relationship,Relationship))
1222
485
 
1223
- if isinstance(self.object_map[record.level-1], Person):
1224
- if record.value == 'M':
1225
- gxobject = Gender(type=GenderType.Male)
1226
- elif record.value == 'F':
1227
- gxobject = Gender(type=GenderType.Female)
1228
- else:
1229
- gxobject = Gender(type=GenderType.Unknown)
1230
- self.object_map[record.level-1].gender = gxobject
1231
-
1232
- self.object_stack.append(gxobject)
1233
- self.object_map[record.level] = gxobject
1234
- else:
1235
- assert False
486
+ agents = data.get('agents', [])
487
+ for agent in agents:
488
+ gx.add_agent(Serialization.deserialize(agent,Agent))
1236
489
 
1237
- def handle_sour(self, record: GedcomRecord):
1238
- if record.level == 0 or record.tag == '_WLNK' or (record.level == 0 and record.tag == 'OBJE'):
1239
- source_description = SourceDescription(id=record.xref.replace('@','') if record.xref else None)
1240
- self.gedcomx.add_source_description(source_description)
1241
- self.object_stack.append(source_description)
1242
- self.object_map[record.level] = source_description
1243
- else:
1244
- # This 'SOUR' is a SourceReference
1245
- if record.xref and record.xref.strip() == '':
1246
- import_log.warning(f"SOUR points to nothing: {record.describe()}")
1247
- return False
1248
- if self.gedcomx.source_descriptions.byId(record.xref):
1249
- gxobject = SourceReference(descriptionId=record.xref, description=self.gedcomx.source_descriptions.byId(record.xref))
1250
- else:
1251
- import_log.warning(f'Could not find source with id: {record.xref}')
1252
- source_description = SourceDescription(id=record.xref)
1253
- gxobject = SourceReference(descriptionId=record.value, description=source_description)
1254
- if isinstance(self.object_map[record.level-1],SourceReference):
1255
- self.object_map[record.level-1].description.add_source(gxobject)
1256
- elif record.parent.tag in ['NOTE']:
1257
- pass
1258
- else:
1259
- self.object_map[record.level-1].add_source(gxobject)
1260
- self.object_stack.append(gxobject)
1261
- self.object_map[record.level] = gxobject
1262
-
1263
- def handle_stae(self, record: GedcomRecord):
1264
- if isinstance(self.object_map[record.level-1], Address):
1265
- self.object_map[record.level-1].stateOrProvince = Translater.clean_str(record.value)
1266
- else:
1267
- raise ValueError(f"I do not know how to handle an 'STAE' tag for a {type(self.object_map[record.level-1])}")
490
+ events = data.get('events', [])
491
+ for event in events:
492
+ gx.add_event(Serialization.deserialize(event,Event))
1268
493
 
1269
- def handle_surn(self, record: GedcomRecord):
1270
- if isinstance(self.object_map[record.level-1], Name):
1271
- surname = NamePart(value=record.value, type=NamePartType.Surname)
1272
- self.object_map[record.level-1]._add_name_part(surname)
1273
- else:
1274
- raise TagConversionError(record=record,levelstack=self.object_map)
1275
-
1276
- def handle_text(self, record: GedcomRecord):
1277
- if record.parent.tag == 'DATA':
1278
- if isinstance(self.object_map[record.level-2], SourceReference):
1279
- gxobject = TextValue(value=record.value)
1280
- self.object_map[record.level-2].description.add_description(gxobject)
1281
- self.object_stack.append(gxobject)
1282
- self.object_map[record.level] = gxobject
1283
- elif isinstance(self.object_map[record.level-1], SourceDescription):
1284
- gxobject = Document(text=record.value)
1285
- self.object_map[record.level-1].analysis = gxobject
1286
- else:
1287
- assert False
1288
-
1289
- def handle_titl(self, record: GedcomRecord):
1290
- if isinstance(self.object_map[record.level-1], SourceDescription):
1291
-
1292
- gxobject = TextValue(value=Translater.clean_str(record.value))
1293
- self.object_map[record.level-1].add_title(gxobject)
1294
-
1295
- self.object_stack.append(gxobject)
1296
- self.object_map[record.level] = gxobject
494
+ return gx
1297
495
 
1298
- elif record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
1299
- gxobject = TextValue(value=record.value)
1300
- self.object_map[record.level-2].add_title(gxobject)
1301
-
1302
- self.object_stack.append(gxobject)
1303
- self.object_map[record.level] = gxobject
1304
- elif self.object_map[record.level] and isinstance(self.object_map[record.level], Name):
1305
- gxobject = NamePart(value=record.value, qualifiers=[NamePartQualifier.Title])
1306
-
1307
- self.object_map[record.level]._add_name_part(gxobject)
1308
- else:
1309
- raise TagConversionError(record=record,levelstack=self.object_map)
1310
-
1311
- def handle_tran(self, record: GedcomRecord):
1312
- pass
1313
-
1314
- def handle_type(self, record: GedcomRecord):
1315
- # peek to see if event or fact
1316
- if isinstance(self.object_map[record.level-1], Event):
1317
- if EventType.guess(record.value):
1318
- self.object_map[record.level-1].type = EventType.guess(record.value)
1319
- else:
1320
- self.object_map[record.level-1].type = None
1321
- self.object_map[record.level-1].add_note(Note(text=Translater.clean_str(record.value)))
1322
- elif isinstance(self.object_map[record.level-1], Fact):
1323
- if not self.object_map[record.level-1].type:
1324
- self.object_map[0].type = FactType.guess(record.value)
1325
- elif isinstance(self.object_map[record.level-1], Identifier):
1326
-
1327
- self.object_map[record.level-1].values.append(Translater.clean_str(record.value))
1328
- self.object_map[record.level-1].type = IdentifierType.Other
1329
-
1330
- elif record.parent.tag == 'FORM':
1331
- if not self.object_map[0].mediaType:
1332
- self.object_map[0].mediaType = record.value
1333
-
1334
- else:
1335
- raise ValueError(f"I do not know how to handle 'TYPE' tag for {type(self.object_map[record.level-1])}")
1336
-
1337
- def handle__url(self, record: GedcomRecord):
1338
- if isinstance(self.object_map[record.level-2], SourceDescription):
1339
- self.object_map[record.level-2].about = URI.from_url(record.value)
1340
- else:
1341
- raise ValueError(f"Could not handle '_URL' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1342
-
1343
- def handle_www(self, record: GedcomRecord):
1344
- if isinstance(self.object_map[record.level-1], Agent):
1345
- self.object_map[record.level-1].homepage = Translater.clean_str(record.value)
1346
- elif isinstance(self.object_map[record.level-2], SourceReference):
1347
- self.object_map[record.level-2].description.add_identifier(Identifier(value=URI.from_url(record.value)))
1348
- else:
1349
- raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1350
-
496
+ @staticmethod
497
+ def make_id(length: int = 12) -> str:
498
+ """Generate a random alphanumeric ID of given length."""
499
+ alphabet = string.ascii_letters + string.digits
500
+ return ''.join(random.choices(alphabet, k=length))