* refactor: Standardize naming conventions * chore: Update the version and re-run experiments * chore: Improve code quality tooling and documentation - Add pre-commit job to CI workflow for automated linting on PRs - Update uniface/__init__.py with copyright header, module docstring, and logically grouped exports - Revise CONTRIBUTING.md to reflect pre-commit handles all formatting - Remove redundant ruff check from CI (now handled by pre-commit) - Update build job Python version to 3.11 (matches requires-python)
5.3 KiB
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
- Fork the repository
- Create a new branch for your feature
- Write clear, documented code with type hints
- Add tests for new functionality
- Ensure all tests pass and pre-commit hooks are satisfied
- Submit a pull request with a clear description
Development Setup
git clone https://github.com/yakhyo/uniface.git
cd uniface
pip install -e ".[dev]"
Setting Up Pre-commit Hooks
We use pre-commit to ensure code quality and consistency. Install and configure it:
# Install pre-commit
pip install pre-commit
# Install the git hooks
pre-commit install
# (Optional) Run against all files
pre-commit run --all-files
Once installed, pre-commit will automatically run on every commit to check:
- Code formatting and linting (Ruff)
- Security issues (Bandit)
- General file hygiene (trailing whitespace, YAML/TOML validity, etc.)
Note: All PRs are automatically checked by CI. The merge button will only be available after all checks pass.
Code Style
This project uses 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):
# 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 for all public APIs:
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:
- Future imports (
from __future__ import annotations) - Standard library (
os,sys,typing, etc.) - Third-party (
numpy,cv2,onnxruntime, etc.) - First-party (
uniface.*) - Local (relative imports like
.base,.models)
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
# 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)
Running Tests
# Run all tests
pytest tests/
# 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
Adding New Features
When adding a new model or feature:
- Create the model class in the appropriate submodule (e.g.,
uniface/detection/) - Add weight constants to
uniface/constants.pywith URLs and SHA256 hashes - Export in
__init__.pyfiles at both module and package levels - Write tests in
tests/directory - Add example usage in
scripts/or update existing notebooks - Update documentation if needed
Examples
Example notebooks demonstrating library usage:
| Example | Notebook |
|---|---|
| Face Detection | 01_face_detection.ipynb |
| Face Alignment | 02_face_alignment.ipynb |
| Face Verification | 03_face_verification.ipynb |
| Face Search | 04_face_search.ipynb |
| Face Analyzer | 05_face_analyzer.ipynb |
| Face Parsing | 06_face_parsing.ipynb |
| Face Anonymization | 07_face_anonymization.ipynb |
| Gaze Estimation | 08_gaze_estimation.ipynb |
Questions?
Open an issue or start a discussion on GitHub.