Thank you for your interest in contributing to the SAMO-DL project! This guide will help you get started and ensure your contributions align with our project standards.
- Getting Started
- Development Setup
- Code Standards
- Testing
- Pull Request Process
- Code Review Guidelines
- Security Guidelines
- Documentation
- Support
- Python: 3.10+
- Git: Latest version
- Docker: 20.10+ (for containerized development)
- Make: For automation scripts
-
Fork the repository
# Fork on GitHub, then clone your fork git clone https://github.com/YOUR_USERNAME/SAMO--DL.git cd SAMO--DL
-
Set up development environment
# Create virtual environment python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate # Install dependencies pip install -r requirements.txt # Install development tools (formatters/linters/test plugins) pip install -r requirements-dev.txt # Enable git hooks pre-commit install
-
Run tests
# Run all tests pytest # Run with coverage pytest --cov=src
Create a .env file for local development:
# .env
ENVIRONMENT=development
DATABASE_URL=postgresql://user:pass@localhost:5432/samo_dl_dev
SECRET_KEY=dev-secret-key-change-in-production
API_KEY=dev-api-key
LOG_LEVEL=DEBUG# Build development container
docker build -f deployment/cloud-run/Dockerfile -t samo-dl-dev .
# Run with development settings
docker run --rm --name samo-dl-dev -p 8080:8080 \
-e ENVIRONMENT=development \
-e DATABASE_URL=postgresql://user:pass@host:5432/db \
samo-dl-dev# Install PostgreSQL (Ubuntu)
sudo apt install postgresql postgresql-contrib
# Create database
sudo -u postgres createdb samo_dl_dev
# Run migrations
alembic upgrade headWe follow PEP 8 with some modifications:
from typing import TypedDict
class EmotionPrediction(TypedDict):
emotion: str
confidence: float
# ✅ Good
def predict_emotion(text: str) -> EmotionPrediction:
"""Predict emotion from text input.
Args:
text: Input text to analyze
Returns:
Dictionary containing emotion prediction and confidence
Raises:
ValueError: If text is empty or invalid
"""
if not text or not isinstance(text, str):
raise ValueError("Text must be a non-empty string")
# Implementation here
return {"emotion": "happy", "confidence": 0.95}
# ❌ Bad
def predict_emotion(text):
if not text:
return None
# Implementation without type hints or docstringsWe use Black for code formatting, Ruff for linting, and Prettier for markdown formatting:
Configuration (pyproject.toml):
[tool.ruff]
lint.select = ["E", "F", "I", "D"]
lint.pydocstyle.convention = "google"Pre-commit hooks automatically format markdown files with Prettier (88-character line width, prose wrapping).
# Format code
black .
# Lint code
ruff check .
# Auto-fix linting issues
ruff check --fix .All functions should include type hints:
from typing import Dict, List, Optional, Any
import torch
from transformers import AutoTokenizer
def load_model(model_path: str) -> Optional[torch.nn.Module]:
"""Load PyTorch model from path."""
pass
def predict_batch(texts: List[str]) -> List[Dict[str, Any]]:
"""Predict emotions for multiple texts."""
passUse Google-style docstrings:
def process_text(text: str, max_length: int = 512) -> str:
"""Process and clean input text.
Args:
text: Raw input text
max_length: Maximum allowed text length
Returns:
Processed and cleaned text
Raises:
ValueError: If text exceeds maximum length
TypeError: If text is not a string
Example:
>>> process_text("Hello, world!", max_length=10)
"Hello, wor"
"""
if not isinstance(text, str):
raise TypeError("Text must be a string")
if len(text) > max_length:
text = text[:max_length]
return text.strip()- Use comments to explain why, not what
- Keep comments up-to-date with code changes
- Use TODO comments for future improvements
# ✅ Good - explains why
# Use CPU for inference to avoid GPU memory issues in production
device = torch.device('cpu')
# ❌ Bad - explains what (obvious from code)
# Set device to CPU
device = torch.device('cpu')tests/
├── unit/ # Unit tests
├── integration/ # Integration tests
├── e2e/ # End-to-end tests
├── fixtures/ # Test data and fixtures
└── conftest.py # Pytest configuration
# tests/unit/test_emotion_detector.py
import pytest
from src.emotion_detector import EmotionDetector
class StubEmotionDetector(EmotionDetector):
"""Stub implementation for testing."""
def predict(self, text):
return {"emotion": "happy", "confidence": 0.99, "text": text}
class TestEmotionDetector:
"""Test cases for EmotionDetector class."""
@pytest.fixture
def detector(self):
"""Create EmotionDetector instance for testing."""
return StubEmotionDetector()
def test_predict_happy_text(self, detector):
"""Test emotion prediction for happy text."""
text = "I'm feeling really happy today!"
result = detector.predict(text)
assert result["emotion"] == "happy"
assert result["confidence"] == 0.99 # Fixed value for testing
assert "text" in result
def test_predict_empty_text(self, detector):
"""Test emotion prediction with empty text."""
with pytest.raises(ValueError, match="Text cannot be empty"):
detector.predict("")
def test_predict_invalid_input(self, detector):
"""Test emotion prediction with invalid input."""
with pytest.raises(TypeError, match="Text must be a string"):
detector.predict(123)# Run all tests
pytest
# Run specific test file
pytest tests/unit/test_emotion_detector.py
# Run with coverage
pytest --cov=src --cov-report=html
# Run integration tests only
pytest tests/integration/
# Run tests in parallel (requires pytest-xdist)
pytest -n autoWe aim for 90%+ test coverage:
# Generate coverage report
pytest --cov=src --cov-report=term-missing
# View HTML coverage report
python -m webbrowser htmlcov/index.html# Create and switch to feature branch
git checkout -b feature/your-feature-name
# Or use conventional commit format
git checkout -b feat/add-new-emotion-model
git checkout -b fix/security-vulnerability
git checkout -b docs/update-api-documentation- Write code following our standards
- Add tests for new functionality
- Update documentation
- Ensure all tests pass
Use conventional commit format:
# Format: type(scope): description
git commit -m "feat(api): add batch prediction endpoint"
git commit -m "fix(security): update dependencies to fix vulnerabilities"
git commit -m "docs(readme): update installation instructions"
git commit -m "test(emotion): add comprehensive test coverage"Commit Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
# Push to your fork
git push origin feature/your-feature-name
# Create Pull Request on GitHubUse our PR template:
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests added/updated
- [ ] No security vulnerabilities introducedBefore submitting PR:
- Self-review your code
- Ensure all tests pass
- Update documentation
- Check for security issues
- Follow naming conventions
During review:
- Respond to feedback promptly
- Be open to suggestions
- Explain your reasoning when needed
- Make requested changes
Review checklist:
- Code follows project standards
- Tests are comprehensive
- Documentation is updated
- No security issues introduced
- Performance considerations addressed
- Error handling is appropriate
Review comments:
- Be constructive and specific
- Suggest alternatives when possible
- Focus on code quality and maintainability
- Consider security implications
-
Input Validation
# ✅ Good def validate_text(text: str) -> str: if not isinstance(text, str): raise TypeError("Text must be a string") if len(text) > 1000: raise ValueError("Text too long") return text.strip()
-
Secrets Management
# ✅ Good - Use environment variables import os api_key = os.getenv('API_KEY') if not api_key: raise RuntimeError("API_KEY is not set") # ❌ Bad - Hardcoded secrets api_key = "your-api-key-here" # Never commit real API keys
-
SQL Injection Prevention
# ✅ Good - Use parameterized queries cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) # ❌ Bad - String concatenation (vulnerable to SQL injection; do NOT use) cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
- No hardcoded secrets
- Input validation implemented
- SQL injection prevention
- XSS protection
- CSRF protection
- Rate limiting implemented
- Error messages don't leak information
- Dependencies are up-to-date
Run these tools locally and in CI:
# Dependency audit
pip-audit
# Static analysis
bandit -q -r src
# Secret scanning
gitleaks detect --no-git
# Container scanning (if shipping images)
trivy image your-image:tag
# SBOM generation
syft packages your-image:tagFor security vulnerabilities:
- DO NOT create a public issue
- Email: security@samo-project.com
- Include detailed description and reproduction steps
- We'll respond within 24 hours
-
README Updates
- Update README.md for user-facing changes
- Include examples and usage instructions
- Update installation steps if needed
-
API Documentation
- Update OpenAPI specification
- Add examples for new endpoints
- Document error responses
-
Code Documentation
- Add docstrings to all functions
- Include type hints
- Add inline comments for complex logic
- README updated
- API docs updated
- Code docstrings added
- Examples provided
- Installation instructions current
- Troubleshooting section updated
- Check existing issues on GitHub
- Search documentation for answers
- Ask in discussions for general questions
- Create issue for bugs or feature requests
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: General questions and discussions
- Email: security@samo-project.com (security issues only)
Use our issue templates:
- Bug Report: For reporting bugs
- Feature Request: For requesting new features
- Documentation: For documentation issues
We recognize contributors in several ways:
- Contributors list in README
- Release notes for significant contributions
- Special thanks for major features
- Bronze: 1-5 contributions
- Silver: 6-20 contributions
- Gold: 21+ contributions
- Platinum: Core team member
By contributing to SAMO-DL, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to SAMO-DL! 🚀
Your contributions help make this project better for everyone in the community.
