1,610
edits
Changes
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..."
{{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 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 [[Addon:Isotammi_addons#SuperTool|SuperTool]] Gramplet for Gramps 6, built directly on Gramps 6's JSON-backed data dictionaries so it can iterate over an entire tree quickly.
{{man warn|1=Scripts run with full access to your tree|2=Code you type or open in {{man label|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 <code>begin_changes()</code>/<code>delete()</code>/<code>set_*()</code> to edit the database.}}
== Usage ==
From the Dashboard use {{man menu|Add a gramplet}} and select {{man label|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 {{man button|Execute <Alt+Enter>}} button.
* A results area below, with three tabs: {{man label|Table}}, {{man label|Output}}, and {{man label|Chart}}.
Press {{man button|Execute <Alt+Enter>}} (or the {{man key press|Alt|Enter}} keyboard shortcut) to run the script currently in the editor. Whichever tab has something to show is switched to automatically: the {{man label|Table}} tab if the script called <code>row()</code>, the {{man label|Chart}} tab if it called <code>chart()</code>, otherwise the {{man label|Output}} tab (also used for tracebacks, when a script raises an exception).
=== Tab completion ===
{{man note|Tab completion (and the addon itself) requires the [https://pypi.org/project/jedi/ jedi] Python module — see [[#Prerequisites|Prerequisites]] below.}}
Press {{man key 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 {{man label|Gram.py Script}} DSL described below (<code>people</code>, <code>active_person</code>, and so on), including the fields and computed properties of the record wrapper once you type a dot, e.g. <code>person.</code>. Use {{man key press|up}}/{{man key press|down}} to move the selection, {{man key press|Tab}} or {{man key press|Enter}} to accept it, and {{man key press|Esc}} or any arrow/Home/End/Page key to dismiss the popup without accepting.
=== Table, Output, and Chart tabs ===
* {{man label|Table}} — one row per call to <code>row(...)</code> 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.
* {{man label|Output}} — anything printed with <code>print()</code>, plus the Python traceback if the script raised an exception, and a line reporting the elapsed execution time.
* {{man label|Chart}} — the drawing made by the last <code>chart()</code> call in the script.
=== Script menu ===
* {{man menu|Script -> New}} — clear the editor.
* {{man menu|Script -> Open...}} — open a <code>.gram.py</code> file. The dialog defaults to this addon's bundled <code>scripts</code> folder (see [[#Bundled example scripts|below]]) and shows each file's title/description as a preview when highlighted.
* {{man menu|Script -> Save}} ({{man key press|CTRL|S}}) — save over the currently open file.
* {{man menu|Script -> Save as...}} — save the current editor contents to a new <code>.gram.py</code> 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 {{man label|Table}}:
* {{man menu|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.
* {{man menu|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) ===
::{|class="wikitable"
! Shortcut !! Action
|-
| {{man key press|Alt|Enter}} || Execute the script
|-
| {{man key press|Tab}} || Open completion popup (or insert 4 spaces if nothing to complete)
|-
| {{man key press|CTRL|Z}} || Undo
|-
| {{man key press|CTRL|Shift|Z}} || Redo
|-
| {{man key press|CTRL|X}} / {{man key press|CTRL|V}} || Cut / Paste
|-
| {{man key press|Alt|C}} || Copy
|-
| {{man key press|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|Record fields]] below) per item in the tree:
* <code>people()</code>, <code>families()</code>, <code>events()</code>, <code>places()</code>, <code>notes()</code>, <code>media()</code>, <code>sources()</code>, <code>citations()</code>, <code>repositories()</code>
Three more give you a subset instead of everything:
* <code>selected("Person")</code> — only the rows currently selected (highlighted) in that category's list view. The argument is the table/category name (<code>"Person"</code>, <code>"Family"</code>, <code>"Event"</code>, ...).
* <code>filtered("Person")</code> — every row currently visible in that category's list view (i.e. after whatever filter/search is applied there).
* <code>custom_filter(name, namespace="Person")</code> — 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 {{man label|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:
* <code>active_person</code>, <code>active_family</code>, <code>active_event</code>, <code>active_place</code>, <code>active_note</code>, <code>active_media</code>, <code>active_source</code>, <code>active_citation</code>, <code>active_repository</code>
When nothing is active, these (and any missing field on a real record) evaluate to a <code>NoneData</code> placeholder: it prints as an empty string, is falsy in an <code>if</code>, and any attribute access or call on it just returns another empty <code>NoneData</code> — so <code>active_person.birth.place.name</code> is always safe to write even with nothing selected.
=== Building the results table ===
* <code>row(*values)</code> — add one row to the {{man label|Table}} tab. The number of arguments determines the number of columns; column widths and sorting are automatic (numbers sort numerically).
* <code>columns(*names)</code> — 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 <code>row()</code>.
=== Charts ===
<code>chart(type, data, count=20, **kwargs)</code> draws on the {{man label|Chart}} tab. <code>type</code> is one of:
* <code>"pie"</code> or <code>"bar"</code> — <code>data</code> is a <code>dict</code> of <code>{label: count}</code> (or a list of <code>[label, count]</code> pairs); only the top <code>count</code> entries by count are drawn.
* <code>"histogram"</code> — <code>data</code> is a plain list of numbers, bucketed into <code>count</code> intervals. Pass <code>decimal_places=N</code> as a keyword argument to control how the bucket-range labels are formatted.
<code>counter()</code> returns a fresh <code>collections.defaultdict(int)</code> — a convenient accumulator for building the <code>data</code> a chart or CSV report needs, e.g. <code>counts[person.gender] += 1</code>.
=== Editing and deleting data ===
{{man warn|Always undoable, never silent|Edits made by a script go through Gramps' normal undo history — {{man menu|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.}}
* <code>begin_changes(message="Gram.py Script Edited Data")</code> / <code>end_changes()</code> — wrap a batch of edits in a single undoable transaction, so {{man menu|Edit -> Undo}} reverts the whole batch in one step instead of one step per record. If a script errors out or you forget <code>end_changes()</code>, the Gramplet closes the transaction automatically once the script finishes.
* Setting an attribute on a record, e.g. <code>person.private = True</code>, or calling one of its <code>set_*()</code> methods, e.g. <code>person.set_privacy(True)</code>, writes the change straight to the database (inside whatever transaction is open).
* <code>delete(record)</code> — permanently remove a record (e.g. <code>delete(repository)</code>). There is no separate confirmation step, so check <code>record.back_references</code> is empty first if you only want to remove records nothing else refers to.
=== Other helpers ===
* <code>today</code> — a Gramps <code>Date</code> object for today's date.
* <code>print(...)</code> — writes to the {{man label|Output}} tab instead of a terminal.
* <code>database</code> — the raw Gramps database object (<code>self.dbstate.db</code>), for anything not covered by the helpers above.
=== Importing your own helper code ===
A script can <code>import</code> a plain <code>.py</code> module the normal way, as long as that module lives next to the script's own <code>.gram.py</code> file, or in the bundled <code>scripts</code> folder. This is a convenient way to share functions between several of your own scripts instead of copy-pasting them. See <code>scripts/script_helpers.py</code> and <code>scripts/11_import_example.gram.py</code> 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 <code>people()</code>, <code>active_person</code>, 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. <code>person.gramps_id</code>, <code>person.handle</code>, <code>person.private</code>), and in addition the wrapper exposes these computed, ready-to-use properties:
::{|class="wikitable"
! Property !! Available on !! Returns
|-
| <code>gender</code> || Person || Display string for the gender ("male"/"female"/"unknown")
|-
| <code>name</code> / <code>surname</code> / <code>names</code> || Person, others || Primary name / primary surname / all names
|-
| <code>birth</code> / <code>death</code> || Person || The Birth/Death Event record, or empty if none
|-
| <code>age</code> || Person || Age at death (birth to death), or empty if either date is missing
|-
| <code>father</code> / <code>mother</code> / <code>parents</code> / <code>spouse</code> / <code>children</code> || Person || Related Person record(s)
|-
| <code>families</code> || Person || Families this person is a parent in
|-
| <code>parent_families</code> || Person || Families this person is a child in
|-
| <code>place</code> || Event || The Place record for the event
|-
| <code>source</code> || Citation || The Source record for the citation
|-
| <code>notes</code> / <code>tags</code> / <code>citations</code> / <code>events</code> || most records || The attached Note/Tag/Citation/Event records
|-
| <code>attributes</code> / <code>addresses</code> / <code>references</code> / <code>lds_ords</code> || Person || The raw attribute/address/person-reference/LDS-ordinance lists
|-
| <code>back_references</code> || any record || Every record that directly refers to this one
|-
| <code>back_references_recursively</code> || any record || Every record reachable by following references from this one, recursively
|}
A list-valued field (e.g. <code>person.citations</code>, <code>family.children</code>) can itself be iterated, indexed, or have an attribute/property looked up across every item at once — e.g. <code>person.citations.source</code> returns the list of Source records for all of that person's citations.
== Bundled example scripts ==
The addon ships with a folder of example <code>.gram.py</code> scripts, opened via {{man menu|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).
::{|class="wikitable"
! File !! Description
|-
| <code>01_list_people.gram.py</code> || List every person with ID, given name, surname, and gender.
|-
| <code>02_filter_by_surname.gram.py</code> || List only people whose surname matches a given value.
|-
| <code>03_family_overview.gram.py</code> || List every family with father, mother, and child count.
|-
| <code>04_gender_pie_chart.gram.py</code> || Pie chart of the gender breakdown of everyone in the tree.
|-
| <code>05_age_histogram.gram.py</code> || Histogram of age at death, for people with both birth and death recorded.
|-
| <code>06_mark_unsourced_people_private.gram.py</code> || Batch-edit example: mark people with no citations as private.
|-
| <code>07_csv_ready_report.gram.py</code> || Tabular report meant to be exported via {{man menu|Data -> Save as CSV}}.
|-
| <code>08_active_person_summary.gram.py</code> || Summary of the active person plus their parents, spouse, and children.
|-
| <code>09_selected_people_report.gram.py</code> || Report on just the rows currently selected in the People view.
|-
| <code>10_find_missing_birth_dates.gram.py</code> || Data-quality check: people with no recorded birth event.
|-
| <code>11_import_example.gram.py</code> || Counts births per decade using <code>decade()</code>, imported from <code>script_helpers.py</code>.
|-
| <code>12_custom_filter_example.gram.py</code> || Runs one of your own custom filters by name via <code>custom_filter()</code>.
|-
| <code>13_delete_unused_repositories.gram.py</code> || Delete example: removes Repository records nothing refers to.
|}
== Prerequisites ==
* [https://pypi.org/project/jedi/ jedi] Python module — required for the addon to load at all (it powers [[#Tab_completion|Tab completion]]).
Enable {{checkbox|1}}{{man label|Allow Gramps to install required python modules}} on the Addon Manager's Settings tab so Gramps installs it automatically when you install {{man label|Gram.py Script}}.
== Credits ==
{{man label|Gram.py Script}} is a reimagining, for Gramps 6, of Kari Kujansuu's [[Addon:Isotammi_addons#SuperTool|SuperTool]] Gramplet, built by Doug Blank on top of Gramps 6's JSON-backed data dictionaries for speed.
== See also ==
* [[Addon:Isotammi_addons#SuperTool|SuperTool]] — the Isotammi addon that inspired {{man label|Gram.py Script}}.
* [https://github.com/gramps-project/addons-source/pull/666 New Gramplet: Gram.py Script] — the pull request that introduced this addon.
* [https://github.com/gramps-project/addons-source/tree/maintenance/gramps61/GrampyScript GrampyScript source] on GitHub.
[[Category:Addons]]
[[Category:Plugins]]
[[Category:Gramplets]]
[[Category:Developers/General]]
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 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 [[Addon:Isotammi_addons#SuperTool|SuperTool]] Gramplet for Gramps 6, built directly on Gramps 6's JSON-backed data dictionaries so it can iterate over an entire tree quickly.
{{man warn|1=Scripts run with full access to your tree|2=Code you type or open in {{man label|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 <code>begin_changes()</code>/<code>delete()</code>/<code>set_*()</code> to edit the database.}}
== Usage ==
From the Dashboard use {{man menu|Add a gramplet}} and select {{man label|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 {{man button|Execute <Alt+Enter>}} button.
* A results area below, with three tabs: {{man label|Table}}, {{man label|Output}}, and {{man label|Chart}}.
Press {{man button|Execute <Alt+Enter>}} (or the {{man key press|Alt|Enter}} keyboard shortcut) to run the script currently in the editor. Whichever tab has something to show is switched to automatically: the {{man label|Table}} tab if the script called <code>row()</code>, the {{man label|Chart}} tab if it called <code>chart()</code>, otherwise the {{man label|Output}} tab (also used for tracebacks, when a script raises an exception).
=== Tab completion ===
{{man note|Tab completion (and the addon itself) requires the [https://pypi.org/project/jedi/ jedi] Python module — see [[#Prerequisites|Prerequisites]] below.}}
Press {{man key 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 {{man label|Gram.py Script}} DSL described below (<code>people</code>, <code>active_person</code>, and so on), including the fields and computed properties of the record wrapper once you type a dot, e.g. <code>person.</code>. Use {{man key press|up}}/{{man key press|down}} to move the selection, {{man key press|Tab}} or {{man key press|Enter}} to accept it, and {{man key press|Esc}} or any arrow/Home/End/Page key to dismiss the popup without accepting.
=== Table, Output, and Chart tabs ===
* {{man label|Table}} — one row per call to <code>row(...)</code> 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.
* {{man label|Output}} — anything printed with <code>print()</code>, plus the Python traceback if the script raised an exception, and a line reporting the elapsed execution time.
* {{man label|Chart}} — the drawing made by the last <code>chart()</code> call in the script.
=== Script menu ===
* {{man menu|Script -> New}} — clear the editor.
* {{man menu|Script -> Open...}} — open a <code>.gram.py</code> file. The dialog defaults to this addon's bundled <code>scripts</code> folder (see [[#Bundled example scripts|below]]) and shows each file's title/description as a preview when highlighted.
* {{man menu|Script -> Save}} ({{man key press|CTRL|S}}) — save over the currently open file.
* {{man menu|Script -> Save as...}} — save the current editor contents to a new <code>.gram.py</code> 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 {{man label|Table}}:
* {{man menu|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.
* {{man menu|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) ===
::{|class="wikitable"
! Shortcut !! Action
|-
| {{man key press|Alt|Enter}} || Execute the script
|-
| {{man key press|Tab}} || Open completion popup (or insert 4 spaces if nothing to complete)
|-
| {{man key press|CTRL|Z}} || Undo
|-
| {{man key press|CTRL|Shift|Z}} || Redo
|-
| {{man key press|CTRL|X}} / {{man key press|CTRL|V}} || Cut / Paste
|-
| {{man key press|Alt|C}} || Copy
|-
| {{man key press|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|Record fields]] below) per item in the tree:
* <code>people()</code>, <code>families()</code>, <code>events()</code>, <code>places()</code>, <code>notes()</code>, <code>media()</code>, <code>sources()</code>, <code>citations()</code>, <code>repositories()</code>
Three more give you a subset instead of everything:
* <code>selected("Person")</code> — only the rows currently selected (highlighted) in that category's list view. The argument is the table/category name (<code>"Person"</code>, <code>"Family"</code>, <code>"Event"</code>, ...).
* <code>filtered("Person")</code> — every row currently visible in that category's list view (i.e. after whatever filter/search is applied there).
* <code>custom_filter(name, namespace="Person")</code> — 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 {{man label|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:
* <code>active_person</code>, <code>active_family</code>, <code>active_event</code>, <code>active_place</code>, <code>active_note</code>, <code>active_media</code>, <code>active_source</code>, <code>active_citation</code>, <code>active_repository</code>
When nothing is active, these (and any missing field on a real record) evaluate to a <code>NoneData</code> placeholder: it prints as an empty string, is falsy in an <code>if</code>, and any attribute access or call on it just returns another empty <code>NoneData</code> — so <code>active_person.birth.place.name</code> is always safe to write even with nothing selected.
=== Building the results table ===
* <code>row(*values)</code> — add one row to the {{man label|Table}} tab. The number of arguments determines the number of columns; column widths and sorting are automatic (numbers sort numerically).
* <code>columns(*names)</code> — 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 <code>row()</code>.
=== Charts ===
<code>chart(type, data, count=20, **kwargs)</code> draws on the {{man label|Chart}} tab. <code>type</code> is one of:
* <code>"pie"</code> or <code>"bar"</code> — <code>data</code> is a <code>dict</code> of <code>{label: count}</code> (or a list of <code>[label, count]</code> pairs); only the top <code>count</code> entries by count are drawn.
* <code>"histogram"</code> — <code>data</code> is a plain list of numbers, bucketed into <code>count</code> intervals. Pass <code>decimal_places=N</code> as a keyword argument to control how the bucket-range labels are formatted.
<code>counter()</code> returns a fresh <code>collections.defaultdict(int)</code> — a convenient accumulator for building the <code>data</code> a chart or CSV report needs, e.g. <code>counts[person.gender] += 1</code>.
=== Editing and deleting data ===
{{man warn|Always undoable, never silent|Edits made by a script go through Gramps' normal undo history — {{man menu|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.}}
* <code>begin_changes(message="Gram.py Script Edited Data")</code> / <code>end_changes()</code> — wrap a batch of edits in a single undoable transaction, so {{man menu|Edit -> Undo}} reverts the whole batch in one step instead of one step per record. If a script errors out or you forget <code>end_changes()</code>, the Gramplet closes the transaction automatically once the script finishes.
* Setting an attribute on a record, e.g. <code>person.private = True</code>, or calling one of its <code>set_*()</code> methods, e.g. <code>person.set_privacy(True)</code>, writes the change straight to the database (inside whatever transaction is open).
* <code>delete(record)</code> — permanently remove a record (e.g. <code>delete(repository)</code>). There is no separate confirmation step, so check <code>record.back_references</code> is empty first if you only want to remove records nothing else refers to.
=== Other helpers ===
* <code>today</code> — a Gramps <code>Date</code> object for today's date.
* <code>print(...)</code> — writes to the {{man label|Output}} tab instead of a terminal.
* <code>database</code> — the raw Gramps database object (<code>self.dbstate.db</code>), for anything not covered by the helpers above.
=== Importing your own helper code ===
A script can <code>import</code> a plain <code>.py</code> module the normal way, as long as that module lives next to the script's own <code>.gram.py</code> file, or in the bundled <code>scripts</code> folder. This is a convenient way to share functions between several of your own scripts instead of copy-pasting them. See <code>scripts/script_helpers.py</code> and <code>scripts/11_import_example.gram.py</code> 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 <code>people()</code>, <code>active_person</code>, 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. <code>person.gramps_id</code>, <code>person.handle</code>, <code>person.private</code>), and in addition the wrapper exposes these computed, ready-to-use properties:
::{|class="wikitable"
! Property !! Available on !! Returns
|-
| <code>gender</code> || Person || Display string for the gender ("male"/"female"/"unknown")
|-
| <code>name</code> / <code>surname</code> / <code>names</code> || Person, others || Primary name / primary surname / all names
|-
| <code>birth</code> / <code>death</code> || Person || The Birth/Death Event record, or empty if none
|-
| <code>age</code> || Person || Age at death (birth to death), or empty if either date is missing
|-
| <code>father</code> / <code>mother</code> / <code>parents</code> / <code>spouse</code> / <code>children</code> || Person || Related Person record(s)
|-
| <code>families</code> || Person || Families this person is a parent in
|-
| <code>parent_families</code> || Person || Families this person is a child in
|-
| <code>place</code> || Event || The Place record for the event
|-
| <code>source</code> || Citation || The Source record for the citation
|-
| <code>notes</code> / <code>tags</code> / <code>citations</code> / <code>events</code> || most records || The attached Note/Tag/Citation/Event records
|-
| <code>attributes</code> / <code>addresses</code> / <code>references</code> / <code>lds_ords</code> || Person || The raw attribute/address/person-reference/LDS-ordinance lists
|-
| <code>back_references</code> || any record || Every record that directly refers to this one
|-
| <code>back_references_recursively</code> || any record || Every record reachable by following references from this one, recursively
|}
A list-valued field (e.g. <code>person.citations</code>, <code>family.children</code>) can itself be iterated, indexed, or have an attribute/property looked up across every item at once — e.g. <code>person.citations.source</code> returns the list of Source records for all of that person's citations.
== Bundled example scripts ==
The addon ships with a folder of example <code>.gram.py</code> scripts, opened via {{man menu|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).
::{|class="wikitable"
! File !! Description
|-
| <code>01_list_people.gram.py</code> || List every person with ID, given name, surname, and gender.
|-
| <code>02_filter_by_surname.gram.py</code> || List only people whose surname matches a given value.
|-
| <code>03_family_overview.gram.py</code> || List every family with father, mother, and child count.
|-
| <code>04_gender_pie_chart.gram.py</code> || Pie chart of the gender breakdown of everyone in the tree.
|-
| <code>05_age_histogram.gram.py</code> || Histogram of age at death, for people with both birth and death recorded.
|-
| <code>06_mark_unsourced_people_private.gram.py</code> || Batch-edit example: mark people with no citations as private.
|-
| <code>07_csv_ready_report.gram.py</code> || Tabular report meant to be exported via {{man menu|Data -> Save as CSV}}.
|-
| <code>08_active_person_summary.gram.py</code> || Summary of the active person plus their parents, spouse, and children.
|-
| <code>09_selected_people_report.gram.py</code> || Report on just the rows currently selected in the People view.
|-
| <code>10_find_missing_birth_dates.gram.py</code> || Data-quality check: people with no recorded birth event.
|-
| <code>11_import_example.gram.py</code> || Counts births per decade using <code>decade()</code>, imported from <code>script_helpers.py</code>.
|-
| <code>12_custom_filter_example.gram.py</code> || Runs one of your own custom filters by name via <code>custom_filter()</code>.
|-
| <code>13_delete_unused_repositories.gram.py</code> || Delete example: removes Repository records nothing refers to.
|}
== Prerequisites ==
* [https://pypi.org/project/jedi/ jedi] Python module — required for the addon to load at all (it powers [[#Tab_completion|Tab completion]]).
Enable {{checkbox|1}}{{man label|Allow Gramps to install required python modules}} on the Addon Manager's Settings tab so Gramps installs it automatically when you install {{man label|Gram.py Script}}.
== Credits ==
{{man label|Gram.py Script}} is a reimagining, for Gramps 6, of Kari Kujansuu's [[Addon:Isotammi_addons#SuperTool|SuperTool]] Gramplet, built by Doug Blank on top of Gramps 6's JSON-backed data dictionaries for speed.
== See also ==
* [[Addon:Isotammi_addons#SuperTool|SuperTool]] — the Isotammi addon that inspired {{man label|Gram.py Script}}.
* [https://github.com/gramps-project/addons-source/pull/666 New Gramplet: Gram.py Script] — the pull request that introduced this addon.
* [https://github.com/gramps-project/addons-source/tree/maintenance/gramps61/GrampyScript GrampyScript source] on GitHub.
[[Category:Addons]]
[[Category:Plugins]]
[[Category:Gramplets]]
[[Category:Developers/General]]