]> Nutra Git (v2) - gamesguru/getmyancestors.git/commitdiff
wip fixes for manual tests and save "main" name
authorShane Jaroch <chown_tee@proton.me>
Sat, 24 Jan 2026 06:50:06 +0000 (01:50 -0500)
committerShane Jaroch <chown_tee@proton.me>
Sat, 24 Jan 2026 06:50:06 +0000 (01:50 -0500)
getmyancestors/classes/tree/core.py
getmyancestors/tests/test_fam_marriage.py [new file with mode: 0644]
getmyancestors/tests/test_indi_name.py [new file with mode: 0644]
pyproject.toml
res/testdata

index 67ee68092c170ee4d10327da19cf6460915e51d3..718cc72480a2afd5da631a996c45892baeb6c414 100644 (file)
@@ -121,17 +121,30 @@ class Indi:
             self.living = data["living"]
             for x in data["names"]:
                 alt = not x.get("preferred", False)
+                name_kind = None
+                target_set = None
+
                 if x["type"] == "http://gedcomx.org/Nickname":
-                    self.nicknames.add(Name(x, self.tree, self.fid, "nickname", alt))
+                    name_kind = "nickname"
+                    target_set = self.nicknames
                 elif x["type"] == "http://gedcomx.org/BirthName":
-                    self.birthnames.add(Name(x, self.tree, self.fid, "birthname", alt))
+                    name_kind = "birthname"
+                    target_set = self.birthnames
                 elif x["type"] == "http://gedcomx.org/AlsoKnownAs":
-                    self.aka.add(Name(x, self.tree, self.fid, "aka", alt))
+                    name_kind = "aka"
+                    target_set = self.aka
                 elif x["type"] == "http://gedcomx.org/MarriedName":
-                    self.married.add(Name(x, self.tree, self.fid, "married", alt))
+                    name_kind = "married"
+                    target_set = self.married
                 else:
                     print("Unknown name type: " + x.get("type"), file=sys.stderr)
                     raise ValueError("Unknown name type")
+
+                name_obj = Name(x, self.tree, self.fid, name_kind, alt)
+                target_set.add(name_obj)
+
+                if not alt and not self.name:
+                    self.name = name_obj
             if "gender" in data:
                 if data["gender"]["type"] == "http://gedcomx.org/Male":
                     self.gender = "M"
@@ -166,7 +179,7 @@ class Indi:
                 sources = self.tree.fs.get_url(
                     "/platform/tree/persons/%s/sources" % self.fid
                 )
-                if sources:
+                if sources and "sourceDescriptions" in sources and "persons" in sources:
                     for quote in sources["persons"][0]["sources"]:
                         source_id = quote["descriptionId"]
                         source_data = next(
@@ -589,18 +602,20 @@ class Fam:
                         sources = self.tree.fs.get_url(
                             "/platform/tree/couple-relationships/%s/sources" % self.fid
                         )
-                        for source in sources["sourceDescriptions"]:
-                            if (
-                                source["id"] in new_sources
-                                and source["id"] not in self.tree.sources
-                            ):
-                                self.tree.sources[source["id"]] = Source(
-                                    source, self.tree
-                                )
+                        if sources and "sourceDescriptions" in sources:
+                            for source in sources["sourceDescriptions"]:
+                                if (
+                                    source["id"] in new_sources
+                                    and source["id"] not in self.tree.sources
+                                ):
+                                    self.tree.sources[source["id"]] = Source(
+                                        source, self.tree
+                                    )
                     for source_fid, change_message in quotes.items():
-                        self.sources.add(
-                            (self.tree.sources[source_fid], change_message)
-                        )
+                        if source_fid in self.tree.sources:
+                            self.sources.add(
+                                (self.tree.sources[source_fid], change_message)
+                            )
 
     def get_notes(self):
         """retrieve marriage notes"""
diff --git a/getmyancestors/tests/test_fam_marriage.py b/getmyancestors/tests/test_fam_marriage.py
new file mode 100644 (file)
index 0000000..ddb009e
--- /dev/null
@@ -0,0 +1,80 @@
+"""Tests based on live failures, fixes exceptions found in manual testing"""
+
+import pytest
+
+from getmyancestors.classes.tree.core import Fam, Tree
+
+
+def test_add_marriage_none_sources(mock_session):
+    """
+    Test that add_marriage handles cases where the sources fetch returns None.
+    This regression test ensures that a TypeError is not raised when sources is None.
+    """
+    tree = Tree(fs=mock_session)
+    tree.sources = {}
+
+    fam = Fam(tree=tree, num="F1")
+    fam.fid = "FAM123"
+
+    # Mock the sequence of calls:
+    # 1. Fetch relationship details (returns valid data with source references)
+    # 2. Fetch source descriptions (returns None, simulating the bug)
+    mock_session.get_url.side_effect = [
+        {
+            "relationships": [
+                {"facts": [], "sources": [{"descriptionId": "S1", "attribution": {}}]}
+            ]
+        },
+        None,
+    ]
+
+    # This should not parse TypeError
+    try:
+        fam.add_marriage("FAM123")
+    except TypeError:
+        pytest.fail("add_marriage raised TypeError when sources was None")
+
+
+def test_add_marriage_missing_source_key(mock_session):
+    """
+    Test that add_marriage verifies source existence in tree.sources before accessing it.
+    This prevents KeyErrors when a referenced source was not successfully fetched.
+    """
+    tree = Tree(fs=mock_session)
+    tree.sources = {}
+
+    fam = Fam(tree=tree, num="F1")
+    fam.fid = "FAM_KEYERROR"
+
+    source_id = "MISSING_SOURCE_ID"
+
+    # Mock the sequence:
+    # 1. Fetch relationship details (referencing a source)
+    # 2. Fetch source details (returns None, so the source is never added to tree.sources)
+    mock_session.get_url.side_effect = [
+        {
+            "relationships": [
+                {
+                    "facts": [],
+                    "sources": [
+                        {
+                            "descriptionId": source_id,
+                            "attribution": {"changeMessage": "msg"},
+                        }
+                    ],
+                }
+            ]
+        },
+        None,
+    ]
+
+    # This should not raise KeyError
+    try:
+        fam.add_marriage("FAM_KEYERROR")
+    except KeyError:
+        pytest.fail(
+            "add_marriage raised KeyError when source_fid was missing from tree.sources"
+        )
+
+    # Verify that the invalid source was truly skipped
+    assert len(fam.sources) == 0
diff --git a/getmyancestors/tests/test_indi_name.py b/getmyancestors/tests/test_indi_name.py
new file mode 100644 (file)
index 0000000..ee9924d
--- /dev/null
@@ -0,0 +1,78 @@
+
+
+from getmyancestors.classes.tree.core import Indi, Tree
+
+
+def test_indi_name_population(mock_session):
+    """
+    Test that Indi.add_data correctly populates self.name when a preferred name is present.
+    """
+    tree = Tree(fs=mock_session)
+    indi = Indi(fid="INDI123", tree=tree)
+
+    data = {
+        "living": False,
+        "names": [
+            {
+                "type": "http://gedcomx.org/BirthName",
+                "preferred": True,
+                "nameForms": [
+                    {
+                        "parts": [
+                            {"type": "http://gedcomx.org/Given", "value": "John"},
+                            {"type": "http://gedcomx.org/Surname", "value": "Doe"},
+                        ]
+                    }
+                ],
+            },
+            {
+                "type": "http://gedcomx.org/Nickname",
+                "preferred": False,
+                "nameForms": [
+                    {"parts": [{"type": "http://gedcomx.org/Given", "value": "Johnny"}]}
+                ],
+            },
+        ],
+    }
+
+    indi.add_data(data)
+
+    assert indi.name is not None
+    assert indi.name.given == "John"
+    assert indi.name.surname == "Doe"
+    assert indi.name.kind == "birthname"
+
+    # Verify other names are still added
+    assert len(indi.nicknames) == 1
+    nickname = list(indi.nicknames)[0]
+    assert nickname.given == "Johnny"
+
+
+def test_indi_name_population_no_preferred(mock_session):
+    """
+    Test fallback behavior or at least ensure no crash if no preferred name (though typically FS provides one).
+    Logic dictates self.name might remain None or be set if logic allows (current logic only sets if not alt).
+    """
+    tree = Tree(fs=mock_session)
+    indi = Indi(fid="INDI124", tree=tree)
+
+    data = {
+        "living": False,
+        "names": [
+            {
+                "type": "http://gedcomx.org/BirthName",
+                "preferred": False,  # All are alternate
+                "nameForms": [
+                    {"parts": [{"type": "http://gedcomx.org/Given", "value": "John"}]}
+                ],
+            }
+        ],
+    }
+
+    indi.add_data(data)
+
+    # Based on current logic "if not alt and not self.name", self.name will remain None if all are alt.
+    # This is acceptable behavior for now, or we might want to relax it.
+    # For now, just asserting it doesn't crash.
+    assert indi.name is None
+    assert len(indi.birthnames) == 1
index 2fb989a64fb1680a6cfb2f26b07604cb5f3caa3a..b0f6009c24407eb8f84f41328af81c7534b81106 100644 (file)
@@ -148,7 +148,7 @@ source = ["getmyancestors"]
 data_file = ".tmp/.coverage"
 
 [tool.coverage.report]
-fail_under = 45.00
+fail_under = 67.98
 precision = 2
 
 show_missing = true
@@ -161,4 +161,4 @@ omit = [
     "**/tests/**"  # do NOT show coverage tests... redundant
 ]
 
-exclude_lines = ["pragma: no cover"]
\ No newline at end of file
+exclude_lines = ["pragma: no cover"]
index b3084953c34c25c3867bcc1e000dfb32e59ae6f5..741c02ced0efd708044045e855cb7fafd6eb6aa8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b3084953c34c25c3867bcc1e000dfb32e59ae6f5
+Subproject commit 741c02ced0efd708044045e855cb7fafd6eb6aa8