gedcom-x 0.5.6__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 Gedcom5x, 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,19 +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
377
  pass #TODO Deal with duplicates
344
378
  #raise ValueError
345
- print(f'Added Agent with id: {agent.id}')
346
379
  self.agents.append(agent)
347
380
 
348
381
  def add_event(self,event_to_add: Event):
349
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()
350
384
  for current_event in self.events:
351
385
  if event_to_add == current_event:
386
+ print("DUPLICATE EVENT")
387
+ print(event_to_add._as_dict_)
388
+ print(current_event._as_dict_)
352
389
  return
353
390
  self.events.append(event_to_add)
391
+ else:
392
+ raise ValueError
354
393
 
355
394
  def get_person_by_id(self,id: str):
356
395
  filtered = [person for person in self.persons if getattr(person, 'id') == id]
@@ -362,6 +401,53 @@ class GedcomX:
362
401
  if filtered: return filtered[0]
363
402
  return None
364
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
365
451
  def json(self):
366
452
  """
367
453
  JSON Representation of the GedcomX Genealogy.
@@ -380,978 +466,35 @@ class GedcomX:
380
466
  }
381
467
  return json.dumps(gedcomx_json, indent=4)
382
468
 
383
- class Translater():
384
- def __init__(self,gedcom: Gedcom5x) -> None:
385
- self.handlers = {}
386
- self.gedcom: Gedcom = gedcom
387
- self.gedcomx = GedcomX()
388
-
389
- self.object_stack = []
390
- self.object_map = {}
391
- self.missing_handler_count = {}
392
-
393
- self.translate()
394
-
395
-
396
- gedcom_even_to_fact = {
397
- # Person Fact Types
398
- "ADOP": FactType.Adoption,
399
- "CHR": FactType.AdultChristening,
400
- "EVEN": FactType.Amnesty, # and other FactTypes with no direct GEDCOM tag
401
- "BAPM": FactType.Baptism,
402
- "BARM": FactType.BarMitzvah,
403
- "BASM": FactType.BatMitzvah,
404
- "BIRT": FactType.Birth,
405
- "BIRT, CHR": FactType.Birth,
406
- "BLES": FactType.Blessing,
407
- "BURI": FactType.Burial,
408
- "CAST": FactType.Caste,
409
- "CENS": FactType.Census,
410
- "CIRC": FactType.Circumcision,
411
- "CONF": FactType.Confirmation,
412
- "CREM": FactType.Cremation,
413
- "DEAT": FactType.Death,
414
- "EDUC": FactType.Education,
415
- "EMIG": FactType.Emigration,
416
- "FCOM": FactType.FirstCommunion,
417
- "GRAD": FactType.Graduation,
418
- "IMMI": FactType.Immigration,
419
- "MIL": FactType.MilitaryService,
420
- "NATI": FactType.Nationality,
421
- "NATU": FactType.Naturalization,
422
- "OCCU": FactType.Occupation,
423
- "ORDN": FactType.Ordination,
424
- "DSCR": FactType.PhysicalDescription,
425
- "PROB": FactType.Probate,
426
- "PROP": FactType.Property,
427
- "RELI": FactType.Religion,
428
- "RESI": FactType.Residence,
429
- "WILL": FactType.Will,
430
-
431
- # Couple Relationship Fact Types
432
- "ANUL": FactType.Annulment,
433
- "DIV": FactType.Divorce,
434
- "DIVF": FactType.DivorceFiling,
435
- "ENGA": FactType.Engagement,
436
- "MARR": FactType.Marriage,
437
- "MARB": FactType.MarriageBanns,
438
- "MARC": FactType.MarriageContract,
439
- "MARL": FactType.MarriageLicense,
440
- "SEPA": FactType.Separation,
441
-
442
- # Parent-Child Relationship Fact Types
443
- # (Note: Only ADOPTION has a direct GEDCOM tag, others are under "EVEN")
444
- "ADOP": FactType.AdoptiveParent
445
- }
446
-
447
- gedcom_even_to_evnt = {
448
- # Person Fact Types
449
- "ADOP": EventType.Adoption,
450
- "CHR": EventType.AdultChristening,
451
- "BAPM": EventType.Baptism,
452
- "BARM": EventType.BarMitzvah,
453
- "BASM": EventType.BatMitzvah,
454
- "BIRT": EventType.Birth,
455
- "BIRT, CHR": EventType.Birth,
456
- "BLES": EventType.Blessing,
457
- "BURI": EventType.Burial,
458
-
459
- "CENS": EventType.Census,
460
- "CIRC": EventType.Circumcision,
461
- "CONF": EventType.Confirmation,
462
- "CREM": EventType.Cremation,
463
- "DEAT": EventType.Death,
464
- "EDUC": EventType.Education,
465
- "EMIG": EventType.Emigration,
466
- "FCOM": EventType.FirstCommunion,
467
-
468
- "IMMI": EventType.Immigration,
469
-
470
- "NATU": EventType.Naturalization,
471
-
472
- "ORDN": EventType.Ordination,
473
-
474
-
475
- # Couple Relationship Fact Types
476
- "ANUL": EventType.Annulment,
477
- "DIV": EventType.Divorce,
478
- "DIVF": EventType.DivorceFiling,
479
- "ENGA": EventType.Engagement,
480
- "MARR": EventType.Marriage
481
-
482
- }
483
-
484
469
  @staticmethod
485
- def clean_str(text: str) -> str:
486
- # Regular expression to match HTML/XML tags
487
- if text is None or text.strip() == '':
488
- return None
489
- clean_text = re.sub(r'<[^>]+>', '', text)
470
+ def from_json(data: dict):
471
+ from .Serialization import Serialization
472
+ gx = GedcomX()
490
473
 
491
- return clean_text
492
-
493
- def translate(self):
494
- for n, repository in enumerate(self.gedcom.repositories):
495
- print(f"Parsing Repository {n}")
496
- self.parse_record(repository)
497
- print(f"Translated {len(self.gedcomx.agents)} 'REPO' records to Agents")
498
- for source in self.gedcom.sources:
499
- self.parse_record(source)
500
- print(f"Translated {len(self.gedcomx.source_descriptions)} 'SOUR' records to SourceDescription")
501
-
502
- for object in self.gedcom.objects:
503
- self.parse_record(object)
504
- print(f"Translated {len(self.gedcom.objects)} 'OBJE' records to SourceDescriptions")
505
-
506
- for individual in self.gedcom.individuals:
507
- self.parse_record(individual)
508
- print(f"Translated {len(self.gedcomx.persons)} 'INDI' records to Persons")
509
-
510
- for key in self.missing_handler_count:
511
- print(f"{key}: {self.missing_handler_count[key]}")
512
-
474
+ source_descriptions = data.get('sourceDescriptions', [])
475
+ for source in source_descriptions:
476
+ gx.add_source_description(Serialization.deserialize(source,SourceDescription))
513
477
 
514
-
515
- fam_count = len(self.gedcom.families)
516
- for family in self.gedcom.families:
517
- self.handle_fam(family)
518
- print(f"Translated {fam_count} 'FAM' records to {len(self.gedcomx.relationships)} Relationship")
478
+ persons = data.get('persons', [])
479
+ for person in persons:
480
+ gx.add_person(Serialization.deserialize(person,Person))
519
481
 
520
- print(f"Translated {len(self.gedcomx.events)} 'EVEN' records to Events")
521
-
522
- def find_urls(self,text: str):
523
- # Regular expression pattern to match URLs
524
- url_pattern = re.compile(r'https?://[^\s]+')
525
- # Find all URLs using the pattern
526
- urls = url_pattern.findall(text)
527
- return urls
528
-
529
- @property
530
- def event_type_conversion_table(self):
531
- return {'BIRT':EventType.Birth,
532
- 'OBIT':FactType.Obituary}
533
-
534
- def parse_record(self,record: GedcomRecord):
535
-
536
- handler_name = 'handle_' + record.tag.lower()
482
+ relationships = data.get('relationships', [])
483
+ for relationship in relationships:
484
+ gx.add_relationship(Serialization.deserialize(relationship,Relationship))
537
485
 
538
- if hasattr(self,handler_name):
539
- convert_log.info(f'Parsing Record: {record.describe()}')
540
- handler = getattr(self,handler_name)
541
- handler(record)
542
- else:
543
- if record.tag in self.missing_handler_count:
544
- self.missing_handler_count[record.tag] += 1
545
- else:
546
- self.missing_handler_count[record.tag] = 1
547
-
548
- convert_log.error(f'Failed Parsing Record: {record.describe()}')
549
- for sub_record in record.subRecords():
550
- self.parse_record(sub_record)
551
-
552
- def handle__apid(self, record: GedcomRecord):
553
- if isinstance(self.object_map[record.level-1], SourceReference):
554
- self.object_map[record.level-1].description.add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
555
- elif isinstance(self.object_map[record.level-1], SourceDescription):
556
- self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('APID://' + record.value)))
557
- else:
558
- raise ValueError(f"Could not handle '_APID' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
559
-
560
- def handle__meta(self, record: GedcomRecord):
561
- if isinstance(self.object_map[record.level-1], SourceDescription):
562
- gxobject = Note(text=Translater.clean_str(record.value))
563
- self.object_map[record.level-1].add_note(gxobject)
564
- self.object_stack.append(gxobject)
565
- self.object_map[record.level] = gxobject
566
- else:
567
- raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
568
-
569
- def handle__wlnk(self, record: GedcomRecord):
570
- return self.handle_sour(record)
486
+ agents = data.get('agents', [])
487
+ for agent in agents:
488
+ gx.add_agent(Serialization.deserialize(agent,Agent))
571
489
 
572
- def handle_addr(self, record: GedcomRecord):
573
- if isinstance(self.object_map[record.level-1], Agent):
574
- # TODO CHeck if URL?
575
- if Translater.clean_str(record.value):
576
- gxobject = Address(value=Translater.clean_str(record.value))
577
- else:
578
- gxobject = Address()
579
- self.object_map[record.level-1].address = gxobject
580
- self.object_stack.append(gxobject)
581
- self.object_map[record.level] = gxobject
582
- else:
583
- raise ValueError(f"I do not know how to handle an 'ADDR' tag for a {type(self.object_map[record.level-1])}")
584
-
585
- def handle_adr1(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].street = Translater.clean_str(record.value)
589
- else:
590
- raise ValueError(f"I do not know how to handle an 'ADR1' tag for a {type(self.object_map[record.level-1])}")
591
-
592
- def handle_adr2(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].street2 = Translater.clean_str(record.value)
596
- else:
597
- raise ValueError(f"I do not know how to handle an 'ADR2' tag for a {type(self.object_map[record.level-1])}")
598
-
599
- def handle_adr3(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].street3 = Translater.clean_str(record.value)
603
- else:
604
- raise ValueError(f"I do not know how to handle an 'ADR3' tag for a {type(self.object_map[record.level-1])}")
605
-
606
- def handle_adr4(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].street4 = Translater.clean_str(record.value)
610
- else:
611
- raise ValueError(f"I do not know how to handle an 'ADR4' tag for a {type(self.object_map[record.level-1])}")
612
-
613
- def handle_adr5(self, record: GedcomRecord):
614
- if isinstance(self.object_map[record.level-1], Address):
615
- if Translater.clean_str(record.value):
616
- self.object_map[record.level-1].street5 = Translater.clean_str(record.value)
617
- else:
618
- raise ValueError(f"I do not know how to handle an 'ADR5' tag for a {type(self.object_map[record.level-1])}")
619
-
620
- def handle_adr6(self, record: GedcomRecord):
621
- if isinstance(self.object_map[record.level-1], Address):
622
- if Translater.clean_str(record.value):
623
- self.object_map[record.level-1].street5 = Translater.clean_str(record.value)
624
- else:
625
- raise ValueError(f"I do not know how to handle an 'ADR6' 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))
626
493
 
627
- def handle_phon(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].phones.append(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])}")
633
-
634
- def handle_email(self, record: GedcomRecord):
635
- if isinstance(self.object_map[record.level-1], Agent):
636
- if Translater.clean_str(record.value):
637
- self.object_map[record.level-1].emails.append(Translater.clean_str(record.value))
638
- else:
639
- raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
640
-
641
- def handle_fax(self, record: GedcomRecord):
642
- if isinstance(self.object_map[record.level-1], Agent):
643
- if Translater.clean_str(record.value):
644
- self.object_map[record.level-1].emails.append('FAX:' + Translater.clean_str(record.value))
645
- else:
646
- raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
647
-
648
- def handle_adop(self, record: GedcomRecord):
649
- if isinstance(self.object_map[record.level-1], Person):
650
- gxobject = Fact(type=FactType.Adoption)
651
- self.object_map[record.level-1].add_fact(gxobject)
652
-
653
- self.object_stack.append(gxobject)
654
- self.object_map[record.level] = gxobject
655
- else:
656
- raise TagConversionError(record=record,levelstack=self.object_map)
657
-
658
- def handle_auth(self, record: GedcomRecord):
659
- if isinstance(self.object_map[record.level-1], SourceDescription):
660
- if self.gedcomx.agents.byName(record.value):
661
- gxobject = self.gedcomx.agents.byName(record.value)[0]
662
- else:
663
- gxobject = Agent(names=[TextValue(record.value)])
664
- self.gedcomx.add_agent(gxobject)
665
-
666
- self.object_map[record.level-1].author = gxobject
667
- self.object_stack.append(gxobject)
668
- self.object_map[record.level] = gxobject
669
- else:
670
- raise TagConversionError(record=record,levelstack=self.object_map)
671
-
672
- def handle_bapm(self, record: GedcomRecord):
673
- if isinstance(self.object_map[record.level-1], Person):
674
- gxobject = Fact(type=FactType.Baptism)
675
- self.object_map[record.level-1].add_fact(gxobject)
676
-
677
- self.object_stack.append(gxobject)
678
- self.object_map[record.level] = gxobject
679
- else:
680
- raise TagConversionError(record=record,levelstack=self.object_map)
681
-
682
- def handle_birt(self, record: GedcomRecord):
683
- if isinstance(self.object_map[record.level-1], Person):
684
- #gxobject = Event(type=EventType.BIRTH, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
685
- gxobject = Fact(type=FactType.Birth)
686
- #self.gedcomx.add_event(gxobject)
687
- self.object_map[record.level-1].add_fact(gxobject)
688
-
689
- self.object_stack.append(gxobject)
690
- self.object_map[record.level] = gxobject
691
- else:
692
- raise TagConversionError(record=record,levelstack=self.object_map)
693
-
694
- def handle_buri(self, record: GedcomRecord):
695
- if isinstance(self.object_map[record.level-1], Person):
696
- gxobject = Fact(type=FactType.Burial)
697
- self.object_map[record.level-1].add_fact(gxobject)
698
-
699
- self.object_stack.append(gxobject)
700
- self.object_map[record.level] = gxobject
701
- else:
702
- raise TagConversionError(record=record,levelstack=self.object_map)
703
-
704
- def handle_caln(self, record: GedcomRecord):
705
- if isinstance(self.object_map[record.level-1], SourceReference):
706
- self.object_map[record.level-1].description.add_identifier(Identifier(value=URI.from_url('Call Number:' + record.value)))
707
- elif isinstance(self.object_map[record.level-1], SourceDescription):
708
- self.object_map[record.level-1].add_identifier(Identifier(value=URI.from_url('Call Number:' + record.value)))
709
- elif isinstance(self.object_map[record.level-1], Agent):
710
- pass
711
- # TODO Why is GEDCOM so shitty? A callnumber for a repository?
712
- else:
713
- raise ValueError(f"Could not handle 'CALN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
714
-
715
- def handle_chan(self, record: GedcomRecord):
716
- if isinstance(self.object_map[record.level-1], SourceDescription):
717
- self.object_map[record.level-1].created = Date(record.subRecord('DATE'))
718
- elif isinstance(self.object_map[record.level-1], Agent):
719
- if self.object_map[record.level-1].attribution is None:
720
- gxobject = Attribution()
721
- self.object_map[record.level-1].attribution = gxobject
722
- self.object_stack.append(gxobject)
723
- self.object_map[record.level] = gxobject
724
- else:
725
- raise ValueError()
726
-
727
- def handle_chr(self, record: GedcomRecord):
728
- if isinstance(self.object_map[record.level-1], Person):
729
- gxobject = Fact(type=FactType.Christening)
730
- self.object_map[record.level-1].add_fact(gxobject)
731
-
732
- self.object_stack.append(gxobject)
733
- self.object_map[record.level] = gxobject
734
- else:
735
- raise TagConversionError(record=record,levelstack=self.object_map)
736
-
737
- def handle_city(self, record: GedcomRecord):
738
- if isinstance(self.object_map[record.level-1], Address):
739
- self.object_map[record.level-1].city = Translater.clean_str(record.value)
740
- else:
741
- raise ValueError(f"I do not know how to handle an 'CITY' tag for a {type(self.object_map[record.level-1])}")
494
+ return gx
742
495
 
743
- def handle_conc(self, record: GedcomRecord):
744
- if isinstance(self.object_map[record.level-1], Note):
745
- gxobject = Translater.clean_str(str(record.value))
746
- self.object_map[record.level-1].append(gxobject)
747
- elif isinstance(self.object_map[record.level-1], Agent):
748
- gxobject = str(record.value)
749
- self.object_map[record.level-1]._append_to_name(gxobject)
750
- elif isinstance(self.object_map[record.level-1], Qualifier):
751
- gxobject = str(record.value)
752
- self.object_map[record.level-2].append(gxobject)
753
- elif isinstance(self.object_map[record.level-1], TextValue):
754
- #gxobject = TextValue(value=Translater.clean_str(record.value))
755
- self.object_map[record.level-1]._append_to_value(record.value)
756
- elif isinstance(self.object_map[record.level-1], SourceReference):
757
- self.object_map[record.level-1].append(record.value)
758
- elif isinstance(self.object_map[record.level-1], Fact):
759
- self.object_map[record.level-1].notes[0].text += record.value
760
-
761
- else:
762
- raise TagConversionError(record=record,levelstack=self.object_map)
763
-
764
- def handle_cont(self, record: GedcomRecord):
765
- if isinstance(self.object_map[record.level-1], Note):
766
- gxobject = str("\n" + record.value if record.value else '')
767
- self.object_map[record.level-1].append(gxobject)
768
- elif isinstance(self.object_map[record.level-1], Agent):
769
- gxobject = str("\n" + record.value if record.value else '')
770
- elif isinstance(self.object_map[record.level-1], Qualifier):
771
- gxobject = str("\n" + record.value if record.value else '')
772
- self.object_map[record.level-1].append(gxobject)
773
- elif isinstance(self.object_map[record.level-1], TextValue):
774
- #gxobject = TextValue(value="\n" + record.value)
775
- self.object_map[record.level-1]._append_to_value(record.value if record.value else '\n')
776
- elif isinstance(self.object_map[record.level-1], SourceReference):
777
- self.object_map[record.level-1].append(record.value)
778
- elif isinstance(self.object_map[record.level-1], Address):
779
- self.object_map[record.level-1]._append(record.value)
780
- else:
781
- raise TagConversionError(record=record,levelstack=self.object_map)
782
-
783
- def handle_crea(self, record: GedcomRecord):
784
- if isinstance(self.object_map[record.level-1], SourceDescription):
785
- self.object_map[record.level-1].created = Date(original=record.subRecord('DATE'))
786
-
787
- elif isinstance(self.object_map[record.level-1], Agent):
788
- if self.object_map[record.level-1].attribution is None:
789
- gxobject = Attribution()
790
- self.object_map[record.level-1].attribution = gxobject
791
- self.object_stack.append(gxobject)
792
- self.object_map[record.level] = gxobject
793
- else:
794
- convert_log.info(f"[{record.tag}] Attribution already exists for SourceDescription with id: {self.object_map[record.level-1].id}")
795
- else:
796
- raise ValueError(f"Could not handle '{record.tag}' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
797
-
798
- def handle_ctry(self, record: GedcomRecord):
799
- if isinstance(self.object_map[record.level-1], Address):
800
- self.object_map[record.level-1].country = Translater.clean_str(record.value)
801
- else:
802
- raise ValueError(f"I do not know how to handle an '{record.tag}' tag for a {type(self.object_map[record.level-1])}")
803
-
804
- def handle_data(self, record: GedcomRecord) -> None:
805
- if record.value != '' and record.value == 'None':
806
- assert False
807
- self.object_map[record.level] = self.object_map[record.level-1]
808
-
809
- def handle_date(self, record: GedcomRecord):
810
- if record.parent.tag == 'PUBL':
811
- #gxobject = Date(original=record.value) #TODO Make a parser for solid timestamps
812
- #self.object_map[0].published = gxobject
813
- #self.object_map[0].published = date_to_timestamp(record.value) if record.value else None
814
- self.object_map[0].published = record.value
815
- #self.object_stack.append(gxobject)
816
- #self.object_map[record.level] = gxobject
817
- elif isinstance(self.object_map[record.level-1], Event):
818
- self.object_map[record.level-1].date = Date(original=record.value)
819
- elif isinstance(self.object_map[record.level-1], Fact):
820
- self.object_map[record.level-1].date = Date(original=record.value)
821
- elif record.parent.tag == 'DATA' and isinstance(self.object_map[record.level-2], SourceReference):
822
- gxobject = Note(text='Date: ' + record.value)
823
- self.object_map[record.level-2].description.add_note(gxobject)
824
- self.object_stack.append(gxobject)
825
- self.object_map[record.level] = gxobject
826
- elif isinstance(self.object_map[record.level-1], SourceDescription):
827
-
828
- self.object_map[record.level-1].ctreated = record.value #TODO String to timestamp
829
- elif isinstance(self.object_map[record.level-1], Attribution):
830
- if record.parent.tag == 'CREA':
831
- self.object_map[record.level-1].created = record.value #TODO G7
832
- elif record.parent.tag == "CHAN":
833
- self.object_map[record.level-1].modified = record.value #TODO G7
834
- elif record.parent.tag in ['CREA','CHAN']:
835
- pass
836
-
837
- else:
838
- raise TagConversionError(record=record,levelstack=self.object_map)
839
-
840
- def handle_deat(self, record: GedcomRecord):
841
- if isinstance(self.object_map[record.level-1], Person):
842
- gxobject = Fact(type=FactType.Death)
843
- self.object_map[record.level-1].add_fact(gxobject)
844
-
845
- self.object_stack.append(gxobject)
846
- self.object_map[record.level] = gxobject
847
- else:
848
- raise TagConversionError(record=record,levelstack=self.object_map)
849
-
850
- def handle_even(self, record: GedcomRecord):
851
- # TODO If events in a @S, check if only 1 person matches?
852
- if record.value and (not record.value.strip() == ''):
853
- values = [value.strip() for value in record.value.split(",")]
854
- for value in values:
855
- if value in Translater.gedcom_even_to_fact.keys():
856
- if isinstance(self.object_map[record.level-1], Person):
857
- gxobject = Fact(type=Translater.gedcom_even_to_fact[value])
858
- self.object_map[record.level-1].add_fact(gxobject)
859
-
860
- self.object_stack.append(gxobject)
861
- self.object_map[record.level] = gxobject
862
-
863
- elif isinstance(self.object_map[record.level-1], SourceDescription):
864
- gxobject = Event(type=Translater.gedcom_even_to_evnt[value],sources=[self.object_map[record.level-1]])
865
- self.gedcomx.add_event(gxobject)
866
- self.object_stack.append(gxobject)
867
- self.object_map[record.level] = gxobject
868
- else:
869
- convert_log.warning(f"Could not convert EVEN '{value}' for object of type {type(self.object_map[record.level-1])} in record {record.describe()}")
870
- return
871
- raise TagConversionError(record=record,levelstack=self.object_map)
872
- assert False
873
- # TODO: Fix, this. making an event to cacth subtags, why are these fact tied to a source? GEDCOM is horrible
874
- gxobject = Event(type=EventType.UNKNOWN)
875
- self.object_stack.append(gxobject)
876
- self.object_map[record.level] = gxobject
877
- else:
878
- raise TagConversionError(record=record,levelstack=self.object_map)
879
-
880
- else:
881
- possible_fact = FactType.guess(record.subRecord('TYPE')[0].value)
882
- if possible_fact:
883
- gxobject = Fact(type=possible_fact)
884
- self.object_map[record.level-1].add_fact(gxobject)
885
-
886
- self.object_stack.append(gxobject)
887
- self.object_map[record.level] = gxobject
888
- return
889
- elif EventType.guess(record.subRecord('TYPE')[0].value):
890
- if isinstance(self.object_map[record.level-1], Person):
891
- gxobject = Event(type=EventType.guess(record.subRecord('TYPE')[0].value), roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
892
- self.gedcomx.add_event(gxobject)
893
- self.object_stack.append(gxobject)
894
- self.object_map[record.level] = gxobject
895
- return
896
- else:
897
- if isinstance(self.object_map[record.level-1], Person):
898
- gxobject = Event(type=None, roles=[EventRole(person=self.object_map[record.level-1], type=EventRoleType.Principal)])
899
- gxobject.add_note(Note(subject='Event', text=record.value))
900
- self.gedcomx.add_event(gxobject)
901
- self.object_stack.append(gxobject)
902
- self.object_map[record.level] = gxobject
903
- return
904
-
905
- else:
906
- assert False
907
-
908
- def handle_exid(self,record: GedcomRecord):
909
- gxobject = Identifier(type=IdentifierType.External,value=[record.value])
910
- self.object_map[record.level-1].add_identifier(gxobject)
911
-
912
- self.object_stack.append(gxobject)
913
- self.object_map[record.level] = gxobject
914
-
915
- def handle_fam(self, record: GedcomRecord) -> None:
916
- if record.tag != 'FAM' or record.level != 0:
917
- raise ValueError("Invalid record: Must be a level 0 FAM record")
918
-
919
- husband, wife, children = None, None, []
920
-
921
- husband_record = record.subRecords('HUSB')
922
- if husband_record:
923
- husband = self.gedcomx.get_person_by_id(husband_record[0].xref)
924
-
925
- wife_record = record.subRecords('WIFE')
926
- if wife_record:
927
- wife = self.gedcomx.get_person_by_id(wife_record[0].xref)
928
-
929
- children_records = record.subRecords('CHIL')
930
- if children_records:
931
- for child_record in children_records:
932
- child = self.gedcomx.get_person_by_id(child_record.xref)
933
- if child:
934
- children.append(child)
935
-
936
- if husband:
937
- for child in children:
938
- relationship = Relationship(person1=husband, person2=child, type=RelationshipType.ParentChild)
939
- self.gedcomx.add_relationship(relationship)
940
- if wife:
941
- for child in children:
942
- relationship = Relationship(person1=wife, person2=child, type=RelationshipType.ParentChild)
943
- self.gedcomx.add_relationship(relationship)
944
- if husband and wife:
945
- relationship = Relationship(person1=husband, person2=wife, type=RelationshipType.Couple)
946
- self.gedcomx.add_relationship(relationship)
947
-
948
- def handle_famc(self, record: GedcomRecord) -> None:
949
- return
950
-
951
- def handle_fams(self, record: GedcomRecord) -> None:
952
- return
953
-
954
- def handle_file(self, record: GedcomRecord):
955
- if record.value and record.value.strip() != '':
956
- #raise ValueError(f"I did not expect the 'FILE' tag to have a value: {record.value}")
957
- #TODO Handle files referenced here
958
- ...
959
- elif isinstance(self.object_map[record.level-1], SourceDescription):
960
- ...
961
- self.object_map[record.level-1].resourceType = ResourceType.DigitalArtifact
962
-
963
- def handle_form(self, record: GedcomRecord):
964
- if record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
965
- if record.value and record.value.strip() != '':
966
- mime_type, _ = mimetypes.guess_type('placehold.' + record.value)
967
- if mime_type:
968
- self.object_map[record.level-2].mediaType = mime_type
969
- else:
970
- print(f"Could not determing mime type from {record.value}")
971
- elif isinstance(self.object_map[record.level-1], PlaceDescription):
972
- self.object_map[record.level-1].names.append(TextValue(value=record.value))
973
- elif record.parent.tag == 'TRAN':
974
- pass #TODO
975
- else:
976
- convert_log.error(f"raise TagConversionError(record=record,levelstack=self.object_map")
977
-
978
- def handle_givn(self, record: GedcomRecord):
979
- if isinstance(self.object_map[record.level-1], Name):
980
- given_name = NamePart(value=record.value, type=NamePartType.Given)
981
- self.object_map[record.level-1]._add_name_part(given_name)
982
- else:
983
- raise TagConversionError(record=record,levelstack=self.object_map)
984
-
985
- def handle_indi(self, record: GedcomRecord):
986
- person = Person(id=record.xref.replace('@',''))
987
- self.gedcomx.add_person(person)
988
- self.object_stack.append(person)
989
- self.object_map[record.level] = person
990
-
991
- def handle_immi(self, record: GedcomRecord):
992
- if isinstance(self.object_map[record.level-1], Person):
993
- gxobject = Fact(type=FactType.Immigration)
994
- self.object_map[record.level-1].add_fact(gxobject)
995
-
996
- self.object_stack.append(gxobject)
997
- self.object_map[record.level] = gxobject
998
- else:
999
- raise TagConversionError(record=record,levelstack=self.object_map)
1000
-
1001
- def handle_marr(self, record: GedcomRecord):
1002
- if isinstance(self.object_map[record.level-1], Person):
1003
- gxobject = Fact(type=FactType.Marriage)
1004
- self.object_map[record.level-1].add_fact(gxobject)
1005
-
1006
- self.object_stack.append(gxobject)
1007
- self.object_map[record.level] = gxobject
1008
- else:
1009
- raise TagConversionError(record=record,levelstack=self.object_map)
1010
-
1011
- def handle_name(self, record: GedcomRecord):
1012
- if isinstance(self.object_map[record.level-1], Person):
1013
- gxobject = Name.simple(record.value)
1014
- #gxobject = Name(nameForms=[NameForm(fullText=record.value)], type=NameType.BirthName)
1015
- self.object_map[record.level-1].add_name(gxobject)
1016
-
1017
- self.object_stack.append(gxobject)
1018
- self.object_map[record.level] = gxobject
1019
- elif isinstance(self.object_map[record.level-1], Agent):
1020
- gxobject = TextValue(value=record.value)
1021
- self.object_map[record.level-1].add_name(gxobject)
1022
- else:
1023
- raise TagConversionError(record=record,levelstack=self.object_map)
1024
-
1025
- def handle_note(self, record: GedcomRecord):
1026
- if isinstance(self.object_map[record.level-1], SourceDescription):
1027
- gxobject = Note(text=Translater.clean_str(record.value))
1028
- self.object_map[record.level-1].add_note(gxobject)
1029
-
1030
- self.object_stack.append(gxobject)
1031
- self.object_map[record.level] = gxobject
1032
- elif isinstance(self.object_map[record.level-1], SourceReference):
1033
- gxobject = Note(text=Translater.clean_str(record.value))
1034
- self.object_map[record.level-1].description.add_note(gxobject)
1035
-
1036
- self.object_stack.append(gxobject)
1037
- self.object_map[record.level] = gxobject
1038
- elif isinstance(self.object_map[record.level-1], Conclusion):
1039
- gxobject = Note(text=record.value)
1040
- self.object_map[record.level-1].add_note(gxobject)
1041
-
1042
- self.object_stack.append(gxobject)
1043
- self.object_map[record.level] = gxobject
1044
- elif isinstance(self.object_map[record.level-1], Agent):
1045
- gxobject = Note(text=record.value)
1046
- self.object_map[record.level-1].add_note(gxobject)
1047
-
1048
- self.object_stack.append(gxobject)
1049
- self.object_map[record.level] = gxobject
1050
- elif isinstance(self.object_map[record.level-1], Attribution):
1051
- if self.object_map[record.level-1].changeMessage is None:
1052
- self.object_map[record.level-1].changeMessage = record.value
1053
- else:
1054
- self.object_map[record.level-1].changeMessage = self.object_map[record.level-1].changeMessage + '' + record.value
1055
- elif isinstance(self.object_map[record.level-1], Note):
1056
- gxobject = Note(text=Translater.clean_str(record.value))
1057
- self.object_map[record.level-2].add_note(gxobject)
1058
-
1059
- self.object_stack.append(gxobject)
1060
- self.object_map[record.level] = gxobject
1061
-
1062
- else:
1063
- raise ValueError(f"Could not handle 'NOTE' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
1064
- assert False
1065
-
1066
- def handle_nsfx(self, record: GedcomRecord):
1067
- if isinstance(self.object_map[record.level-1], Name):
1068
- surname = NamePart(value=record.value, type=NamePartType.Suffix)
1069
- self.object_map[record.level-1]._add_name_part(surname)
1070
- else:
1071
- raise TagConversionError(record=record,levelstack=self.object_map)
1072
-
1073
- def handle_occu(self, record: GedcomRecord):
1074
- if isinstance(self.object_map[record.level-1], Person):
1075
- gxobject = Fact(type=FactType.Occupation)
1076
- self.object_map[record.level-1].add_fact(gxobject)
1077
-
1078
- self.object_stack.append(gxobject)
1079
- self.object_map[record.level] = gxobject
1080
- else:
1081
- raise TagConversionError(record=record,levelstack=self.object_map)
1082
-
1083
- def handle_obje(self, record: GedcomRecord):
1084
- self.handle_sour(record)
1085
-
1086
- def handle_page(self, record: GedcomRecord):
1087
- if isinstance(self.object_map[record.level-1], SourceReference):
1088
- self.object_map[record.level-1].descriptionId = record.value
1089
- self.object_map[record.level-1].add_qualifier(KnownSourceReference(name=str(KnownSourceReference.Page),value=record.value))
1090
-
1091
- #self.object_stack.append(gxobject)
1092
- #self.object_map[record.level] = gxobject
1093
- self.object_map[record.level] = self.object_map[record.level-1]
1094
- else:
1095
- raise ValueError(f"Could not handle 'PAGE' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1096
-
1097
- def handle_plac(self, record: GedcomRecord):
1098
- if isinstance(self.object_map[record.level-1], Agent):
1099
- gxobject = Address(value=record.value)
1100
- self.object_map[record.level-1].add_address(gxobject)
1101
-
1102
- self.object_stack.append(gxobject)
1103
- self.object_map[record.level] = gxobject
1104
- elif isinstance(self.object_map[record.level-1], Event):
1105
- if self.gedcomx.places.byName(record.value):
1106
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=self.gedcomx.places.byName(record.value)[0])
1107
- else:
1108
- place_des = PlaceDescription(names=[TextValue(value=record.value)])
1109
- self.gedcomx.add_place_description(place_des)
1110
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=place_des)
1111
- if len(record.subRecords()) > 0:
1112
- self.object_map[record.level]= place_des
1113
-
1114
- elif isinstance(self.object_map[record.level-1], Fact):
1115
- if self.gedcomx.places.byName(record.value):
1116
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=self.gedcomx.places.byName(record.value)[0])
1117
- else:
1118
- place_des = PlaceDescription(names=[TextValue(value=record.value)])
1119
- self.gedcomx.add_place_description(place_des)
1120
- self.object_map[record.level-1].place = PlaceReference(original=record.value, description=place_des)
1121
- elif isinstance(self.object_map[record.level-1], SourceDescription):
1122
- gxobject = Note(text='Place: ' + record.value)
1123
- self.object_map[record.level-1].add_note(gxobject)
1124
- self.object_stack.append(gxobject)
1125
- self.object_map[record.level] = gxobject
1126
- else:
1127
- raise TagConversionError(record=record,levelstack=self.object_map)
1128
-
1129
- def handle_post(self, record: GedcomRecord):
1130
- if isinstance(self.object_map[record.level-1], Address):
1131
- self.object_map[record.level-1].postalCode = Translater.clean_str(record.value)
1132
- else:
1133
- raise ValueError(f"I do not know how to handle an 'POST' tag for a {type(self.object_map[record.level-1])}")
1134
-
1135
- def handle_publ(self, record: GedcomRecord):
1136
- if isinstance(self.object_map[record.level-1], SourceDescription):
1137
- if record.value and self.gedcomx.agents.byName(record.value):
1138
- gxobject = self.gedcomx.agents.byName(record.value)[0]
1139
- else:
1140
- gxobject = Agent(names=[TextValue(record.value)])
1141
- self.gedcomx.add_agent(gxobject)
1142
- self.object_map[record.level-1].publisher = gxobject
1143
-
1144
- self.object_stack.append(gxobject)
1145
- self.object_map[record.level] = gxobject
1146
- else:
1147
- raise TagConversionError(record=record,levelstack=self.object_map)
1148
-
1149
- def handle_prob(self, record: GedcomRecord):
1150
- if isinstance(self.object_map[record.level-1], Person):
1151
- gxobject = Fact(type=FactType.Probate)
1152
- self.object_map[record.level-1].add_fact(gxobject)
1153
-
1154
- self.object_stack.append(gxobject)
1155
- self.object_map[record.level] = gxobject
1156
- else:
1157
- raise TagConversionError(record=record,levelstack=self.object_map)
1158
-
1159
- def handle_uid(self, record: GedcomRecord):
1160
- if isinstance(self.object_map[record.level-1], Agent):
1161
- gxobject = Identifier(value=['UID:' + record.value],type=IdentifierType.Primary)
1162
- self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
1163
- self.object_stack.append(gxobject)
1164
- self.object_map[record.level] = gxobject
1165
-
1166
- def handle_refn(self, record: GedcomRecord):
1167
- if isinstance(self.object_map[record.level-1], Person) or isinstance(self.object_map[record.level-1], SourceDescription):
1168
- gxobject = Identifier(value=[URI.from_url('Reference Number:' + record.value)])
1169
- self.object_map[record.level-1].add_identifier(gxobject)
1170
- self.object_stack.append(gxobject)
1171
- self.object_map[record.level] = gxobject
1172
- elif isinstance(self.object_map[record.level-1], Agent):
1173
- gxobject = Identifier(value=['Reference Number:' + record.value])
1174
- self.object_map[record.level-1].add_identifier(gxobject) #NOTE GC7
1175
- self.object_stack.append(gxobject)
1176
- self.object_map[record.level] = gxobject
1177
- else:
1178
- raise ValueError(f"Could not handle 'REFN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
1179
-
1180
- def handle_repo(self, record: GedcomRecord):
1181
-
1182
- if record.level == 0:
1183
-
1184
- gxobject = Agent(id=record.xref)
1185
- self.gedcomx.add_agent(gxobject)
1186
- self.object_stack.append(gxobject)
1187
- self.object_map[record.level] = gxobject
1188
-
1189
- elif isinstance(self.object_map[record.level-1], SourceDescription):
1190
- if self.gedcomx.agents.byId(record.xref) is not None:
1191
-
1192
- # TODO WHere and what to add this to?
1193
- gxobject = self.gedcomx.agents.byId(record.xref)
1194
- self.object_map[record.level-1].repository = gxobject
1195
- self.object_map[record.level] = gxobject
1196
-
1197
- else:
1198
- print(record.describe())
1199
- raise ValueError()
1200
- gxobject = Agent(names=[TextValue(record.value)])
1201
- else:
1202
- 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])}")
1203
-
1204
-
1205
- self.object_stack.append(gxobject)
1206
- self.object_map[record.level] = gxobject
1207
-
1208
- def handle_resi(self, record: GedcomRecord):
1209
- if isinstance(self.object_map[record.level-1], Person):
1210
- gxobject = Fact(type=FactType.Residence)
1211
- if record.value and record.value.strip() != '':
1212
- gxobject.add_note(Note(text=record.value))
1213
- self.object_map[record.level-1].add_fact(gxobject)
1214
-
1215
- self.object_stack.append(gxobject)
1216
- self.object_map[record.level] = gxobject
1217
- else:
1218
- raise TagConversionError(record=record,levelstack=self.object_map)
1219
-
1220
- def handle_rin(self, record: GedcomRecord):
1221
- if isinstance(self.object_map[record.level-1], SourceDescription):
1222
- self.object_map[record.level-1].id = record.value
1223
- self.object_map[record.level-1].add_note(Note(text=f"Source had RIN: of {record.value}"))
1224
-
1225
- else:
1226
- raise ValueError(f"Could not handle 'RIN' tag in record {record.describe()}, last stack object {type(self.object_map[record.level-1])}")
1227
-
1228
- def handle_sex(self, record: GedcomRecord):
1229
-
1230
- if isinstance(self.object_map[record.level-1], Person):
1231
- if record.value == 'M':
1232
- gxobject = Gender(type=GenderType.Male)
1233
- elif record.value == 'F':
1234
- gxobject = Gender(type=GenderType.Female)
1235
- else:
1236
- gxobject = Gender(type=GenderType.Unknown)
1237
- self.object_map[record.level-1].gender = gxobject
1238
-
1239
- self.object_stack.append(gxobject)
1240
- self.object_map[record.level] = gxobject
1241
- else:
1242
- assert False
1243
-
1244
- def handle_sour(self, record: GedcomRecord):
1245
- if record.level == 0 or record.tag == '_WLNK' or (record.level == 0 and record.tag == 'OBJE'):
1246
- source_description = SourceDescription(id=record.xref.replace('@','') if record.xref else None)
1247
- self.gedcomx.add_source_description(source_description)
1248
- self.object_stack.append(source_description)
1249
- self.object_map[record.level] = source_description
1250
- else:
1251
- # This 'SOUR' is a SourceReference
1252
- if record.xref and record.xref.strip() == '':
1253
- import_log.warning(f"SOUR points to nothing: {record.describe()}")
1254
- return False
1255
- if self.gedcomx.source_descriptions.byId(record.xref):
1256
- gxobject = SourceReference(descriptionId=record.xref, description=self.gedcomx.source_descriptions.byId(record.xref))
1257
- else:
1258
- import_log.warning(f'Could not find source with id: {record.xref}')
1259
- source_description = SourceDescription(id=record.xref)
1260
- gxobject = SourceReference(descriptionId=record.value, description=source_description)
1261
- if isinstance(self.object_map[record.level-1],SourceReference):
1262
- self.object_map[record.level-1].description.add_source(gxobject)
1263
- elif record.parent.tag in ['NOTE']:
1264
- pass
1265
- else:
1266
- self.object_map[record.level-1].add_source(gxobject)
1267
- self.object_stack.append(gxobject)
1268
- self.object_map[record.level] = gxobject
1269
-
1270
- def handle_stae(self, record: GedcomRecord):
1271
- if isinstance(self.object_map[record.level-1], Address):
1272
- self.object_map[record.level-1].stateOrProvince = Translater.clean_str(record.value)
1273
- else:
1274
- raise ValueError(f"I do not know how to handle an 'STAE' tag for a {type(self.object_map[record.level-1])}")
1275
-
1276
- def handle_surn(self, record: GedcomRecord):
1277
- if isinstance(self.object_map[record.level-1], Name):
1278
- surname = NamePart(value=record.value, type=NamePartType.Surname)
1279
- self.object_map[record.level-1]._add_name_part(surname)
1280
- else:
1281
- raise TagConversionError(record=record,levelstack=self.object_map)
1282
-
1283
- def handle_text(self, record: GedcomRecord):
1284
- if record.parent.tag == 'DATA':
1285
- if isinstance(self.object_map[record.level-2], SourceReference):
1286
- gxobject = TextValue(value=record.value)
1287
- self.object_map[record.level-2].description.add_description(gxobject)
1288
- self.object_stack.append(gxobject)
1289
- self.object_map[record.level] = gxobject
1290
- elif isinstance(self.object_map[record.level-1], SourceDescription):
1291
- gxobject = Document(text=record.value)
1292
- self.object_map[record.level-1].analysis = gxobject
1293
- else:
1294
- assert False
1295
-
1296
- def handle_titl(self, record: GedcomRecord):
1297
- if isinstance(self.object_map[record.level-1], SourceDescription):
1298
-
1299
- gxobject = TextValue(value=Translater.clean_str(record.value))
1300
- self.object_map[record.level-1].add_title(gxobject)
1301
-
1302
- self.object_stack.append(gxobject)
1303
- self.object_map[record.level] = gxobject
1304
-
1305
- elif record.parent.tag == 'FILE' and isinstance(self.object_map[record.level-2], SourceDescription):
1306
- gxobject = TextValue(value=record.value)
1307
- self.object_map[record.level-2].add_title(gxobject)
1308
-
1309
- self.object_stack.append(gxobject)
1310
- self.object_map[record.level] = gxobject
1311
- elif self.object_map[record.level] and isinstance(self.object_map[record.level], Name):
1312
- gxobject = NamePart(value=record.value, qualifiers=[NamePartQualifier.Title])
1313
-
1314
- self.object_map[record.level]._add_name_part(gxobject)
1315
- else:
1316
- convert_log.error(f"raise TagConversionError(record=record,levelstack=self.object_map)")
1317
-
1318
- def handle_tran(self, record: GedcomRecord):
1319
- pass
1320
-
1321
- def handle_type(self, record: GedcomRecord):
1322
- # peek to see if event or fact
1323
- if isinstance(self.object_map[record.level-1], Event):
1324
- if EventType.guess(record.value):
1325
- self.object_map[record.level-1].type = EventType.guess(record.value)
1326
- else:
1327
- self.object_map[record.level-1].type = None
1328
- self.object_map[record.level-1].add_note(Note(text=Translater.clean_str(record.value)))
1329
- elif isinstance(self.object_map[record.level-1], Fact):
1330
- if not self.object_map[record.level-1].type:
1331
- self.object_map[0].type = FactType.guess(record.value)
1332
- elif isinstance(self.object_map[record.level-1], Identifier):
1333
-
1334
- self.object_map[record.level-1].values.append(Translater.clean_str(record.value))
1335
- self.object_map[record.level-1].type = IdentifierType.Other
1336
-
1337
- elif record.parent.tag == 'FORM':
1338
- if not self.object_map[0].mediaType:
1339
- self.object_map[0].mediaType = record.value
1340
-
1341
- else:
1342
- raise ValueError(f"I do not know how to handle 'TYPE' tag for {type(self.object_map[record.level-1])}")
1343
-
1344
- def handle__url(self, record: GedcomRecord):
1345
- if isinstance(self.object_map[record.level-2], SourceDescription):
1346
- self.object_map[record.level-2].about = URI.from_url(record.value)
1347
- else:
1348
- raise ValueError(f"Could not handle '_URL' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1349
-
1350
- def handle_www(self, record: GedcomRecord):
1351
- if isinstance(self.object_map[record.level-1], Agent):
1352
- self.object_map[record.level-1].homepage = Translater.clean_str(record.value)
1353
- elif isinstance(self.object_map[record.level-2], SourceReference):
1354
- self.object_map[record.level-2].description.add_identifier(Identifier(value=URI.from_url(record.value)))
1355
- else:
1356
- raise ValueError(f"Could not handle 'WWW' tag in record {record.describe()}, last stack object {self.object_map[record.level-1]}")
1357
-
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))