gedcom-x 0.5.2__py3-none-any.whl → 0.5.6__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.
- gedcom_x-0.5.6.dist-info/METADATA +144 -0
- gedcom_x-0.5.6.dist-info/RECORD +45 -0
- gedcomx/Address.py +2 -0
- gedcomx/Agent.py +9 -2
- gedcomx/Attribution.py +10 -46
- gedcomx/Conclusion.py +85 -21
- gedcomx/Coverage.py +10 -0
- gedcomx/Date.py +2 -7
- gedcomx/Document.py +27 -6
- gedcomx/Event.py +20 -1
- gedcomx/Exceptions.py +6 -0
- gedcomx/ExtensibleEnum.py +183 -0
- gedcomx/Fact.py +7 -8
- gedcomx/Gedcom.py +38 -404
- gedcomx/Gedcom5x.py +579 -0
- gedcomx/GedcomX.py +48 -26
- gedcomx/Gender.py +6 -40
- gedcomx/Identifier.py +151 -97
- gedcomx/LoggingHub.py +186 -0
- gedcomx/Mutations.py +228 -0
- gedcomx/Name.py +6 -0
- gedcomx/Person.py +49 -90
- gedcomx/PlaceDescription.py +23 -14
- gedcomx/PlaceReference.py +12 -15
- gedcomx/Relationship.py +23 -54
- gedcomx/Resource.py +17 -3
- gedcomx/Serialization.py +352 -31
- gedcomx/SourceDescription.py +6 -9
- gedcomx/SourceReference.py +20 -86
- gedcomx/Subject.py +4 -4
- gedcomx/Translation.py +219 -0
- gedcomx/URI.py +1 -0
- gedcomx/__init__.py +8 -1
- gedcom_x-0.5.2.dist-info/METADATA +0 -17
- gedcom_x-0.5.2.dist-info/RECORD +0 -42
- gedcomx/_Links.py +0 -37
- gedcomx/g7interop.py +0 -205
- {gedcom_x-0.5.2.dist-info → gedcom_x-0.5.6.dist-info}/WHEEL +0 -0
- {gedcom_x-0.5.2.dist-info → gedcom_x-0.5.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: gedcom-x
|
3
|
+
Version: 0.5.6
|
4
|
+
Summary: Python implimentation of gedcom-x standard
|
5
|
+
Author-email: "David J. Cartwright" <davidcartwright@hotmail.com>
|
6
|
+
License: MIT
|
7
|
+
Keywords: gedcom,gedcomx,ged
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Classifier: Environment :: Console
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Operating System :: OS Independent
|
13
|
+
Classifier: Topic :: Utilities
|
14
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
15
|
+
Requires-Python: >=3.6
|
16
|
+
Description-Content-Type: text/markdown
|
17
|
+
Dynamic: requires-python
|
18
|
+
|
19
|
+
# GEDCOM-X Python Toolkit (gedcom-x beta 0.5.5)
|
20
|
+
|
21
|
+
A lightweight, class-based Python implementation of the [GEDCOM-X data model](https://github.com/FamilySearch/gedcomx).
|
22
|
+
|
23
|
+
## ⚠️ Project Status
|
24
|
+
|
25
|
+
This project is currently in **beta**.
|
26
|
+
While the core GEDCOM-X classes and serialization are functional, some features may not be fully implemented or may not behave exactly as expected.
|
27
|
+
|
28
|
+
- Certain GEDCOM 7 tags are not yet mapped
|
29
|
+
- Some classes may be missing methods or fields
|
30
|
+
- Error handling and validation are still evolving
|
31
|
+
- Backward compatibility is **not guaranteed** until the first stable release
|
32
|
+
|
33
|
+
### ✅ What You Can Do
|
34
|
+
- Create and manipulate GEDCOM-X objects in Python
|
35
|
+
- Serialize and deserialize data to/from JSON
|
36
|
+
- Experimentally convert GEDCOM 5x & 7 files into GEDCOM-X JSON
|
37
|
+
- Extend the classes to handle new GEDCOM tags or custom attributes
|
38
|
+
- Use the library as a foundation for genealogy-related tooling or RAG pipelines
|
39
|
+
|
40
|
+
### ❌ What You Can’t Do (Yet)
|
41
|
+
- Rely on complete coverage of all GEDCOM 7 tags
|
42
|
+
- Expect perfect compliance with the GEDCOM-X specification
|
43
|
+
- Assume strong validation or error recovery on malformed input
|
44
|
+
- Use it as a drop-in replacement for production genealogy software
|
45
|
+
- Write GEDCOM-X to GEDCOM 5x / 7
|
46
|
+
- Create Graphs from Genealogies
|
47
|
+
|
48
|
+
Contributors and testers are welcome — feedback will help stabilize the library!
|
49
|
+
|
50
|
+
---
|
51
|
+
|
52
|
+
This library aims to provide:
|
53
|
+
|
54
|
+
- Python classes for every GEDCOM-X type (Person, Fact, Source, etc.)
|
55
|
+
- Extensibility, with current GEDCOM RS etc, extension built in
|
56
|
+
- Serialization and Deserialization to/from GEDCOM-X JSON
|
57
|
+
- Utilities to convert GEDCOM 5x & 7 GEDCOM Files into GEDCOM-X and back
|
58
|
+
- Type-safe field definitions and extensibility hooks for future tags
|
59
|
+
|
60
|
+
---
|
61
|
+
|
62
|
+
## Features
|
63
|
+
|
64
|
+
- **Complete GEDCOM-X Class Coverage**
|
65
|
+
Each GEDCOM-X type is represented as a Python class with fields and types.
|
66
|
+
|
67
|
+
- **Serialization / Deserialization**
|
68
|
+
Every class can serialize to JSON and reconstruct from JSON via `_as_dict_()` and `_from_json()` methods.
|
69
|
+
|
70
|
+
- **Type Checking & Enum Validation**
|
71
|
+
Uses Python type hints and enums to ensure correct values (e.g. FactType, EventType, ConfidenceLevel).
|
72
|
+
|
73
|
+
- **Composable / Nestable Classes**
|
74
|
+
Nested objects (e.g. Person → Name → NameForm → TextValue) are constructed and validated recursively.
|
75
|
+
|
76
|
+
- **GEDCOM 7 → GEDCOM-X Conversion**
|
77
|
+
Experimental parser to read GEDCOM 7 files and convert them into structured GEDCOM-X JSON.
|
78
|
+
|
79
|
+
---
|
80
|
+
|
81
|
+
## Installation
|
82
|
+
|
83
|
+
Clone the repository and install dependencies:
|
84
|
+
|
85
|
+
```bash
|
86
|
+
git clone https://github.com/yourusername/gedcom-x.git
|
87
|
+
cd gedcom-x
|
88
|
+
pip install -r requirements.txt
|
89
|
+
```
|
90
|
+
or
|
91
|
+
```
|
92
|
+
pip install gedcom-x
|
93
|
+
```
|
94
|
+
---
|
95
|
+
|
96
|
+
## Examples
|
97
|
+
|
98
|
+
<details>
|
99
|
+
|
100
|
+
<summary>Create a Person Gedcom-X Type</summary>
|
101
|
+
|
102
|
+
```python
|
103
|
+
import json
|
104
|
+
from gedcomx import Person, Name, NameForm, TextValue
|
105
|
+
|
106
|
+
person = Person(
|
107
|
+
id="P-123",
|
108
|
+
names=[Name(
|
109
|
+
nameForms=[NameForm(
|
110
|
+
fullText=TextValue(value="John Doe")
|
111
|
+
)]
|
112
|
+
)]
|
113
|
+
)
|
114
|
+
|
115
|
+
print(json.dumps(person._as_dict_,indent=4))
|
116
|
+
```
|
117
|
+
result
|
118
|
+
```text
|
119
|
+
{
|
120
|
+
"id": "P-123",
|
121
|
+
"lang": "en",
|
122
|
+
"private": false,
|
123
|
+
"living": false,
|
124
|
+
"gender": {
|
125
|
+
"lang": "en",
|
126
|
+
"type": "http://gedcomx.org/Unknown"
|
127
|
+
},
|
128
|
+
"names": [
|
129
|
+
{
|
130
|
+
"lang": "en",
|
131
|
+
"nameForms": [
|
132
|
+
{
|
133
|
+
"lang": "en",
|
134
|
+
"fullText": {
|
135
|
+
"lang": "en",
|
136
|
+
"value": "John Doe"
|
137
|
+
}
|
138
|
+
}
|
139
|
+
]
|
140
|
+
}
|
141
|
+
]
|
142
|
+
}
|
143
|
+
|
144
|
+
</details>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
gedcomx/Address.py,sha256=FDBic6oQB30eKMWM7-6_YVPHaJdPhziU5LybwE5TY5Q,4855
|
2
|
+
gedcomx/Agent.py,sha256=C-tzfqcjuU22iJ2LjoatKdCbI_i0xskpmZsuj58K6WY,8555
|
3
|
+
gedcomx/Attribution.py,sha256=2bcl2UNsMPn10kDrA080qFRzxK-KYqZBgmPGNBZ2M4Y,2608
|
4
|
+
gedcomx/Conclusion.py,sha256=t8n8FuWwzinFTPHp9D2Umu93-4A12I9L5fCx510mfqA,8414
|
5
|
+
gedcomx/Coverage.py,sha256=BVlB3kWDoOP2j86j67hNJLC4LqoLwqs3N93z0ZbXYTw,1227
|
6
|
+
gedcomx/Date.py,sha256=cv2UeyOcTHuH2CVHq9EjTnj3FR-r4_OVuPiuc8sbOPc,2130
|
7
|
+
gedcomx/Document.py,sha256=32nWfDNVWkPK2_I0-hhcNQkrjH3ssdbtw-II3QMMelw,2957
|
8
|
+
gedcomx/Event.py,sha256=BHhmO2UlxbkSzB5htdMRf2h-WNuJQsWfrSC8tNGQ6Mg,10375
|
9
|
+
gedcomx/EvidenceReference.py,sha256=WXZpmcKzwb3lYQmGVf-TY2IsbNG3fIInPY1khRjtOSg,348
|
10
|
+
gedcomx/Exceptions.py,sha256=0OdPM3euhBMgX8o61ZwPuKeN8zPuSuuDcSBFflVGFqk,587
|
11
|
+
gedcomx/ExtensibleEnum.py,sha256=DftCZLMBNul3C9hwh-rf0GE3SVdvylvyd5mt7bX_l6o,6535
|
12
|
+
gedcomx/Fact.py,sha256=-Zz321xeFd93riaX4C4i7gIPwpqdArAYZDlWRoXA1Uk,24444
|
13
|
+
gedcomx/Gedcom.py,sha256=l_BuLBynQacDtpLjhs2Afrabfiqt2Opoo_5_7myI7Z4,1709
|
14
|
+
gedcomx/Gedcom5x.py,sha256=ZaMqvmDTn684m4uSDRy3uxgKk442K5WZjDy_0s2ga-8,22459
|
15
|
+
gedcomx/GedcomX.py,sha256=mFviKVvk8dSn4tHPd1hkHBxoTOMNKlBv7gH3Q1n87IU,63666
|
16
|
+
gedcomx/Gender.py,sha256=AV125vECC5JSgvNJRmotjDEt-A3cFzth6pcSLFwJBEE,2328
|
17
|
+
gedcomx/Group.py,sha256=VNI_cI_-YnJ9cHzwMmHD8qwDNMe89kEocPuQ67rwStA,1606
|
18
|
+
gedcomx/Identifier.py,sha256=pJB8DlMF1k5DNR0Lha6rGTTiOtwe0joVLRLQCuoXtIw,8507
|
19
|
+
gedcomx/Logging.py,sha256=vBDOjawVXc4tCge1laYjy6_2Ves-fnGzG0m6NnLZejE,624
|
20
|
+
gedcomx/LoggingHub.py,sha256=lOeMP_0hFPydVNuMcUC31FMBRHtRMP02pBMM8TuhsNg,7143
|
21
|
+
gedcomx/Mutations.py,sha256=idhQsnikCTovmNEGAhDsOe97V0L9AnFTRaufzUPm64w,6298
|
22
|
+
gedcomx/Name.py,sha256=en_VkGjpZPP_Dbl9HSq2h2JCtLS2NMzmLvis5RdBPeM,12913
|
23
|
+
gedcomx/Note.py,sha256=cvV4-fCZ0oh2zXfzD-YYoIM_WTox-fk2_bfl3i4CoNc,2251
|
24
|
+
gedcomx/OnlineAccount.py,sha256=P24o98IXo_8XQoICYZPgALjdzS0q8t2l4DU3Od9KxyI,291
|
25
|
+
gedcomx/Person.py,sha256=LyGPCZh6rZU_dE3GCJE92x1lLk41c_Edr_Po9smhPLc,7321
|
26
|
+
gedcomx/PlaceDescription.py,sha256=TRHIkDiErHa_mlx_x8gYCF6UnQ-XgT08uSmYmFNa4u0,3255
|
27
|
+
gedcomx/PlaceReference.py,sha256=3NyEYq0FaMI8m3l4H6-Ov-n9NUq_m751iYVxofqtv30,870
|
28
|
+
gedcomx/Qualifier.py,sha256=mZ_GWT3gca8g9nWidlXIRTN5dEtf_rmnLHYl1jJkQYs,728
|
29
|
+
gedcomx/Relationship.py,sha256=oyT501vR5jvWxqEYy3KvW9egD4CPL5JaAYWJmlNy9Ig,3599
|
30
|
+
gedcomx/Resource.py,sha256=bZ2dV-OdpvmDRCppyfHJXiarIKL7-OcofwvYRnpOJW0,2324
|
31
|
+
gedcomx/Serialization.py,sha256=ubtmrvi-nKmVUCK1XGwuLijrPMggNJe--kkCIC-87Ds,18580
|
32
|
+
gedcomx/SourceCitation.py,sha256=aW-lEb7bT9QU49GiBjJppFMBvtisR6fhVVuXjr5y4vQ,742
|
33
|
+
gedcomx/SourceDescription.py,sha256=zOkXo-fy-uCl_EGU8B-c6pzhlMk3nYNHn13ln1AkYk0,11914
|
34
|
+
gedcomx/SourceReference.py,sha256=swVzZ5A0jt5yFYJNJvMnQZtb7d-2YEAQPxp2a4lEY1k,5071
|
35
|
+
gedcomx/Subject.py,sha256=znee3SxYKk99JLP6KmZHkXs5hIOGu_jeLwxagENNfXs,3298
|
36
|
+
gedcomx/TextValue.py,sha256=6B0wMxL0nigFNzhXZDhbTONvFGbnM2t2NcDZiZuu4Zw,1112
|
37
|
+
gedcomx/TopLevelTypeCollection.py,sha256=nvTO6GwFwEZk9jX4fVqhy75ygsshomNb20tnlExKqyY,1495
|
38
|
+
gedcomx/Translation.py,sha256=NWa1NtTOC_VgQ-EGwWG06zUpddRxdKFSLPP6066JFaA,12485
|
39
|
+
gedcomx/URI.py,sha256=S2pFsu_VyKgOsRdHIj8pjnh6_tdA3OjAYiIugoEd70k,4271
|
40
|
+
gedcomx/Zip.py,sha256=lBxcv-Vip45884EHj56wZJJ5I36Q38UuHUidDxQBoS8,14
|
41
|
+
gedcomx/__init__.py,sha256=O8LkNk9b8BHIN3mf0RowfR9M2HdKYhF8Fgi3qxW2RSs,1660
|
42
|
+
gedcom_x-0.5.6.dist-info/METADATA,sha256=rNO-ZyEC3th_8iML9XtfJOQcnPJI1uksyWz2MB9DAV8,4332
|
43
|
+
gedcom_x-0.5.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
44
|
+
gedcom_x-0.5.6.dist-info/top_level.txt,sha256=smVBF4nxSU-mzCd6idtRYTbYjPICMMi8pTqewEmqF8Y,8
|
45
|
+
gedcom_x-0.5.6.dist-info/RECORD,,
|
gedcomx/Address.py
CHANGED
gedcomx/Agent.py
CHANGED
@@ -139,6 +139,14 @@ class Agent:
|
|
139
139
|
}
|
140
140
|
return Serialization.serialize_dict(type_as_dict)
|
141
141
|
|
142
|
+
@classmethod
|
143
|
+
def _from_json_(cls, data: dict):
|
144
|
+
"""
|
145
|
+
Create a Person instance from a JSON-dict (already parsed).
|
146
|
+
"""
|
147
|
+
type_as_dict = Serialization.get_class_fields('Agent')
|
148
|
+
return Serialization.deserialize(data, type_as_dict)
|
149
|
+
|
142
150
|
def __str__(self):
|
143
151
|
"""
|
144
152
|
Return a human-readable string representation of the Agent.
|
@@ -179,8 +187,7 @@ class Agent:
|
|
179
187
|
self.uri == other.uri
|
180
188
|
)
|
181
189
|
'''
|
182
|
-
|
183
|
-
print(self)
|
190
|
+
|
184
191
|
self_names = {n.value for n in self.names if hasattr(n, "value")}
|
185
192
|
other_names = {n.value for n in other.names if hasattr(n, "value")}
|
186
193
|
if self_names & other_names: # intersection not empty
|
gedcomx/Attribution.py
CHANGED
@@ -10,11 +10,11 @@ class Attribution:
|
|
10
10
|
"""Attribution Information for a Genealogy, Conclusion, Subject and child classes
|
11
11
|
|
12
12
|
Args:
|
13
|
-
contributor (Agent): Contributor to object being attributed.
|
14
|
-
modified (timestamp): timestamp for when this record was modified.
|
15
|
-
changeMessage (str): Birth date (YYYY-MM-DD).
|
13
|
+
contributor (Agent, optional): Contributor to object being attributed.
|
14
|
+
modified (timestamp, optional): timestamp for when this record was modified.
|
15
|
+
changeMessage (str, optional): Birth date (YYYY-MM-DD).
|
16
16
|
creator (Agent, optional): Creator of object being attributed.
|
17
|
-
created (timestamp): timestamp for when this record was created
|
17
|
+
created (timestamp, optional): timestamp for when this record was created
|
18
18
|
|
19
19
|
Raises:
|
20
20
|
|
@@ -56,45 +56,9 @@ class Attribution:
|
|
56
56
|
"""
|
57
57
|
# contributor
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
# creator
|
66
|
-
creat = None
|
67
|
-
if 'creator' in data:
|
68
|
-
raw = data['creator']
|
69
|
-
if isinstance(raw, dict):
|
70
|
-
creat = Resource._from_json_(raw)
|
71
|
-
elif isinstance(raw, str):
|
72
|
-
creat = Resource(uri=raw)
|
73
|
-
|
74
|
-
# parse created date
|
75
|
-
raw_created = data.get('created')
|
76
|
-
if isinstance(raw_created, (int, float)):
|
77
|
-
created_dt = datetime.fromtimestamp(raw_created / 1000.0)
|
78
|
-
elif isinstance(raw_created, str):
|
79
|
-
created_dt = datetime.fromisoformat(raw_created)
|
80
|
-
else:
|
81
|
-
created_dt = None
|
82
|
-
|
83
|
-
# parse modified date
|
84
|
-
raw_modified = data.get('modified')
|
85
|
-
if isinstance(raw_modified, (int, float)):
|
86
|
-
modified_dt = datetime.fromtimestamp(raw_modified / 1000.0)
|
87
|
-
elif isinstance(raw_modified, str):
|
88
|
-
modified_dt = datetime.fromisoformat(raw_modified)
|
89
|
-
else:
|
90
|
-
modified_dt = None
|
91
|
-
|
92
|
-
change_msg = data.get('changeMessage')
|
93
|
-
|
94
|
-
return cls(
|
95
|
-
contributor=contrib,
|
96
|
-
created=created_dt,
|
97
|
-
creator=creat,
|
98
|
-
modified=modified_dt,
|
99
|
-
changeMessage=change_msg
|
100
|
-
)
|
59
|
+
"""
|
60
|
+
Create a Person instance from a JSON-dict (already parsed).
|
61
|
+
"""
|
62
|
+
from .Serialization import Serialization
|
63
|
+
|
64
|
+
return Serialization.deserialize(data, Attribution)
|
gedcomx/Conclusion.py
CHANGED
@@ -11,7 +11,7 @@ from .Qualifier import Qualifier
|
|
11
11
|
from .Serialization import Serialization
|
12
12
|
from .SourceReference import SourceReference
|
13
13
|
from .Resource import Resource, URI
|
14
|
-
from .
|
14
|
+
from .Extensions.rs10.rsLink import _rsLinkList, rsLink
|
15
15
|
|
16
16
|
from collections.abc import Sized
|
17
17
|
|
@@ -19,15 +19,72 @@ class ConfidenceLevel(Qualifier):
|
|
19
19
|
High = "http://gedcomx.org/High"
|
20
20
|
Medium = "http://gedcomx.org/Medium"
|
21
21
|
Low = "http://gedcomx.org/Low"
|
22
|
-
|
22
|
+
|
23
|
+
_NAME_TO_URI = {
|
24
|
+
"high": High,
|
25
|
+
"medium": Medium,
|
26
|
+
"low": Low,
|
27
|
+
}
|
28
|
+
|
29
|
+
@classmethod
|
30
|
+
def _from_json_(cls, data):
|
31
|
+
"""
|
32
|
+
Accepts:
|
33
|
+
- "High" | "Medium" | "Low"
|
34
|
+
- "http://gedcomx.org/High" | ".../Medium" | ".../Low"
|
35
|
+
- {"type": "..."} or {"value": "..."} or {"confidence": "..."} or {"level": "..."} or {"uri": "..."}
|
36
|
+
- existing ConfidenceLevel instance
|
37
|
+
Returns:
|
38
|
+
ConfidenceLevel instance with .value set to the canonical URI.
|
39
|
+
"""
|
40
|
+
if data is None:
|
41
|
+
return None
|
42
|
+
|
43
|
+
if isinstance(data, cls):
|
44
|
+
return data
|
45
|
+
|
46
|
+
# Extract token from dicts or use the raw scalar
|
47
|
+
if isinstance(data, dict):
|
48
|
+
token = (
|
49
|
+
data.get("confidence")
|
50
|
+
or data.get("type")
|
51
|
+
or data.get("value")
|
52
|
+
or data.get("level")
|
53
|
+
or data.get("uri")
|
54
|
+
)
|
55
|
+
else:
|
56
|
+
token = data
|
57
|
+
|
58
|
+
if token is None:
|
59
|
+
return None
|
60
|
+
|
61
|
+
token_str = str(token).strip()
|
62
|
+
|
63
|
+
# Normalize to canonical URI
|
64
|
+
if token_str.lower() in cls._NAME_TO_URI:
|
65
|
+
uri = cls._NAME_TO_URI[token_str.lower()]
|
66
|
+
elif token_str in (cls.High, cls.Medium, cls.Low):
|
67
|
+
uri = token_str
|
68
|
+
else:
|
69
|
+
raise ValueError(f"Unknown ConfidenceLevel: {token!r}")
|
70
|
+
|
71
|
+
# Create a ConfidenceLevel instance without invoking Qualifier.__init__
|
72
|
+
obj = cls.__new__(cls)
|
73
|
+
# store the canonical URI on the instance; used by description and (optionally) serialization
|
74
|
+
obj.value = uri
|
75
|
+
return obj
|
76
|
+
|
23
77
|
@property
|
24
78
|
def description(self):
|
25
79
|
descriptions = {
|
26
|
-
|
27
|
-
|
28
|
-
|
80
|
+
self.High: "The contributor has a high degree of confidence that the assertion is true.",
|
81
|
+
self.Medium: "The contributor has a medium degree of confidence that the assertion is true.",
|
82
|
+
self.Low: "The contributor has a low degree of confidence that the assertion is true."
|
29
83
|
}
|
30
|
-
|
84
|
+
# Works whether the instance holds .value or (edge-case) if `self` is compared directly
|
85
|
+
key = getattr(self, "value", self)
|
86
|
+
return descriptions.get(key, "No description available.")
|
87
|
+
|
31
88
|
|
32
89
|
class Conclusion:
|
33
90
|
"""
|
@@ -53,13 +110,7 @@ class Conclusion:
|
|
53
110
|
uri (Resource, optional): A URI reference for the conclusion. Defaults to a
|
54
111
|
URI with the fragment set to the `id`.
|
55
112
|
links (_LinkList, optional): A list of links associated with the conclusion.
|
56
|
-
Defaults to an empty `_LinkList`.
|
57
|
-
|
58
|
-
Methods:
|
59
|
-
add_note(note_to_add): Adds a note if it is not a duplicate and does not
|
60
|
-
exceed the maximum allowed notes.
|
61
|
-
add_source(source_to_add): Adds a source reference if it is not already present.
|
62
|
-
add_link(link): Adds a link to the `_LinkList`.
|
113
|
+
Defaults to an empty `_LinkList`.
|
63
114
|
"""
|
64
115
|
identifier = 'http://gedcomx.org/v1/Conclusion'
|
65
116
|
version = 'http://gedcomx.org/conceptual-model/v1'
|
@@ -75,20 +126,20 @@ class Conclusion:
|
|
75
126
|
return short_uuid
|
76
127
|
|
77
128
|
def __init__(self,
|
78
|
-
id: Optional[str],
|
129
|
+
id: Optional[str] = None,
|
79
130
|
lang: Optional[str] = 'en',
|
80
131
|
sources: Optional[List[SourceReference]] = None,
|
81
132
|
analysis: Optional[object | Resource] = None,
|
82
|
-
notes: Optional[List[Note]] =
|
133
|
+
notes: Optional[List[Note]] = None,
|
83
134
|
confidence: Optional[ConfidenceLevel] = None,
|
84
135
|
attribution: Optional[Attribution] = None,
|
85
136
|
uri: Optional[Resource] = None,
|
86
137
|
_max_note_count: int = 20,
|
87
|
-
links: Optional[
|
138
|
+
links: Optional[_rsLinkList] = None) -> None:
|
88
139
|
|
89
140
|
self._id_generator = Conclusion.default_id_generator
|
90
141
|
|
91
|
-
self.id = id if id else
|
142
|
+
self.id = id if id else None
|
92
143
|
self.lang = lang
|
93
144
|
self.sources = sources if sources else []
|
94
145
|
self.analysis = analysis
|
@@ -96,8 +147,8 @@ class Conclusion:
|
|
96
147
|
self.confidence = confidence
|
97
148
|
self.attribution = attribution
|
98
149
|
self.max_note_count = _max_note_count
|
99
|
-
self.uri = uri if uri else URI(fragment=id)
|
100
|
-
self.links = links if links else
|
150
|
+
self.uri = uri if uri else URI(fragment=id if id else self.id)
|
151
|
+
self.links = links if links else _rsLinkList() #NOTE This is not in specification, following FS format
|
101
152
|
|
102
153
|
def add_note(self,note_to_add: Note):
|
103
154
|
if self.notes and len(self.notes) >= self.max_note_count:
|
@@ -118,9 +169,22 @@ class Conclusion:
|
|
118
169
|
else:
|
119
170
|
raise ValueError()
|
120
171
|
|
121
|
-
def add_link(self,link:
|
122
|
-
|
172
|
+
def add_link(self,link: rsLink) -> bool:
|
173
|
+
"""
|
174
|
+
Adds a link to the Conclusion link list.
|
175
|
+
|
176
|
+
Args:
|
177
|
+
link (rsLink): The link to be added.
|
178
|
+
|
179
|
+
Returns:
|
180
|
+
bool: The return value. True for success, False otherwise.
|
181
|
+
|
182
|
+
Note: Duplicate checking not impimented at this level
|
183
|
+
"""
|
184
|
+
if link and isinstance(link,rsLink):
|
123
185
|
self.links.add(link)
|
186
|
+
return True
|
187
|
+
return False
|
124
188
|
|
125
189
|
@property
|
126
190
|
def _as_dict_(self):
|
gedcomx/Coverage.py
CHANGED
@@ -2,6 +2,7 @@ from typing import Optional
|
|
2
2
|
|
3
3
|
from .Date import Date
|
4
4
|
from .PlaceReference import PlaceReference
|
5
|
+
from .Serialization import Serialization
|
5
6
|
|
6
7
|
class Coverage:
|
7
8
|
identifier = 'http://gedcomx.org/v1/Coverage'
|
@@ -13,6 +14,15 @@ class Coverage:
|
|
13
14
|
|
14
15
|
# ...existing code...
|
15
16
|
|
17
|
+
@property
|
18
|
+
def _as_dict_(self):
|
19
|
+
type_as_dict = {
|
20
|
+
'spatial': self.spatial if self.spatial else None,
|
21
|
+
'temporal': self. temporal if self.temporal else None
|
22
|
+
}
|
23
|
+
|
24
|
+
return Serialization.serialize_dict(type_as_dict)
|
25
|
+
|
16
26
|
@classmethod
|
17
27
|
def _from_json_(cls, data: dict):
|
18
28
|
"""
|
gedcomx/Date.py
CHANGED
@@ -21,7 +21,8 @@ class Date:
|
|
21
21
|
|
22
22
|
self.normalized: DateNormalization | None = normalized if normalized else None
|
23
23
|
|
24
|
-
|
24
|
+
@property
|
25
|
+
def _as_dict_(self):
|
25
26
|
return {'original': self.orginal,
|
26
27
|
'formal': self.formal}
|
27
28
|
|
@@ -33,12 +34,6 @@ class Date:
|
|
33
34
|
return Date(original=original,formal=formal)
|
34
35
|
|
35
36
|
|
36
|
-
Date._to_dict_ = lambda self: {
|
37
|
-
'original': self.orginal,
|
38
|
-
'formal': self.formal}
|
39
|
-
|
40
|
-
|
41
|
-
|
42
37
|
|
43
38
|
def date_to_timestamp(date_str: str, assume_utc_if_naive: bool = True, print_definition: bool = True):
|
44
39
|
"""
|
gedcomx/Document.py
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
from enum import Enum
|
2
2
|
from typing import Optional, List
|
3
3
|
|
4
|
-
from
|
5
|
-
|
6
|
-
from
|
7
|
-
from
|
8
|
-
from gedcomx.Resource import Resource
|
4
|
+
from .Attribution import Attribution
|
5
|
+
from .Note import Note
|
6
|
+
from .SourceReference import SourceReference
|
7
|
+
from .Resource import Resource
|
9
8
|
|
10
9
|
from .Conclusion import Conclusion
|
10
|
+
from .Serialization import Serialization
|
11
11
|
|
12
12
|
class DocumentType(Enum):
|
13
13
|
Abstract = "http://gedcomx.org/Abstract"
|
@@ -49,4 +49,25 @@ class Document(Conclusion):
|
|
49
49
|
self.type = type
|
50
50
|
self.extracted = extracted
|
51
51
|
self.textType = textType
|
52
|
-
self.text = text
|
52
|
+
self.text = text
|
53
|
+
|
54
|
+
@property
|
55
|
+
def _as_dict(self):
|
56
|
+
type_as_dict = super()._as_dict_
|
57
|
+
if self.type:
|
58
|
+
type_as_dict['type'] = self.type.value
|
59
|
+
if self.extracted is not None:
|
60
|
+
type_as_dict['extracted'] = self.extracted
|
61
|
+
if self.textType:
|
62
|
+
type_as_dict['textType'] = self.textType.value
|
63
|
+
if self.text:
|
64
|
+
type_as_dict['text'] = self.text
|
65
|
+
return Serialization.serialize_dict(type_as_dict)
|
66
|
+
|
67
|
+
@classmethod
|
68
|
+
def _from_json_(cls, data: dict):
|
69
|
+
"""
|
70
|
+
Create a Person instance from a JSON-dict (already parsed).
|
71
|
+
"""
|
72
|
+
type_as_dict = Serialization.get_class_fields('Document')
|
73
|
+
return Serialization.deserialize(data, type_as_dict)
|
gedcomx/Event.py
CHANGED
@@ -9,6 +9,7 @@ from .Conclusion import Conclusion, ConfidenceLevel
|
|
9
9
|
from .Date import Date
|
10
10
|
from .Note import Note
|
11
11
|
from .PlaceReference import PlaceReference
|
12
|
+
from .Serialization import Serialization
|
12
13
|
from .SourceReference import SourceReference
|
13
14
|
from .Subject import Subject
|
14
15
|
from .Resource import Resource
|
@@ -84,6 +85,7 @@ class EventType(Enum):
|
|
84
85
|
Naturalization = "http://gedcomx.org/Naturalization"
|
85
86
|
Ordination = "http://gedcomx.org/Ordination"
|
86
87
|
Retirement = "http://gedcomx.org/Retirement"
|
88
|
+
MarriageSettlment = 'https://gedcom.io/terms/v7/MARS'
|
87
89
|
|
88
90
|
@property
|
89
91
|
def description(self):
|
@@ -192,4 +194,21 @@ class Event(Subject):
|
|
192
194
|
date: Optional[Date] = None,
|
193
195
|
place: Optional[PlaceReference] = None,
|
194
196
|
roles: Optional[List[EventRole]] = []) -> None:
|
195
|
-
super().__init__(id, lang, sources, analysis, notes, confidence, attribution, extracted, evidence, media, identifiers)
|
197
|
+
super().__init__(id, lang, sources, analysis, notes, confidence, attribution, extracted, evidence, media, identifiers)
|
198
|
+
|
199
|
+
self.type = type if type and isinstance(type, EventType) else None
|
200
|
+
self.date = date if date and isinstance(date, Date) else None
|
201
|
+
self.place = place if place and isinstance(place, PlaceReference) else None
|
202
|
+
self.roles = roles if roles and isinstance(roles, list) else []
|
203
|
+
|
204
|
+
@property
|
205
|
+
def _as_dict_(self):
|
206
|
+
raise NotImplementedError("Not implemented yet")
|
207
|
+
|
208
|
+
@classmethod
|
209
|
+
def _from_json_(cls, data: dict):
|
210
|
+
"""
|
211
|
+
Create a Person instance from a JSON-dict (already parsed).
|
212
|
+
"""
|
213
|
+
type_as_dict = Serialization.get_class_fields('Event')
|
214
|
+
return Serialization.deserialize(data, type_as_dict)
|
gedcomx/Exceptions.py
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
class GedcomXError(Exception):
|
4
4
|
"""Base for all app-specific errors."""
|
5
5
|
|
6
|
+
class GedcomClassAttributeError(GedcomXError):
|
7
|
+
def __init__(self, *args: object) -> None:
|
8
|
+
msg = f"This class need more information to be created: {args}"
|
9
|
+
super().__init__(msg)
|
10
|
+
|
11
|
+
|
6
12
|
class TagConversionError(GedcomXError):
|
7
13
|
def __init__(self, record,levelstack):
|
8
14
|
msg = f"Cannot convert: #{record.line} TAG: {record.tag} {record.xref if record.xref else ''} Value:{record.value} STACK: {type(levelstack[record.level-1]).__name__}"
|