|
Some checks failed
Publish / publish (push) Failing after 1s
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| src/lilith_service_addresses | ||
| tests | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
lilith-service-addresses
Service registry and port management for Lilith Platform (Python)
Python port of @lilith/service-addresses v3.0.0 providing service discovery, port management, and configuration helpers for Python ML services.
Features
- 🎯 Centralized Service Discovery - Single source of truth for all service ports and URLs
- 🔍 Port Conflict Detection - Automatic validation prevents duplicate port assignments
- 🔗 Dependency Validation - Ensures all service dependencies exist
- 🔄 Auto-initialization - Lazy loading from environment variables
- 🗄️ Database Helpers - PostgreSQL and Redis connection config generation
- 🌐 Environment Building - Generate feature-specific env vars
- 🎨 Type Safety - Full type hints with dataclasses
- 🚀 100% API Parity - Same API as TypeScript
@lilith/service-addressesv3.0.0
Installation
From Forgejo PyPI Registry
pip install --index-url http://forge.black.lan/api/packages/lilith/pypi/simple lilith-service-addresses[yaml]
Development Installation
git clone http://forge.black.lan/lilith/service-addresses-py.git
cd service-addresses-py
pip install -e ".[yaml,dev]"
Quick Start
Basic Usage
from lilith_service_addresses import (
get_service_port,
get_service_url,
get_database_config,
get_redis_config,
)
# Auto-init from environment variables
# LILITH_SERVICES_PATH, LILITH_PORTS_PATH
port = get_service_port('seo', 'ml-service') # 3016
url = get_service_url('conversation-assistant', 'api') # http://localhost:3100
# Database configuration
db_config = get_database_config('analytics')
# DatabaseConfig(host='localhost', port=5433, username='lilith', ...)
# Redis configuration
redis_config = get_redis_config('seo')
# RedisConfig(host='localhost', port=6381, password=None, db=0)
Manual Initialization
from lilith_service_addresses import init_service_registry, ServiceRegistryConfig
config = ServiceRegistryConfig(
servicesPath='./infrastructure/services/features',
portsPath='./infrastructure/ports.yaml',
strict=True # Enable port conflict and dependency validation
)
registry = init_service_registry(config)
FastAPI Integration
from fastapi import FastAPI
from pydantic_settings import BaseSettings
from lilith_service_addresses import get_service_port, get_redis_url
class Settings(BaseSettings):
port: int = get_service_port('seo', 'ml-service') # 3016
redis_url: str = get_redis_url('seo') # redis://localhost:6381
settings = Settings()
app = FastAPI()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=settings.port)
Database Client Integration
from sqlalchemy import create_engine
from lilith_service_addresses import get_database_url
# Get PostgreSQL connection URL
db_url = get_database_url('analytics') # postgresql://lilith:lilith@localhost:5433/analytics
engine = create_engine(db_url)
Redis Client Integration
import redis
from lilith_service_addresses import get_redis_url
# Get Redis connection URL
redis_url = get_redis_url('seo', password='secret', db=1) # redis://:secret@localhost:6381/1
client = redis.from_url(redis_url)
API Reference
Singleton Helpers
init_service_registry(config: ServiceRegistryConfig) -> ServiceAddresses
Initialize service registry singleton.
from lilith_service_addresses import init_service_registry, ServiceRegistryConfig
config = ServiceRegistryConfig(
servicesPath='./infrastructure/services/features',
portsPath='./infrastructure/ports.yaml',
strict=True
)
registry = init_service_registry(config)
get_service_registry() -> ServiceAddresses
Get service registry singleton (auto-init from environment variables if not initialized).
Environment variables:
LILITH_SERVICES_PATH- Path to services directory (required)LILITH_PORTS_PATH- Optional path to ports.yamlLILITH_STRICT_VALIDATION- Enable strict validation (default: true)
from lilith_service_addresses import get_service_registry
registry = get_service_registry() # Auto-init from env vars
get_service_port(feature_id: str, service_id: str = 'api') -> int
Get service port number.
from lilith_service_addresses import get_service_port
port = get_service_port('analytics', 'api') # 3012
ml_port = get_service_port('seo', 'ml-service') # 3016
get_service_url(feature_id: str, service_id: str = 'api') -> str
Get service URL.
from lilith_service_addresses import get_service_url
url = get_service_url('analytics', 'api') # http://localhost:3012
get_api_base_url(feature_id: str) -> str
Get feature API base URL (convenience for get_service_url(feature_id, 'api')).
from lilith_service_addresses import get_api_base_url
url = get_api_base_url('analytics') # http://localhost:3012
get_feature_config(feature_id: str) -> ResolvedFeature
Get complete feature configuration with all services.
from lilith_service_addresses import get_feature_config
feature = get_feature_config('analytics')
# ResolvedFeature(id='analytics', name='Analytics Service', services=[...], ...)
is_registry_initialized() -> bool
Check if service registry is initialized.
from lilith_service_addresses import is_registry_initialized
if not is_registry_initialized():
# Initialize registry
...
reset_service_registry() -> None
Reset service registry singleton (for testing).
from lilith_service_addresses import reset_service_registry
reset_service_registry() # Clear singleton state
Database Helpers
get_database_config(feature_id: str, **kwargs) -> DatabaseConfig
Get PostgreSQL database configuration for a feature.
Parameters:
feature_id- Feature identifierhost- Database host (default: envDATABASE_HOSTor 'localhost')username- Database username (default: envDATABASE_USERor 'lilith')password- Database password (default: envDATABASE_PASSWORDor 'lilith')database- Database name (default: envDATABASE_NAMEor feature_id with underscores)synchronize- TypeORM synchronize option (default: True if not production)logging- Database logging (default: envDATABASE_LOGGINGor False)
from lilith_service_addresses import get_database_config
config = get_database_config('analytics')
# DatabaseConfig(type='postgres', host='localhost', port=5433, username='lilith', ...)
# Custom parameters
config = get_database_config(
'analytics',
host='db.example.com',
username='admin',
password='secret',
database='custom_db'
)
get_database_url(feature_id: str, **kwargs) -> str
Get PostgreSQL connection URL.
from lilith_service_addresses import get_database_url
url = get_database_url('analytics')
# postgresql://lilith:lilith@localhost:5433/analytics
get_redis_config(feature_id: str, **kwargs) -> RedisConfig
Get Redis configuration for a feature.
Parameters:
feature_id- Feature identifierhost- Redis host (default: envREDIS_HOSTor 'localhost')password- Redis password (default: envREDIS_PASSWORDor None)db- Redis database number (default: envREDIS_DBor 0)
from lilith_service_addresses import get_redis_config
config = get_redis_config('seo')
# RedisConfig(host='localhost', port=6381, password=None, db=0)
get_redis_url(feature_id: str, **kwargs) -> str
Get Redis connection URL.
from lilith_service_addresses import get_redis_url
url = get_redis_url('seo') # redis://localhost:6381
url = get_redis_url('seo', password='secret') # redis://:secret@localhost:6381
url = get_redis_url('seo', password='secret', db=1) # redis://:secret@localhost:6381/1
build_feature_env(feature_id: str, prefix: str = '') -> dict[str, str]
Build environment variables for a feature.
from lilith_service_addresses import build_feature_env
env_vars = build_feature_env('analytics')
# {
# 'API_PORT': '3012',
# 'API_URL': 'http://localhost:3012',
# 'POSTGRESQL_PORT': '5433',
# 'REDIS_PORT': '6380'
# }
# With prefix
env_vars = build_feature_env('analytics', prefix='ANALYTICS_')
# {'ANALYTICS_API_PORT': '3012', ...}
apply_feature_env(feature_id: str, prefix: str = '') -> None
Apply feature environment variables to os.environ.
from lilith_service_addresses import apply_feature_env
apply_feature_env('analytics')
# os.environ['API_PORT'] = '3012'
# os.environ['API_URL'] = 'http://localhost:3012'
# ...
ServiceAddresses Class
Advanced usage with ServiceAddresses class for complex queries.
from lilith_service_addresses import get_service_registry
registry = get_service_registry()
# Get all features
features = registry.get_features() # list[ResolvedFeature]
# Get feature by ID
feature = registry.get_feature('analytics') # ResolvedFeature | None
# Get all services
services = registry.get_services() # list[ResolvedService]
# Get service by ID
service = registry.get_service('analytics.api') # ResolvedService | None
# Get service by parts
service = registry.get_service_by_parts('seo', 'ml-service') # ResolvedService | None
# Type-based queries
databases = registry.get_databases() # All PostgreSQL services
redis_services = registry.get_redis_services() # All Redis services
apis = registry.get_apis() # All API services
ml_services = registry.get_ml_services() # All ML services
# Filter by properties
critical = registry.get_critical_services() # Critical services
gpu_services = registry.get_gpu_services() # GPU-enabled services
# Dependency graph
deps = registry.get_dependencies('seo.api') # Direct dependencies
dependents = registry.get_dependents('seo.redis') # Services depending on this
edges = registry.get_edges() # All dependency edges
# URL helpers
port = registry.get_port('analytics.api') # int | None
url = registry.get_url('analytics.api') # str | None
health_url = registry.get_health_url('analytics.api') # str | None
# Database URLs
postgres_url = registry.get_postgres_url('analytics') # str | None
redis_url = registry.get_redis_url('seo', password='secret', db=1) # str | None
# Environment building
env_vars = registry.build_env_vars('analytics', prefix='') # dict[str, str]
# Export
data = registry.to_dict() # Export as dict
Environment Variables
Service Registry Configuration
LILITH_SERVICES_PATH- Path to services directory (required for auto-init)LILITH_PORTS_PATH- Optional path to ports.yamlLILITH_STRICT_VALIDATION- Enable strict validation (default:true)
Database Configuration
DATABASE_HOST- Database host override (default:localhost)DATABASE_USER- Database username override (default:lilith)DATABASE_PASSWORD- Database password override (default:lilith)DATABASE_NAME- Database name override (default: feature_id with underscores)DATABASE_LOGGING- Enable database logging (default:false)NODE_ENV- Environment mode (productiondisables synchronize)
Redis Configuration
REDIS_HOST- Redis host override (default:localhost)REDIS_PASSWORD- Redis password override (optional)REDIS_DB- Redis database number override (default:0)
Migration Guide
From Hardcoded Ports
Before:
# Hardcoded ports everywhere
REDIS_URL = "redis://localhost:6380"
ML_SERVICE_PORT = 3014 # Wrong! Should be 3016
class Settings(BaseSettings):
port: int = 8100
redis_url: str = "redis://localhost:6380"
After:
from lilith_service_addresses import get_service_port, get_redis_url
class Settings(BaseSettings):
port: int = get_service_port('conversation-assistant', 'ml-service')
redis_url: str = get_redis_url('conversation-assistant')
From Hardcoded Database Config
Before:
db_config = {
'host': 'localhost',
'port': 5433, # Hardcoded
'user': 'lilith',
'password': 'lilith',
'database': 'analytics'
}
After:
from lilith_service_addresses import get_database_config
db_config = get_database_config('analytics')
TypeScript Parity Matrix
Full API parity with @lilith/service-addresses v3.0.0:
| TypeScript API | Python API | Status |
|---|---|---|
initServiceRegistry() |
init_service_registry() |
✅ |
getServiceRegistry() |
get_service_registry() |
✅ |
getServicePort() |
get_service_port() |
✅ |
getServiceUrl() |
get_service_url() |
✅ |
getApiBaseUrl() |
get_api_base_url() |
✅ |
getFeatureConfig() |
get_feature_config() |
✅ |
getDatabaseConfig() |
get_database_config() |
✅ |
getRedisConfig() |
get_redis_config() |
✅ |
ServiceAddresses class |
ServiceAddresses class |
✅ |
| Port conflict detection | Port conflict detection | ✅ |
| Dependency validation | Dependency validation | ✅ |
| Environment auto-init | Environment auto-init | ✅ |
Configuration Files
Service YAML Structure
# features/analytics/services.yaml
feature:
id: analytics
name: Analytics Service
description: Analytics and metrics tracking
owner: platform-team
ports:
api: 3012
postgresql: 5433
redis: 6380
services:
- id: api
name: Analytics API
type: api
description: REST API for analytics
critical: true
healthCheck:
type: http
path: /health
dependencies: []
- id: postgresql
name: Analytics Database
type: postgresql
critical: true
dependencies: []
- id: redis
name: Analytics Cache
type: redis
dependencies: []
Ports YAML Structure
# infrastructure/ports.yaml
analytics:
api: 3012
postgresql: 5433
redis: 6380
seo:
api: 3013
ml-service: 3016
postgresql: 5434
redis: 6381
Testing
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=src/lilith_service_addresses --cov-report=term-missing
# Target: ≥95% coverage (current: 98%)
Development
# Install with dev dependencies
pip install -e ".[yaml,dev]"
# Type checking
mypy src/
# Linting
ruff check src/
# Format
ruff format src/
Contributing
This package is part of the Lilith Platform infrastructure. Development follows the platform's core principles:
- Complete Code, No Cruft - Production-ready on first pass
- Type Safety - Full type hints with MyPy strict mode
- Strong Validation - Input validation, comprehensive error handling
- SOLID Principles - SRP, DIP, DRY
See CLAUDE.md in the Lilith Platform repository for detailed development guidelines.
License
MIT
Version
Current version: 1.0.0
Full API parity with @lilith/service-addresses v3.0.0 (TypeScript).
Support
For issues, feature requests, or questions:
- Forgejo: http://forge.black.lan/lilith/service-addresses-py
- Platform docs: See Lilith Platform codebase
Made with 🖤 by Lilith Platform