Thanks for your interest in contributing to Formiko!
Formiko is a GNOME/GTK desktop application before anything else. When in doubt, prefer the option that fits the platform over the one that is merely convenient in Python:
- Follow the GNOME Human Interface Guidelines for UI, layout, icons and interaction patterns. New windows, dialogs and widgets should look and behave like a native GNOME application, not like a generic cross-platform toolkit app.
- Prefer GTK/GLib idioms (
Gio.Settings,Gtk.Applicationactions, signals,GObjectproperties) over ad-hoc Python state where GTK already offers a standard mechanism. Formiko already reads system font settings via GNOMEgsettings(seeformiko/window.py) — new features should integrate with the desktop the same way rather than reinventing configuration or storage. - Do not add behaviour that conflicts with GNOME conventions: no custom
window chrome/title bars unless following
Adwaita/libadwaitapatterns, no blocking the main loop (use GLib idle/timeout or async APIs), no silently writing files or telemetry a GNOME user wouldn't expect. - This does not override sane Python practice — GNOME/GTK conventions govern how the app behaves and is structured, PEP 8 / PEP 257 still govern how the Python code is written (see below). The two are not in conflict; when they appear to be, ask before picking one over the other.
Formiko is distributed as a Flatpak, so changes should stay sandbox-friendly:
- Don't assume unrestricted filesystem access — use portals
(
xdg-desktop-portal,Gtk.FileChooserNative, etc.) for file access instead of raw paths outside the sandbox. - Don't shell out to host tools that may not exist inside the Flatpak runtime; if an external tool is genuinely required, check it degrades gracefully when missing.
- Keep the application id (
cz.zeropage.Formiko) consistent across the.desktopfile,.metainfo.xmland any code that references it (e.g.StartupWMClass,Gio.Settingsschema paths). - If a change affects the runtime/SDK version, permissions, or added dependencies, mention it explicitly in the PR description — those need a matching update in the Flatpak manifest maintained outside this repository.
Formiko targets Python 3 and follows PEP 8 / PEP 257 conservatively. Linting is enforced locally and in CI — please run it before opening a PR, not after:
ruff(seeruff.toml) — a fairly wide rule set (pyflakes, pycodestyle, pydocstyle, bugbear, simplify, pylint subset, …), 79-column line length. Fix what ruff reports rather than adding newnoqa/ignore entries; if a rule genuinely doesn't apply, discuss it in the PR instead of silencing it locally.flake8— runs alongside ruff via pre-commit.codespell— spelling is checked repo-wide (config inpyproject.toml); fix typos rather than adding words to the ignore list unless they are genuine false positives (e.g. GObject Introspection's.girfiles).rst-linter(pre-commit-hooks-markup) — for.rstdocumentation.- Standard pre-commit hygiene: no trailing whitespace, files end with a newline, YAML stays valid.
Install and enable the hooks once per checkout:
pip install pre-commit pre-commit install
Then just git commit as usual; if a hook rewrites a file, review the
diff, git add it, and commit again.
Tests live under tests/ and run with pytest (see
[tool.pytest.ini_options] in pyproject.toml). Add or update tests
for any behavioural change.
Tests must pass without a graphical session — no X11 or Wayland display
server (e.g. unset DISPLAY WAYLAND_DISPLAY before running them, as CI
does). This does not mean that GTK, GObject Introspection, or the GTK
typelibs are optional: the test environment still needs the libraries
used by the imported code. Keep application state and file-discovery logic
separate from GTK widgets so it can be tested in this job.
GTK integration tests are marked gtk_integration and run in a separate
job under a private headless Mutter Wayland compositor. They use real GTK
objects, but do not connect to or display anything in the user's desktop.
Run them locally with the same kind of isolated compositor used by CI:
dbus-run-session -- mutter --wayland --no-x11 --sm-disable --headless --
python3 -m pytest -m gtk_integration -q. The normal test job keeps
DISPLAY and WAYLAND_DISPLAY unset and excludes these integration
tests.
Sanity check: env -u DISPLAY -u WAYLAND_DISPLAY python3 -m pytest
-m "not gtk_integration" -q should pass without a graphical session. The
full suite, including GTK integration tests, requires the private Mutter
headless compositor described above.
Prefer a precise but modest commit message: describe what changed, in
one short line, without embellishment. A commit message documents the
change for other developers reading git log — it does not need to
sell the change or restate the obvious from the diff.
Good:
Fix RST include directive with relative paths
Avoid:
Massive improvement to include handling, finally works great!
If more explanation is genuinely needed, add it as a short body after a blank line — still plain and factual, not a marketing pitch.
The ChangeLog file is written for users, not just developers —
keep that audience in mind. Not every commit deserves an entry; add one
when a change is something a user would notice or care about (a new
feature, a fixed bug, a behaviour change), and skip it for purely
internal changes (refactors, lint fixes, CI tweaks, typo fixes with no
user-visible effect).
When an entry is warranted:
- Add it under the current
Version X.Y.Z.devheading at the top ofChangeLog, following the existing bullet style. - Keep it short and clear — one line for a simple change, with nested sub-bullets only if the feature genuinely has multiple user-facing parts (see the existing entries for the tab support or custom directives as examples of when that's warranted).
- Write it in plain language a non-developer user can understand; avoid internal file/function names, issue numbers, or implementation detail that only makes sense to someone reading the code.
- Keep PRs focused — one logical change per PR is easier to review than a bundle of unrelated fixes.
- Make sure
pre-commitandpytestpass locally before opening the PR; CI runs the same checks (see.github/workflows). - Mention any GNOME/GTK HIG or Flatpak sandboxing implications in the PR description, even if you believe they don't apply — it saves a review round-trip.