GeoPublicHealth

GeoPublicHealth Agent Development Guide

This document provides essential information for AI coding agents working on the GeoPublicHealth QGIS plugin.

Project Overview

GeoPublicHealth is a QGIS 3.x plugin for epidemiology and public health GIS analysis. It’s written in Python and uses PyQGIS, PyQt5, and spatial analysis libraries.

Key Technologies:

Autocorrelation Coverage:

Autocorrelation UI Notes:

Build, Lint, and Test Commands

Running Tests

Run all tests:

python test_suite.py

Run a single test:

python -m unittest src.test.test_pep8.TestPep8.test_pep8

Run specific test module:

python -m unittest discover -s src/test -p "test_*.py"

Test Harness

Run unit tests (script):

./scripts/run_tests.sh

Run unit tests (make):

make test

Run processing tests (make):

make processing-test

Testing Standards

QGIS Testing Practices (Reference)

References:

Architecture & Services

Code Style Checking

Run PEP8 style check:

make pep8

PEP8 configuration:

Translation Commands

Update translation strings:

make update-translation-strings

Compile translation strings:

make compile-translation-strings

Test translations:

make test-translations

Translation stats:

make translation-stats

Code Style Guidelines

File Headers

All Python files must start with UTF-8 encoding declaration and GPL license header:

# -*- coding: utf-8 -*-
"""
/***************************************************************************

                                 GeoPublicHealth
                                 A QGIS plugin

                              -------------------
        begin                : YYYY-MM-DD
        copyright            : (C) YYYY by Author Name
        email                : email@example.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

Import Organization

Imports should be organized in this order:

  1. Future imports (from __future__ or builtins)
  2. Standard library imports
  3. Third-party imports (numpy, libpysal, etc.)
  4. PyQt/QGIS imports (group together)
  5. Local/plugin imports (GeoPublicHealth.*)

Example:

from builtins import str
from uuid import uuid4
from tempfile import NamedTemporaryFile

import numpy as np
import libpysal

from qgis.PyQt.QtCore import QSettings, QVariant
from qgis.PyQt.QtWidgets import QApplication, QDialog
from qgis.core import QgsVectorLayer, Qgis
from qgis.gui import QgsMessageBar

from GeoPublicHealth.src.core.tools import tr
from GeoPublicHealth.src.core.exceptions import GeoPublicHealthException

Naming Conventions

Type Hints

Use type hints for function parameters and return types, especially in newer code:

from typing import Dict, List, Optional, Union, Any, Tuple

def create_memory_layer(
        layer_name: str, 
        geometry: QgsWkbTypes, 
        coordinate_reference_system: Optional[QgsCoordinateReferenceSystem] = None, 
        fields: Optional[QgsFields] = None) -> QgsVectorLayer:
    """Create a vector memory layer."""
    pass

Docstrings

Use Google-style docstrings with type information:

def copy_layer(source, target):
    """Copy a vector layer to another one.

    :param source: The vector layer to copy.
    :type source: QgsVectorLayer

    :param target: The destination.
    :type target: QgsVectorLayer
    """
    pass

Exception Handling

Example:

from GeoPublicHealth.src.core.exceptions import (
    GeoPublicHealthException,
    NoLayerProvidedException,
    DifferentCrsException
)

if not layer:
    raise NoLayerProvidedException()

Translation Support

Always wrap user-facing strings with tr() function:

from GeoPublicHealth.src.core.tools import tr

message = tr(u'No layer was provided.')
display_message_bar(tr(u'Error while processing'), Qgis.Critical)

UI Components

Project Structure

GeoPublicHealth/
├── src/
│   ├── core/            # Core functionality and utilities
│   │   ├── blurring/    # Blurring algorithms
│   │   ├── gis/         # GIS utilities
│   │   └── accessibility/
│   ├── gui/             # GUI dialogs and windows
│   │   ├── analysis/    # Analysis dialogs
│   │   ├── import_gui/  # Import dialogs
│   │   └── export/      # Export dialogs
│   ├── processing_geopublichealth/  # QGIS Processing algorithms
│   ├── datastore/       # Data storage implementations
│   ├── ui/              # Qt Designer .ui files
│   ├── test/            # Unit tests
│   ├── doc/             # Documentation
│   └── utilities/       # Utility functions
├── sample_data/         # Sample data for testing
├── scripts/             # Build and helper scripts
└── docs/                # Documentation files

Common Patterns

Memory Layer Creation

from GeoPublicHealth.src.core.tools import create_memory_layer
from qgis.core import QgsWkbTypes

layer = create_memory_layer(
    layer_name='my_layer',
    geometry=QgsWkbTypes.Point,
    coordinate_reference_system=source_crs,
    fields=source_fields
)

Warning Suppression for PySAL

import warnings
warnings.filterwarnings("ignore", category=FutureWarning, 
                       message="Objects based on the `Geometry` class will deprecated")
warnings.filterwarnings("ignore", category=ResourceWarning, 
                       message="unclosed file")

Fallback Imports

Always check for optional dependencies:

try:
    import libpysal
    PYSAL_AVAILABLE = True
except ImportError:
    PYSAL_AVAILABLE = False

Important Notes

  1. QGIS Compatibility: Target QGIS 3.42.x Münster
  2. Python Version: Python 3.x (bundled with QGIS)
  3. DRY Principle: Don’t Repeat Yourself - reuse existing functions
  4. Testing: All code changes should include or update tests
  5. PEP8 Compliance: Code must pass make pep8 with the project’s ignore rules
  6. Localization: All user-facing strings must be translatable (wrapped in tr())
  7. Qt Compatibility: Use PyQt5 (or PyQt6 if migrating, but currently PyQt5)
  8. macOS dialogs: File dialogs fall back to manual path prompts for stability

Contributing Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b my-new-feature
  3. Make changes following style guidelines
  4. Run tests: python test_suite.py
  5. Run PEP8 check: make pep8
  6. Commit with descriptive message: git commit -am 'Add some feature'
  7. Push to branch: git push origin my-new-feature
  8. Open a Pull Request

Commit Messages

Release Packaging Notes

References