Contributions are welcome. This document covers everything you need to get from zero to a merged PR.
git clone https://github.com/withoutbg/withoutbg
cd withoutbg
# Recommended: install with uv
uv sync --extra dev
# Or with pip
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit installVerify everything works:
make test-fast # fast unit tests only
make quality # lint + format check + type check- Fork and clone the repo
- Create a branch:
git checkout -b feat/your-feature - Make changes with tests
- Run
make qualityandmake test-fast— both must pass - Commit with a conventional commit message
- Open a pull request against
main
This repo uses Conventional Commits. Format:
<type>[optional scope]: <description>
Types that matter for releases:
| Type | Effect | Example |
|---|---|---|
feat |
minor version bump | feat: add GPU support |
fix |
patch version bump | fix: handle RGBA inputs correctly |
perf |
patch version bump | perf: reduce model load time |
refactor |
patch version bump | refactor: extract preprocessing step |
docs |
no release | docs: update CLI examples |
test |
no release | test: add edge case for empty image |
chore |
no release | chore: update dev dependencies |
feat! or BREAKING CHANGE: |
major version bump |
See .github/COMMIT_CONVENTION.md for the full reference.
- Formatting: Black at 88 characters — run
make format - Linting: Ruff — run
make lint - Types: All new public functions need type annotations
- Docstrings: Google-style for all public symbols
Example:
def remove_background(
input_image: Union[str, Path, Image.Image],
progress_callback: Optional[Callable[[float], None]] = None,
) -> Image.Image:
"""Remove the background from an image.
Args:
input_image: File path or PIL Image.
progress_callback: Optional function called with progress in [0, 1].
Returns:
PIL Image in RGBA mode with the background removed.
Raises:
WithoutBGError: If processing fails.
"""make test # all tests (requires model download on first run)
make test-fast # unit tests only, no model download needed
make test-unit # same as test-fast
make test-coverage # full suite with HTML coverage reportTests are marked with pytest markers:
| Marker | When it runs | Use for |
|---|---|---|
unit |
always | fast, isolated, mocked |
integration |
--run-real-processing |
multi-component, real images |
performance |
--run-performance |
benchmarks, memory checks |
Write unit tests for all new code. Mock file I/O and model calls in unit tests:
@pytest.mark.unit
class TestMyFeature:
def test_does_the_thing(self):
# Arrange
model = MagicMock(spec=OpenWeightsModel)
model.remove_background.return_value = Image.new("RGBA", (100, 100))
# Act / Assert
...Coverage gate is 80%. New code should not lower it.
Use the pull request template. Keep PRs focused — one logical change per PR makes review easier and faster.
Open an issue using the bug report template. Include:
- Python version and OS
- Whether you are using Local (
open_weights()) or Cloud (api()) - Minimal repro snippet
For Docker / self-hosted inference issues, open an issue in withoutbg-inference instead.
Do not create public issues for security vulnerabilities. Email contact@withoutbg.com instead.
By contributing, you agree your contributions are licensed under the Apache License 2.0.