Difference between revisions of "User:Ahs3/Contributing"

From Gramps
(Files included in addon distribution)
(Create a Gramps Plugin Registration file)
Line 398: Line 398:
  
 
== Create a Gramps Plugin Registration file ==
 
== Create a Gramps Plugin Registration file ==
 +
First, create the <tt>NewProjectName.gpr.py</tt> file. The registration takes this general form:
  
First, create the NewProjectName.gpr.py file. The registration takes this general form:
+
    register(PTYPE,
 
+
        gramps_target_version = "6.0",
<pre>
+
        version = "1.0.0",
register(PTYPE,
+
        ATTR = value,
    gramps_target_version = "6.0",
+
    )
    version = "1.0.0",
 
    ATTR = value,
 
)
 
</pre>
 
  
 
[https://github.com/gramps-project/gramps/blob/master/gramps/gen/plug/_pluginreg.py#L76 PTYPE] values include: TOOL, GRAMPLET, REPORT, QUICKVIEW (formerly QUICKREPORT), IMPORT, EXPORT, DOCGEN, GENERAL, MAPSERVICE, VIEW, RELCALC, SIDEBAR, DATABASE, RULE, THUMBNAILER, and CITE.
 
[https://github.com/gramps-project/gramps/blob/master/gramps/gen/plug/_pluginreg.py#L76 PTYPE] values include: TOOL, GRAMPLET, REPORT, QUICKVIEW (formerly QUICKREPORT), IMPORT, EXPORT, DOCGEN, GENERAL, MAPSERVICE, VIEW, RELCALC, SIDEBAR, DATABASE, RULE, THUMBNAILER, and CITE.
  
 +
ATTR depends on the PTYPE.
  
ATTR depends on the PTYPE. But you must have '''gramps_target_version''' and addon '''version'''. '''gramps_target_version''' should be a string of the form "X.Y" version number matching Gramps X major, Y minor integer.  '''version''' is a string of the form "X.Y.Z" representing the version of your addon. X, Y, and Z should all be integers.
+
You must include a <tt>gramps_target_version</tt> and addon <tt>version</tt>. <tt>gramps_target_version</tt> should be a string of the form "X.Y" version number matching Gramps X (major), Y (minor) integer.  <tt>version</tt> is a string of the form "X.Y.Z" representing the version of your addon; X, Y, and Z should all be integers.
  
 
Be sure to include attributes for author name(s) and email(s) in the form of an array of comma-separated strings.  
 
Be sure to include attributes for author name(s) and email(s) in the form of an array of comma-separated strings.  
  
There is an additional set of attributes, '''maintainers''' and '''maintainers_email'''. {{new|5.2}} If you, the author, are also the maintainer it will be identical to the author attributes, but you may also designate a maintainer, in which case the maintainer will become the primary point of contact.
+
There is an additional set of attributes, <tt>maintainers</tt> and <tt>maintainers_email</tt> {{new|5.2}}. If you, the author, are also the maintainer it will be identical to the author attributes, but you may also designate a maintainer, in which case the maintainer will become the primary point of contact.
  
 
Here is a sample Tool GPR file:
 
Here is a sample Tool GPR file:
  
<pre>
+
    register(TOOL,  
register(TOOL,  
 
 
         id    = 'AttachSource',
 
         id    = 'AttachSource',
 
         name  = _("Attach Source"),
 
         name  = _("Attach Source"),
Line 438: Line 435:
 
         tool_modes = [TOOL_MODE_GUI],
 
         tool_modes = [TOOL_MODE_GUI],
 
         help_url = "Addon:AttachSourceTool"
 
         help_url = "Addon:AttachSourceTool"
        )
+
    )
</pre>
 
  
 
You can see examples of the kinds of addons [https://github.com/gramps-project/gramps/plugins here] (for example, see [https://github.com/gramps-project/gramps/plugins/drawreport/drawplugins.gpr.py gramps/plugins/drawreport/drawplugins.gpr.py]) and see the full documentation in the [https://github.com/gramps-project/gramps/blob/3f0db9303f29811b43325c30149c8844c7ce24b6/gramps/gen/plug/_pluginreg.py#L23 master/gramps/gen/plug/_pluginreg.py] comments and docstrings.
 
You can see examples of the kinds of addons [https://github.com/gramps-project/gramps/plugins here] (for example, see [https://github.com/gramps-project/gramps/plugins/drawreport/drawplugins.gpr.py gramps/plugins/drawreport/drawplugins.gpr.py]) and see the full documentation in the [https://github.com/gramps-project/gramps/blob/3f0db9303f29811b43325c30149c8844c7ce24b6/gramps/gen/plug/_pluginreg.py#L23 master/gramps/gen/plug/_pluginreg.py] comments and docstrings.
  
Note that this .gpr.py will automatically use translations if you have them (see below). That is, the function "_" is predefined to use your locale translations; you only need to mark the text with _("TEXT") and include a translation of "TEXT" in your translation file. For example, in the above example, _("Attach Source") is marked for translation. If you have developed and packaged your addon with translation support, then that phrase will be converted into the user's language.
+
Note that this <tt>.gpr.py</tt> will automatically use translations if you have them (see [[#Localization|Localization]). That is, the function "_" is predefined to use your locale translations; you only need to mark the text with <tt>_("TEXT")</tt> and include a translation of "TEXT" in your translation file. For example, in the above example, <tt>_("Attach Source")</tt> is marked for translation. If you have developed and packaged your addon with translation support, then that phrase will be converted into the user's language.
  
 
=== Report plugins ===
 
=== Report plugins ===

Revision as of 02:33, 21 May 2025

Tango-Dialog-information.png
Looking for Gramps addons to install?

If you are looking for existing addons to install to your Gramps desktop, visit: Third-party Addons. This page is concerned only with creating new addons.


Contents

CONTRIBUTING Addons

This document describes the API, methods, and best practices for developing third-party addons for Gramps 6.0 and later.

Gramps-notes.png
Gramps Is Usually Developed Using Linux

We assume that most addons will be developed using a Linux development environment. While it is possible to do so under Windows or MacOS, many of the steps will differ and the documented processes have not been as thoroughly reviewed. Developer beware. Beyond here there be dragons.

See Portal:Developers for details.

Working knowledge of Python and git is required. Ideally, all addons will be contributed and maintained using github, but having a github account is not required.

The addons source tree in github is licensed under the [GNU Public License v2 (GPL-2.0)](https://opensource.org/license/gpl-2-0). We assume you agree with redsitribution under that license when contributing addon source.

If you're looking for *existing* addons to install, see [Third-Party Addons](https://gramps-project.org/wiki/index.php/Third-party_Addons).

If you're looking to contribute to Gramps directly, see [Portal:Developers](https://gramps-project.org/wiki/index.php/Getting_started_with_Gramps_development).


What Can Addons Extend?

Addons for Gramps can extend the program in many different ways. You can add any of the following types of addons:

  • Importer (IMPORT) - adds additional file format import options to Gramps
  • Exporter (EXPORT) - adds additional file format export options to Gramps
  • Gramplet (GRAMPLET) - adds a new interactive interface section to a Gramps view mode, which can be activated by right-clicking on the dashboard View or from the menu of the Sidebar/Bottombar in the other view categories.
  • Gramps View (mode) (VIEW) - adds a new view mode to the list of views available within a View Category
  • Map Service (MAPSERVICE) - adds new mapping options to Gramps
  • Plugin lib (GENERAL) - libraries that are present giving extra functionality; can add, replace, and/or modify builtin Gramps options.
  • Quickreport/Quickview (QUICKREPORT) - a view that you can run by right-clicking on an object, or if a person quickview, then via the Quick View Gramplet
  • Report (REPORT) - adds a new output report; this includes Website that outputs a static genealogy website based on your Gramps Family Tree data.
  • Rule (RULE) - adds new filter rules. — ⚡new for version 5.1
  • Tool (TOOL) - adds a utility that helps process data from your family tree.
  • Doc creator (DOCGEN)
  • Relationships (RECALC)
  • Sidebar (SIDEBAR)
  • Database (DATABASE) - add support for another database backend. — ⚡new for version 5.0
  • Thumbnailer (THUMBNAILER) — ⚡new for version 5.2
  • Citation formatter (CITE) — ⚡new for version 5.2

Overview of Writing an Addon

Writing an addon is fairly straightforward if you have a bit of Python experience. And, sharing your addon is the right thing to do. The general steps to writing an addon and sharing your own addons are:

  1. Develop your addon
  2. Create a Gramps plugin registration file (.gpr.py)
  3. Addon Checklist
  4. Create a Pull Request for your addon
  5. Announce it on the Gramps Forum - Let users know it exist and how to use it.
  6. Support it through the issue tracker
  7. Maintain the code as Gramps continues to evolve

We'll now expand on each of these steps.

Develop Your Addon

Addons are found in two locations:

  1. The source code repository, where the addons are developed and maintained: addons-source
  2. The download repository, which stores the packages that Gramps Addons Manager users download and update for addons they want:

addons

Addons Source Code Repository

The addons-source github repository holds the source code for addons, with branches for each version of the different Gramps releases.

Example commands refer to the current public release and maintenance branch rather than the master branch. Only addons maintainers will merge changes into the current release branch(es); the master branch is only used by the repository maintainers, and only as needed.

Hence, the branches in addons-source to be concerned with are:

  • master - managed only by addon maintainers, and not necessarily current
  • maintenance/gramps52 - the Gramps 5.2 current release branch, for the previous version of Gramps
  • maintenance/gramps60 - the Gramps 6.0 current release branch, for the _current_ version of Gramps

If you are working on an addon for gramps for the current Gramps 6.0 public release, be sure to use the maintenance/gramps60 git branch. NB: there are branches for older releases should they be needed.

The source code in addons-source has the following structure, with the code for each addon in its own subdirectory:

   /addons-source
       /IndividualNameOfAddon1
       /IndividualNameOfAddon2
       /...

There are some command line tools and documentation in the root directory as well.

Addons Download Repository

The addons git repository holds packaged versions of the addons for each release of Gramps. As an addon developer, you shouldn't have to do anything with this repository. You should only need to use this repository if you want to have a model of an addon repository in order to make and manage your own, or to test the packaging of your addon. The repository has the following structure:

   /addons
       /gramps52
           /download
           /listings
       /gramps60
           /download
           /listings

Set Up a Github Account

In order to use all of the tools github repositories can offer, it is necessary to have a github account. While this is not absolutely required to develop and addon (see [Addons External to Github](#addons-external-to-github)), it can make things easier. For those new to github and git:

Even if you are not using github, you will need some familiarity with git.

Create Project Forks in Github

Github assumes a similar development process for all projects:

  1. Find the project you wish to contribute to -- your upstream project.
  2. Create a github fork of that upstream project in your user account.
  3. Make modifications in your fork of the upstream project.
  4. Once your modifications are ready, create a PR (Pull Request) in the upstream project pointing to the work in your fork.
  5. The upstream maintainers will then work with you, through the PR, to make sure your modification fits into their project.

This may require several iterations of the addon code for the PR.

Gramps addon development will only require one fork of a github upstream project: addons-source. For testing of the addon packaging, a fork of addons will be needed:

In the github web interface, login and go to each of the links above. There is a Fork pull-down menu in the upper right hand side of the page. Just click and follow the directions. In this document, we will assume that your github user name is user and that your forks just re-use the names addons-source and addons (these names are not required, but are simpler).

This can also be done from the command line with the gh command. First, authenticate with github, then do the forks:

   $ gh auth login         # just follow instructions ....
   $ mkdir myaddon
   $ cd myaddon
   $ gh repo fork https://github.com/gramps-project/addons-source
   $ gh repo fork https://github.com/gramps-project/addons

You'll be asked if you wish to clone the fork. It's not required but if you respond yes it will save you a step later. When the forks are ready, you should be able to see them:

   $ gh repo list
 
   Showing 2 of 2 repositories in @user
 
   NAME                      DESCRIPTION           INFO          UPDATED
   user/addons               Contributed 3rd p...  public, fork  about 1 day ago
   user/addons-source        Contributed 3rd p...  public, fork  about 1 day ago
Gramps-notes.png
Git URIs

Whilst we use the URI https://github.com/gramps-project/addons-source above, the URI [email protected]:gramps-project/addons-source.git points to exactly the same place, and accomplishes the same thing. The former relies on HTTPS for security, and the latter relies on SSH. In general, HTTPS is often used for read-only copies of repositories, or when networking precludes SSH usage; SSH however is usually more secure and less subject to man-in-the-middle attacks and thus often used when write access to repositories is needed.

Set Up Addon Development Environment

Next, we need to download the addon source and its dependencies to build up a development environment. We will need copies of three repositories: addons-source, addons and the main Gramps source gramps. All three of these local copies need to have the same root directory so that the make.py script to be used later works properly.

To continue the examples above, assume our github user name is user and the root directory for development is called myaddon.

Gramps Repository

In developing an addon, we will not need to change the upstream Gramps source, but we will need access to it for the make.py packaging script (described later) to work properly. So, just clone a copy of the current release branch. With SSH:

   $ cd myaddon
   $ git clone -b maintenance/gramps60 [email protected]:gramps-project/gramps

Or with HTTPS:

   $ cd myaddon
   $ git clone -b maintenance/gramps60 https://github.com/gramps-project/gramps.git

The -b parameter tells git to checkout and clone from the named branch.

Addons Repository

The addons repository will hold the package and packaging metadata for the addon being written -- the myaddon.gpr.py registration file, for example, and a compressed tarball of the addon itself. Changes to the upstream addons repository only happens via PRs and using the make.py script.

A recommended structure for your local repository is to have two git remotes, one for upstream, and one for your addon work. If the gh repo fork command was used and it cloned for you, this has already been done. You can see this with:

   $ cd myaddon
   $ cd addons
   $ git remote -v
   origin	[email protected]:user/addons.git (fetch)
   origin	[email protected]:user/addons.git (push)
   upstream	[email protected]:gramps-project/addons.git (fetch)
   upstream	[email protected]:gramps-project/addons.git (push)

where origin is your fork of the upstream repository, and upstream is the original source.

If just a fork was made, either on github or some other location, an upstream remote should be added:

   $ cd myaddon
   $ cd addons
   $ git remote -v
   origin	[email protected]:user/addons.git (fetch)
   origin	[email protected]:user/addons.git (push)
   $ git remote add upstream [email protected]:gramps-project/addons.git
   $ git pull -a
   $ git remote -v
   origin	[email protected]:user/addons.git (fetch)
   origin	[email protected]:user/addons.git (push)
   upstream	[email protected]:gramps-project/addons.git (fetch)
   upstream	[email protected]:gramps-project/addons.git (push)

If not using github, setup is a little different:

   $ cd myaddon
   $ mkdir addons
   $ cd addons
   # git init
   $ git remote add upstream [email protected]:gramps-project/addons.git
   $ git pull -a
   $ git remote -v
   origin	<your-git-repository> (fetch)
   origin	<your-git-repository> (push)
   upstream	[email protected]:gramps-project/addons.git (fetch)
   upstream	[email protected]:gramps-project/addons.git (push)
   $ git push origin --all

In all cases, cloning will check out the default branch to start. However, we will not change these branches so we can always refer back to the original upstream source.

Addons Source Repository

The addons-source repository will hold your addon source code. Changes to the upstream addons-source repository will only happen via PRs, and only in the current maintenance branch (e.g., maintenance/gramps60). All of your work will be in your github fork of the addons source repository.

We recommend the same structure for your local repository as above for the addons tree: two git remotes, one for upstream, and one for your addon source. If the gh repo fork command was used and it cloned for you, this has already been done. You can see this with:

   $ cd myaddon
   $ cd addons-source
   $ git remote -v
   origin	[email protected]:user/addons-source.git (fetch)
   origin	[email protected]:user/addons-source.git (push)
   upstream	[email protected]:gramps-project/addons-source.git (fetch)
   upstream	[email protected]:gramps-project/addons-source.git (push)

where origin is your fork of the upstream repository, and upstream is the original source.

If just a fork was made, either on github or some other location, the upstream remote will have to be added:

   $ cd myaddon
   $ cd addons-source
   $ git remote -v
   origin	[email protected]:user/addons-source.git (fetch)
   origin	[email protected]:user/addons-source.git (push)
   $ git remote add upstream [email protected]:gramps-project/addons-source.git
   $ git pull -a
   $ git remote -v
   origin	[email protected]:user/addons-source.git (fetch)
   origin	[email protected]:user/addons-source.git (push)
   upstream	[email protected]:gramps-project/addons-source.git (fetch)
   upstream	[email protected]:gramps-project/addons-source.git (push)

If not using github, setup is a little different:

   $ cd myaddon
   $ git clone <your-git-repository> addons-source
   $ cd addons-source
   $ git remote add upstream [email protected]:gramps-project/addons-source.git
   $ git pull -a
   $ git remote -v
   origin	<your-git-repository> (fetch)
   origin	<your-git-repository> (push)
   upstream	[email protected]:gramps-project/addons-source.git (fetch)
   upstream	[email protected]:gramps-project/addons-source.git (push)

In all cases, cloning will check out the default branch to start. However, we will not change these branches so we can always refer back to the original upstream source.

Create Your Development Branch

Now that copies of all the necessary upstream code have been set up, create the branches that will be used to save your addon and where all of your work will occur:

   $ cd myaddon
   $ cd addons-source
   $ git checkout -b myaddon60 origin/maintenance/gramps60
   $ git push --set-upstream origin myaddon60
   $ cd ../addons
   $ git checkout -b myaddon60 origin/master
   $ git push --set-upstream origin myaddon60
  

The checkout will create the branch myaddon60 and then set the current branch to the one just checked out. The push should be done in order to declare the repository for the branch, and to make sure you have a good starting point.

Tango-Dialog-information.png
Branches are cheap

You can create as many branches as you wish; they have minimal overhead. Using them for experimentation is highly encouraged. If you end up with multiple addons, put each in a separate branch. When doing maintenance on your addon, it can be useful to create a branch for each bug fix -- all of these simplify the PR process for everyone.


Create Your Addon Subdirectory

Make a new directory in addons-source for your addon:

   $ cd myaddon
   $ cd addons-source
   $ git checkout myaddon60
   $ mkdir NewProjectName                     # camel case, please

This makes sure we're on the right branch (myaddon60 created in the previous step), and then creates the new directory where your addon development will occur, NewProjectName.

Follow the Development API

Create the two required files: NewProjectName.py that provides the addon implementation, and NewProjectName.gpr.py that provides the information to package the addon so that Gramps can load it and run it.

From this point on, just follow the development API for your specific class of tool: report, view, or Gramplets development. Place all of your associated .py, .glade, and any other files in your addon-source directory. For general information on Gramps development, see Portal:Developers and Writing a Plugin specifically.

Test Your Addon As You Develop

To test your addon as you develop, we recommend you copy your NewProjectName plugin into your Gramps user plugin directory from your addon development directory, prior to testing. Or, just edit in the Gramps user plugin directory until it is ready to publish, then copy back to your addon development directory. Your installed Gramps desktop application will search this folder (and subdirectories) for any .gpr.py files, and add them to the plugin list.

You can of course still use the git branch for your addon to store intermediate steps and other work in progress.

Gnome-important.png
Bug 10436

Symbolic links to folders in the gramps plugin directory are not scanned, so you cannot just create a symbolic link pointing to your addon source tree; you will have to copy it.

If you have code that you want to share between addons, you don't need to do anything special. Gramps adds each directory in which a .gpr.py is found onto the PYTHONPATH which is searched when you perform an import. Thus import NewProjectName will work from other addons. You should always make sure you name your addons with a name appropriate for Python imports.

Addon Configuration

Some addons may want to have persistent data (data settings that remain between sessions). You can handle this yourself, or you can use Gramps' builtin configure system.

At the top of the source file for your addon, you would do this:

   from config import config as configman
   config = configman.register_manager("grampletname")
   # register the values to save:
   config.register("section.option-name1", value1)
   config.register("section.option-name2", value2)
   ...
   # load an existing file, if one:
   config.load()
   # save it, it case it didn't exist:
   config.save()

This will create the file grampletname.ini and put it in the same directory as the addon. If the config file already exists, it remains intact. The natural location for .ini files is in the directory in which the addon is installed; using the main gramps.ini file for addon preferences could potentially lead to a conflict between addons. Other locations and file formats are possible. See The Gramps architect recommends leaving this decision to the addon developer.

In the addon, you can then:

   x = config.get("section.option-name1")
   config.set("section.option-name1", 3)

and when this code is exiting, you might want to save the config. In a Gramplet that would be:

    def on_save(self):
        config.save()

If your code is a system-level file, then you might want to save the config in the Gramps system folder:

   config = configman.register_manager("system", use_config_path=True)

This is rare; most .ini files go into the plugins directory.

In other code that might use this config file, you would do this:

   from config import config as configman
   config = configman.get_manager("grampletname")
   x = config.get("section.option-name1")
Gnome-important.png
Restart Here!

Everything up to here is okay.

Localization

Gramps-notes.png
Python Strings Only

These instructions will only work for Python strings. If you have a glade file, it will not get translated.

For general help with translations for Gramps, see Coding for translation. However, that will only use translations that come with Gramps, or allow you to contribute translations to the Gramps core. To have your own managed translations that will be packaged with your addon, you will need to add a way to retrieve the translation. Add the following to the top of your NewProjectName.py file:

   from gramps.gen.const import GRAMPS_LOCALE as glocale
       = glocale.get_addon_translator(__file__).gettext

Then you can use the standard "_()" function to translate phrases in your addon.

You can use one of a few different types of translation functions:

   gettext
   lgettext
   ngettext
   lngettext
   sgettext

These are obsolete starting in Gramps 4.x; gettext, ngettext, and sgettext always return translated strings in Unicode for consistent portability between Python2 and Python3.

See the Python documentation for using gettext and ngettext. The "l" versions return the string encoded according to the currently set locale; the "u" versions return Unicode strings in Python2 and are no longer available in Python3.

The method sgettext should always be used; it is a Gramps extension that filters out clarifying comments for translators, such as in:

   _("Remaining names | rest")

where "rest" is the English string that we want to present and "Remaining names" is a hint for translators.

Files Included in Addon Distribution

The process that creates the compressed tar file that the Gramps Download Manager installs in Gramps to use your addon automatically includes the following files:

   *.py
   *.glade
   *.xml
   *.txt
   locale/*/LC_MESSAGES/*.mo

Starting with Gramp 5.0, if you have files other than those listed above, you should create a MANIFEST file in the root of your addon folder that lists the files (or pattern) to be added, one per line, like this sample MANIFEST file:

   README.md
   extra_dir/*
   help_files/docs/help.html
Tango-Dialog-information.png
Use Weblate

Starting with Gramps 6.0 (and only 6.0) translations can be done on Weblate. Initial testing has appeared successful, but please let us know if you notice any problems. The Weblate Addons component contains aggregated translations for every addon.

See https://hosted.weblate.org/projects/gramps-project/addons/.


Create a Gramps Plugin Registration file

First, create the NewProjectName.gpr.py file. The registration takes this general form:

   register(PTYPE,
        gramps_target_version = "6.0",
        version = "1.0.0",
        ATTR = value,
   )

PTYPE values include: TOOL, GRAMPLET, REPORT, QUICKVIEW (formerly QUICKREPORT), IMPORT, EXPORT, DOCGEN, GENERAL, MAPSERVICE, VIEW, RELCALC, SIDEBAR, DATABASE, RULE, THUMBNAILER, and CITE.

ATTR depends on the PTYPE.

You must include a gramps_target_version and addon version. gramps_target_version should be a string of the form "X.Y" version number matching Gramps X (major), Y (minor) integer. version is a string of the form "X.Y.Z" representing the version of your addon; X, Y, and Z should all be integers.

Be sure to include attributes for author name(s) and email(s) in the form of an array of comma-separated strings.

There is an additional set of attributes, maintainers and maintainers_email — ⚡new for version 5.2. If you, the author, are also the maintainer it will be identical to the author attributes, but you may also designate a maintainer, in which case the maintainer will become the primary point of contact.

Here is a sample Tool GPR file:

   register(TOOL, 
        id    = 'AttachSource',
        name  = _("Attach Source"),
        description =  _("Attaches a shared source to multiple objects."),
        version = '1.0.0',
        gramps_target_version = '6.0',
        status = STABLE,
        fname = 'AttachSourceTool.py',
        authors = ["Douglas S. Blank"],
        authors_email = ["[email protected]"],
        maintainers = ["Douglas S. Blank"],
        maintainers_email = ["[email protected]"],
        category = TOOL_DBPROC,
        toolclass = 'AttachSourceWindow',
        optionclass = 'AttachSourceOptions',
        tool_modes = [TOOL_MODE_GUI],
        help_url = "Addon:AttachSourceTool"
   )

You can see examples of the kinds of addons here (for example, see gramps/plugins/drawreport/drawplugins.gpr.py) and see the full documentation in the master/gramps/gen/plug/_pluginreg.py comments and docstrings.

Note that this .gpr.py will automatically use translations if you have them (see [[#Localization|Localization]). That is, the function "_" is predefined to use your locale translations; you only need to mark the text with _("TEXT") and include a translation of "TEXT" in your translation file. For example, in the above example, _("Attach Source") is marked for translation. If you have developed and packaged your addon with translation support, then that phrase will be converted into the user's language.

Report plugins

The possible report categories are (gen/plug/_pluginreg.py):

#possible report categories
CATEGORY_TEXT       = 0
CATEGORY_DRAW       = 1
CATEGORY_CODE       = 2
CATEGORY_WEB        = 3
CATEGORY_BOOK       = 4
CATEGORY_GRAPHVIZ   = 5
CATEGORY_TREE       = 6
REPORT_CAT          = [ CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
                        CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE]

Each report category has a set of standards and interface. The categories CATEGORY_TEXT and CATEGORY_DRAW use the Document interface of Gramps. See also Report API for a draft view on this.

The application programming interface or API for reports is treated at Report-writing_tutorial. For general information on Gramps development see Portal:Developers and Writing a Plugin specifically.

General plugins

The plugin framework also allows you to create generic plugins for use. This includes the ability to create libraries of functions, and plugins of your own design.

Example: A library of functions

In this example, a file name library.py will be imported at time of registration (when Gramps starts):

# file: library.gpr.py

register(GENERAL, 
   id    = 'My Library',
   name  = _("My Library"),
   description =  _("Provides a library for doing something."),
   version = '1.0',
   gramps_target_version = '6.0',
   status = STABLE,
   fname = 'library.py',
   load_on_reg = True,
  )

The code in the file library.py will be imported when Gramps begins. You can access the loaded module in other code by issuing an "import library" as Python keeps track of files already imported. However, the amount of useful code that you can run when the program is imported is limited. You might like to have the code do something that requires a dbstate or uistate object, and neither of these is available when just importing a file.

If "load_on_reg" was not True, then this code would be unavailable until manually loaded. There is no automatic mechanism in Gramps to load GENERAL plugins automatically.

In addition to importing a file at startup, one can also run a single function inside a GENERAL plugin, and it will be passed the dbstate, the uistate, and the plugin data. The function must be called "load_on_reg", and take those three parameters, like this:

# file: library.py

def load_on_reg(dbstate, uistate, plugin):
    """
    Runs when plugin is registered.
    """
    print("Hello World!")

Here, you could connect signals to the dbstate, open windows, etc.

Another example of what one can do with the plugin interface is to create a general purpose plugin framework for use by other plugins. Here is the basis for a plugin system that:

  • allows plugins to list data files
  • allows the plugin to process all of the data files

First, the gpr.py file:


register(GENERAL, 
  id    = "ID",
  category = "CATEGORY",
  load_on_reg = True,
  process = "FUNCTION_NAME",
  )

This example uses three new features:

  1. GENERAL plugins can have a category
  2. GENERAL plugins can have a load_on_reg function that returns data
  3. GENERAL plugins can have a function (called "process") which will process the data

If you (or someone else) create additional general plugins of this category, and they follow your load_on_reg data format API, then they could be used just like your original data. For example, here is an additional general plugin in the 'WEBSTUFF' category:

# anew.gpr.py

register(GENERAL, 
  id    = 'a new plugin',
  category = "WEBSTUFF",
  version = '1.0',
  gramps_target_version = '6.0',
  data = ["a", "b", "c"],
  )

This doesn't have load_on_reg = True, nor does it have a fname or process, but it does set the data directly in the .gpr.py file. Then we have the following results:

>>> from gui.pluginmanager import GuiPluginManager
>>> PLUGMAN = GuiPluginManager.get_instance()
>>> PLUGMAN.get_plugin_data('WEBSTUFF')
["a", "b", "c", "Stylesheet.css", "Another.css"]
>>> PLUGMAN.process_plugin_data('WEBSTUFF')
["A", "B", "C", "STYLESHEET.CSS", "ANOTHER.CSS"]

Registered GENERAL Categories

The following are the published secondary plugins API's (type GENERAL, with the following categories):

WEBSTUFF

A sample gpr.py file:

# stylesheet.gpr.py

register(GENERAL, 
  id    = 'system stylesheets',
  category = "WEBSTUFF",
  name  = _("CSS Stylesheets"),
  description =  _("Provides a collection of stylesheets for the web"),
  version = '1.0',
  gramps_target_version = '6.0',
  fname = "stylesheet.py",
  load_on_reg = True,
  process = "process_list",
  )

Here is the associated program:

# file: stylesheet.py

def load_on_reg(dbstate, uistate, plugin):
    """
    Runs when plugin is registered.
    """
    return ["Stylesheet.css", "Another.css"]

def process_list(files):
    return [file.upper() for file in files]

Filters

For example:

register(GENERAL,
   category="Filters",
   ...
   load_on_reg = True
)
def load_on_reg(dbstate, uistate, plugin):
    # returns a function that takes a namespace, 'Person', 'Family', etc.

    def filters(namespace):
        print("Ok...", plugin.category, namespace, uistate)
        # return a Filter object here
    return filters

List the Prerequistes your addon depends on

In your gpr file, you can have a line like:

depends_on = ["libwebconnect"],

which is a list of plug-in identifier's from other gpr files. This example will ensure that libwebconnect is loaded before your addon. If that ID can't be found, or you have a cycle (circular import), then your addons won't be loaded. The Gramps architect summarizes: "The depends_on list is used to specify other plugins which the plugin depends on. These will be installed automatically."

example code used in the Addon:Web_Connect_Pack that references libwebconnect Prerequistes RUWebPack.gpr.py#L17

This means that common Prerequisites can be shared between addons. So that code can be maintained in its own gpr/addon file instead of synchronizing the maintenance of multiple copies across various silos.

Additional requirements properties were implemented in the Registration Options to specify prerequisites for plug-ins: requires_mod (modules), requires_gi (GObject introspection) and requires_exe (executable). — ⚡new for version 5.2

Addon Checklist

Before you publish your new addon, review this checklist for completeness

  • Is it a good Addon name and description
  • Is it in the right tool, report, rule, view, gramplet category
  • Does it need translatable strings marked
  • Does it need a different location for config files
  • Has a wiki page been generated
  • Has the help_url been changed from the GitHub repository to the wiki page

Create PR

The section describes how to create a branch, upload your code, and create a PR for your addon

Create Branch of addons-source

Create a new branch of the current maintenance branch (gramps60).

git checkout gramps60
git checkout -b NewProjectName

Commit to Branch

To commit your changes so that others can see your addon source.

  • Add the project to the repository:
git add NewProjectName
  • Commit it with an appropriate message
git commit -m "A message describing what this addon is"

This update is now available for review by the Addons Repository maintainer. If they have questions, they will add Comments to the PR.

Create PR in maintenance branch

Create the PR for approval. This requests that the changes you created in the NewProjectName be merged with the gramps60 branch.

gh pr create --base gramps60 --head NewProjectName --title "Addon New Project Name" --body "This PR creates the addon New Project Name"

List and document your addon on the wiki

List your addon

Add a short description of your addon to the Addons list by editing the current release listing eg: 6.0_Addons or if the addon is meant for a future release 6.1_Addons when available.

Example addon template

Examine the listing for other addons and refer to the Addon list legend for details of on the meaning of each columns.

|- <!-- Copy this section and list your Addon -->
|<!-- Plugin / Documentation -->
|<!-- Type -->
|<!-- Image -->
|<!-- Description -->
|<!-- Use -->
|<!-- Rating (out of 4) -->
|<!-- Contact -->
|<!-- Download -->
|-

Document your addon

Document the addon in the wiki using the page name format of Addon:NewProjectName examine the other addon support pages for the general format to use.

Tango-Dialog-information.png
Hint on creating a new wiki page.

To create a new wiki page use the search box to search for the name of your page that doesn't exist then on the search results page you will be provided with a link to create the new page, by selecting and you can add your content


Example addon article

Consider including the following information:

<!-- Copy this section to your Addon support page-->
{{Third-party plugin}}<!-- This is a mediawiki template that expands out to display the standard addon message you see at the top of each addon page-->

<!--sections only add if needed-->
== Usage ==

=== Configure Options ===

==Features==

== Prerequisites ==

== Issues ==

<!--default categories-->
[[Category:Addons]]
[[Category:Plugins]]
[[Category:Developers/General]]

Announce the addon

Join the Gramps Forum and announce it to the users with general information on why you created and how to use it.

Support it through issue tracker

Become a user on the Gramps MantisBT (Mantis BugTracker). and please check it regularly. There is no automated notification of issues (and possible feature requests) related to your addon when reported by users.

Users tend to not understand coding and they make assumptions. So be kind and guiding if a report is ambiguous or inaccurate. A negative remark from an addon developer or anyone can be very discouraging.

Maintain the code as Gramps continues to evolve

Tango-Dialog-information.png
When submitting an update the patch part of the version number MAJOR.MINOR.PATCH is updated during the addon build process e.g. 1.1.3 to 1.1.4

You can find this step in addons-source/make.py.[1]


Remember that Gramps addons exist for many reasons and there are many Gramps developers that do support addons in various ways (translations, triage, keeping in sync with master, download infrastructure, etc).

Some reasons why the addons exist; they provide:

  • A quick way for anyone to share their work; the Gramps-project has never denied adding a addon.
  • A method to continuously update and develop a stand-alone component, often before being officially accepted.
  • A place for controversial plugins that will never be accepted into core, but are loved by many users (eg, Data Entry Gramplet).
  • A place for experimental components to live.

Example code adding common enhancements

Repository Management

There are steps that only the repo manager need complete once the gramplet has a PR submitted. If you are not managing a repo, you do not need to do any of these steps.

Gnome-important.png
These instructions, the make.py script etc.

are designed to operate in a Linux environment. They won't work on Windows without modifications.

Prerequisites

  • Gramps uses Python version 3.2 or higher. You must have at least that version installed. If you have installed Gramps 4.2 or higher on your Linux system already, then a sufficient version of Python will be present. If you have more than one version of Python installed, then you must use the correct version for these scripts. On some systems, both Python 2.x and 3.x are installed. It is possible that the normal invocation of python starts up Python 2.x, and that to start up Python 3.x requires invoking with python3 or python3.4 etc. You can test the version by python –version or python3 –version. If this is so, replace any usage of 'python' in the examples below with the appropriate invocation.
  • The make.py used in construction of the addons requires that the LANGUAGE environment variable be set to 'en_US.UTF-8'.
  • The make.py used in construction of the addons requires that the GRAMPSPATH environment variable be set to your path to the Gramps source tree.
  • intltool must be installed;
sudo apt-get install intltool

For example if your home directory is '/home/name' and you use the suggested path names, use

GRAMPSPATH=/home/name/gramps LANGUAGE='en_US.UTF-8' python3 make.py ...

to replace the ./make.py in the examples below.

Package your addon

To create a downloadable package:

./make.py gramps60 build NewProjectName or
./make.py gramps52 build NewProjectName for the older 5.2 branch.

Addons should not be created on the master branch.

Gramps-notes.png
Note:

Running the command make.py xxx build will increment the third number in your dotted version number of all addons in the *.gpr.py file. Consider this number to be a "build number".

This will leave your 'addons-source' with untracked changes according to git. The updated 'NewProjectName/NewProjectName.gpr.py ' is ready to add and commit.

Commit the updated gpr.py

 cd addons-source
 git add gramps60/download/NewProjectName.gpr.py
 git commit -m "Updated new plugin gpr: NewProjectName"

Commit the updated compressed tar file:

 cd ../addons
 git add gramps60/download/NewProjectName.addon.tgz
 git commit -m "Added new plugin: NewProjectName"

List your addon in the Gramps Plugin Manager

Gnome-important.png
Gramps needs to have been built

Make sure you have already built gramps60 or master. Change to the appropriate git branch in your gramps directory, and run python3 setup.py build See Linux:Build_from_source

To create a listing:

cd '~/gramps-addons' or wherever you have built your addon
GRAMPSPATH=path/to/your/gramps/install ./make.py gramps60 listing NewProjectName


That will create a series of files in the ../listings/ directory.

Then commit the updated listing to GitHub:

 cd addons
 git add gramps60/listings/*
 git commit -m "Added new plugin to listings: NewProjectName"


Commands to compile translations using make.py

You need the gramps.pot file that is currently being used for the Weblate translations in your local gramps 6.0 tree. It is used to exclude strings from the Addons translation component that have already been translated in the core Program component. This is:

https://github.com/gramps-project/gramps/blob/maintenance/gramps60/po/gramps.pot


Translation workflow with make.py:

  1. Run the command init to add any new strings to the template.pot file.
  2. The command aggregate-pot is run to aggregate all the addon template.pot files into a single po/addons.pot file which is then used by Weblate for translations. Note: The GRAMPSPATH environment variable must be set to a current gramps60 repository for this step. If run with no updates in any template.pot, the resulting addons.pot file will only have a timestamp update. In this case, it does not need merged back.

The Weblate translators can now translate the strings. Weblate generates a pull request. This can be merged on a regular basis. You can do this from the GitHub GUI, but don’t squash the commits.

The local.po files (which were updated by Weblate) are updated for publishing using the extract-po command. These updates should be merged back to the gramps60 branch.

At this point, the translations are committed but not published. Since publishing updates every addon, the timing for this action is TBD.

Example use of make.py

  • If you run the aggregate-pot command without any recent commits, the only change is to the POT-Creation-Date line.
  • As a test, if you change a single string in the AllNamesQuickview addon and then run init, you see the change and also the string at line 5 in the source code gets moved. Then if you run aggregate-pot you see the modified string and a moved string. This shouldn’t cause a problem.


Pre-6.0 only

Tango-Dialog-information.png
From Gramps 6.x translations can be done on Weblate. Initial testing has appeared successful, but please let us know if you notice any problems. The Weblate Addons component contains aggregated translations for every addon.

https://hosted.weblate.org/projects/gramps-project/addons/


Get translators to translate your addon into multiple languages

If you designed for localization, the addon will begin supporting a single language. Make your addon inviting for volunteers to translate it into their native language.

  • Initialize and update the template.pot for your addon:
cd ~/addons-source
./make.py gramps52 init NewProjectName
  • You should edit the header of template.pot with your information, so it gets copied to individual language files.
  • Initialize a language for your addon (say French, fr):
./make.py gramps52 init NewProjectName fr
  • Update it from gramps and other addons:
./make.py gramps52 update NewProjectName fr
  • Edit the translations file manually:
/NewProjectName/po/fr-local.po
  • Compile the language:
./make.py gramps5 compile NewProjectName
  • Add or update your local language file, and commit changes:
git add NewProjectName/po/fr-local.po
git commit NewProjectName/po/fr-local.po -m "Added fr po file"
  • If you have been given 'push' rights to GitHub 'gramps-project/addons-source', then;
git push origin gramps52


Resources

Gramps Addons site for Gramps 4.2 and newer
Gramps Addons site for Gramps 4.1 and older

Addon Development Tutorials and Samples