System & Integration Utilities¶
This guide details the disdantic helper utilities, including runtime self-introspection, lazy loading proxies, thread-safe singletons, structured logging with OpenTelemetry, and settings configurations.
1. Runtime Self-Introspection & Serialization¶
The InfoMixin class provides recursive object self-introspection, converting arbitrary object graphs into primitive types safely.
Object Serialization¶
Inheriting from InfoMixin exposes the .info property, which generates a sanitized dictionary mapping, along with JSON and YAML exporters:
from disdantic import InfoMixin
class Resource(InfoMixin):
def __init__(self, name: str):
self.name = name
res = Resource("Database")
print(res.info) # Sanitized dictionary representation
print(res.info_json(indent=2)) # JSON string representation
print(res.info_yaml()) # YAML string (raises ImportError if PyYAML is not installed)
Circular Reference Safety¶
To prevent infinite loops during traversal, InfoMixin tracks visited memory addresses. If a cycle is detected, the traversal halts and logs a <CircularReference: ID <id>> placeholder:
from disdantic import InfoMixin
class Resource(InfoMixin):
def __init__(self, name: str):
self.name = name
res = Resource("Database")
res.self_reference = res # Establish cycle
assert "CircularReference" in res.info_json()
2. Thread-Safe Lazy Loading & Proxying¶
disdantic defers imports or expensive instantiation paths until object attributes are read.
LazyProxy¶
LazyProxy acts as a placeholder, only calling the initialization factory function when attributes, string representation (__repr__), or directory listings (__dir__) are requested. Resolution is fully thread-safe:
import types
from disdantic.loading import LazyProxy
def expensive_factory():
return types.SimpleNamespace(status="ok")
proxy = LazyProxy(expensive_factory)
# Factory is NOT called yet
print(proxy.status) # Triggers thread-safe resolution and prints: ok
LazyLoader Class Attributes Descriptor¶
Use @LazyLoader.class_attributes to bind lazy properties to class variables:
from disdantic.loading import LazyLoader
@LazyLoader.class_attributes({"sys_mod": "sys"})
class Controller:
pass
ctrl = Controller()
# 'sys' is only imported when sys_mod is accessed
print(ctrl.sys_mod.version)
3. Thread-Safe Singleton Lifecycle Management¶
SingletonMeta is a thread-safe singleton metaclass using double-checked locking to enforce single-instance lifecycle constraints.
Metaclass Instantiation¶
Classes using SingletonMeta share a single instance across all constructor invocations:
from disdantic.singleton import SingletonMeta
class ConfigService(metaclass=SingletonMeta):
pass
c1 = ConfigService()
c2 = ConfigService()
assert c1 is c2
Instance Eviction & Cleaning¶
For test isolation, you can evict singleton instances programmatically:
from disdantic.singleton import SingletonMeta
class ConfigService(metaclass=SingletonMeta):
pass
c1 = ConfigService()
# Evict instance of a specific singleton class
ConfigService.clear_instances()
# Evict all active singletons globally
SingletonMeta.clear_all_singletons()
4. Structured Logging & Telemetry Instrumentation¶
Configure global logging and automatically track function execution paths.
Function Autologging¶
Decorate functions with @autolog to log inputs on entry, results on exit, and exceptions before re-raising:
from disdantic.logging import autolog
@autolog
def divide(a: int, b: int) -> float:
return a / b
# Optionally configure exception log level
@autolog(exception_log_level="WARNING")
def risky_calculation(x: int) -> int:
return x * 10
OpenTelemetry JSON Logging¶
When logging under an active OpenTelemetry span, disdantic formats log statements as structured JSON with tracing metadata:
from disdantic.logging import configure_logger, LoggingSettings
configure_logger(
LoggingSettings(
enabled=True,
otel_formatting="enable" # Enable OTEL-compliant JSON logging
)
)
5. Unified Global Configuration Hierarchy¶
disdantic loads and validates configurations dynamically using Pydantic Settings.
Precedence Priority¶
Settings resolve variables across the following priority ladder:
- Constructor arguments (e.g.
Settings(default_schema_discriminator="custom_type")) - Environment variables prefixed with
DISDANTIC__(e.g.DISDANTIC__DEFAULT_SCHEMA_DISCRIMINATOR="custom_type") - Dotenv files (
.env) pyproject.tomlconfig table (under[tool.disdantic])- CLI arguments (prefixed with
disdantic_) - Defaults declared in the settings schema
Settings Singleton Manager¶
Manage settings globally using double-checked thread-safe loaders: