Enterprise-grade Python SDK for TelemetryFlow - the observability platform that provides unified metrics, logs, and traces collection following OpenTelemetry standards.
Thank you for your interest in contributing to the TelemetryFlow Python SDK! This document provides guidelines and information for contributors.
- Code of Conduct
- Getting Started
- Development Setup
- Project Structure
- Making Changes
- Testing
- Submitting Changes
- Style Guide
- Architecture Guidelines
- CLI Generators
- Release Process
By participating in this project, you agree to maintain a respectful and inclusive environment. We expect all contributors to:
- Be respectful and constructive in discussions
- Welcome newcomers and help them learn
- Focus on what is best for the community
- Show empathy towards other community members
- Python 3.12 or higher (minimum supported version)
- Git
- Make (optional, for using Makefile commands)
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/telemetryflow-python-sdk.git
cd telemetryflow-python-sdk- Add the upstream remote:
git remote add upstream https://github.com/telemetryflow/telemetryflow-python-sdk.git# Create virtual environment
python -m venv .venv
# Activate (Linux/macOS)
source .venv/bin/activate
# Activate (Windows)
.venv\Scripts\activate# Install package in development mode with dev dependencies
pip install -e ".[dev]"# Run tests
pytest tests/ -v
# Run linter
ruff check src/ tests/
# Run formatter check
ruff format --check src/ tests/
# Run type checker
mypy src/ --ignore-missing-importsWe recommend using an IDE with Python support:
- VS Code with the Python extension
- PyCharm by JetBrains
- Vim/Neovim with pylsp or pyright
The SDK follows Domain-Driven Design (DDD) and CQRS patterns:
telemetryflow-python-sdk/
├── src/telemetryflow/
│ ├── __init__.py # Public exports
│ ├── client.py # TelemetryFlow client
│ ├── builder.py # Builder pattern for configuration
│ ├── domain/ # Domain layer (entities, value objects)
│ │ ├── config.py # TelemetryConfig entity
│ │ └── credentials.py # Credentials value object
│ ├── application/ # Application layer (CQRS)
│ │ ├── commands.py # Command definitions
│ │ └── queries.py # Query definitions
│ ├── infrastructure/ # Infrastructure layer
│ │ ├── exporters.py # OTLP exporter factory
│ │ └── handlers.py # Command handlers
│ └── cli/ # CLI generators
│ ├── generator.py # telemetryflow-gen
│ ├── generator_restapi.py # telemetryflow-restapi
│ └── templates/ # Template files for code generation
│ ├── gen/ # Basic SDK templates
│ └── restapi/ # RESTful API templates
│ ├── project/ # Project structure templates
│ ├── domain/ # Domain layer templates
│ ├── application/ # Application layer templates
│ ├── infrastructure/ # Infrastructure templates
│ ├── entity/ # Entity generation templates
│ └── docs/ # Documentation templates
├── tests/
│ ├── unit/ # Unit tests
│ │ └── cli/ # CLI generator tests
│ ├── integration/ # Integration tests
│ └── e2e/ # End-to-end tests
├── docs/
│ ├── ARCHITECTURE.md # Architecture documentation
│ └── QUICKSTART.md # Quickstart guide
├── examples/ # Usage examples
├── pyproject.toml # Project configuration
├── CHANGELOG.md # Version history
└── README.md # Project overview
| Layer | Responsibility | Dependencies |
|---|---|---|
| Domain | Business logic, entities, value objects | None (pure Python) |
| Application | Use cases, commands, queries | Domain only |
| Infrastructure | Technical implementations, exporters | Domain, Application |
| Interface | Public API (Client, Builder) | All layers |
| CLI | Code generators | All layers |
Use descriptive branch names:
feature/add-custom-metric-typesfix/connection-timeout-handlingdocs/update-api-referencerefactor/simplify-command-handlers
# Sync with upstream
git fetch upstream
git checkout main
git merge upstream/main
# Create feature branch
git checkout -b feature/your-feature-nameFollow conventional commits format:
type(scope): short description
Longer description if needed.
Fixes #123
Types:
feat: New featurefix: Bug fixdocs: Documentation changestest: Adding or updating testsrefactor: Code refactoringchore: Maintenance tasks
Examples:
feat(metrics): add support for exponential histograms
Implement exponential histogram recording for more efficient
distribution tracking of high-cardinality data.
Fixes #45
fix(exporter): handle connection timeout gracefully
Added proper timeout handling and retry logic when the
OTLP endpoint is temporarily unavailable.
# Run all tests
pytest tests/ -v
# Run only unit tests
pytest tests/unit/ -v
# Run tests with coverage
pytest tests/ -v --cov=src/telemetryflow --cov-report=html
# Run specific test file
pytest tests/unit/cli/test_generator.py -v
# Run tests matching a pattern
pytest tests/ -v -k "test_credentials"Follow these guidelines for tests:
- Unit Tests: Test individual functions and methods in isolation
- Integration Tests: Test interactions between layers
- Parametrized Tests: Use pytest parametrize for multiple scenarios
Example test structure:
import pytest
from telemetryflow.domain import Credentials
class TestCredentials:
"""Tests for Credentials value object."""
@pytest.mark.parametrize("key_id,key_secret,should_raise", [
("tfk_valid_key", "tfs_valid_secret", False),
("", "tfs_valid_secret", True),
("tfk_valid_key", "", True),
("invalid", "tfs_valid_secret", True),
])
def test_credentials_validation(
self,
key_id: str,
key_secret: str,
should_raise: bool,
) -> None:
"""Test credentials validation with various inputs."""
if should_raise:
with pytest.raises(ValueError):
Credentials(key_id, key_secret)
else:
creds = Credentials(key_id, key_secret)
assert creds.key_id == key_id
assert creds.key_secret == key_secretWe aim for high test coverage, especially in:
- Domain layer: 90%+
- Application layer: 85%+
- Infrastructure layer: 80%+
- CLI generators: 85%+
- Run tests:
pytest tests/ -v - Run linter:
ruff check src/ tests/ - Run formatter:
ruff format src/ tests/ - Run type checker:
mypy src/ --ignore-missing-imports - Update documentation if needed
- Add tests for new functionality
- Push your branch to your fork:
git push origin feature/your-feature-name-
Create a Pull Request on GitHub
-
Fill in the PR template with:
- Description of changes
- Related issue numbers
- Testing performed
- Checklist items
-
Wait for review and address feedback
Use the same format as commit messages:
feat(metrics): add exponential histogram support
fix(exporter): handle connection timeouts
docs(api): update method signatures
Follow PEP 8 and modern Python conventions:
- Use
rufffor linting and formatting - Use type hints for all public functions and methods
- Use dataclasses or Pydantic for data structures
- Prefer f-strings over string formatting
| Type | Convention | Example |
|---|---|---|
| Modules | lowercase, underscores | domain, application |
| Classes | PascalCase | TelemetryConfig, Credentials |
| Functions | snake_case | new_credentials, handle_command |
| Constants | UPPER_SNAKE_CASE | PROTOCOL_GRPC, SIGNAL_METRICS |
| Private | leading underscore | _validate_config, _internal_state |
- Use custom exceptions for domain-specific errors
- Always include helpful error messages
- Use exception chaining with
from
# Good
class InvalidCredentialsError(ValueError):
"""Raised when credentials are invalid."""
pass
def validate_credentials(key_id: str, key_secret: str) -> None:
if not key_id.startswith("tfk_"):
raise InvalidCredentialsError(
f"Invalid key ID format: must start with 'tfk_', got '{key_id[:10]}...'"
)
# With exception chaining
try:
result = external_api_call()
except ExternalAPIError as e:
raise ConnectionError("Failed to connect to telemetry endpoint") from e- Document all public types, functions, and methods
- Use Google-style docstrings
- Include type hints in signatures
def new_credentials(key_id: str, key_secret: str) -> Credentials:
"""Create a new Credentials value object.
Creates and validates new credentials for authenticating with
the TelemetryFlow API.
Args:
key_id: The API key ID, must start with 'tfk_'.
key_secret: The API key secret, must start with 'tfs_'.
Returns:
A validated Credentials object.
Raises:
InvalidCredentialsError: If either key_id or key_secret is invalid.
Example:
>>> creds = new_credentials("tfk_example", "tfs_secret")
>>> print(creds.key_id)
'tfk_example'
"""
# Implementation...When contributing, maintain the architectural principles:
- Value Objects: Immutable, validate on creation
- Entities: Have identity, can change state through methods
- Aggregate Roots: Entry point for accessing aggregates
- Commands: Represent intentions to change state
- Queries: Represent requests for data
- Handlers: Execute commands and queries
- Single Responsibility: One reason to change per type
- Open/Closed: Open for extension, closed for modification
- Liskov Substitution: Subtypes must be substitutable
- Interface Segregation: Small, focused interfaces (protocols)
- Dependency Inversion: Depend on abstractions (protocols)
When adding new features:
- Define domain concepts first (if applicable)
- Create commands/queries in the application layer
- Implement handlers in the infrastructure layer
- Expose through the public API (Client)
- Add comprehensive tests
The SDK includes two CLI generators that use template-based code generation:
Basic SDK code generator:
# Generate example project
telemetryflow-gen example basic -o ./my-project
# Generate configuration file
telemetryflow-gen config -k tfk_key -s tfs_secret -o .envDDD + CQRS RESTful API generator using Flask:
# Create new project
telemetryflow-restapi new -n my-api -o ./
# Add entity to existing project
telemetryflow-restapi entity -n User -f 'name:string,email:string' -o ./my-apiTemplates are stored in src/telemetryflow/cli/templates/ and use Python's string.Template for substitution:
- Templates use
${variable_name}syntax - Templates are loaded via
importlib.resources - Each generator has its own template subdirectory
- Create
.tpltemplate file in appropriate directory - Use
${variable}for substitutions - Update generator to load and render template
- Add tests for new templates
Releases follow semantic versioning (SemVer):
- MAJOR: Breaking API changes
- MINOR: New features, backward compatible
- PATCH: Bug fixes, backward compatible
The project uses GitHub Actions for CI/CD:
| Workflow | Trigger | Purpose |
|---|---|---|
ci.yml |
Push/PR | Lint, test, build verification |
docker.yml |
Push to main/tags | Build Docker images |
release.yml |
Tags (v*..) | Publish to PyPI, create GitHub release |
Update CHANGELOG.md with your changes under the "Unreleased" section.
- Update version in
pyproject.toml - Update version badge in
README.mdandCONTRIBUTING.md - Move "Unreleased" section in CHANGELOG.md to new version
- Create and push tag:
git tag v1.2.0
git push origin v1.2.0GitHub Actions will automatically:
- Run tests
- Build packages
- Publish to PyPI
- Create GitHub release
- Questions: Open a GitHub Discussion
- Bugs: Open a GitHub Issue with the bug template
- Features: Open a GitHub Issue with the feature request template
- Security: Email security@telemetryflow.id (do not open public issues)
Contributors are recognized in:
- GitHub Contributors page
- CHANGELOG.md for significant contributions
- README.md acknowledgments section
Thank you for contributing to TelemetryFlow Python SDK!
Built with care by the DevOpsCorner Indonesia community