Always follow PEP-8 with the exception of line breaks.
New features should be developed always in its own branch. When creating your own branch,
please prefix that branch by the date of creation.
For example, if you begin working on implementing pagination on 6th April 2023, the branch could be called 2023-04-06-pagination
.
Prepend you commits with a shortcut indicating the type of changes they contain:
BUG
: Bug fixCI
: Changes to the CI configurationDEP
: Update in 3rd-party dependenciesDOC
: Changes to documentation stringsENH
: Enhancement (e.g. a new feature)MAINT
: Maintenance (e.g. fixing a typo)TST
: Changes to the unit test environmentWIP
: Work in progress
The dtool-lookup-gui uses GTK 3 to provide a platform-independent graphical user interface (GUI). GTK originates at the GNOME project. At it's core sits GLib, and on top of that lives the GObject library. Again higher live the Gio and Gdk libraries and on top of them all the GTK toolkit. The dtool-lookup-gui interfaces all GLib, GObject, Gio, Gtk, and Gdk functionality with PyGObject. The Python GTK+ 3 Tutorial helps with learning how to build GTK applications with Python.
GTK applications run asynchronously in the GLib main event loop. gbulb provides an implementation of the PEP 3156 interface to this GLib event loop for Python-native use of asyncio.
Within the dtool-lookup-gui's code, and importantly within test/conftest.py
you will hence find gbulb
bits that configure asyncio
and GTK
to share the same event loop.
Next to signals and events, actions are an important concept. Actions implement functionality that is not necessarily bound to a specific element in the graphical representation. Wrapping as much behavior as possible into atomic actions helps to structure the code and let the application evolve in the spirit of a clean separation between model, view, and controlling logic (MVC software design pattern). Furthermore, actions can be evoked by other means than user interaction via the GUI, such as via the command line or a keyboard shortcut. They facilitate writing unit tests as well.
When implementing new features, think about how to break them down into atomic actions.
In most cases, you will want to use the Gio.SimpleAction interface.
You will find usage examples within the code, in the GTK Python developer handbook: Working with GIO Actions.
Write actions as methods prefixed with do_*
, e.g. do_search
and attach them to the app itself or to the window they relate to.
Write at least one unit test for each action, e.g. test_do_search
for the action do_search
.
For testing, we mock the dtool_lookup_api
in conftest.py
to return dummy data on all API calls used within dtool-lookup-gui
.
With for functionality packed in atomic actions, it is then straight forward to write unit tests.
We aim at writing two test cases for each action. One test case directly calls the action, e.g. app.do_reset_config(...)
and tests against its operation on the provided dummy data without mocking anything other than the dtool_lookup_api
calls.
The second test mocks many internal functions evoked by an action, activates the action via the intended GTK framework mechanism, e.g. app.activate_action('reset-config')
and subsequently asserts the expected evocation of mocked methods.