Schema Base Class
The Schema class is the foundation for defining configuration schemas in pydoover. It provides automatic element registration, JSON Schema generation, and deployment configuration injection.
Import
from pydoover import config
Class Definition
class Schema:
"""Represents the configuration schema for a Doover application."""
Creating a Schema
Subclass Schema and define configuration elements in __init__:
from pydoover import config
class PumpControlConfig(config.Schema):
def __init__(self):
self.pump_pin = config.Integer(
"Digital Output Number",
description="The digital output pin to drive the pump."
)
self.pump_on_time = config.Number(
"Pump On Time",
default=5.2,
description="The time in seconds to run the pump."
)
self.engine_type = config.Enum(
"Engine Type",
choices=["Honda", "John Deere", "Cat"],
default="Honda",
description="The type of diesel engine."
)
How Element Registration Works
When you assign a ConfigElement to an attribute, the Schema class automatically:
- Transforms the display name to a key (lowercase, spaces to underscores)
- Assigns a position based on definition order
- Registers the element in an internal map
# When you write:
self.pump_pin = config.Integer("Digital Output Number")
# The Schema class:
# 1. Sets element._name to "digital_output_number"
# 2. Sets element._position to the current count
# 3. Stores element in the internal map
Methods
to_dict()
Converts the schema to a JSON Schema dictionary.
def to_dict(self) -> dict
Returns: A dictionary representing the JSON Schema (draft 2020-12).
Example:
schema = PumpControlConfig()
json_schema = schema.to_dict()
# Result structure:
# {
# "$schema": "https://json-schema.org/draft/2020-12/schema",
# "$id": "",
# "title": "Application Config",
# "type": "object",
# "properties": { ... },
# "additionalElements": True,
# "required": [ ... ]
# }
export()
Exports the schema to a JSON file.
def export(self, fp: pathlib.Path, app_name: str) -> None
Parameters:
| Parameter | Type | Description |
|---|---|---|
fp | pathlib.Path | Path to the JSON file (typically doover_config.json) |
app_name | str | Application name used as the key in the config file |
Example:
from pathlib import Path
from pydoover import config
class MyConfig(config.Schema):
def __init__(self):
self.setting = config.String("Setting", default="value")
if __name__ == "__main__":
schema = MyConfig()
schema.export(Path("doover_config.json"), "my_app")
The export method:
- Reads existing
doover_config.jsonif it exists - Updates or creates the
config_schemafield under the app name - Writes the updated JSON back to the file
add_element()
Manually adds an element to the schema. Usually not needed as attribute assignment handles this automatically.
def add_element(self, element: ConfigElement) -> None
Parameters:
| Parameter | Type | Description |
|---|---|---|
element | ConfigElement | The configuration element to add |
Raises: ValueError if an element with the same name already exists.
_inject_deployment_config()
Internal method that loads deployment configuration values into elements.
def _inject_deployment_config(self, config: dict[str, Any]) -> None
Parameters:
| Parameter | Type | Description |
|---|---|---|
config | dict[str, Any] | Dictionary of configuration values |
Behavior:
- For each key in the config, finds the matching element and calls
load_data() - For elements not in the config:
- Required elements raise
ValueError - Optional elements are set to their default value
- Required elements raise
- Unknown keys are logged and skipped
Complete Example
from pathlib import Path
from pydoover import config
class SensorConfig(config.Schema):
def __init__(self):
# Required element (no default)
self.sensor_id = config.String(
"Sensor ID",
description="Unique identifier for the sensor"
)
# Optional elements (have defaults)
self.poll_interval = config.Number(
"Poll Interval",
default=1.0,
description="Seconds between sensor readings"
)
self.enable_logging = config.Boolean(
"Enable Logging",
default=True,
description="Whether to log sensor readings"
)
# Enum with choices
self.sensor_type = config.Enum(
"Sensor Type",
choices=["Temperature", "Humidity", "Pressure"],
default="Temperature"
)
# Export the schema
if __name__ == "__main__":
SensorConfig().export(Path("doover_config.json"), "sensor_app")
Integration with Applications
In a Doover application, the schema is typically a class attribute:
from pydoover.docker import Application
from pydoover import config
class SensorConfig(config.Schema):
def __init__(self):
self.poll_interval = config.Number("Poll Interval", default=1.0)
class SensorApp(Application):
config = SensorConfig()
def setup(self):
# Access configuration values
interval = self.config.poll_interval.value
print(f"Polling every {interval} seconds")
The framework automatically calls _inject_deployment_config() with values from the deployment before your application's setup() method runs.
Key Validation
Display names (and thus keys) must match the pattern:
^[ a-zA-Z0-9_-]*$
Valid characters:
- Letters (a-z, A-Z)
- Numbers (0-9)
- Spaces
- Hyphens (
-) - Underscores (
_)
Invalid keys raise a ValueError at element creation time.