Contribution Guidelines¶
Note: Before reading this section, it is recommended to read the Code Style Guidelines first, which covers coding conventions, naming rules, type hints, docstring format, and code quality checks that all contributions must follow.
Welcome to the ZooUI contribution guidelines! We appreciate your interest in contributing to this project.
Project Expectations¶
Important Notice: This is an open-source project maintained on a voluntary basis. Please do not expect:
Bug fixing on demand
Feature requests to be implemented by maintainers
However, contributions are welcome at any level, including:
Feature implementations
Bug fixes
Test improvements
Documentation enhancements
All contributions will be reviewed as soon as possible. Forking the repository is encouraged for any purpose that respect the GNU General Public License v3 terms.
Getting Started with Contributing¶
Fork the Repository
Start by forking the ZooUI repository on GitHub to your own account.
Clone Your Fork
git clone https://github.com/YOUR_USERNAME/pyzui.git cd zooui
Set Up the Development Environment
Follow the installation instructions in the ZooUI Installation section:
Install Miniconda and create a Python 3.12.12 environment:
conda create -n <env-name> python=3.12.12 conda activate <env-name>
Install core dependencies from the default Anaconda channel:
conda install pyside6=6.7.2 pillow=12.0.0 pyvips=3.0.0
Install additional dependencies from conda-forge:
conda install -c conda-forge poppler=24.12.0
Install testing dependencies:
conda install pytest
Install linting and type-checking tools from conda-forge:
conda install -c conda-forge ruff mypy pre-commit
Install the pre-commit hooks (one-time setup):
pre-commit install
Create a Feature Branch
git checkout -b feature/your-feature-name
The type of feature you are implementing determines how you should structure your code and tests. There are three main scenarios:
Scenario A: Adding a New Class or Method to an Existing Module
When adding a new class or method to an existing
.pymodule (e.g., adding a newCacheTileProviderclass totileproviders/or adding a newmerge_tiles()method totile.py):Locate the corresponding test file that already exists for the module (e.g.,
test/unittest/tilesystem/test_tile.py)Add new test methods to the existing test class, or create a new test class within the same test file if testing a new class
Follow the existing test structure in that file
Guidelines for adding test methods:
# In test/unittest/tilesystem/test_tile.py # If adding a new method 'merge()' to the Tile class: class TestTile: """Existing test class for Tile""" # ... existing tests ... def test_merge_two_tiles(self): """ Scenario: Merge two tiles horizontally Given two tiles of equal height When merge is called with horizontal orientation Then a new tile with combined width is returned """ # Test implementation def test_merge_with_none_tile(self): """ Scenario: Merge with None tile Given a valid tile and a None value When merge is called Then it should handle the None gracefully """ # Test implementation # If adding a new class 'TileBatch' to tile.py: class TestTileBatch: """ Feature: Tile Batch Operations The TileBatch class manages collections of tiles for batch processing. """ def test_init(self): """ Scenario: Initialize a tile batch Given a list of tiles When a TileBatch is created Then it should store all tiles """ # Test implementation
Scenario B: Modifying an Existing Class or Method
When modifying the behavior of an existing class or method (e.g., changing how
Tile.crop()handles edge cases, or adding parameters to an existing method):First, run the existing tests to understand current expected behavior
Determine if existing tests need modification:
Modify existing tests when the expected behavior changes (e.g., a method now returns a different type, or handles inputs differently)
Add new tests when you’re adding new functionality without changing existing behavior (e.g., adding optional parameters with default values)
Do both when the modification changes some behaviors and adds new ones
Guidelines for modifying existing test methods:
# BEFORE: Original test for crop method def test_crop(self): """ Scenario: Crop a tile to smaller region ... """ t = Tile(qimage) cropped = t.crop((10, 10, 50, 50)) assert cropped.size == (40, 40) # AFTER: If crop() now accepts an optional 'mode' parameter # Update docstring to reflect new behavior def test_crop(self): """ Scenario: Crop a tile to smaller region with default mode Given a tile with size 100x100 When cropping to region (10, 10, 50, 50) without specifying mode Then the default mode should be used And the new tile size should be 40x40 """ t = Tile(qimage) cropped = t.crop((10, 10, 50, 50)) # Uses default mode assert cropped.size == (40, 40) # ADD: New test for the new parameter def test_crop_with_clamp_mode(self): """ Scenario: Crop with clamp mode enabled Given a tile with size 100x100 When cropping with mode='clamp' Then pixels outside bounds should be clamped """ t = Tile(qimage) cropped = t.crop((10, 10, 150, 150), mode='clamp') assert cropped.size == (90, 90) # Clamped to available size
When to modify vs. add tests:
Modify Existing Tests
Add New Tests
Return type changes
New optional parameters with default values
Method signature changes (required parameters)
New edge case handling
Exception types change
Additional validation added
Core algorithm changes affecting output
Performance optimizations (behavior unchanged)
Scenario C: Creating a Completely New Module
When creating a new
.pymodule (e.g.,zooui/tilesystem/tileoptimizer.py):Create a corresponding test file mirroring the source structure
Include all necessary imports and fixtures
Create test classes for each class in the module
Ensure comprehensive coverage from the start
Guidelines for creating a new test module:
# File: test/unittest/tilesystem/test_tileoptimizer.py """ Unit Tests: Tile Optimizer ========================== This module contains unit tests for the TileOptimizer class which handles tile compression and quality optimization. """ import pytest from unittest.mock import Mock, patch, MagicMock from PIL import Image from zooui.tilesystem.tileoptimizer import TileOptimizer, OptimizationResult class TestTileOptimizer: """ Feature: Tile Optimization The TileOptimizer class provides methods for optimizing tile storage size while maintaining visual quality. """ def test_init(self): """ Scenario: Initialize tile optimizer with default settings Given no parameters When a TileOptimizer is instantiated Then it should use default quality settings """ optimizer = TileOptimizer() assert optimizer.quality == 85 assert optimizer.format == 'jpg' def test_init_with_custom_quality(self): """ Scenario: Initialize with custom quality Given a quality parameter of 95 When a TileOptimizer is instantiated Then it should use the specified quality """ optimizer = TileOptimizer(quality=95) assert optimizer.quality == 95 def test_optimize_reduces_size(self): """ Scenario: Optimize a tile reduces file size Given a tile with unoptimized data When optimize is called Then the resulting tile should have smaller size """ # Test implementation def test_optimize_invalid_input(self): """ Scenario: Handle invalid input gracefully Given None as input When optimize is called Then it should raise ValueError """ optimizer = TileOptimizer() with pytest.raises(ValueError): optimizer.optimize(None) class TestOptimizationResult: """ Feature: Optimization Result Container The OptimizationResult class holds the outcome of tile optimization including the optimized tile and metadata. """ def test_init(self): """ Scenario: Create optimization result Given an optimized tile and metadata When an OptimizationResult is created Then it should store all provided data """ # Test implementation
Checklist for new test modules:
[ ] File path mirrors source path (
zooui/x/y.py->test/unittest/x/test_y.py)[ ] Module docstring describes what is being tested
[ ] All necessary imports are included
[ ] Test class for each public class in the source module
[ ]
test_initmethod for each class testing instantiation[ ] Tests for all public methods
[ ] Tests for error conditions and edge cases
[ ] BDD-style docstrings for all test classes and methods
[ ] Mocks used appropriately for external dependencies
Make Your Changes
Follow the coding conventions in the Code Style Guidelines.
Run Tests
Ensure all tests pass before submitting:
pytest test/unittest/ pytest test/integrationtest/
Submit a Pull Request
Push your changes and create a pull request against the main branch.
Testing Requirements¶
All contributions must include appropriate tests. The project uses pytest as the testing framework.
Test Structure¶
Tests are organized in two directories:
test/unittest/: Unit tests for individual componentstest/integrationtest/: Integration tests for component interactions
The test directory structure mirrors the source code structure:
test/
├── unittest/
│ ├── conftest.py
│ ├── tilesystem/
│ │ ├── test_tile.py
│ │ ├── test_tilemanager.py
│ │ ├── tileproviders/
│ │ │ ├── test_statictileprovider.py
│ │ │ └── ...
│ │ └── ...
│ ├── objects/
│ │ └── ...
│ └── ...
└── integrationtest/
├── test_tiling_pipeline.py
└── ...
Test Docstring Format¶
Tests should use BDD-style (Behavior-Driven Development) docstrings:
For Test Classes:
class TestClassName:
"""
Feature: Feature Name
Description of what feature or component is being tested.
"""
For Test Methods:
def test_method_name(self):
"""
Scenario: Description of the scenario
Given some initial condition
When some action is performed
Then some expected result occurs
And additional assertions if needed
"""
Example:
class TestTile:
"""
Feature: Tile Image Operations
The Tile class wraps image data (PIL or QImage) and provides operations
for manipulating tiles including cropping, resizing, saving, and rendering.
"""
def test_crop(self):
"""
Scenario: Crop a tile to smaller region
Given a tile with size 100x100
When cropping to region (10, 10, 50, 50)
Then a new Tile instance should be returned
And the new tile size should be 40x40
"""
qimage = QtGui.QImage(100, 100, QtGui.QImage.Format_RGB32)
t = Tile(qimage)
cropped = t.crop((10, 10, 50, 50))
assert isinstance(cropped, Tile)
assert cropped.size == (40, 40)
Testing Routine for Development¶
When developing, follow this testing routine:
Before Making Changes:
Run the existing test suite to ensure everything passes:
pytest test/unittest/ -v pytest test/integrationtest/ -v
During Development:
Run specific tests related to your changes:
# Run tests for a specific module pytest test/unittest/tilesystem/test_tile.py -v # Run tests matching a pattern pytest -k "test_crop" -v
Before Submitting:
Run the complete test suite:
pytest test/ -v
Ensure there are no failures or errors.
Test Requirements for Contributions¶
For Bug Fixes:
Add a test that reproduces the bug (should fail before the fix)
Ensure the test passes after the fix
For New Features:
Add unit tests covering the new functionality
Add integration tests if the feature interacts with multiple components
Aim for comprehensive coverage of edge cases
For Code Refactoring:
Ensure existing tests continue to pass
Add tests for any previously untested behavior discovered during refactoring
Test Guidelines¶
Use Mocking Appropriately:
Use
unittest.mockfor isolating componentsMock external dependencies (file system, network, etc.)
from unittest.mock import Mock, patch, MagicMock @patch('zooui.tilesystem.tileproviders.statictileprovider.Image.open') def test_load_success(self, mock_open): ...
Use Fixtures:
Define fixtures in
conftest.pyfor shared test resourcesUse pytest’s built-in fixtures (
tmp_path,tmpdir, etc.)
@pytest.fixture def temp_tilestore(tmp_path): """ Fixture: Isolated Temporary Tile Store """ ...
Test Naming:
Use descriptive names:
test_<what>_<condition>_<expected>Examples:
test_load_exceeds_maxtilelevel,test_crop,test_init_with_pil_image
Assertions:
Use pytest assertions (
assert) rather than unittest methodsInclude descriptive messages for complex assertions
assert result is None, "Should return None for invalid tilelevel"
Guidelines for Contributing to the Test Codebase¶
When contributing tests, please follow these guidelines:
Mirror the Source Structure:
Place tests in a location that mirrors the source code structure:
Source:
zooui/tilesystem/tile.pyTest:
test/unittest/tilesystem/test_tile.py
One Test Class per Feature/Class:
Each test file should focus on testing a specific module or class.
Test Independence:
Tests should be independent and not rely on execution order
Use fixtures for setup and teardown
Clean up any created resources (files, directories, etc.)
Test Both Success and Failure Cases:
Test happy paths (expected usage)
Test error conditions and edge cases
Test boundary conditions
Keep Tests Fast:
Mock expensive operations (I/O, network, etc.)
Use small test data
Document Test Purpose:
Use BDD-style docstrings as shown above
Make the test’s intent clear from its name and documentation
Integration Tests:
For integration tests, document the components being tested and their interactions:
class TestTilingPipelineEndToEnd: """ Feature: Complete Tiling Pipeline The tiling system converts large images into pyramidal tile structures that enable efficient zooming and panning. This test suite validates the complete pipeline from image input to tile retrieval. """
Versioning and Release Workflow¶
ZooUI uses Semantic Versioning (SemVer) in MAJOR.MINOR.PATCH format.
The single source of truth for the version is zooui/__init__.py →
__version__.
Version bump criteria:
PATCH (0.4.0 → 0.4.1) |
MINOR (0.4.0 → 0.5.0) |
|---|---|
Bug fixes |
Major new features (new modules) |
Minor new features (no new modules) |
New capabilities (new modules) |
Internal refactors |
New architectures (e.g. process pools) |
Type annotations and code quality |
New subsystems |
Documentation improvements |
|
Minor UI elements and enhancements |
A minor feature extends behaviour within existing modules (e.g. adding
methods to an existing class, new menu items, keyboard shortcuts). A major
feature introduces new Python modules or packages under zooui/ and
requires significant new infrastructure.
MAJOR (0.x.y → 1.0.0): Breaking changes to config format, data file format, or public API.
Release workflow:
Update
CHANGELOG.md: move entries from[Unreleased]to a new version heading with the release dateRun the bump script. This updates three locations automatically:
zooui/__init__.py— the canonical__version__stringzooui/data/home.pzs— the version text displayed in the default scene
python scripts/bump_version.py patch # for fixes python scripts/bump_version.py minor # for features python scripts/bump_version.py major # for breaking changes
Use
--tagto also create an annotated git tag in one step:python scripts/bump_version.py minor --tag
Push the tag upstream:
git push origin vX.Y.Z
Keep ``CHANGELOG.md`` updated as you work — add entries under
[Unreleased] at the top of the file following the
Keep a Changelog format. This
ensures the changelog is ready when it is time to cut a release.
Submitting Your Contribution¶
Ensure all tests pass (
pytest test/unittest/)Ensure ruff reports no issues (
ruff check)Ensure ruff-format reports no changes (
ruff format --check)Ensure your code follows the coding conventions in the Code Style Guidelines
Ensure all new code has docstrings and type hints
Update
CHANGELOG.mdunder[Unreleased]with your changesCreate a pull request with a clear description of your changes
Be responsive to feedback during the review process
Thank you for contributing to ZooUI!
Contributing to Documentation¶
Documentation is a critical part of ZooUI that helps users understand and
effectively use the software. This section covers guidelines for contributing
to the Sphinx-based documentation in the ./docs/ directory.
Documentation Structure:
Source files: RST (
.rst) files indocs/source/directoryConfiguration:
docs/source/conf.pyfor Sphinx settingsBuild output: HTML files in
docs/build/html/Auto-generated API docs: Created from Python docstrings using Sphinx extensions
Sphinx Extensions Used:
ZooUI documentation uses the following Sphinx extensions:
sphinx.ext.autodoc: Automatically documents Python docstringssphinx.ext.autosummary: Creates summary tables for modulessphinx.ext.napoleon: Supports Google/NumPy-style docstringssphinx.ext.viewcode: Adds links to highlighted source code
These extensions automatically generate API documentation from Python docstrings following the formats described in the Code Style Guidelines.
Documentation Quality Standards¶
Clarity and Completeness:
Write for the target audience (users, developers, or contributors)
Cover all relevant aspects without assuming prior knowledge
Use simple, direct language avoiding unnecessary jargon
Include practical examples for complex concepts
Examples and Use Cases:
Provide real-world examples from the ZooUI codebase
Include complete, tested code snippets
Document edge cases and common pitfalls
Show before/after comparisons when demonstrating improvements
Consistency with Existing Documentation:
Follow established patterns in existing documentation files
Use consistent terminology (e.g., “tile” not “image chunk”)
Maintain the same heading hierarchy and formatting style
Cross-reference related documentation sections appropriately
Proper RST Formatting:
Use RST directives correctly (
.. code-block::,.. note::,.. warning::)Ensure heading underline lengths match title length exactly
Use consistent indentation (3 spaces for directives, 4 spaces for code blocks)
Include descriptive alt text for images and diagrams
Use backticks for inline code references
Accuracy and Verification:
Ensure documentation matches actual code behavior
Test code examples before including them
Verify command-line instructions work as described
Update documentation when related code changes
Accessibility and Navigation:
Use meaningful section titles that describe content
Include table of contents for longer documents
Add cross-references (
:doc:,:ref:) to related contentEnsure documentation builds without warnings
Documentation Workflow¶
1. Set Up Documentation Environment:
# Navigate to documentation directory
cd docs/
# Install Sphinx via conda (recommended)
conda install sphinx
# Alternatively install via pip
# pip install sphinx
# Build documentation locally to verify current state
make clean
make html
2. Make Documentation Changes:
Edit RST (
.rst) files indocs/source/directoryFollow RST syntax and project conventions
Use existing documentation as reference for style
Keep changes focused and manageable
3. Build and Test Documentation:
# Build HTML documentation
make html
# Check for warnings or errors in the output
# Address any Sphinx warnings before submitting
# Open built documentation in browser to verify
# Linux:
xdg-open build/html/index.html
# macOS:
open build/html/index.html
# Windows:
start build/html/index.html
4. Verify Build Quality:
[ ] Documentation builds without warnings
[ ] All internal links work correctly
[ ] Code examples are accurate and tested
[ ] Formatting is consistent with existing docs
[ ] Cross-references are properly linked
[ ] Images and diagrams display correctly
5. Deploy to GitHub Pages (Optional):
For maintainers or those with push access, documentation can be deployed to
GitHub Pages using ghp-import:
# Install ghp-import
conda install ghp-import
# Build documentation
make clean
make html
# Deploy to gh-pages branch
ghp-import -n -p -f build/html
# The documentation will be available at:
# https://[username].github.io/pyzui/
Note: GitHub Pages deployment requires appropriate repository permissions and is typically handled by project maintainers.
6. Types of Documentation Contributions:
Minor Improvements: - Fix typos, grammar, or formatting issues - Update outdated information - Improve clarity of existing content - Fix broken links or references
Moderate Enhancements: - Add missing documentation for existing features - Improve examples or add new ones - Reorganize content for better flow - Add diagrams or visual aids
Major Contributions: - Create new documentation sections or tutorials - Implement documentation automation - Improve documentation infrastructure - Add comprehensive API documentation
7. Submission Process:
Documentation contributions follow the same submission process as code contributions (fork, branch, pull request). Ensure your documentation:
Builds successfully with
make htmlFollows the quality standards above
Maintains consistency with existing documentation
Includes appropriate examples and cross-references
Thank you for contributing to ZooUI!