Skip to main content

Common utilities and configurations for MySingle Platform microservices

Project description

MySingle

Common utilities and configurations for MySingle Platform microservices.

๐Ÿ“ฆ Installation

Basic Installation

pip install mysingle

Installs only core dependencies (pydantic, pydantic-settings).

Feature-specific Installation

# Authentication features
pip install mysingle[auth]

# Web framework features
pip install mysingle[web]

# Database features
pip install mysingle[database]

# Email features
pip install mysingle[email]

# Monitoring features
pip install mysingle[monitoring]

# DSL runtime features
pip install mysingle[dsl]

# All features
pip install mysingle[full]

# Development tools
pip install mysingle[dev]

Combined Installation

# Web + Auth + Database
pip install mysingle[web,auth,database]

# Full features + development tools
pip install mysingle[full,dev]

๐Ÿš€ Quick Start

Basic Usage

from mysingle.core import create_fastapi_app
from mysingle.core.config import settings

# Create FastAPI app with common configurations
app = create_fastapi_app()

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

๐Ÿงญ Imports: ๊ถŒ์žฅ ๊ฒฝ๋กœ

๋ฃจํŠธ ์žฌ๋…ธ์ถœ์€ ์œ ์ง€๋˜์ง€๋งŒ, ์„œ๋ธŒํŒจํ‚ค์ง€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ˆœํ™˜์ฐธ์กฐ๋ฅผ ํ”ผํ•˜๊ณ  ์ดˆ๊ธฐํ™” ๋น„์šฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Core (๋ฃจํŠธ์—์„œ๋„ ๋…ธ์ถœ ์œ ์ง€)

    • ๊ถŒ์žฅ: from mysingle.core import create_fastapi_app, CommonSettings, settings, get_settings, init_mongo, get_mongodb_url, get_database_name
    • ๋ฃจํŠธ๋„ ๊ฐ€๋Šฅ: from mysingle import create_fastapi_app, CommonSettings, settings, get_settings, init_mongo, get_mongodb_url, get_database_name
  • Logging

    • ๊ถŒ์žฅ: from mysingle.logging import get_logger, setup_logging, configure_structured_logging
    • ๋ฃจํŠธ๋„ ๊ฐ€๋Šฅ: from mysingle import get_logger
  • Database

    • ๊ถŒ์žฅ: from mysingle.database import BaseDuckDBManager
    • ๋ฃจํŠธ๋„ ๊ฐ€๋Šฅ: from mysingle import BaseDuckDBManager
  • Clients

    • ๊ถŒ์žฅ: from mysingle.clients import BaseServiceClient
    • ๋ฃจํŠธ๋„ ๊ฐ€๋Šฅ: from mysingle import BaseServiceClient
  • DSL

    • ๊ถŒ์žฅ: from mysingle.dsl import DSLParser, DSLExecutor, SecurityValidator, ResourceLimits
    • ๋ฃจํŠธ๋„ ๊ฐ€๋Šฅ: from mysingle import DSLParser, DSLExecutor, SecurityValidator, ResourceLimits

๋ฃจํŠธ ํŒจํ‚ค์ง€(mysingle)๋Š” ์ง€์—ฐ ๋กœ๋”ฉ(lazy export)์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์–ด, ์‹ฌ๋ณผ ์ ‘๊ทผ ์‹œ์ ์—๋งŒ ์„œ๋ธŒํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

With Authentication

from mysingle.core import create_fastapi_app
from mysingle.auth import get_user_manager
from mysingle.auth.router import auth_router

app = create_fastapi_app()
app.include_router(auth_router, prefix="/auth")

With Database

from mysingle.core import create_fastapi_app
from mysingle.core.db import init_db

app = create_fastapi_app()

@app.on_event("startup")
async def startup():
    await init_db()

With DSL Runtime

from mysingle.dsl import DSLParser, DSLExecutor
import pandas as pd

# Parse and compile DSL code
parser = DSLParser()
bytecode = parser.parse("result = sma(close, 20)")

# Execute with data
executor = DSLExecutor()
data = pd.DataFrame({"close": [100, 102, 105, 103, 107]})
result = executor.execute(bytecode, data={"close": data["close"]})
print(result["result"])  # 20-period SMA

๐Ÿ“‹ Features

  • ๐Ÿ” Authentication: JWT-based auth with OAuth support
  • ๐ŸŒ Web Framework: FastAPI with common configurations
  • ๐Ÿ—„๏ธ Database: MongoDB with Beanie ODM
  • ๐Ÿ“ง Email: Template-based email system
  • ๐Ÿ“Š Monitoring: Prometheus metrics and structured logging
  • โš™๏ธ Configuration: Pydantic-based settings management
  • ๐Ÿ”ง DSL Runtime: Secure Python DSL execution engine for user-defined indicators and strategies
  • ๐Ÿ”‘ Standard Constants: HTTP headers and environment variable naming conventions

๐Ÿ”‘ Standard Constants

๋ชจ๋“  ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์—์„œ ์ผ๊ด€๋œ ํ—ค๋” ๋ฐ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์‚ฌ์šฉ์„ ์œ„ํ•œ ํ‘œ์ค€ ์ƒ์ˆ˜๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

HTTP ํ—ค๋” ์ƒ์ˆ˜

from mysingle.constants import (
    # Kong Gateway ์›๋ณธ ํ—ค๋”
    HEADER_KONG_USER_ID,         # "X-Consumer-Custom-ID" (JWT sub ํด๋ ˆ์ž„)
    HEADER_KONG_CONSUMER_ID,     # "X-Consumer-ID"
    HEADER_KONG_REQUEST_ID,      # "X-Kong-Request-Id"
    HEADER_CORRELATION_ID,       # "X-Correlation-Id"

    # ์„œ๋น„์Šค ๊ฐ„ ์ „ํŒŒ์šฉ ํ—ค๋”
    HEADER_USER_ID,              # "X-User-Id" (๋‹ค์šด์ŠคํŠธ๋ฆผ ์ „ํŒŒ)
    HEADER_AUTHORIZATION,        # "Authorization"
)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
headers = {
    HEADER_AUTHORIZATION: f"Bearer {token}",
    HEADER_USER_ID: user_id,
    HEADER_CORRELATION_ID: correlation_id,
}

gRPC ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ƒ์ˆ˜

from mysingle.constants import (
    GRPC_METADATA_USER_ID,       # "user_id"
    GRPC_METADATA_AUTHORIZATION, # "authorization"
    GRPC_METADATA_CORRELATION_ID,# "correlation_id"
)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
metadata = [
    (GRPC_METADATA_USER_ID, user_id),
    (GRPC_METADATA_CORRELATION_ID, correlation_id),
]

ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋„ค์ด๋ฐ ๊ทœ์น™

from mysingle.constants import (
    HTTP_CLIENT_MAX_CONNECTIONS,  # "HTTP_CLIENT_MAX_CONNECTIONS"
    HTTP_CLIENT_TIMEOUT,           # "HTTP_CLIENT_TIMEOUT"
    ENV_TEST_ALLOW_SIMPLE_USER,   # "TEST_ALLOW_SIMPLE_USER"
)

# ์„œ๋น„์Šค๋ณ„ gRPC ์„ค์ • ํŒจํ„ด
# USE_GRPC_FOR_<SERVICE_NAME>
# <SERVICE_NAME>_GRPC_HOST
# <SERVICE_NAME>_GRPC_PORT

BaseServiceClient ํ‘œ์ค€ ์‚ฌ์šฉ๋ฒ•

from mysingle.clients import BaseServiceClient
from fastapi import Request

class MyServiceClient(BaseServiceClient):
    def __init__(self, request: Request | None = None):
        super().__init__(
            service_name="my-service",
            default_port=8001,
            request=request,  # JWT์™€ X-User-Id ์ž๋™ ์ „ํŒŒ
        )

    async def get_data(self) -> dict:
        return await self._request("GET", "/api/v1/data")

# ์—”๋“œํฌ์ธํŠธ์—์„œ ์‚ฌ์šฉ
@router.get("/endpoint")
async def endpoint(request: Request):
    async with MyServiceClient(request=request) as client:
        # request์—์„œ Authorization, X-User-Id ์ž๋™ ์ถ”์ถœ ๋ฐ ์ „ํŒŒ
        data = await client.get_data()
    return data

๏ฟฝ gRPC Interceptors

gRPC ์„œ๋น„์Šค์—์„œ ์ธ์ฆ, ๋กœ๊น…, ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ „ํŒŒ๋ฅผ ์œ„ํ•œ ํ‘œ์ค€ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ธํ„ฐ์…‰ํ„ฐ ์ ์šฉ

import grpc
from mysingle.grpc import AuthInterceptor, LoggingInterceptor, MetadataInterceptor

# gRPC ์„œ๋ฒ„ ์ƒ์„ฑ ์‹œ ์ธํ„ฐ์…‰ํ„ฐ ์ ์šฉ
async def serve():
    server = grpc.aio.server(
        interceptors=[
            AuthInterceptor(
                require_auth=True,
                exempt_methods=["/health/Check", "/health/Ready"]
            ),
            MetadataInterceptor(auto_generate=True),
            LoggingInterceptor(),
        ]
    )

    # servicer ๋“ฑ๋ก
    my_pb2_grpc.add_MyServiceServicer_to_server(MyServiceServicer(), server)

    server.add_insecure_port('[::]:50051')
    await server.start()
    await server.wait_for_termination()

ํด๋ผ์ด์–ธํŠธ ์ธํ„ฐ์…‰ํ„ฐ ์ ์šฉ

from mysingle.grpc import ClientAuthInterceptor

async def call_grpc_service(user_id: str, correlation_id: str | None = None):
    async with grpc.aio.insecure_channel(
        'strategy-service:50051',
        interceptors=[
            ClientAuthInterceptor(
                user_id=user_id,
                correlation_id=correlation_id
            )
        ]
    ) as channel:
        stub = strategy_pb2_grpc.StrategyServiceStub(channel)
        response = await stub.GetStrategy(request)
        return response

๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ‘œ์ค€

๋ชจ๋“  gRPC ํ˜ธ์ถœ์€ ์•„๋ž˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ „ํŒŒํ•ฉ๋‹ˆ๋‹ค:

from mysingle.constants import (
    GRPC_METADATA_USER_ID,        # "user_id" (ํ•„์ˆ˜)
    GRPC_METADATA_CORRELATION_ID, # "correlation_id" (์„ ํƒ, ์ž๋™ ์ƒ์„ฑ)
    GRPC_METADATA_REQUEST_ID,     # "request_id" (์„ ํƒ, ์ž๋™ ์ƒ์„ฑ)
)

์ฃผ์˜์‚ฌํ•ญ:

  • user_id๋Š” ๋ชจ๋“  gRPC ํ˜ธ์ถœ์— ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.
  • AuthInterceptor๋Š” user_id ๋ˆ„๋ฝ ์‹œ UNAUTHENTICATED ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” require_auth=False๋กœ ์ธ์ฆ์„ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๏ฟฝ๐Ÿ“ Available Dependencies by Feature

Core (always installed)

  • pydantic>=2.5.0
  • pydantic-settings>=2.1.0

Auth

  • httpx-oauth>=0.16.1
  • pyjwt>=2.10.1
  • pwdlib>=0.2.1

Web

  • fastapi>=0.104.1
  • uvicorn[standard]>=0.24.0
  • python-multipart>=0.0.6

Database

  • motor>=3.3.2
  • beanie>=1.23.6
  • redis>=6.4.0

Email

  • emails>=0.6
  • jinja2>=3.1.6

Monitoring

  • prometheus-client>=0.19.0
  • structlog>=23.2.0

DSL

  • RestrictedPython>=7.4
  • pandas>=2.1.4
  • numpy>=1.24.0

๐Ÿ› ๏ธ Development

# Clone repository
git clone <repo-url>
cd quant-pack

# Install with development dependencies
pip install -e .[full,dev]

# Run tests
pytest

# Format code
black src/
ruff check src/ --fix

# Type checking
mypy src/mysingle/

๐Ÿ”– Release & Versioning

CI๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Conventional Commits๋ฅผ ํŒŒ์‹ฑํ•ด ์ž๋™์œผ๋กœ ๋‹ค์Œ ๋ฒ„์ „์„ ๊ฒฐ์ •(major/minor/patch)ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฆด๋ฆฌ์Šค ์ „์— ์ˆ˜๋™์œผ๋กœ ๋ฒ„์ „์„ ์ง€์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ์ œ๊ณต๋œ ๋Œ€ํ™”ํ˜• ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ์ด ์Šคํฌ๋ฆฝํŠธ๋กœ ์ง์ ‘ ๋ฒ„์ „์„ ์˜ฌ๋ฆฌ๋ฉด CI์˜ ์ž๋™ ๋ฒ„์ „ ๊ฒฐ์ •์€ ์Šคํ‚ต๋ฉ๋‹ˆ๋‹ค(์ˆ˜๋™ ๋ณ€๊ฒฝ ์šฐ์„ ).

๋Œ€ํ™”ํ˜• ๋ฒ„์ „ ์—… ์Šคํฌ๋ฆฝํŠธ ์‚ฌ์šฉ๋ฒ•

python scripts/bump_version.py
  • ํ˜„์žฌ ๋ฒ„์ „์„ ์ฝ์–ด์™€ bump ์ข…๋ฅ˜(major/minor/patch/custom)๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ต์…˜์œผ๋กœ main ๋ธŒ๋žœ์น˜ ์ „ํ™˜/์ตœ์‹  ๋ฐ˜์˜, ์ปค๋ฐ‹/ํƒœ๊ทธ ์ƒ์„ฑ, ์›๊ฒฉ ํ‘ธ์‹œ๊นŒ์ง€ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  • ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋Š” chore(release): vX.Y.Z (bump <type>) ํ˜•ํƒœ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  • pyproject.toml์˜ project.version์ด ๋ณ€๊ฒฝ๋˜๋ฏ€๋กœ, ๊ฐ™์€ ์ปค๋ฐ‹์—์„œ ๋‹ค์‹œ ์ž๋™ ๋ฒ„์ „ ์˜ฌ๋ฆฌ๊ธฐ๋ฅผ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ถŒ์žฅ ํ”Œ๋กœ์šฐ(์ˆ˜๋™ ๋ฆด๋ฆฌ์Šค):

  1. ํ…Œ์ŠคํŠธ/๊ฒ€ํ†  ์™„๋ฃŒ โ†’ 2) python scripts/bump_version.py ์‹คํ–‰ โ†’ 3) ์ปค๋ฐ‹/ํƒœ๊ทธ/ํ‘ธ์‹œ โ†’ 4) CI๊ฐ€ ๋นŒ๋“œ/ํผ๋ธ”๋ฆฌ์‹œ ์ˆ˜ํ–‰(์ˆ˜๋™ ๋ฒ„์ „ ์œ ์ง€)

๏ฟฝ๏ธ Roadmap

Phase 1: Enhanced Developer Experience (Current)

  • DI Functions Compatibility: Add Depends() wrapper functions for backward compatibility
  • ServiceConfig Extensions: Add ServiceCategory enum and internal routes flag
  • Configuration Documentation: Create inheritance pattern templates for services

Phase 2: Advanced Architecture (Q4 2024)

  • Service Templates: Generate service-specific configuration templates
  • Service Type Expansion: Add ORCHESTRATOR, EXECUTION, DATA, ANALYTICS, UTILITY types
  • Enhanced Routing: Support for internal vs external API separation

Phase 3: Developer Tools (Q1 2025)

  • CLI Tools: Service generator and validator commands
  • Testing Utilities: Enhanced auth helpers and service testing framework
  • Auto Documentation: Generate service documentation from configuration

Completed Features โœ…

  • App Factory Standardization: Unified FastAPI app creation with automatic middleware setup
  • HTTP Client Pooling: Standardized service-to-service communication with connection pooling
  • Structured Logging: JSON logging with correlation ID support and context management
  • Kong Gateway Integration: Complete header standardization and authentication flow
  • Metrics Collection: Prometheus-compatible metrics with performance monitoring
  • Audit Logging: Comprehensive request/response logging system

Migration Status

  • All services using App Factory pattern
  • HTTP client standardization implemented
  • Kong Gateway headers standardized
  • Structured logging system deployed
  • CommonSettings inheritance pattern adoption
  • Request-based DI pattern migration
  • Test code updates
  • Environment configuration migration

๏ฟฝ๐Ÿ“„ License

This project is licensed under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mysingle-1.6.0-py3-none-any.whl (157.3 kB view details)

Uploaded Python 3

File details

Details for the file mysingle-1.6.0-py3-none-any.whl.

File metadata

  • Download URL: mysingle-1.6.0-py3-none-any.whl
  • Upload date:
  • Size: 157.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.10 {"installer":{"name":"uv","version":"0.9.10"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for mysingle-1.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f21ecebc67620154ef04a56566d6308e70f12d65ec0a2ce3d9da480c4b7e84ab
MD5 0771a89e14818f15f1e52ef50f2c4932
BLAKE2b-256 c41a81516d0f650cbe7dca317650633cf28743d18f43b1b5f38ff9fa31a95aeb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page