Addon:GrampyScript

From Gramps
Revision as of 22:31, 6 July 2026 by Dsblank (talk | contribs) (Created page with "{{Third-party addon}} The {{man label|Gram.py Script}} Gramplet lets you write and run small Python scripts directly against your Gramps family tree, from a code editor embedd...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Gramps-notes.png
This is a Third-party Addon. The Addon/Plugin system is controlled by the Plugin Manager.

Please use carefully on data that is backed up, and help make it better by reporting any issues to the bug tracker.
Unless otherwise stated on this page, you can download this addon by following these instructions.
Please note that some Addons have prerequisites that need to be installed before they can be used.

The Gram.py Script Gramplet lets you write and run small Python scripts directly against your Gramps family tree, from a code editor embedded in the Dashboard. Results show up as a sortable, double-click-to-edit table, as plain text output, or as a simple bar/pie/histogram chart. It is a reimagining of the SuperTool Gramplet for Gramps 6, built directly on Gramps 6's JSON-backed data dictionaries so it can iterate over an entire tree quickly.

Gnome-important.png
Scripts run with full access to your tree

Code you type or open in Gram.py Script executes as plain Python, with the same permissions as Gramps itself. Only run scripts you wrote yourself or that come from a source you trust, especially anything using begin_changes()/delete()/set_*() to edit the database.

Usage

From the Dashboard use Add a gramplet and select Gram.py Script. It is recommended to detach/undock the gramplet, or give it a tall spot in the Dashboard, since the editor and results area both want vertical space (the addon defaults to a height of 800 pixels).

The Gramplet has three parts:

  • A code editor at the top, with Python syntax highlighting (keywords in blue, the DSL functions in green, the DSL constants in red, comments in grey).
  • An Execute <Alt+Enter> button.
  • A results area below, with three tabs: Table, Output, and Chart.

Press Execute <Alt+Enter> (or the Alt+ Enter keyboard shortcut) to run the script currently in the editor. Whichever tab has something to show is switched to automatically: the Table tab if the script called row(), the Chart tab if it called chart(), otherwise the Output tab (also used for tracebacks, when a script raises an exception).

Tab completion

Gramps-notes.png
Tab completion (and the addon itself) requires the jedi Python module — see Prerequisites below.

Press Tab while typing in the editor to open a completion popup for the name at the cursor. It covers both Python builtins and the Gram.py Script DSL described below (people, active_person, and so on), including the fields and computed properties of the record wrapper once you type a dot, e.g. person.. Use / to move the selection, Tab or Enter to accept it, and Esc or any arrow/Home/End/Page key to dismiss the popup without accepting.

Table, Output, and Chart tabs

  • Table — one row per call to row(...) in the script, with sortable columns (click a column header). Double-click any row to open the standard Gramps editor for that record (Person, Family, Event, Place, Repository, Source, Citation, Media, or Note) — handy for reviewing or fixing records a script found.
  • Output — anything printed with print(), plus the Python traceback if the script raised an exception, and a line reporting the elapsed execution time.
  • Chart — the drawing made by the last chart() call in the script.

Script menu

  • Script -> New — clear the editor.
  • Script -> Open... — open a .gram.py file. The dialog defaults to this addon's bundled scripts folder (see below) and shows each file's title/description as a preview when highlighted.
  • Script -> Save (CTRL+S) — save over the currently open file.
  • Script -> Save as... — save the current editor contents to a new .gram.py file.

The last file you had open is remembered and reloaded automatically the next time you open the Gramplet.

Data menu

Once a script has produced a Table:

  • Data -> Save as CSV — export the table's rows to a CSV file, with a choice of UTF-8/ISO8859-1 encoding and comma/semicolon delimiter.
  • Data -> Copy to clipboard — copy the table's rows to the clipboard as tab-separated text, ready to paste into a spreadsheet.

Keyboard shortcuts (while editing)

Shortcut Action
Alt+ Enter Execute the script
Tab Open completion popup (or insert 4 spaces if nothing to complete)
CTRL+Z Undo
CTRL+ Shift+Z Redo
CTRL+X / CTRL+V Cut / Paste
Alt+C Copy
CTRL+S Save script

Writing scripts

A script is plain Python, executed in a namespace that additionally provides the names described below. The simplest possible script:

<syntaxhighlight lang="python"> for person in people():

   row(person.gramps_id, person.name.first_name, person.surname.surname, person.gender)

</syntaxhighlight>

Iterating over records

Each of these is a zero-argument generator yielding one wrapped record (see Record fields below) per item in the tree:

  • people(), families(), events(), places(), notes(), media(), sources(), citations(), repositories()

Three more give you a subset instead of everything:

  • selected("Person") — only the rows currently selected (highlighted) in that category's list view. The argument is the table/category name ("Person", "Family", "Event", ...).
  • filtered("Person") — every row currently visible in that category's list view (i.e. after whatever filter/search is applied there).
  • custom_filter(name, namespace="Person") — runs one of your own named filters, created with the Filters gramplet/editor, and yields its matches. If no filter with that name exists for that namespace, a warning is printed to the Output tab and nothing is yielded.

The active record

These constants hold the record currently active/selected elsewhere in Gramps (e.g. the Active Person shown in the status bar), or a blank placeholder if nothing is active:

  • active_person, active_family, active_event, active_place, active_note, active_media, active_source, active_citation, active_repository

When nothing is active, these (and any missing field on a real record) evaluate to a NoneData placeholder: it prints as an empty string, is falsy in an if, and any attribute access or call on it just returns another empty NoneData — so active_person.birth.place.name is always safe to write even with nothing selected.

Building the results table

  • row(*values) — add one row to the Table tab. The number of arguments determines the number of columns; column widths and sorting are automatic (numbers sort numerically).
  • columns(*names) — set the column headers shown above the table. Call it once near the top of the script, matching the number and order of the values passed to row().

Charts

chart(type, data, count=20, **kwargs) draws on the Chart tab. type is one of:

  • "pie" or "bar"data is a dict of {label: count} (or a list of [label, count] pairs); only the top count entries by count are drawn.
  • "histogram"data is a plain list of numbers, bucketed into count intervals. Pass decimal_places=N as a keyword argument to control how the bucket-range labels are formatted.

counter() returns a fresh collections.defaultdict(int) — a convenient accumulator for building the data a chart or CSV report needs, e.g. counts[person.gender] += 1.

Editing and deleting data

Gnome-important.png
Always undoable, never silent

Edits made by a script go through Gramps' normal undo history — Edit -> Undo reverts them like any other change — but they are not asked for confirmation first. Test on a backup copy of your tree first if you are not sure what a script will do.

  • begin_changes(message="Gram.py Script Edited Data") / end_changes() — wrap a batch of edits in a single undoable transaction, so Edit -> Undo reverts the whole batch in one step instead of one step per record. If a script errors out or you forget end_changes(), the Gramplet closes the transaction automatically once the script finishes.
  • Setting an attribute on a record, e.g. person.private = True, or calling one of its set_*() methods, e.g. person.set_privacy(True), writes the change straight to the database (inside whatever transaction is open).
  • delete(record) — permanently remove a record (e.g. delete(repository)). There is no separate confirmation step, so check record.back_references is empty first if you only want to remove records nothing else refers to.

Other helpers

  • today — a Gramps Date object for today's date.
  • print(...) — writes to the Output tab instead of a terminal.
  • database — the raw Gramps database object (self.dbstate.db), for anything not covered by the helpers above.

Importing your own helper code

A script can import a plain .py module the normal way, as long as that module lives next to the script's own .gram.py file, or in the bundled scripts folder. This is a convenient way to share functions between several of your own scripts instead of copy-pasting them. See scripts/script_helpers.py and scripts/11_import_example.gram.py for a working example:

<syntaxhighlight lang="python"> from script_helpers import decade

columns("Decade", "Births") counts = counter() for person in people():

   birth = person.birth
   if birth:
       year = birth.get_date_object().get_year()
       if year:
           counts[decade(year)] += 1

for decade_start, count in sorted(counts.items()):

   row("%ds" % decade_start, count)

</syntaxhighlight>

Record fields

Every record yielded by people(), active_person, and so on is a dict-like wrapper around the record's raw JSON data. All of that raw data's own fields are available as attributes (e.g. person.gramps_id, person.handle, person.private), and in addition the wrapper exposes these computed, ready-to-use properties:

Property Available on Returns
gender Person Display string for the gender ("male"/"female"/"unknown")
name / surname / names Person, others Primary name / primary surname / all names
birth / death Person The Birth/Death Event record, or empty if none
age Person Age at death (birth to death), or empty if either date is missing
father / mother / parents / spouse / children Person Related Person record(s)
families Person Families this person is a parent in
parent_families Person Families this person is a child in
place Event The Place record for the event
source Citation The Source record for the citation
notes / tags / citations / events most records The attached Note/Tag/Citation/Event records
attributes / addresses / references / lds_ords Person The raw attribute/address/person-reference/LDS-ordinance lists
back_references any record Every record that directly refers to this one
back_references_recursively any record Every record reachable by following references from this one, recursively

A list-valued field (e.g. person.citations, family.children) can itself be iterated, indexed, or have an attribute/property looked up across every item at once — e.g. person.citations.source returns the list of Source records for all of that person's citations.

Bundled example scripts

The addon ships with a folder of example .gram.py scripts, opened via Script -> Open.... It is also the default save location, so you can keep your own scripts there alongside the examples (an addon update only overwrites files that share a name with one of the numbered examples below, so anything you save under another name is safe).

File Description
01_list_people.gram.py List every person with ID, given name, surname, and gender.
02_filter_by_surname.gram.py List only people whose surname matches a given value.
03_family_overview.gram.py List every family with father, mother, and child count.
04_gender_pie_chart.gram.py Pie chart of the gender breakdown of everyone in the tree.
05_age_histogram.gram.py Histogram of age at death, for people with both birth and death recorded.
06_mark_unsourced_people_private.gram.py Batch-edit example: mark people with no citations as private.
07_csv_ready_report.gram.py Tabular report meant to be exported via Data -> Save as CSV.
08_active_person_summary.gram.py Summary of the active person plus their parents, spouse, and children.
09_selected_people_report.gram.py Report on just the rows currently selected in the People view.
10_find_missing_birth_dates.gram.py Data-quality check: people with no recorded birth event.
11_import_example.gram.py Counts births per decade using decade(), imported from script_helpers.py.
12_custom_filter_example.gram.py Runs one of your own custom filters by name via custom_filter().
13_delete_unused_repositories.gram.py Delete example: removes Repository records nothing refers to.

Prerequisites

Enable

Allow Gramps to install required python modules on the Addon Manager's Settings tab so Gramps installs it automatically when you install Gram.py Script.

Credits

Gram.py Script is a reimagining, for Gramps 6, of Kari Kujansuu's SuperTool Gramplet, built by Doug Blank on top of Gramps 6's JSON-backed data dictionaries for speed.

See also