Contributing¶
Thank you for your interest in contributing to S3 Asyncio Client! This guide will help you get started with development and understand our contribution process.
Development Environment Setup¶
Prerequisites¶
- Python 3.11 or higher
- uv package manager
- Git
Setting Up the Development Environment¶
-
Clone the repository:
-
Install dependencies:
-
Activate the virtual environment:
-
Verify installation:
Development Workflow¶
Code Quality¶
We use several tools to maintain code quality:
- ruff: For linting and formatting
- pytest: For testing
- mypy: For type checking (optional but recommended)
Running Code Quality Checks¶
# Format code
uv run ruff format
# Check for linting issues
uv run ruff check
# Fix auto-fixable issues
uv run ruff check --fix
# Run all checks before committing
uv run ruff check && uv run ruff format --check
Running Tests¶
# Run all tests
uv run pytest
# Run tests with coverage
uv run pytest --cov=s3_asyncio_client
# Run specific test file
uv run pytest tests/test_client.py
# Run tests with verbose output
uv run pytest -v
# Run tests and stop on first failure
uv run pytest -x
Testing with MinIO¶
For integration testing, you can set up a local MinIO server:
# Start MinIO with Docker
docker run -p 9000:9000 -p 9001:9001 \
-e "MINIO_ROOT_USER=minioadmin" \
-e "MINIO_ROOT_PASSWORD=minioadmin" \
minio/minio server /data --console-address ":9001"
# Run integration tests
export S3_TEST_ENDPOINT=http://localhost:9000
export S3_TEST_ACCESS_KEY=minioadmin
export S3_TEST_SECRET_KEY=minioadmin
uv run pytest tests/test_integration.py
Project Structure¶
s3-asyncio-client/
├── src/s3_asyncio_client/
│ ├── __init__.py # Public API exports
│ ├── client.py # Main S3Client class
│ ├── auth.py # AWS Signature V4 authentication
│ ├── exceptions.py # Exception hierarchy
│ └── multipart.py # Multipart upload functionality
├── tests/
│ ├── test_client.py # Client tests
│ ├── test_auth.py # Authentication tests
│ ├── test_exceptions.py # Exception tests
│ ├── test_multipart.py # Multipart upload tests
│ └── conftest.py # Test configuration
├── docs/ # Documentation
├── pyproject.toml # Project configuration
└── README.md
Contributing Guidelines¶
Types of Contributions¶
We welcome several types of contributions:
- Bug Fixes: Fix issues in existing functionality
- New Features: Add new S3 operations or capabilities
- Documentation: Improve docs, examples, or guides
- Tests: Add or improve test coverage
- Performance: Optimize existing code
Before You Start¶
- Check existing issues: Look for related issues or discussions
- Create an issue: For significant changes, create an issue first to discuss
- Fork the repository: Create your own fork to work on
Making Changes¶
-
Create a branch: Use descriptive branch names
-
Make your changes: Follow the coding standards below
-
Add tests: All new functionality must include tests
-
Update documentation: Update relevant documentation files
-
Run quality checks: Ensure all checks pass
Coding Standards¶
Code Style¶
- Use ruff for formatting and linting
- Follow PEP 8 style guidelines
- Use type hints for all function parameters and return values
- Maximum line length: 88 characters
Code Organization¶
# Good: Clear type hints and docstrings
async def put_object(
self,
bucket: str,
key: str,
data: bytes,
content_type: str | None = None,
metadata: dict[str, str] | None = None
) -> dict[str, Any]:
"""Upload an object to S3.
Args:
bucket: The S3 bucket name
key: The object key
data: The object data as bytes
content_type: The MIME type of the object
metadata: Custom metadata for the object
Returns:
A dictionary containing the response data
Raises:
S3ClientError: If the request fails
"""
Error Handling¶
- Use specific exception types from
exceptions.py
- Provide helpful error messages
- Include relevant context in exceptions
# Good: Specific exception with context
if response.status == 404:
raise S3NotFoundError(
f"Object '{key}' not found in bucket '{bucket}'",
status_code=404
)
# Avoid: Generic exceptions
if response.status == 404:
raise Exception("Not found")
Async/Await Patterns¶
- Use
async
/await
consistently - Properly handle
aiohttp
sessions - Use context managers where appropriate
# Good: Proper async context management
async with self._session.get(url) as response:
data = await response.read()
return data
# Avoid: Not awaiting properly
response = self._session.get(url) # Missing await
Testing Guidelines¶
Test Structure¶
- Use pytest for all tests
- Use pytest-asyncio for async tests
- Mock external dependencies when appropriate
import pytest
from unittest.mock import AsyncMock, Mock
@pytest.mark.asyncio
async def test_put_object_success(client):
"""Test successful object upload."""
# Arrange
mock_response = Mock()
mock_response.headers = {"ETag": '"abc123"'}
client._make_request = AsyncMock(return_value=mock_response)
# Act
result = await client.put_object("bucket", "key", b"data")
# Assert
assert result["etag"] == '"abc123"'
client._make_request.assert_called_once()
Test Coverage¶
- Aim for high test coverage (>90%)
- Test both success and error cases
- Include edge cases and boundary conditions
Documentation Guidelines¶
Docstring Style¶
Use Google-style docstrings:
def function(param1: str, param2: int = 0) -> str:
"""Brief description of the function.
Longer description if needed, explaining the purpose,
behavior, and any important details.
Args:
param1: Description of param1
param2: Description of param2, defaults to 0
Returns:
Description of the return value
Raises:
ValueError: If param1 is empty
S3ClientError: If the S3 request fails
Example:
>>> result = function("hello", 42)
>>> print(result)
"hello42"
"""
Documentation Files¶
- Use Markdown for all documentation
- Include code examples in documentation
- Keep examples practical and runnable
Submitting Changes¶
Pull Request Process¶
-
Push your branch: Push to your fork
-
Create a pull request: Use the GitHub interface
-
Fill out the PR template: Provide a clear description
-
Ensure CI passes: All checks must pass
-
Respond to feedback: Address reviewer comments
PR Description Template¶
## Summary
Brief description of the changes made.
## 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
- [ ] Tests pass locally
- [ ] New tests added for new functionality
- [ ] Integration tests pass (if applicable)
## Checklist
- [ ] Code follows the project's style guidelines
- [ ] Self-review of code completed
- [ ] Code is commented, particularly in hard-to-understand areas
- [ ] Corresponding documentation changes made
- [ ] No new warnings introduced
Release Process¶
Versioning¶
We follow Semantic Versioning (SemVer):
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
Release Checklist¶
- Update version in
pyproject.toml
- Update
CHANGELOG.md
- Create and push git tag
- GitHub Actions will handle PyPI release
Getting Help¶
Communication¶
- Issues: For bug reports and feature requests
- Discussions: For questions and general discussion
- Email: For security issues (security@example.com)
Development Questions¶
If you have questions while developing:
- Check existing documentation and examples
- Search existing issues and discussions
- Create a new discussion for general questions
- Create an issue for specific bugs or feature requests
Code of Conduct¶
We are committed to providing a welcoming and inclusive environment. Please:
- Be respectful and constructive in all interactions
- Focus on what is best for the community
- Show empathy towards other contributors
- Accept constructive criticism gracefully
Recognition¶
Contributors will be recognized in:
- CONTRIBUTORS.md file
- Release notes for significant contributions
- Documentation for major feature additions
Thank you for contributing to S3 Asyncio Client! 🚀