Development¶
Notes for developers of geoextent.
Environment¶
All commands in this file assume you work in a Python virtual environment. We recommend using Python’s built-in venv module:
# Create a virtual environment
python -m venv .venv
# Activate the environment (Linux/macOS)
source .venv/bin/activate
# Activate the environment (Windows)
.venv\Scripts\activate
# Deactivate the environment
deactivate
# Remove the environment (if needed)
rm -rf .venv
Required packages¶
System Dependencies¶
First, ensure you have the required system packages installed. On Debian/Ubuntu:
sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
sudo apt-get update
sudo apt-get install -y libproj-dev libgeos-dev libspatialite-dev libgdal-dev gdal-bin netcdf-bin
Python Dependencies¶
In the virtual environment created above, install geoextent in development mode with all dependencies:
# Install GDAL Python bindings first (matching your system GDAL version)
GDAL_VERSION=$(gdal-config --version)
pip install "GDAL==$GDAL_VERSION"
# Install geoextent in editable mode with all optional dependencies
pip install -e .[dev,test,docs]
This will install all required and optional dependencies defined in pyproject.toml.
Run tests¶
After installing geoextent with development dependencies (see above), run the test suite using pytest.
Parallel Test Execution (Default)
The project is configured to run tests in parallel by default using pytest-xdist with automatic CPU detection. This significantly speeds up the test suite:
# Run all tests (parallel execution with auto CPU detection - default)
pytest
# Explicit parallel execution options
pytest -n auto # Auto-detect number of CPUs (default)
pytest -n 4 # Use 4 workers
pytest -n 1 # Single worker (minimal parallelism)
pytest -n 0 # Disable parallelism (useful for debugging)
Test Selection and Filtering
# Run specific test file (parallel execution still applies)
pytest tests/test_api.py
# Run specific test categories
pytest tests/test_api_*.py # API tests
pytest tests/test_cli*.py # CLI tests
pytest -m "not slow" # Exclude slow tests
# Run with coverage
pytest --cov=geoextent --cov-report=term-missing
# Run specific test class or method (disable parallelism for debugging)
pytest -n 0 tests/test_api.py::TestClassName::test_method_name
Performance Tips
Parallel execution works best with many independent tests
Use
-n 0when debugging individual test failuresThe
-n autooption automatically scales with available CPU coresOn CI systems, consider using
-n logicalto match virtual CPUs
Local GitHub Actions Testing¶
Test workflows locally using act to validate changes before pushing to GitHub.
Installing act¶
# macOS
brew install act
# Linux
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
# Windows
choco install act-cli
Configuration¶
The project includes an .actrc configuration file with Ubuntu 24.04 image settings.
Running Local Tests¶
Use the provided script for easy local testing:
# Run main Python package tests (default)
./scripts/test-local-ci.sh
# Run with specific Python version
./scripts/test-local-ci.sh --python-version 3.11
# List all available jobs
./scripts/test-local-ci.sh --list-jobs
# Show what would be executed (dry run)
./scripts/test-local-ci.sh --dry-run
Direct act Commands¶
# Run main test workflow
act -W .github/workflows/pythonpackage.yml
# Run with specific Python version
act -W .github/workflows/pythonpackage.yml --matrix python-version:3.11
# List all jobs in a workflow
act -W .github/workflows/pythonpackage.yml --list
Code Formatting¶
Format code with black and set up pre-commit hooks:
# Format code
black geoextent/ tests/
# Set up pre-commit hooks (run once)
pre-commit install
# Run pre-commit hooks manually
pre-commit run --all-files
Documentation¶
The documentation is based on Sphinx.
The source files can be found in the directory docs/ and the rendered online documentation is at https://nuest.github.io/geoextent/.
Build documentation locally¶
# Ensure documentation dependencies are installed
pip install -e .[docs]
# Build HTML documentation
cd docs/
make html
# View the documentation (Linux)
xdg-open build/html/index.html
# Clean build artifacts
make clean
Release¶
Prerequisites¶
Required tools:
setuptoolswheeltwine
pip install --upgrade setuptools wheel twine
Run tests¶
Make sure that all tests work locally by running
pytest
Bump version for release¶
Follow the Semantic Versioning specification to clearly mark changes as a new major version, minor changes, or patches. The version number is managed using setuptools-scm via git tags. So simply add a tag to the latest commit, e.g., for version 1.2.3:
git tag v1.2.3
Update changelog¶
Update the changelog in file docs/source/changelog.rst, use the sphinx-issues syntax for referring to pull requests and contributors for changes where appropriate.
Build distribution archive¶
See the PyPI documentation on generating a distribution archive, https://packaging.python.org/en/latest/tutorials/packaging-projects/, for details.
# remove previous releases and builds
rm dist/*
rm -rf build *.egg-info
# build source distribution
source .venv/bin/activate # if not already in venv
python3 -m build
python -m build --sdist
Upload to test repository¶
First upload to the test repository and check everything is in order.
# upload with twine, make sure only one wheel is in dist/
python3 -m twine upload --repository testpypi dist/*
Check if the information on https://test.pypi.org/project/geoextent/ is correct. Then switch to a new Python environment or use a Python 3 container to get an “empty” setup. Install geoextent from TestPyPI and ensure the package is functional, using Debian Testing container to try out a more recent version of GDAL:
docker run --rm -it -v $(pwd)/tests/testdata/:/testdata debian:testing
# Python + PIP
apt-get update
apt-get install python3 python3-pip wget
# System dependencies
apt-get install gdal-bin libgdal-dev libproj-dev libgeos-dev
# Package dependencies (from regular PyPI)
pip install -r requirements.txt
python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps geoextent-nuest
#pip install -i https://test.pypi.org/simple/ geoextent
geoextent --help
geoextent --version
geoextent -b /testdata/geojson/muenster_ring_zeit.geojson
geoextent -b -t --geojsonio /testdata/shapefile/gis_osm_buildings_a_free_1.shp
wget https://github.com/nuest/geoextent/blob/main/tests/testdata/tif/wf_100m_klas.tif
geoextent -b --format WKT wf_100m_klas.tif
Upload to PyPI¶
python3 -m twine upload dist/*
Check if information on https://pypi.org/project/geoextent/ is all correct. Install the library from PyPI into a new environment, e.g., by reusing the container session from above, and check that everything works.
Add tag¶
Add a version tag to the commit of the release and push it to the main repository. Go to GitHub and create a new release by using the “Draft a new release” button and using the just pushed tag. Releases are automatically stored on Zenodo - double-check that the release is also available on Zenodo