Contributing to FolioClient#
Thank you for your interest in contributing to FolioClient! This guide will help you get started with contributing to this Python library for interacting with FOLIO Platform APIs. These are guidelines to help make collaboration easier. They are not intended to be barriers to contribution—we just ask for good-faith efforts.
Table of Contents#
Code of Conduct#
By participating in this project, you agree to abide by the FOLIO Community Code of Conduct. Please be respectful and constructive in all interactions with maintainers and other contributors.
Getting Started#
Prerequisites#
Python 3.10 or higher (Python 3.13 recommended)
uv for dependency management
Git for version control
A FOLIO system for testing (optional, but recommended for comprehensive testing)
You can use the community reference environments, but please be considerate of others
First Steps#
Fork the repository on GitHub
Clone your fork locally:
git clone https://github.com/yourusername/FolioClient.git cd FolioClient
Add the upstream remote:
git remote add upstream https://github.com/FOLIO-FSE/FolioClient.git
Development Setup#
# Install dependencies (including dev and docs)
uv sync --all-groups
# Install with JSON performance optimizations
uv sync --extra orjson
Environment Setup#
Set up environment variables (if testing against a FOLIO system):
export FOLIO_URL="https://your-folio-instance.example.com" export FOLIO_TENANT="your_tenant" export FOLIO_USERNAME="your_username" export FOLIO_PASSWORD="your_password"
Create a
.envfile (optional, for local development):FOLIO_URL=https://your-folio-instance.example.com FOLIO_TENANT=your_tenant FOLIO_USERNAME=your_username FOLIO_PASSWORD=your_password GITHUB_TOKEN=your_github_token # For GitHub API tests
Making Changes#
Branch Naming Convention#
Feature branches:
feature/description-of-featureBug fixes:
fix/description-of-bugDocumentation:
docs/description-of-updateRefactoring:
refactor/description-of-change
Development Workflow#
Create a new branch from
master:git checkout master git pull upstream master git checkout -b feature/your-feature-name
Make your changes following the code style guidelines below
Commit your changes with descriptive commit messages:
git add . git commit -m "Add feature: description of what you added"
Keep your branch up to date:
git fetch upstream git rebase upstream/master
Keep commits clean - Use meaningful commit messages and consider interactive rebase (
git rebase -i) to clean up your commit history before submitting
Commit Message Guidelines#
Prefer the present tense (“Add feature” not “Added feature”)
Prefer the imperative mood (“Move cursor to…” not “Moves cursor to…”)
Limit the first line to 72 characters or less
Reference issues and pull requests liberally after the first line
Examples:
Add async support for batch operations
- Implement async_batch_get method
- Add comprehensive async tests
- Update documentation with async examples
Fixes #123
Testing#
Running Tests#
# Run all tests
uv run pytest
# Run tests with coverage
uv run pytest --cov=src/folioclient --cov-report=html
# Run specific test file
uv run pytest tests/test_folio_client.py
# Run tests with verbose output
uv run pytest -v
# Run async tests only
uv run pytest -k "async"
Integration tests#
We provide a limited set of integration tests to verify network functionality of FolioClient. These tests are not included in the standard pytest test run, and require additional configuration. By default they are run against the current community Okapi snapshot environment, Eureka snapshot environment, Eureka ECS snapshot environment, and the most recent Bugfest environment. You can specify a single environment from the available options:
snapshotsnapshot-2eureka(eureka snapshot)eureka-ecs(eureka snapshot ECS)snapshot-2-eureka(eureka backup snapshot)bugfest(currently Sunflower bugfest)
# Set up environment variables for integration testing
export FOLIO_SNAPSHOT_USERNAME=<snapshot_admin_usernae>
export FOLIO_SNAPSHOT_PASSWORD=<snapshot_admin_password>
export FOLIO_ECS_EUREKA_USERNAME=<eureka_ecs_snapshot_admin_username>
export FOLIO_ECS_EUREKA_PASSWORD=<eureka_ecs_snapshot_admin_password>
export FOLIO_BUGFEST_USERNAME=<bugfest_admin_username>
export FOLIO_BUGFEST_PASSWORD=<bugfest_admin_password>
# Run integration tests
uv run pytest --run-integration
# Run integration tests against snapshot only (others will be skipped)
uv run pytest --run-integration --integration-server snapshot
Writing Tests#
Location: Add tests to the
tests/directoryNaming: Test files should be named
test_*.pyAsync tests: Use
@pytest.mark.asynciofor async test functionsMocking: Use
unittest.mockfor mocking external dependenciesCoverage: Aim for high test coverage, especially for new features
Example test structure:
import pytest
from unittest.mock import Mock, patch
from folioclient import FolioClient
class TestFolioClient:
@patch.object(FolioClient, '_initial_ecs_check')
def test_feature_name(self, mock_ecs_check):
# Test implementation
pass
@pytest.mark.asyncio
async def test_async_feature(self):
# Async test implementation
pass
Code Style#
Linting and Formatting#
We use Ruff for both linting and formatting:
# Check for linting issues
uv run ruff check
# Auto-fix linting issues
uv run ruff check --fix
# Format code
uv run ruff format
# Check formatting without applying
uv run ruff format --check
Type Checking#
We use mypy for static type checking:
# Run type checking
uv run mypy src/folioclient --ignore-missing-imports
Code Style Guidelines#
Line length: Maximum 99 characters
Import sorting: Use Ruff’s import sorting
Type hints: Add type hints for all function parameters and return values
Docstrings: Use Google-style docstrings for all public methods
Async/Sync patterns: Maintain parallel sync and async implementations where applicable
Documentation Strings#
def folio_get(self, path: str, key: str | None = None, query: str = "",
query_params: dict = None) -> Any:
"""
Fetches data from FOLIO and returns it as a JSON object.
Args:
path: FOLIO API endpoint path
key: Key in JSON response that contains the array of results
query: CQL query string for filtering results
query_params: Additional query parameters for the request
Returns:
JSON response data, optionally filtered by key
Raises:
HTTPStatusError: If the HTTP request fails
FolioClientClosed: If the client has been closed
Example:
>>> client.folio_get("/users", "users", "username==admin")
"""
Submitting Changes#
Pull Request Process#
Update documentation if you’ve changed APIs or added features
Add or update tests for your changes
Ensure all tests pass and linting is clean
Update the changelog if appropriate
Submit a pull request with a clear description
Pull Request Template#
## Description
Brief description of what this PR does.
## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass (if applicable)
- [ ] New tests added for new functionality
## Checklist
- [ ] Code follows the project's style guidelines
- [ ] Self-review of code completed
- [ ] Code is commented, particularly in hard-to-understand areas
- [ ] Corresponding changes to documentation have been made
- [ ] Changes generate no new warnings
Review Process#
Automated checks must pass (GitHub Actions, linting, tests)
At least one maintainer review is required
Address feedback promptly and professionally
Clean commit history - We use rebase and merge to maintain a linear history for all pull requests, so be sure your branch does not have conflicts with the main branch
Reporting Issues#
Bug Reports#
When reporting bugs, please include:
Python version and operating system
FolioClient version
FOLIO system version (if applicable)
Minimal code example that reproduces the issue
Full error traceback with any sensitive data removed/redacted
Expected vs actual behavior
Feature Requests#
For feature requests, please include:
Use case description - what problem does this solve?
Proposed API - how should the feature work?
Alternative solutions - what other approaches have you considered?
FOLIO API documentation - links to relevant FOLIO API docs
Security Issues#
For security-related issues, please do not open a public issue. Instead:
Email the maintainers directly
Include a detailed description of the vulnerability
Provide steps to reproduce (if applicable)
Allow reasonable time for response before disclosure
Documentation#
Building Documentation#
# Install documentation dependencies
uv sync --group docs
# Build documentation
cd docs
make html
# Serve documentation locally
make serve
# Open http://localhost:8000 in your browser
# Check for broken links
make linkcheck
Documentation Standards#
API documentation: All public methods must have comprehensive docstrings
Examples: Include working code examples in docstrings
Type hints: All parameters and return values must be type-hinted
Changelog: Update
CHANGELOG.mdfor user-facing changes
Release Process#
Note: This section is primarily for maintainers
Version Numbering#
We follow Semantic Versioning:
Major (1.0.0): Breaking changes
Minor (1.1.0): New features, backwards compatible
Patch (1.1.1): Bug fixes, backwards compatible
Pre-release
(1.0.0b1): Beta versions
(1.1.0a1): Alpha versions
(1.1.0rc1): Release candidates
Release Checklist#
Update version in
pyproject.tomlUpdate
CHANGELOG.mdRun full test suite, including integration tests
Create release tag in GitHub
Approve submit workflow to publish to pypi
Update GitHub release notes
Getting Help#
GitHub Issues: For bugs, features, and questions
GitHub Discussions: For general discussion and questions
Documentation: Check the README and inline documentation first
FOLIO Community: FOLIO Project for FOLIO-specific questions
Recognition#
Contributors will be recognized in:
GitHub contributors list
pyproject.toml project authors list
Changelog acknowledgments
Release notes (for significant contributions)
Thank you for contributing to FolioClient! Your efforts help make FOLIO integration easier for libraries worldwide. 🚀