]> Nutra Git (v1) - gamesguru/getmyancestors.git/commitdiff
fixup
authorShane Jaroch <chown_tee@proton.me>
Sat, 24 Jan 2026 05:56:44 +0000 (00:56 -0500)
committerShane Jaroch <chown_tee@proton.me>
Sat, 24 Jan 2026 05:56:44 +0000 (00:56 -0500)
Makefile
getmyancestors/classes/session.py
getmyancestors/classes/tree/core.py
getmyancestors/mergemyanc.py
res/testdata
tests/offline_test.py

index f0eae5ca0e896454b4938b1c8d241e9b7c8128a1..f9f5e3701ea4a4cc74749a7a9a1b3e327ee20f59 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -89,15 +89,13 @@ format:     ##H@@ Format with black & isort
                ruff check --fix --exit-zero $(ARGS) ${PY_CHANGED_FILES}; \
        fi
 
-.PHONY: lint/
-lint/: lint/ruff lint/pylint lint/mypy
-lint/: ##H@@ Lint with ruff, pylint, and mypy
-
 .PHONY: lint
-lint: lint/
+lint: ruff pylint mypy
+lint:  ##H@@ Lint with ruff, pylint, and mypy
+
 
-.PHONY: lint/ruff
-lint/ruff:
+.PHONY: ruff
+ruff:
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # ruff (lint)
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -105,8 +103,8 @@ lint/ruff:
                ruff check ${PY_CHANGED_FILES}; \
        fi
 
-.PHONY: lint/pylint
-lint/pylint:
+.PHONY: pylint
+pylint:
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # pylint
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -114,8 +112,8 @@ lint/pylint:
                pylint -j 0 ${PY_CHANGED_FILES}; \
        fi
 
-.PHONY: lint/mypy
-lint/mypy:
+.PHONY: mypy
+mypy:
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # mypy
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -123,12 +121,6 @@ lint/mypy:
                mypy ${PY_CHANGED_FILES}; \
        fi
 
-.PHONY: pylint
-pylint: lint/pylint
-
-.PHONY: mypy
-mypy: lint/mypy
-
 
 .PHONY: clean
 clean: ##H@@ Clean up build files/cache
index 67c59546215d7b7ac8b4e5afbe785a9d48185baf..b2cc6035833e0c5aed702a84c79a6d65ec0e5f45 100644 (file)
@@ -817,11 +817,15 @@ class CachedSession(GMASession, CSession):
             self,
             cache_path,
             backend="filesystem",
+            serializer="json",
             expire_after=expire_after,
             allowable_codes=(200, 204),
             cache_control=cache_control,  # Enable HTTP conditional requests (ETag/Last-Modified)
             allow_to_fetch_missing=(not offline_mode),  # prevent fetch on miss
         )
+        print(
+            f"DEBUG: CachedSession initialized. Backend=filesystem, Path={cache_path}, Offline={offline_mode}"
+        )
         # Re-apply default headers as CSession.__init__ might have wiped them
         with self.lock:
             self.headers.update(self.DEFAULT_HEADERS)
index f1228daf6f6880f39e34f4012c466facfcf9bd93..67ee68092c170ee4d10327da19cf6460915e51d3 100644 (file)
@@ -10,6 +10,7 @@ import threading
 import time
 import xml.etree.ElementTree as ET
 from datetime import datetime
+from enum import Enum
 from typing import Any, BinaryIO, Dict, Iterable, List, Optional, Set, Tuple, Union
 
 # global imports
@@ -27,6 +28,32 @@ from .records import Fact, Memorie, Note, Source
 from .utils import GEONAME_FEATURE_MAP, cont
 
 
+class ParentRelType(str, Enum):
+    """Parental relationship type in FamilySearch (PEDI)"""
+
+    BIRTH = "birth"
+    ADOPTED = "adopted"
+    STEP = "step"
+    FOSTER = "foster"
+
+    @staticmethod
+    def from_fs_type(facts: list | None) -> "ParentRelType | None":
+        """Parse from FamilySearch fact/relationship type"""
+        if not facts:
+            return None
+        for fact in facts:
+            ftype = fact.get("type", "")
+            if ftype == "http://gedcomx.org/BiologicalParent":
+                return ParentRelType.BIRTH
+            if ftype == "http://gedcomx.org/StepParent":
+                return ParentRelType.STEP
+            if ftype == "http://gedcomx.org/AdoptiveParent":
+                return ParentRelType.ADOPTED
+            if ftype == "http://gedcomx.org/FosterParent":
+                return ParentRelType.FOSTER
+        return None
+
+
 class Indi:
     """GEDCOM individual class
     :param fid' FamilySearch id
@@ -49,7 +76,7 @@ class Indi:
         self.tree = tree
         self.num_prefix = "I"
         self.origin_file: Optional[str] = None
-        self.famc: Set["Fam"] = set()
+        self.famc: Dict["Fam", Optional[ParentRelType]] = {}
         self.fams: Set["Fam"] = set()
         self.famc_fid: Set[str] = set()
         self.fams_fid: Set[str] = set()
@@ -150,11 +177,17 @@ class Indi:
                             ),
                             None,
                         )
-                        source = (
-                            self.tree.ensure_source(source_data)
-                            if self.tree and source_data
-                            else None
-                        )
+                        if self.tree:
+                            if source_data:
+                                source = self.tree.ensure_source(source_data)
+                            else:
+                                existing_source = self.tree.sources.get(source_id)
+                                if existing_source:
+                                    source = existing_source
+                                else:
+                                    source = self.tree.ensure_source({"id": source_id})
+                        else:
+                            source = None
                         if source and self.tree:
                             citation = self.tree.ensure_citation(quote, source)
                             self.citations.add(citation)
@@ -189,9 +222,9 @@ class Indi:
         """add family fid (for spouse or parent)"""
         self.fams.add(fam)
 
-    def add_famc(self, fam: "Fam"):
+    def add_famc(self, fam: "Fam", rel_type: Optional[ParentRelType] = None):
         """add family fid (for child)"""
-        self.famc.add(fam)
+        self.famc[fam] = rel_type
 
     def get_notes(self):
         """retrieve individual notes"""
@@ -417,8 +450,11 @@ class Indi:
             self.sealing_child.print(file)
         for fam in sorted(self.fams, key=lambda x: x.id or ""):
             file.write("1 FAMS @F%s@\n" % fam.id)
-        for fam in sorted(self.famc, key=lambda x: x.id or ""):
+        for fam in sorted(self.famc.keys(), key=lambda x: x.id or ""):
             file.write("1 FAMC @F%s@\n" % fam.id)
+            val = self.famc[fam]
+            if val:
+                file.write("2 PEDI %s\n" % val.value)
         # print(f'Fams Ids: {self.fams_ids}, {self.fams_fid}, {self.fams_num}', file=sys.stderr)
         # for num in self.fams_ids:
         # print(f'Famc Ids: {self.famc_ids}', file=sys.stderr)
index 0db172480505ab7f794570e4b032b17691631c66..e3e9e8611859d1b8ad35884f4f1f2c4d38ab7aa6 100755 (executable)
@@ -113,16 +113,18 @@ def main(
             def merge_names(target_set, source_set):
                 # Combine all names and sort deterministically
                 all_names = list(target_set) + list(source_set)
-                all_names.sort(key=lambda x: (
-                    str(x),
-                    x.given or "",
-                    x.surname or "",
-                    x.prefix or "",
-                    x.suffix or "",
-                    x.kind or "",
-                    str(x.alternative) if hasattr(x, 'alternative') else "",
-                    x.note.text if hasattr(x, 'note') and x.note else "",
-                ))
+                all_names.sort(
+                    key=lambda nm: (
+                        str(nm),
+                        nm.given or "",
+                        nm.surname or "",
+                        nm.prefix or "",
+                        nm.suffix or "",
+                        nm.kind or "",
+                        str(nm.alternative) if hasattr(nm, "alternative") else "",
+                        nm.note.text if hasattr(nm, "note") and nm.note else "",
+                    )
+                )
                 # Rebuild target_set keeping first occurrence by string
                 target_set.clear()
                 seen = set()
@@ -365,7 +367,7 @@ def main(
             for chil_fid in fam.chil_fid:
                 if chil_fid in tree.indi:
                     fam.children.add(tree.indi[chil_fid])
-                    tree.indi[chil_fid].famc.add(fam)
+                    tree.indi[chil_fid].add_famc(fam)
 
         # compute number for family relationships and print GEDCOM file
         tree.reset_num()
index cefbd8dbd42cbb85209bae8e242e57add0c0e520..b3084953c34c25c3867bcc1e000dfb32e59ae6f5 160000 (submodule)
@@ -1 +1 @@
-Subproject commit cefbd8dbd42cbb85209bae8e242e57add0c0e520
+Subproject commit b3084953c34c25c3867bcc1e000dfb32e59ae6f5
index 34e268d38950c7490fa062dd0486f2b541c22b68..ad04938521b53528dc341085f668f3c9dfec2bb4 100644 (file)
@@ -132,7 +132,6 @@ def test_offline():
     expectations = load_expectations()
     exp_ada = expectations.get("EXPECTED_ADA_LINES", 0)
     exp_marie = expectations.get("EXPECTED_MARIE_LINES", 0)
-    exp_merged = expectations.get("EXPECTED_MERGED_LINES", 0)
 
     # 2. Setup Cache
     setup_cache()
@@ -303,10 +302,31 @@ def test_offline():
 
     # Check merged file with exact diff (no line count tolerance)
     diff_result = subprocess.run(
-        ["git", "diff", "--no-index", "--exit-code", "--color=always", str(merged), str(ARTIFACTS_DIR / "merged_scientists.ged")],
+        [
+            "git",
+            "diff",
+            "--no-index",
+            "--exit-code",
+            "--color=always",
+            str(merged),
+            str(ARTIFACTS_DIR / "merged_scientists.ged"),
+        ],
+        check=False,
     )
     if diff_result.returncode != 0:
-        print(f"❌ Merged file differs from artifact (see diff above)")
+        print("❌ Merged file differs from artifact (see diff above)")
+        print("Diff Stat:")
+        subprocess.run(
+            [
+                "git",
+                "diff",
+                "--no-index",
+                "--stat",
+                str(merged),
+                str(ARTIFACTS_DIR / "merged_scientists.ged"),
+            ],
+            check=False,
+        )
         failed = True
     else:
         print(f"✓ Merged file matches artifact exactly ({l_merged} lines).")