greatgramps is a static site generator for your Gramps family tree.
The site now includes a relationship chain to show how you’re related to someone, and also a graphical explorer to build up a tree view of your own choosing.
Even if you don’t need/want a static site, the CLI is quite handy for all sorts of things - and now for finding and deleting unconnected people, events and such.
New in greatgramps 0.4.0:
Interactive tree explorer: full-screen page to open and close branches around any person, with an Explore tab on every person page.
“How you’re related” section: the chain of people between you and any relative, including by marriage.
Common ancestor shown in the header for cousins, aunts and uncles.
Half-siblings and unmarried partners labelled accurately.
Exact ages from full dates.
exclude_pages config option to leave pages out of the build and nav.
grgr orphans command to find and delete orphaned people, families, events and places.
Most gramps users are not aware of the underlying infrastructure. But it helps to understand how all of the pieces fit together. I specifically did not mention the “website generator projects” in my overview:
But in the next iteration I will because it is important to understand them. As greatgramps documentation starts off, it describes itself as “a static site generator”. That means that (like the Narrative web) it creates HTML pages that don’t change. If the database is edited, or more people are added, you’d need to run the generator again.
@Woody
This website building utility has a Command Line interface and is run from outside of Gramps. CLI tools require a lot more effort on the user side. But require a lot less effort on the programmer side … since the defaults usually do what the programmer needed. And GUIs require building a lot of error handling for when the user doesn’t follow the expected workflow.
@bennuttall
It seems like an AI coding tool could be prompted to assess the CLI parameter passing code and (provided the Narrated Website Report code as sample GUI code for a similar site builder) be asked to build a Report addon plugin that provides a parameter GUI and passes them to Great Gramps.
It looks interesting, but I’ve been away from Python programming too
long to figure out what I am missing. I am running Gramps 6.0.8 on
CachyOS with KDE desktop. Based on the message I got when I attempted
to use pip to install greatgramps, I used the command
pipx install --system-site-packages greatgramps[cli,html,pdf]
and it appeared to work fine. However, when I run ‘grgr config’ I get
the following message:
Traceback (most recent call last):
File “/home/allen/.local/bin/grgr”, line 3, in
from greatgramps.cli import app
File
“/home/allen/.local/share/pipx/venvs/greatgramps/lib/python3.14/site-packages/greatgramps/cli.py”,
line 18, in
from gramps.gen.const import HOME_DIR as GRAMPS_HOME_DIR
ImportError: cannot import name ‘HOME_DIR’ from ‘gramps.gen.const’
(/usr/lib/python3.14/site-packages/gramps/gen/const.py)
I considered making it into a plugin. The problem is installing the third party dependencies into the same environment Gramps runs in. Maybe this is a solved problem or there are known workarounds - I’m not sure.
Ah this looks like a Gramps 6 compatibility problem. I will work on a fix and make sure it’s compatible with 5 and 6 in future. I’ll post here when I’ve got a release out.
I got a couple of errors that you might be interested in looking at.
They apparently prevented the build from completing, so I haven’t got
enough results to form an opinion on the generated website.
Output from “grgr build”:
Opening Gramps database: /home/allen/.local/share/gramps/grampsdb/698d00a6
Building root I003907…
Built I003907/ancestors.pdf (6 generations)
Built index.html
Building 79326 person pages…
Built 79325/79326 person pages in 2266.9s (1 error)
ERROR I003909: DecompressionBombError: Image size (217993728
pixels) exceeds limit of 178956970 pixels, could be decompression bomb
DOS attack.
Built people/index.html
Building 17851 place pages…
Built 17851 place pages in 12.4s
╭─────────────────────────────────────────────── Traceback (most recent
call last) ────────────────────────────────────────────────╮
│
/home/allen/.local/share/pipx/venvs/greatgramps/lib/python3.14/site-packages/greatgramps/cli.py:1250
in build_site │
│
│
│ 1247 │ │ from .build import build
│
│ 1248 │ except ImportError:
│
│ 1249 │ │ _require_extra(“html”)
│
│ ❱ 1250 │ build()
│
│ 1251
│
│ 1252
│
│ 1253 @app.command(“census-check”, no_args_is_help=True)
│
│
│
│
/home/allen/.local/share/pipx/venvs/greatgramps/lib/python3.14/site-packages/greatgramps/build.py:1494
in build │
│
│
│ 1491 │
│
│ 1492 │ for root_id in config.roots:
│
│ 1493 │ │ ctx = _make_root_ctx(shared, root_id)
│
│ ❱ 1494 │ │ _build_root(ctx)
│
│ 1495 │
│
│ 1496 │ _render_global_index(config, shared)
│
│ 1497
│
│
│
│
/home/allen/.local/share/pipx/venvs/greatgramps/lib/python3.14/site-packages/greatgramps/build.py:1393
in _build_root │
│
│
│ 1390 │ if _excluded(ctx, ‘events’):
│
│ 1391 │ │ _skip(‘events/index.html’)
│
│ 1392 │ else:
│
│ ❱ 1393 │ │ num_events = _render_events_index(ctx, relation_map)
│
│ 1394 │ │ print(f’Built events/index.html ({num_events} events)‘)
│
│ 1395 │
│
│ 1396 │ # Individual event pages
│
│
│
│
/home/allen/.local/share/pipx/venvs/greatgramps/lib/python3.14/site-packages/greatgramps/build.py:999
in _render_events_index │
│
│
│ 996 │ render = ctx[‘render’]
│
│ 997 │ ancestor_events = [
│
│ 998 │ │ {**e, ‘is_descendant_event’: any(p[‘gramps_id’] in
my_descendants for p in e[‘people’])} │
│ ❱ 999 │ │ for e in build_event_list(db, set(my_ancestors) -
{root_id}) │
│ 1000 │ ]
│
│ 1001 │ (ctx[‘events_dir’] / ‘index.html’).write_text(
│
│ 1002 │ │ render(‘events’, page_title=f’Events —
{config.site_title}’, │
│
│
│
/home/allen/.local/share/pipx/venvs/greatgramps/lib/python3.14/site-packages/greatgramps/gramps_data.py:951
in build_event_list │
│
│
│ 948 │ │ │
db.get_media_from_handle(ref.get_reference_handle()).get_mime_type().startswith(‘image/’)
│
│ 949 │ │ │ for ref in event.get_media_list()
│
│ 950 │ │ )
│
│ ❱ 951 │ │ lat = float(place_obj.get_latitude()) if place_obj and
place_obj.get_latitude() else None │
│ 952 │ │ lon = float(place_obj.get_longitude()) if place_obj and
place_obj.get_longitude() else None │
│ 953 │ │ grave_url = None
│
│ 954 │ │ if etype == int(EventType.BURIAL):
│
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ValueError: could not convert string to float: ‘37°46′55″N’
The first error is probably an error on my part that I am going to have
to resolve. The source for person I003909 was a website that no longer
exists, so I need to remove it and try to find another source.
I don’t know whether gramps stores latitudes and longitudes in the
format that they are entered when creating the place or if it converts
to a common format internally. I usually copy and paste coordinates
from Wikipedia or other website where I find the information and let
gramps deal with it, which has always worked as far as I know. That
means that most coordinates have been entered as degrees, minutes,
seconds although some are entered as decimal degrees.
Rather than flood the chat here with errors stack traces, can people either open GitHub issues or just send me an email (see my website Ben Nuttall — About Me ) and I’ll see if I can fix any issues.
@jacrider I’ve caught the decompression bomb error (from pillow) with a warning and a suggestion to resize large images. Also added a warning for bad coordinates (these places will be skipped).
I should also point out that if you have gallery items (especially if you have a lot of them), the first build will be very slow as they’re all resized, cropped and converted to webp, but this is a one-off process for each image. The rebuild will be much faster once the images are generated. Just avoid deleting the media directory from your output.