gedcom-lite
A lightweight, fidelity-preserving GEDCOM parser, writer, and command-line toolkit for genealogy files. Supports GEDCOM 5.5.1, 5.5.5, and the current FamilySearch GEDCOM 7.0+ standard.
The "lite" in the name is a deliberate scope choice: pure Python, no runtime dependencies, no schema validation, no genealogy domain modelling beyond what the file format itself defines. The library models GEDCOM as a tree of Structure records and exposes search and mutation primitives that round-trip every file in the official sample suite byte-for-byte.
Why use it
- Round-trip fidelity. Parse a file and write it back unchanged: BOM, line endings,
CONC/CONTchoice, sibling order, and unknown extension tags are all preserved. - Targeted edits. Mutation primitives mark only the structures you change as dirty; every other line emits byte-identical to the source. An update that touches a single
NAMEproduces a one-line diff. - Encoding coverage. Detects UTF-8 (with or without BOM), UTF-16 LE/BE (with BOM), and ANSEL (legacy 5.5.1) — the ANSEL codec ships in-package.
- No dependencies. Pure Python 3.11+ standard library.
- Three CLI tools.
gedcom-read,gedcom-search,gedcom-updatecover the common verbs without scripting.
Install
# from PyPI
pip install gedcom-lite
# from git
pip install "git+https://github.com/vaelen/gedcom-lite@v0.1.0"
# editable, for hacking
git clone https://github.com/vaelen/gedcom-lite
cd gedcom-lite
pip install -e ".[dev]"
Library usage
from gedcom_lite import GedcomDocument
doc = GedcomDocument.parse("tree.ged")
print(doc.version) # '7.0'
print(doc.encoding) # 'utf-8-sig'
print(doc.record_counts()) # {'INDI': 142, 'FAM': 47, ...}
indi = doc.resolve("@I1@")
name = indi.find("NAME")
name.set_payload("Jane /Doe/")
doc.write("tree-edited.ged")
The full surface is documented in src/gedcom_lite/__init__.py. Common helpers:
from gedcom_lite import (
GedcomDocument, Structure,
parse_date_value, DateValue,
parents_of, children_of, ancestors_of, descendants_of,
document_to_dict, structure_to_dict,
)
CLI usage
Three console scripts are installed:
gedcom-read FILE [...]
gedcom-search FILE [filters...]
gedcom-update FILE [-o OUT | --in-place] SUBCOMMAND ...
Examples:
# overview of a file
gedcom-read tree.ged
# list every individual
gedcom-read tree.ged list INDI
# show one record with pointers resolved
gedcom-read tree.ged record @I1@
# JSON dump for piping into jq
gedcom-read tree.ged --json | jq '.records | length'
# find people named Smith
gedcom-search tree.ged --person Smith
# people born between 1900 and 1910
gedcom-search tree.ged --born-between 1900 1910
# died before 1776 (MIN/MAX work as unbounded sentinels on either side)
gedcom-search tree.ged --died-between MIN 1776
# combine person/date/place filters — they AND together
gedcom-search tree.ged --person Smith --born-between 1800 1850 --died-in Boston
# children, parents, ancestors, descendants
gedcom-search tree.ged --children-of @I1@
gedcom-search tree.ged --ancestors-of @I1@ --depth 4
# traversal composes with person/date/place filters as a post-filter
gedcom-search tree.ged --ancestors-of @I1@ --born-in Boston --facts
# ancestor records carry their generation in JSON (subject = 0, parents = 1, …)
gedcom-search tree.ged --ancestors-of @I1@ --json | jq '.[].generation'
# canonical per-INDI facts (xref, name, birth, death, parents, famc)
gedcom-search tree.ged --xref @I1@ --facts
gedcom-search tree.ged --ancestors-of @I1@ --facts | jq '.[] | {xref, name, generation}'
# Sosa-Stradonitz numbered ancestors (subject = 1, father of N = 2N, mother = 2N+1)
gedcom-search tree.ged --ahnentafel @I1@ --primary-famc-only
# list individuals with conflicting (multiple) FAMC links
gedcom-search tree.ged --famc-conflicts --facts
# edit a name (default writes to stdout)
gedcom-update tree.ged set-payload @I1@ NAME "Jane /Doe/" > new.ged
# add a NOTE to a record (write to a file)
gedcom-update tree.ged -o new.ged add-substructure @I1@ "" NOTE "Met at reunion"
# delete a record, voiding inbound pointers
gedcom-update tree.ged -o new.ged delete-record @I7@ --orphan-pointers void
# overwrite the source (be sure)
gedcom-update tree.ged --in-place set-payload @I1@ NAME "Jane /Doe/"
gedcom-update never modifies the input file unless --in-place is given.
Run any tool with --help for the full flag list.
Tests
pip install -e ".[dev]"
pytest
The suite covers:
- Tokenizer edge cases (xref slot, missing payload, malformed lines)
- Encoding detection (BOM-first, then
1 CHAR, then ANSEL) - ANSEL codec round-trips, including combining-mark ordering
- Date parsing across
ABT,BET … AND …,FROM … TO …, calendar escapes - Round-trip of every fixture in
examples/(the gating test) - Mutation primitives, including the "only-touched-lines-change" property
- Ancestry/descendancy traversal
- CLI smoke tests for
gedcom-read,gedcom-search,gedcom-update
Releasing
Maintainer notes — releases publish to PyPI from .github/workflows/release.yml via OIDC trusted publishing (no stored tokens).
- Bump the version in
pyproject.toml,src/gedcom_lite/__init__.py, andCHANGELOG.md. Push the changes to themainbranch. - (Optional) Rehearse to TestPyPI:
gh workflow run release.yml. - Cut the release:
gh release create vX.Y.Z --generate-notes. The workflow builds and uploads to PyPI on therelease: publishedevent.
The PyPI / TestPyPI trusted-publisher entries and the matching pypi / testpypi GitHub Environments are one-time setup, documented at the top of release.yml. CI runs pytest on push and PR across Python 3.11/3.12/3.13.
Versions in scope
- GEDCOM 5.5.1 (1999) — the de-facto interchange format used by virtually every genealogy app shipped before 2022.
- GEDCOM 5.5.5 (2019) — cleanup release of the 5.5.x line.
- FamilySearch GEDCOM 7.0+ (2021–) — current, actively maintained. UTF-8 only, real extension mechanism, GEDZIP packaging, no
CONC.
GEDCOM 7 is a breaking change from 5.5.x. gedcom-lite reads any of the three; on write it never silently promotes a file to a different version.
License
MIT — see LICENSE.
References
Metadata
Release files for gedcom-lite 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gedcom_lite-0.2.0.tar.gz | 143.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gedcom_lite-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 174.0 kB
Release files / gedcom_lite-0.2.0.tar.gz
| Download URL | gedcom_lite-0.2.0.tar.gz |
|---|---|
| Size | 143.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7fdddbdc469abaae00163ccddf5848d48d99fb677741ee6f936f1d50b7c6b1c
|
|
BLAKE2b-256 checksum How to use checksums |
174d3f2b7bd901190cf668826f050c30d9b19ecf2a45650c0058af9e6706eb60
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 6, 2026.
Transparency logRelease files / gedcom_lite-0.2.0-py3-none-any.whl
| Download URL | gedcom_lite-0.2.0-py3-none-any.whl |
|---|---|
| Size | 30.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0f71a3e77e6c451c900c7fc5030f437f9fc9d49dbd525dc222ae0197cc310559
|
|
BLAKE2b-256 checksum How to use checksums |
78a1a47fdbb7eb8ed5ef45c8d426dc227324e778d6c2e988a90a4425be9649e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 6, 2026.
Transparency log