Skip to main content

DealerTower Python Framework (dtpyfw)

Python Version Code Style Type Checked License

DealerTower Python Framework (dtpyfw) is a production-ready internal framework providing reusable building blocks for DealerTower microservices. It covers API development, database orchestration, caching, event streaming, object storage, task scheduling, and structured logging — all with full type safety and consistent interfaces.

PEP 561 typed package — py.typed marker is shipped so mypy/pyright narrow types in consumer services automatically.


Installation

Requires Python 3.13 or newer.

Base

pip install dtpyfw

Includes dtpyfw.core (env, retry, hashing, chunking, validation, …) and dtpyfw.log (structured logging).

From git tag (recommended for internal services)

dtpyfw @ git+https://github.com/datgate/dtpyfw.git@v1.0

Development

poetry install -E all

Check installed version

import dtpyfw
print(dtpyfw.__version__)  # "1.0"

Optional extras

Extras can be combined: pip install dtpyfw[api,db,redis].

Extra Key dependencies Install
api FastAPI, Uvicorn, Gunicorn pip install dtpyfw[api]
db SQLAlchemy 2, asyncpg, psycopg2 pip install dtpyfw[db]
db-mysql PyMySQL, aiomysql pip install dtpyfw[db-mysql]
bucket boto3 pip install dtpyfw[bucket]
redis redis-py + hiredis pip install dtpyfw[redis]
redis_streamer redis-py pip install dtpyfw[redis_streamer]
worker Celery, celery-redbeat, celery_once pip install dtpyfw[worker]
kafka kafka-python pip install dtpyfw[kafka]
opensearch opensearch-py pip install dtpyfw[opensearch]
ftp paramiko pip install dtpyfw[ftp]
encrypt python-jose, passlib, bcrypt pip install dtpyfw[encrypt]
all Everything above pip install dtpyfw[all]

Common profiles:

pip install dtpyfw[api,db,redis]        # API microservice
pip install dtpyfw[worker,db,redis]     # Celery worker service
pip install dtpyfw[api,db,opensearch,redis]  # Search-enabled service
pip install dtpyfw[bucket,db,ftp]       # Data processing service

Documentation


Quick start examples

FastAPI application

from dtpyfw.api import Application
from dtpyfw.api.routes import Router, Route, RouteMethod
from dtpyfw.api.routes.authentication import Auth, AuthType
from dtpyfw.core.env import Env

gateway_auth = Auth.from_env(
    auth_type=AuthType.HEADER,
    header_key="x-gateway-key",
    env_var="gateway_key",
)

router = Router(prefix="/health", tags=["health"])
router.add_route(Route(
    method=RouteMethod.GET,
    path="/",
    endpoint=lambda: {"status": "ok"},
))

app = Application(
    title="My Microservice",
    version="1.0",
    routers=[router],
    auth=gateway_auth,
).get_app()

Database

from dtpyfw.db.config import DatabaseConfig
from dtpyfw.db.database import DatabaseInstance

db_config = DatabaseConfig.from_env()   # reads db_host, db_port, db_user, …
db = DatabaseInstance(db_config)

with db.get_db_cm_sync() as session:
    result = session.execute(select(User)).scalars().all()

Structured logging

from dtpyfw.log.config import LogConfig
from dtpyfw.log.initializer import log_initializer

log_config = LogConfig.from_env()   # reads logging_ms_url, log_level, …
log_initializer(config=log_config)

# Inside any function:
from dtpyfw.log import footprint

footprint.leave(
    log_type="info",
    controller=f"{__name__}.my_func",
    subject="Task started",
    message="Processing item.",
    payload={"item_id": item_id},
)

Redis caching

from dtpyfw.redis.config import RedisConfig
from dtpyfw.redis.connection import RedisInstance

redis = RedisInstance(RedisConfig.from_env())   # reads redis_url / redis_host, …

from dtpyfw.redis.caching import cache_function

@cache_function(redis_instance=redis, expire_time=3600)
def get_dealer(dealer_id: str) -> dict:
    ...

S3-compatible storage

from dtpyfw.bucket.bucket import Bucket

bucket = Bucket.from_env()          # reads s3_bucket_name, s3_access_key, …
bucket = Bucket.from_env("media_s3_")  # custom prefix

url = bucket.upload("path/to/file.pdf", "dealers/123/file.pdf")
bucket.download("dealers/123/file.pdf", "/tmp/file.pdf")
exists = bucket.exists("dealers/123/file.pdf")

Celery worker

from dtpyfw.worker.task import Task
from dtpyfw.worker.worker import Worker
from dtpyfw.redis.config import RedisConfig
from dtpyfw.redis.connection import RedisInstance

task = Task()
task.register("myapp.tasks.process_data", queue="default")
task.add_periodic("myapp.tasks.cleanup", crontab(hour=0, minute=0))

redis = RedisInstance(RedisConfig.from_env())
worker = Worker()
worker.set_name("my_worker").set_redis(redis).set_task(task)
celery_app = worker.get_celery()

Startup diagnostics report

Emit a structured boot-time snapshot (environment variables, dependency health, process metadata) to stdout and footprint. All dependency probes run concurrently; the function never raises regardless of which probes fail.

from dtpyfw.diagnostics import emit_startup_report

# Minimal (process info + env snapshot, no dependency probes)
emit_startup_report(service_name="my-service", process_role="api")

# With dependencies
from app.config.database import database
from app.config.redis import redis_instance, redis_queue_instance
from app.config.log import log_config

emit_startup_report(
    service_name="my-service",
    process_role="api",
    service_version="1.4.2",
    database=database,
    redis=[redis_instance, redis_queue_instance],
    log_config=log_config,
    probe_timeout_seconds=3.0,
)

# Collect without emitting
from dtpyfw.diagnostics import collect_startup_report
import json

report = collect_startup_report(service_name="my-service", process_role="script")
print(json.dumps(report, indent=2, default=str))

The returned dict always has schema_version=1 and the following top-level keys: status ("ok" / "degraded" / "down"), process, environment, logging, dependencies, extras, notes.


Redis Streams (event bus)

from dtpyfw.redis.config import RedisConfig
from dtpyfw.redis.connection import RedisInstance
from dtpyfw.redis_streamer.synchronize import RedisStreamer
from dtpyfw.redis_streamer.message import Message

redis = RedisInstance(RedisConfig.from_env("redis_queue_"))
streamer = RedisStreamer(redis_instance=redis, consumer_name="my_service")

streamer.register_channel("my_service_events")
streamer.subscribe("dealer_updated")
streamer.register_handler("dealer_updated", handle_dealer_updated)

# Publish
streamer.send_message("my_service_events", Message(name="event_name", body=payload))

# Consume (blocking)
streamer.persist_consume()

Module reference

Module Extra Docs
dtpyfw.core base docs/core/
dtpyfw.log base docs/log/
dtpyfw.api api docs/api/
dtpyfw.db db docs/db/
dtpyfw.bucket bucket docs/bucket/
dtpyfw.redis redis docs/redis/
dtpyfw.redis_streamer redis_streamer docs/redis_streamer/
dtpyfw.worker worker docs/worker/
dtpyfw.kafka kafka docs/kafka/
dtpyfw.mongo mongo
dtpyfw.opensearch opensearch docs/opensearch/
dtpyfw.ftp ftp docs/ftp/
dtpyfw.encrypt encrypt docs/encrypt/
dtpyfw.mcp mcp docs/mcp/
dtpyfw.diagnostics base

Development

# Install all dependencies
poetry install -E all

# Run tests
pytest

# Format
black .

# Lint
ruff check . --fix

# Type check
mypy dtpyfw

Version history

Current version: see CHANGELOG.md for full history and UPGRADE.md for migration guides.

Releases are version-driven: bump [tool.poetry] version in pyproject.toml in your PR and merge to main. CI then runs two jobs in publish.ymlrelease (creates the v<version> tag + GitHub Release if the version is new), then publish (OIDC-publishes to PyPI via Trusted Publishing). The flow is idempotent; re-publishing is just re-running the workflow run. See docs/RELEASING.md for the flow and the one-time PyPI setup.


License

DealerTower Python Framework is proprietary software. See LICENSE for complete terms and conditions.


Resources

Download files

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

Source Distribution

dtpyfw-1.32.tar.gz (225.3 kB view details)

Uploaded Source

Built Distribution

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

dtpyfw-1.32-py3-none-any.whl (282.4 kB view details)

Uploaded Python 3

File details

Details for the file dtpyfw-1.32.tar.gz.

File metadata

  • Download URL: dtpyfw-1.32.tar.gz
  • Upload date:
  • Size: 225.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for dtpyfw-1.32.tar.gz
Algorithm Hash digest
SHA256 086370b81fb4d342784e3acda90db0ef39286d436522eb104f4aa4d79b8a37e1
MD5 7c1a773ff502c5d11e358432b021c928
BLAKE2b-256 2c63b4e2af72ac2d62b22a3f038b2da0103aa37fb077622bf326649e8c9141d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for dtpyfw-1.32.tar.gz:

Publisher: publish.yml on datgate/dtpyfw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dtpyfw-1.32-py3-none-any.whl.

File metadata

  • Download URL: dtpyfw-1.32-py3-none-any.whl
  • Upload date:
  • Size: 282.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for dtpyfw-1.32-py3-none-any.whl
Algorithm Hash digest
SHA256 7d3d753e9cbcb277d96ae11d50d6cbbab6b99bbef89cf87573d1a6dd2dc3c03a
MD5 4adb85fd26145360b66b350bc7e1e4ff
BLAKE2b-256 259a754b3d45287c222ca418ef47a87c9a6e47bef9defc30142611d486af8822

See more details on using hashes here.

Provenance

The following attestation bundles were made for dtpyfw-1.32-py3-none-any.whl:

Publisher: publish.yml on datgate/dtpyfw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.35

2 files

1.34

2 files

1.33

2 files

This release

1.32 This release

2 files

1.31

2 files

1.30

2 files

1.29

2 files

1.28

2 files

1.27

2 files

1.26

2 files

1.25

2 files

1.24

2 files

1.23

2 files

1.22

2 files

1.21

2 files

1.20

2 files

1.19

2 files

1.18

2 files

1.17

2 files

1.16

2 files

1.15

2 files

1.14

2 files

1.13

2 files

1.12

2 files

1.11

2 files

1.10

2 files

1.9

2 files

1.8

2 files

1.7

2 files

1.6

2 files

1.5

2 files

1.4

2 files

1.3

2 files

1.2

2 files

1.1

2 files

1.0

2 files

0.6.51

2 files

0.6.50

2 files

0.6.49

2 files

0.6.48

2 files

0.6.47

2 files

0.6.46

2 files

0.6.45

2 files

0.6.44

2 files

0.6.43

2 files

0.6.42

2 files

0.6.41

2 files

0.6.40

2 files

0.6.39

2 files

0.6.38

2 files

0.6.37

2 files

0.6.36

2 files

0.6.35

2 files

0.6.34

2 files

0.6.33

2 files

0.6.32

2 files

0.6.31

2 files

0.6.30

2 files

0.6.29

2 files

0.6.28

2 files

0.6.27

2 files

0.6.26

2 files

0.6.25

2 files

0.6.24

2 files

0.6.23

2 files

0.6.22

2 files

0.6.20

2 files

0.6.19

2 files

0.6.18

2 files

0.6.17

2 files

0.6.16

2 files

0.6.15

2 files

0.6.14

2 files

0.6.13

2 files

0.6.12

2 files

0.6.11

2 files

0.6.10

2 files

0.6.9

2 files

0.6.8

2 files

0.6.7

2 files

0.6.6

2 files

0.6.5

2 files

0.6.4

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.26

2 files

0.5.25

2 files

0.5.24

2 files

0.5.23

2 files

0.5.22

2 files

0.5.21

2 files

0.5.20

2 files

0.5.19

2 files

0.5.18

2 files

0.5.17

2 files

0.5.16

2 files

0.5.15

2 files

0.5.13

2 files

0.5.12

2 files

0.5.11

2 files

0.5.10

2 files

0.5.9

2 files

0.5.8

2 files

0.5.7

2 files

0.5.6

2 files

0.5.5

2 files

0.5.4

2 files

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.13

2 files

0.4.12

2 files

0.4.11

2 files

0.4.10

2 files

0.4.9

2 files

0.4.8

2 files

0.4.7

2 files

0.4.6

2 files

0.4.5

2 files

0.4.4

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.2.76

2 files

0.2.75

2 files

0.2.74

2 files

0.2.73

2 files

0.2.72

2 files

0.2.71

2 files

0.2.70

2 files

0.2.69

2 files

0.2.68

2 files

0.2.67

2 files

0.2.66

2 files

0.2.65

2 files

0.2.64

2 files

0.2.63

2 files

0.2.62

2 files

0.2.61

2 files

0.2.60

2 files

0.2.59

2 files

0.2.58

2 files

0.2.56

2 files

0.2.55

2 files

0.2.54

2 files

0.2.53

2 files

0.2.52

2 files

0.2.51

2 files

0.2.50

2 files

0.2.49

2 files

0.2.48

2 files

0.2.47

2 files

0.2.46

2 files

0.2.45

2 files

0.2.44

2 files

0.2.43

2 files

0.2.42

2 files

0.2.41

2 files

0.2.40

2 files

0.2.39

2 files

0.2.38

2 files

0.2.37

2 files

0.2.36

2 files

0.2.35

2 files

0.2.34

2 files

0.2.33

2 files

0.2.32

2 files

0.2.31

2 files

0.2.30

2 files

0.2.29

2 files

0.2.28

2 files

0.2.27

2 files

0.2.26

2 files

0.2.25

2 files

0.2.24

2 files

0.2.23

2 files

0.2.22

2 files

0.2.21

2 files

0.2.20

2 files

0.2.19

2 files

0.2.18

2 files

0.2.17

2 files

0.2.16

2 files

0.2.15

2 files

0.2.14

2 files

0.2.13

2 files

0.2.12

2 files

0.2.11

2 files

0.2.10

2 files

0.2.9

2 files

0.2.8

2 files

0.2.7

2 files

0.2.6

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

0.1.13

2 files

0.1.12

2 files

0.1.11

2 files

0.1.10

2 files

0.1.9

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page