Skip to content

Pin GTK and GDK to 3.0 for the repo-root test suite#950

Merged
GaryGriffin merged 1 commit into
gramps-project:maintenance/gramps60from
eduralph:pin/gtk-gdk-3-unit-tests
Jun 15, 2026
Merged

Pin GTK and GDK to 3.0 for the repo-root test suite#950
GaryGriffin merged 1 commit into
gramps-project:maintenance/gramps60from
eduralph:pin/gtk-gdk-3-unit-tests

Conversation

@eduralph

Copy link
Copy Markdown
Contributor

Independent of #820 (based on clean maintenance/gramps60).

What

The repo-root tests/ suite — run by python3 -m unittest discover -s tests -p "test_*.py" -t . — imports gramps.gui.* modules directly, which bypasses the Gramps GUI launcher's own gi.require_version. On a host where GTK 4 is the default GI resolution, Gtk/Gdk then load unpinnedPyGIWarning and the risk of loading the wrong stack (GUI-touching tests can silently skip).

Pin both in tests/__init__.py, which unittest discover -s tests imports before any test module, so the whole repo-root suite runs on the GTK 3 / GDK 3 stack a real Gramps session uses:

gi.require_version("Gdk", "3.0")
gi.require_version("Gtk", "3.0")

tests/test_gtk_version_pin.py guards it (asserts both are pinned; skips where the 3.0 typelibs aren't installed).

Verification

python3 -m unittest discover -s tests -p "test_*.py" -t . → 3 tests OK, with the guard passing (get_required_version("Gtk"|"Gdk") == "3.0"). The guard is red without the pin (AssertionError: None != '3.0').

Draft until review/sign-off.

🤖 Generated with Claude Code

The tests/ suite (run by `python3 -m unittest discover -s tests`) imports
gramps.gui.* modules directly, which bypasses the Gramps GUI launcher's own
gi.require_version. On a host where GTK 4 is the default GI resolution, Gtk/Gdk
then load unpinned — emitting PyGIWarning and risking the wrong stack (and the
GUI-touching tests silently skipping).

Pin both in tests/__init__.py, which `unittest discover -s tests` imports before
any test module, so the whole repo-root suite runs on the GTK 3 / GDK 3 stack a
real Gramps session uses. tests/test_gtk_version_pin.py guards it (skips where
the 3.0 typelibs are absent).

Verified: `python3 -m unittest discover -s tests -p "test_*.py" -t .` pins both
(get_required_version == "3.0"); the guard is red without the pin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@eduralph eduralph marked this pull request as ready for review June 13, 2026 14:41
@GaryGriffin

GaryGriffin commented Jun 13, 2026

Copy link
Copy Markdown
Member

My typical approach is to run the tests manually. Will this migration to code in the upper level tests directory break the specific tests if they do not have the version pinning in Addon/tests/__init__.py? Or is the upper level tests/__init__.py also run in these cases?

python3 -m unittest Form.tests.test_form_validator
python3 -m unittest Form.tests.test_integration_form
python3 -m unittest Form.tests.test_editform_save_guards
python3 -m unittest LinesOfDescendency.tests.test_linesofdescendency_guards
python3 -m unittest libaccess.tests.test_libaccess_setattr
python3 -m unittest JSON.tests.test_jsonimport_ignored_log

@eduralph

Copy link
Copy Markdown
Contributor Author

@GaryGriffin it only works for full runs over all tests, not manual - yet. Once 820 lands, the command looks like this

PYTHONPATH=.github/scripts/gi_bootstrap python3 -m unittest Form.tests.test_form_validator

You can make it work right now with

python3 -m unittest tests.test_make_listing Form.tests.test_

important is that you call tests.test_make_listing first. How about extending the make.py to commands like

python3 make.py <gramps_version> <command> [addon]

?

@GaryGriffin

Copy link
Copy Markdown
Member

Why not put it in the Addon/tests/__init__.py as needed. Nothing breaks, unittest works as expected (without touching the tests directory), doesn't violate the principal of least astonishment.

@eduralph

eduralph commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

Why not put it in the Addon/tests/__init__.py as needed. Nothing breaks, unittest works as expected (without touching the tests directory), doesn't violate the principal of least astonishment.

You could put it there, but then you need to make sure that every implementor thinks of this. I was trying to abstract it away from the Addon developer. The GraphView implemented it's own pinning and dependency loading which is great that the author thought of, but also counter productive because that broke the unit testing with dogtail and doesn't conform to the loading rules with Gramps.

There are 2 ways to solve this: have clear guidelines on what the Addon developer must and musn't do or you need to find a way to abstract it.

I have been building some guidelines which I will put up for review once I feel the quality is sufficient and I've seen there are contributing pages in the repository and more in the wiki itself. I've been working on automating it as well and we can include if 820 lands, but it's always better to hide such implementation details.

This is here is the attempt of "abstracting" it which honestly works great if you are testing everything but breaks in your scenario.

Ultimately, you have to choose your poison here. We can close this item and stick with the guideline approach if you like.

@dsblank

dsblank commented Jun 14, 2026

Copy link
Copy Markdown
Member

I will always vote for the abstraction, and making it easy on the addon developer.

This seems like a good compromise:

python3 make.py <gramps_version> <command> [addon]

@GaryGriffin

Copy link
Copy Markdown
Member

I have been building some guidelines

I added some comments there. Great work.

Question - does every addon test folder need the pinning? Or just some of them? I thought it was just some. I see 28 unittests currently and 14 have import gi. I dont see any errors or warnings on the other 14. And some do not have require_version for Gdk, just for Gtk. I am just trying to understand the scope of the issue.

If all addons need Gtk/Gdk pinning, then abstraction makes sense. Is there any sense that in the future, there will be additional needs for pinning (easier to add in a single location rather than in each test case)?

I see two users for testing: Developer generating tests; CI running tests. I have been focused on the first case. The second case gets automated. Is abstracting making it easier or harder for the developer to add a unittest?

Do addon developers normally have a built source tree locally? That is needed for them to run make.py . I know I developed addons for years without a locally built source tree. And make.py syntax seems weird to use for testing since the <gramps_version> is irrelevant. I can imagine someone running make.py gramps61 unittest Addon for testing all the unittests of an Addon, but it is still weird to include the version when it is not needed. And this may be the only time the developer uses make.py (unless they have their own repo).

As the maintainer, it would be much easier for me to use make.py version unittest Addon, but what about the developer?

Sorry for the ramblings.

@eduralph

Copy link
Copy Markdown
Contributor Author

I added some comments there. Great work.

Thanks, I'll make sure they find their way back in.

Question - does every addon test folder need the pinning? Or just some of them? I thought it was just some.

Not all need pinning necessarily - strictly speaking, only the ones that have any GUI elements. The core problem is that Gramps implements a certain environment and provides some infrastructure that the Addons can then use if they need to. GTK pinning and loading of dependencies are the two I'm currently aware of, there might be more or Gramps might choose to implement more sometime later.

The Addon developer should be shielded from the "dirty details" to be able to focus on their core objective: building logic. The problem we've seen is that developers write their unit code with certain assumptions that don't hold true.

For example the bsdbb tests (that's core, but the example still counts) was written with the assumption that bsdbb modules are installed and started failing on systems where they could no longer be loaded. The reason they didn't get noticed was because the Exception got swallowed, showing all green.

Similar with the GraphView logic where the developer realized there were dependencies they needed to take care of, but didn't realize it was handled by Gramps and therefore wrote dependency loading logic. The problem was that it worked fine in the Gramps environment because it had already loaded there and the developer had written the logic without any infrastructure around it.

You do need to provide a baseline and that can be the CI 820 PR, but that will make assumptions about the environment (e.g. loading dependencies, GTK pinning, etc.) that aren't given with the Addon unless the developer thinks of implementing it at Addon level. The result will be that the unit tests run fine for the Addon developer in their local environment and fail when trying to submit a PR.

I see two users for testing: Developer generating tests; CI running tests. I have been focused on the first case. The second case gets automated. Is abstracting making it easier or harder for the developer to add a unittest?

Yes, you are right to ask about that. As I said: you need to choose which way you want to go, both are valid options. The reason I chose the "central" instead of "distributed" variant was that it's easier to change if the Gramps environment changes. It might end up breaking several Addons, but that's a benefit: we see which Addons have issues with whatever Gramps changes are introduced (e.g. a switch to Gtk 4.0) while in the distributed case, we'd have to update all Addons.

Do addon developers normally have a built source tree locally? That is needed for them to run make.py . I know I developed addons for years without a locally built source tree.

No, not necessary. We are extending what the make.py does.

And make.py syntax seems weird to use for testing since the <gramps_version> is irrelevant.

That's an "flurish" which we can also drop. I was just considering if developers want to use it to test for the upcoming release, etc. like now: build it for 6.0 but test it for 6.1 to be ready.

As the maintainer, it would be much easier for me to use make.py version unittest Addon, but what about the developer?

We can do it that way.

Sorry for the ramblings.

I rather you questioning every aspect based on your experience then introducing something that doesn't fit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants