diff --git a/doc/_static/singlehtml_nav_fix.js b/doc/_static/singlehtml_nav_fix.js new file mode 100644 index 0000000..0fa24a0 --- /dev/null +++ b/doc/_static/singlehtml_nav_fix.js @@ -0,0 +1,17 @@ +/** + * Fix broken sidebar navigation links generated by pydata-sphinx-theme + * in singlehtml mode. + * + * The theme produces hrefs like "#document-installation#how-to-install" + * (double fragment) instead of "#how-to-install". This script strips the + * "document-#" prefix so the browser navigates to the correct anchor. + */ +document.addEventListener("DOMContentLoaded", function () { + document.querySelectorAll("a.nav-link, a.reference.internal").forEach(function (a) { + var href = a.getAttribute("href"); + if (href && href.indexOf("#") !== href.lastIndexOf("#")) { + // Keep only the last fragment: "#doc-name#section" → "#section" + a.setAttribute("href", "#" + href.split("#").pop()); + } + }); +}); diff --git a/doc/cli.rst b/doc/cli.rst new file mode 100644 index 0000000..690bc47 --- /dev/null +++ b/doc/cli.rst @@ -0,0 +1,120 @@ +Command-Line Reference +====================== + +ModuleTester provides two entry points: the **GUI launcher** and the +**CLI utility**. + + +GUI launcher: ``moduletester`` +------------------------------ + +Launch the graphical interface. + +.. code-block:: console + + $ moduletester [OPTIONS] + +**Options** + +.. list-table:: + :header-rows: 1 + :widths: 20 15 65 + + * - Flag + - Type + - Description + * - ``-p``, ``--package`` + - str + - Python package to load on startup. The package must be importable. + * - ``-f``, ``--file`` + - str + - Path to a ``.mt`` project file to open on startup. + +**Examples** + +.. code-block:: console + + # Launch with no project (empty window) + $ moduletester + + # Open directly on a package + $ moduletester -p guidata + + # Open a saved project file + $ moduletester -f /path/to/project.mt + +.. note:: + + ``--package`` and ``--file`` are mutually exclusive. If both are provided, + only one will be used. + + +CLI utility: ``moduletester-cli`` +--------------------------------- + +Run tests and export reports without the GUI. + +.. code-block:: console + + $ moduletester-cli [OPTIONS] + +**Commands** + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Command + - Description + * - ``run `` + - Run all tests of the given Python package headlessly. + * - ``export `` + - Export test results to a document. + +**Export options** + +.. list-table:: + :header-rows: 1 + :widths: 20 15 65 + + * - Flag + - Type + - Description + * - ``--output`` + - str + - Output file path. The format is inferred from the file extension + (``.html``, ``.docx``, ``.odt``, ``.pdf``, ``.md``, ``.rst``). + +**Examples** + +.. code-block:: console + + # Run all tests of a package + $ moduletester-cli run mypackage + + # Export results to HTML + $ moduletester-cli export mypackage --output report.html + + +Python API +---------- + +You can also launch ModuleTester programmatically: + +.. code-block:: python + + from moduletester.gui.main import run_gui + + # Launches the GUI (blocking call) + run_gui() + +Or use the ``run()`` function for more control: + +.. code-block:: python + + from guidata.qthelpers import qt_app_context + from moduletester.gui.main import run + + with qt_app_context(True): + main = run(package="mypackage") + main.window.show() diff --git a/doc/conf.py b/doc/conf.py index 7ff14c4..179fab5 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -34,6 +34,7 @@ html_theme_options = {"show_toc_level": 2} htmlhelp_basename = project html_static_path = ["_static"] +html_js_files = ["singlehtml_nav_fix.js"] # -- Options for sphinx-intl package ----------------------------------------- diff --git a/doc/configuration.rst b/doc/configuration.rst new file mode 100644 index 0000000..9925f20 --- /dev/null +++ b/doc/configuration.rst @@ -0,0 +1,211 @@ +Configuration Reference +======================= + +ModuleTester is configured through an INI file named ``moduletester.ini`` +placed at the root of the target Python package. When ModuleTester loads a +package, it looks for this file automatically. + +If the file is absent, default values are used for every option. + + +Complete example +---------------- + +.. code-block:: ini + + [general] + docstring_fmt = rst + category = visible + + [export] + template_dir = default_templates + test_results_template_name = test_results_template.j2 + test_list_template_name = test_list_template.j2 + docx_reference = custom-reference.docx + odt_reference = custom-reference.odt + css_style = default_style.css + export_fmts = html, docx + reload_templates_on_export = 0 + docstrings_header_shift = 3 + toc_depth = 2 + + [gui] + test_list_visible = 1 + test_list_pos = left + test_props_visible = 1 + test_props_pos = right + result_tab_visible = 1 + result_tab_pos = bottom + result_props_visible = 1 + result_props_pos = right + cli_visible = 0 + cli_pos = bottom + toolbox_visible = 0 + toolbox_pos = bottom + + +``[general]`` section +--------------------- + +.. list-table:: + :header-rows: 1 + :widths: 25 10 15 50 + + * - Option + - Type + - Default + - Description + * - ``docstring_fmt`` + - str + - ``rst`` + - Format used to interpret test docstrings. Supported values: ``rst`` + (reStructuredText), ``md`` (Markdown), ``plain`` (plain text). + * - ``category`` + - str + - ``visible`` + - Which test category to load. ``visible`` loads only scripts annotated + with ``# guitest: show``. ``all`` loads every script in the package. + + +``[export]`` section +-------------------- + +.. list-table:: + :header-rows: 1 + :widths: 25 10 15 50 + + * - Option + - Type + - Default + - Description + * - ``template_dir`` + - str + - ``default_templates`` + - Path to the directory containing Jinja2 templates, CSS, and reference + documents. Relative paths are resolved from the package directory. + * - ``test_results_template_name`` + - str + - ``test_results_template.j2`` + - Filename of the Jinja2 template used for test result reports. + * - ``test_list_template_name`` + - str + - ``test_list_template.j2`` + - Filename of the Jinja2 template used for test list documents. + * - ``docx_reference`` + - str + - ``custom-reference.docx`` + - Filename of the DOCX reference document used by Pandoc for styling + Word exports. + * - ``odt_reference`` + - str + - ``custom-reference.odt`` + - Filename of the ODT reference document used by Pandoc for styling + LibreOffice exports. + * - ``css_style`` + - str + - ``default_style.css`` + - Filename of the CSS stylesheet embedded in HTML exports. + * - ``export_fmts`` + - list + - ``html, docx`` + - Comma-separated list of export formats enabled in the GUI export + dialog. Supported values: ``html``, ``docx``, ``odt``, ``pdf``, + ``rst``, ``md``. + * - ``reload_templates_on_export`` + - bool + - ``0`` + - When set to ``1``, templates are reloaded from disk on every export. + Useful during template development. + * - ``docstrings_header_shift`` + - int + - ``3`` + - Number of heading levels to shift when rendering docstrings inside + the exported document (avoids clashing with report headings). + * - ``toc_depth`` + - int + - ``2`` + - Maximum depth of the table of contents generated in HTML exports. + + +``[gui]`` section +----------------- + +Each dockable panel has two options: ``*_visible`` (boolean, ``0`` or ``1``) +controls whether the panel is shown on startup, and ``*_pos`` (string) +controls its initial dock position (``left``, ``right``, ``top``, or +``bottom``). + +.. list-table:: + :header-rows: 1 + :widths: 25 10 15 50 + + * - Option + - Type + - Default + - Description + * - ``test_list_visible`` + - bool + - ``1`` + - Show the test list tree view on startup. + * - ``test_list_pos`` + - str + - ``left`` + - Dock position of the test list panel. + * - ``test_props_visible`` + - bool + - ``1`` + - Show the test properties panel on startup. + * - ``test_props_pos`` + - str + - ``right`` + - Dock position of the test properties panel. + * - ``result_tab_visible`` + - bool + - ``1`` + - Show the execution results panel (Comment/Output/Error tabs) on + startup. + * - ``result_tab_pos`` + - str + - ``bottom`` + - Dock position of the execution results panel. + * - ``result_props_visible`` + - bool + - ``1`` + - Show the result properties panel on startup. + * - ``result_props_pos`` + - str + - ``right`` + - Dock position of the result properties panel. + * - ``cli_visible`` + - bool + - ``0`` + - Show the CLI command panel on startup. + * - ``cli_pos`` + - str + - ``bottom`` + - Dock position of the CLI command panel. + * - ``toolbox_visible`` + - bool + - ``0`` + - Show the toolbox panel on startup. + * - ``toolbox_pos`` + - str + - ``bottom`` + - Dock position of the toolbox panel. + + +Error handling +-------------- + +When loading ``moduletester.ini``, the following errors may occur: + +- **ConfigConflictError**: raised when the INI file contains extra keys not + recognised by ModuleTester, or is missing expected keys. If you pass + ``resolve=True`` to the loader, ModuleTester will automatically add missing + keys with default values and remove unknown keys. + +- **InvalidPathError**: raised when a path option (``template_dir``, + ``docx_reference``, ``odt_reference``, ``css_style``, or template names) + points to a file or directory that does not exist. + +See :doc:`faq` for troubleshooting tips. diff --git a/doc/faq.rst b/doc/faq.rst new file mode 100644 index 0000000..49efbf2 --- /dev/null +++ b/doc/faq.rst @@ -0,0 +1,132 @@ +FAQ & Troubleshooting +===================== + + +No tests found after loading a package +--------------------------------------- + +**Symptom**: ModuleTester opens but the tree view is empty. + +**Cause**: Test scripts must contain the ``# guitest: show`` annotation for +ModuleTester to discover them. + +**Fix**: Add the following comment at the top of each test file: + +.. code-block:: python + + # guitest: show + +Alternatively, set ``category = all`` in the ``[general]`` section of +``moduletester.ini`` to load every script regardless of annotations. + +See :doc:`user_guide` for more details on test discovery. + + +Pandoc not found +---------------- + +**Symptom**: Export fails with a message about Pandoc not being available. + +**Cause**: ModuleTester uses `Pandoc `_ (via +`pypandoc `_) to convert reports to +DOCX, ODT, PDF, and other formats. + +**Fix**: Install Pandoc using one of these methods: + +.. code-block:: python + + import pypandoc + from pypandoc.pandoc_download import download_pandoc + download_pandoc() + +Or download it directly from https://pandoc.org/installing.html. + +After installation, verify with: + +.. code-block:: python + + import pypandoc + print(pypandoc.get_pandoc_path()) + + +Configuration conflict error +----------------------------- + +**Symptom**: ``ConfigConflictError`` when loading a package. + +**Cause**: The ``moduletester.ini`` file contains keys that do not match the +expected configuration schema — either unknown keys or missing required keys +(e.g. after upgrading ModuleTester). + +**Fix**: Delete or rename the ``moduletester.ini`` file and let ModuleTester +recreate it with default values. Alternatively, edit the file to match the +expected options listed in :doc:`configuration`. + + +Invalid path in configuration +------------------------------ + +**Symptom**: ``InvalidPathError`` when loading a package. + +**Cause**: A path option in ``moduletester.ini`` (``template_dir``, +``docx_reference``, ``odt_reference``, ``css_style``, or a template name) +points to a file or directory that does not exist. + +**Fix**: Check that all paths in the ``[export]`` section are correct and +that the referenced files exist. Relative paths are resolved from the +package directory. + + +Export produces empty or broken output +-------------------------------------- + +**Symptom**: The exported document is empty, malformed, or missing styles. + +**Possible causes**: + +- Pandoc is not installed (see above). +- The CSS stylesheet or reference document is missing or corrupted. +- A custom template has a Jinja2 syntax error. + +**Fix**: + +1. Verify Pandoc is installed and accessible. +2. Reset to default templates by removing the ``template_dir`` option from + ``moduletester.ini``. +3. Check the application console for Jinja2 error messages. +4. Set ``reload_templates_on_export = 1`` in ``moduletester.ini`` to force + template reloading during development. + + +Dark theme rendering issues on Windows 10 +------------------------------------------ + +**Symptom**: Some UI elements are hard to read with the dark theme on +Windows 10. + +**Cause**: Known compatibility issue with the Qt dark theme on Windows 10. + +**Fix**: This issue has been addressed in version 1.0.0. Make sure you are +running the latest version: + +.. code-block:: console + + $ pip install --upgrade ModuleTester + + +Test runs but result stays "None" +--------------------------------- + +**Symptom**: A test finishes but its result is not recorded. + +**Possible causes**: + +- The test process exited abnormally or was killed. +- An encoding error prevented output capture. + +**Fix**: Version 1.0.0 includes fixes for ``end_time`` remaining ``None`` +and for non-UTF8 output encoding. Upgrade to the latest version: + +.. code-block:: console + + $ pip install --upgrade ModuleTester diff --git a/doc/index.rst b/doc/index.rst index b7a499a..3a6f5d5 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -38,7 +38,12 @@ External resources: installation usage + user_guide + configuration + cli + templates example + faq changelog Copyrights and licensing diff --git a/doc/templates.rst b/doc/templates.rst new file mode 100644 index 0000000..de43e3f --- /dev/null +++ b/doc/templates.rst @@ -0,0 +1,178 @@ +Template Customisation +====================== + +ModuleTester uses `Jinja2 `_ templates +and `Pandoc `_ to generate reports in multiple formats. +You can customise the appearance and content of exported documents by +providing your own templates, CSS stylesheets, and reference documents. + + +Architecture overview +--------------------- + +The export pipeline works as follows: + +1. A Jinja2 template (``*.j2``) is rendered to an intermediate HTML string. +2. Pandoc converts the HTML to the target format (DOCX, ODT, PDF, etc.). +3. For HTML output, a CSS stylesheet is embedded directly in the file. +4. For DOCX/ODT output, a reference document controls styles and formatting. + +The export engine is implemented in ``moduletester.new_exporter`` and uses a +``FileSystemLoader`` pointed at the ``template_dir`` directory configured in +``moduletester.ini``. + + +Default templates +----------------- + +ModuleTester ships with the following files in its ``default_templates/`` +directory: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - File + - Purpose + * - ``test_results_template.j2`` + - Main report template. Renders test descriptions, commands, results, + and status icons grouped by sub-module. + * - ``test_list_template.j2`` + - Simplified template that lists tests without detailed results. + * - ``default_style.css`` + - CSS stylesheet embedded in HTML exports. Controls layout, code block + styling, and result formatting. + * - ``custom-reference.docx`` + - Word reference document used by Pandoc. Defines heading styles, fonts, + and page layout for DOCX exports. + * - ``custom-reference.odt`` + - LibreOffice reference document used by Pandoc. Same role as the DOCX + reference for ODT exports. + + +Using custom templates +---------------------- + +To override the default templates: + +1. Create a directory in your package (e.g. ``my_templates/``). + +2. Copy the default templates you want to modify into that directory. + +3. Set ``template_dir`` in your ``moduletester.ini``: + + .. code-block:: ini + + [export] + template_dir = my_templates + + The path is relative to the package root directory. + +4. Edit the copied templates as needed. + +.. tip:: + + Set ``reload_templates_on_export = 1`` in ``moduletester.ini`` while + developing templates. This forces ModuleTester to reload templates from + disk on every export, so you can iterate without restarting the + application. + + +Template variables +------------------ + +Inside a Jinja2 template, the main context object is ``doc_obj``, an instance +of ``DocumentExporter``. The most useful attributes are: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Variable + - Description + * - ``doc_obj.test_suite`` + - The ``TestSuite`` object containing all tests and results. + * - ``doc_obj.test_suite.package`` + - The ``Module`` object for the loaded package (name, path, etc.). + * - ``doc_obj.test_suite.package.full_name`` + - Fully qualified package name (e.g. ``guidata``). + * - ``doc_obj.test_suite.author`` + - Author string (or ``None``). + * - ``doc_obj.test_suite.last_run`` + - Date/time of the last test execution. + * - ``doc_obj.test_suite.tests`` + - List of all ``Test`` objects. + * - ``doc_obj.test_suite.group_tests()`` + - Returns a dict grouping tests by sub-module name. + * - ``doc_obj.docstrings_header_shift`` + - Heading level shift for embedded docstrings. + * - ``doc_obj.toc_depth`` + - Table of contents depth. + +Each ``Test`` object provides: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Attribute + - Description + * - ``test.package.last_name`` + - Test script filename (without path). + * - ``test.command`` + - The command line used to execute the test. + * - ``test.result`` + - The ``TestResult`` object (or ``None`` if not yet run). + * - ``test.result.result_name`` + - Human-readable result string (e.g. "Accepted", "Failed"). + * - ``test.result.result.icon_path`` + - Path to the status icon image. + * - ``test.result.last_run`` + - Date/time of this test's last run. + * - ``test.get_html_description(...)`` + - Renders the test docstring as HTML. + +The translation function ``_()`` is available globally in templates for +internationalised strings. + + +CSS customisation +----------------- + +The ``default_style.css`` file controls the appearance of HTML exports. You +can override it by placing your own CSS file in your custom template +directory and setting the ``css_style`` option: + +.. code-block:: ini + + [export] + css_style = my_style.css + +The CSS is embedded directly in the HTML output using Pandoc's +``--embed-resources`` flag. + + +DOCX and ODT reference documents +--------------------------------- + +Pandoc uses reference documents to control styles in Word and LibreOffice +exports. To customise: + +1. Open the default reference document (``custom-reference.docx`` or + ``custom-reference.odt``) in your word processor. + +2. Modify the styles (headings, body text, fonts, margins, etc.) without + changing the content structure. + +3. Save the modified file in your custom template directory and update + ``moduletester.ini``: + + .. code-block:: ini + + [export] + docx_reference = my-reference.docx + odt_reference = my-reference.odt + +See the `Pandoc documentation on reference documents +`_ for details on +which styles are used. diff --git a/doc/usage.rst b/doc/usage.rst index 913b012..1b2b06e 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -57,4 +57,16 @@ ModuleTester stores its configuration in a user-specific directory managed by `guidata `_. The configuration can be edited from the GUI via the **Settings** menu -or by editing the configuration file directly through the built-in editor. \ No newline at end of file +or by editing the configuration file directly through the built-in editor. + +See :doc:`configuration` for the full reference of all ``moduletester.ini`` +options. + + +Next steps +---------- + +- :doc:`user_guide` — step-by-step tutorial covering the full workflow +- :doc:`cli` — complete command-line reference +- :doc:`templates` — how to customise export templates +- :doc:`faq` — common issues and solutions \ No newline at end of file diff --git a/doc/user_guide.rst b/doc/user_guide.rst new file mode 100644 index 0000000..065d77e --- /dev/null +++ b/doc/user_guide.rst @@ -0,0 +1,138 @@ +User Guide +========== + +This guide walks you through the full ModuleTester workflow: setting up a +project, discovering tests, running them, and exporting reports. + + +Setting up your project +----------------------- + +ModuleTester discovers tests inside a Python package by looking for the +``# guitest: show`` annotation at the top of each test script. + +1. Make sure your package is importable (installed or on ``PYTHONPATH``). + +2. Add the annotation comment to every test file you want ModuleTester to + manage: + + .. code-block:: python + + # guitest: show + + def test_example(): + assert 1 + 1 == 2 + + Scripts without this annotation are ignored by default (see the + ``category`` option in :doc:`configuration`). + +3. *(Optional)* Create a ``moduletester.ini`` file at the root of your + package to customise export templates, GUI layout, and other options. + See :doc:`configuration` for the full reference. + + +Test discovery +-------------- + +When you open a package in ModuleTester, it uses +``guidata.guitest.get_test_package()`` to scan the package tree and collect +every script annotated with ``# guitest: show`` (or ``# guitest: skip`` to +explicitly exclude a script). + +The discovered tests are displayed in a **tree view** that mirrors the package +structure. Each node shows the test name, its last execution status, and the +date of the last run. + +.. figure:: images/shots/empty.png + :align: center + + ModuleTester main window with dockable panels and tree view navigation + + +Running tests +------------- + +**From the GUI** + +1. Launch ModuleTester on your package: + + .. code-block:: console + + $ moduletester -p mypackage + +2. Select one or more tests in the tree view. + +3. Click the **Run** button in the toolbar (or double-click a test). + +4. While a test is running, a spinner appears next to it in the tree view. + The **Output** and **Error** tabs in the Execution Results panel update + in real time. A notification icon appears when new output is available. + +5. When the test finishes, its status icon updates (accepted, failed, etc.). + +**From the command line** + +You can also run tests headlessly. See :doc:`cli` for details. + + +Viewing results +--------------- + +After execution, select a test in the tree view to inspect its results in +the dockable panels: + +- **Test Properties** — shows the test module path, command, and parameters. +- **Execution Results** — contains three tabs: + + - *Comment* — free-text field to annotate the result. + - *Output Message* — standard output captured during execution. + - *Error Message* — standard error captured during execution. + +- **CLI** — displays the exact command line used to run the test. + +.. figure:: images/shots/guidata.moduletester.png + :align: center + + Running tests on the ``guidata`` package — tree view with status icons, + test properties, and execution results panels + + +Working with project files +-------------------------- + +ModuleTester can save and load project files (**.mt** format) that persist +the test list, results, and comments. + +- **Save**: *File → Save* (or *Save As* for a new file). +- **Open**: *File → Open* and select an existing ``.mt`` file. +- **Reload**: *File → Reload* to refresh the test list from the package + without losing saved results. + +You can also open a project file directly from the command line: + +.. code-block:: console + + $ moduletester -f /path/to/project.mt + + +Exporting reports +----------------- + +ModuleTester can export test results to several document formats through its +Jinja2-based export engine. + +**Supported formats**: HTML, DOCX, ODT, PDF, Markdown, reStructuredText. + +**From the GUI** + +Use *File → Export* to generate a report. The export dialog lets you choose +the output format and destination. + +**From the command line** + +.. code-block:: console + + $ moduletester-cli export mypackage --output report.html + +See :doc:`templates` to learn how to customise the report appearance using +your own Jinja2 templates and CSS styles.