2025-12-07 19:51:08 +09:00
# Contributing to UniFace
Thank you for considering contributing to UniFace! We welcome contributions of all kinds.
## How to Contribute
### Reporting Issues
- Use GitHub Issues to report bugs or suggest features
- Include clear descriptions and reproducible examples
- Check existing issues before creating new ones
### Pull Requests
1. Fork the repository
2. Create a new branch for your feature
3. Write clear, documented code with type hints
4. Add tests for new functionality
2025-12-30 00:20:34 +09:00
5. Ensure all tests pass and pre-commit hooks are satisfied
2025-12-07 19:51:08 +09:00
6. Submit a pull request with a clear description
2025-12-30 00:20:34 +09:00
## Development Setup
```bash
git clone https://github.com/yakhyo/uniface.git
cd uniface
pip install -e ".[dev]"
```
2025-12-07 19:51:08 +09:00
2025-12-30 00:20:34 +09:00
### Setting Up Pre-commit Hooks
We use [pre-commit ](https://pre-commit.com/ ) to ensure code quality and consistency. Install and configure it:
2025-12-24 00:34:24 +09:00
```bash
2025-12-30 00:20:34 +09:00
# Install pre-commit
pip install pre-commit
2025-12-24 00:34:24 +09:00
2025-12-30 00:20:34 +09:00
# Install the git hooks
pre-commit install
2025-12-24 00:34:24 +09:00
2025-12-30 00:20:34 +09:00
# (Optional) Run against all files
pre-commit run --all-files
2025-12-24 00:34:24 +09:00
```
2025-12-30 00:20:34 +09:00
Once installed, pre-commit will automatically run on every commit to check:
2025-12-07 19:51:08 +09:00
2025-12-30 00:20:34 +09:00
- Code formatting and linting (Ruff)
- Security issues (Bandit)
- General file hygiene (trailing whitespace, YAML/TOML validity, etc.)
2025-12-24 00:34:24 +09:00
2025-12-30 00:20:34 +09:00
**Note:** All PRs are automatically checked by CI. The merge button will only be available after all checks pass.
2025-12-07 19:51:08 +09:00
2025-12-30 00:20:34 +09:00
## Code Style
This project uses [Ruff ](https://docs.astral.sh/ruff/ ) for linting and formatting, following modern Python best practices. Pre-commit handles all formatting automatically.
### Style Guidelines
#### General Rules
- **Line length:** 120 characters maximum
- **Python version:** 3.11+ (use modern syntax)
- **Quote style:** Single quotes for strings, double quotes for docstrings
#### Type Hints
Use modern Python 3.11+ type hints (PEP 585 and PEP 604):
```python
# Preferred (modern)
def process(items: list[str], config: dict[str, int] | None = None) -> tuple[int, str]:
...
# Avoid (legacy)
from typing import List, Dict, Optional, Tuple
def process(items: List[str], config: Optional[Dict[str, int]] = None) -> Tuple[int, str]:
...
```
#### Docstrings
Use [Google-style docstrings ](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings ) for all public APIs:
```python
def detect_faces(image: np.ndarray, threshold: float = 0.5) -> list[Face]:
"""Detect faces in an image.
Args:
image: Input image as a numpy array with shape (H, W, C) in BGR format.
threshold: Confidence threshold for filtering detections. Defaults to 0.5.
Returns:
List of Face objects containing bounding boxes, confidence scores,
and facial landmarks.
Raises:
ValueError: If the input image has invalid dimensions.
Example:
>>> from uniface import detect_faces
>>> faces = detect_faces(image, threshold=0.8)
>>> print(f"Found {len(faces)} faces")
"""
```
#### Import Order
Imports are automatically sorted by Ruff with the following order:
1. **Future ** imports (`from __future__ import annotations` )
2. **Standard library ** (`os` , `sys` , `typing` , etc.)
3. **Third-party ** (`numpy` , `cv2` , `onnxruntime` , etc.)
4. **First-party ** (`uniface.*` )
5. **Local ** (relative imports like `.base` , `.models` )
```python
from __future __ import annotations
import os
from typing import Any
import cv2
import numpy as np
from uniface.constants import RetinaFaceWeights
from uniface.log import Logger
from .base import BaseDetector
```
#### Code Comments
- Add comments for complex logic, magic numbers, and non-obvious behavior
- Avoid comments that merely restate the code
- Use `# TODO:` with issue links for planned improvements
```python
# RetinaFace FPN strides and corresponding anchor sizes per level
steps = [8, 16, 32]
min_sizes = [[16, 32], [64, 128], [256, 512]]
# Add small epsilon to prevent division by zero
similarity = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-5)
2025-12-07 19:51:08 +09:00
```
## Running Tests
```bash
2025-12-30 00:20:34 +09:00
# Run all tests
2025-12-07 19:51:08 +09:00
pytest tests/
2025-12-30 00:20:34 +09:00
# Run with verbose output
pytest tests/ -v
# Run specific test file
pytest tests/test_factory.py
# Run with coverage
pytest tests/ --cov=uniface --cov-report=html
2025-12-07 19:51:08 +09:00
```
2025-12-30 00:20:34 +09:00
## Adding New Features
When adding a new model or feature:
1. **Create the model class ** in the appropriate submodule (e.g., `uniface/detection/` )
2. **Add weight constants ** to `uniface/constants.py` with URLs and SHA256 hashes
3. **Export in `__init__.py` ** files at both module and package levels
4. **Write tests ** in `tests/` directory
5. **Add example usage ** in `scripts/` or update existing notebooks
6. **Update documentation ** if needed
2025-12-07 19:51:08 +09:00
## Examples
Example notebooks demonstrating library usage:
| Example | Notebook |
|---------|----------|
2025-12-30 00:20:34 +09:00
| Face Detection | [01_face_detection.ipynb ](examples/01_face_detection.ipynb ) |
| Face Alignment | [02_face_alignment.ipynb ](examples/02_face_alignment.ipynb ) |
| Face Verification | [03_face_verification.ipynb ](examples/03_face_verification.ipynb ) |
| Face Search | [04_face_search.ipynb ](examples/04_face_search.ipynb ) |
| Face Analyzer | [05_face_analyzer.ipynb ](examples/05_face_analyzer.ipynb ) |
| Face Parsing | [06_face_parsing.ipynb ](examples/06_face_parsing.ipynb ) |
| Face Anonymization | [07_face_anonymization.ipynb ](examples/07_face_anonymization.ipynb ) |
| Gaze Estimation | [08_gaze_estimation.ipynb ](examples/08_gaze_estimation.ipynb ) |
2025-12-07 19:51:08 +09:00
## Questions?
Open an issue or start a discussion on GitHub.