Skip to content

Configuration Elements

Configuration elements are the building blocks of a pydoover configuration schema. Each element type maps to a JSON Schema type and provides validation, UI rendering, and type-safe value access.

Import

from pydoover import config

Common Properties

All configuration elements share these common properties:

PropertyTypeDefaultDescription
display_namestrRequiredThe label shown in the UI
defaultvariesNotSetDefault value; if not set, element is required
descriptionstrNoneHelp text displayed in the UI
hiddenboolFalseWhether to hide the element in the UI
deprecatedboolNoneMarks the element as deprecated
positionintNoneOverride automatic ordering

Required vs Optional

Elements without a default are required. Elements with a default are optional:

# Required - user must provide a value
api_key = config.String("API Key")

# Optional - uses default if not provided
timeout = config.Integer("Timeout", default=30)

The value Property

After configuration injection, access the element's value:

class MyConfig(config.Schema):
    def __init__(self):
        self.timeout = config.Integer("Timeout", default=30)

# In your application:
timeout_value = self.config.timeout.value  # Returns int

Accessing value before injection raises ValueError.

Integer

Represents a JSON integer type. Internally stored as Python int.

config.Integer(
    display_name: str,
    *,
    default: int = NotSet,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None,
    minimum: int = None,
    exclusive_minimum: int = None,
    maximum: int = None,
    exclusive_maximum: int = None,
    multiple_of: int = None
)

Integer Constraints

ParameterDescription
minimumValue must be >= this
exclusive_minimumValue must be > this
maximumValue must be <= this
exclusive_maximumValue must be < this
multiple_ofValue must be divisible by this

Integer Examples

# Basic integer
pin_number = config.Integer("Pin Number", default=1)

# With range constraints
temperature = config.Integer(
    "Temperature Setpoint",
    default=25,
    minimum=0,
    maximum=100,
    description="Target temperature in degrees Celsius"
)

# Must be positive (exclusive minimum)
count = config.Integer(
    "Item Count",
    exclusive_minimum=0,
    description="Must be at least 1"
)

# Multiple of a value
step_size = config.Integer(
    "Step Size",
    default=10,
    multiple_of=5,
    description="Must be a multiple of 5"
)

Number

Represents a JSON number type for floating-point values. Internally stored as Python float. Inherits all constraints from Integer.

config.Number(
    display_name: str,
    *,
    default: float = NotSet,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None,
    minimum: float = None,
    exclusive_minimum: float = None,
    maximum: float = None,
    exclusive_maximum: float = None,
    multiple_of: float = None
)

Number Examples

# Basic number
voltage = config.Number("Voltage", default=3.3)

# With constraints
gain = config.Number(
    "Amplifier Gain",
    default=1.0,
    minimum=0.1,
    maximum=10.0,
    description="Signal amplification factor"
)

# Percentage value
threshold = config.Number(
    "Threshold Percentage",
    default=0.5,
    minimum=0.0,
    maximum=1.0
)

Boolean

Represents a JSON boolean type. Internally stored as Python bool.

config.Boolean(
    display_name: str,
    *,
    default: bool = NotSet,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None
)

Boolean Examples

# Toggle feature
enable_logging = config.Boolean(
    "Enable Logging",
    default=True,
    description="Whether to log debug information"
)

# Required boolean
accept_terms = config.Boolean(
    "Accept Terms",
    description="User must accept terms of service"
)

String

Represents a JSON string type. Internally stored as Python str.

config.String(
    display_name: str,
    *,
    default: str = NotSet,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None,
    length: int = None,
    pattern: str = None
)

String Constraints

ParameterDescription
lengthExact length the string must have
patternRegex pattern the string must match

String Examples

# Basic string
device_name = config.String(
    "Device Name",
    default="Sensor-01",
    description="Human-readable device identifier"
)

# With pattern validation (email format)
contact_email = config.String(
    "Contact Email",
    pattern=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$",
    description="Notification email address"
)

# Fixed length (e.g., product code)
product_code = config.String(
    "Product Code",
    length=8,
    description="8-character product identifier"
)

# Hidden string (e.g., for internal use)
internal_id = config.String(
    "Internal ID",
    default="default-id",
    hidden=True
)

Enum

Represents a choice selection. Rendered as a dropdown in the UI.

config.Enum(
    display_name: str,
    *,
    choices: list | EnumType,
    default: Any,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None
)

Enum with String Choices

engine_type = config.Enum(
    "Engine Type",
    choices=["Honda", "John Deere", "Cat"],
    default="Honda",
    description="Type of diesel engine"
)

# Access value
engine = engine_type.value  # Returns "Honda", "John Deere", or "Cat"

Enum with Python Enum

Using Python's enum.Enum provides type safety and allows custom attributes:

import enum
from pydoover import config

class SensorType(enum.Enum):
    TEMPERATURE = "Temperature"
    HUMIDITY = "Humidity"
    PRESSURE = "Pressure"

class MyConfig(config.Schema):
    def __init__(self):
        self.sensor_type = config.Enum(
            "Sensor Type",
            choices=SensorType,
            default=SensorType.TEMPERATURE
        )

Enum with Custom Objects

Enum values can be objects with custom attributes. The object must implement __str__:

import enum
from pydoover import config

class SensorSpec:
    def __init__(self, name: str, unit: str, precision: int):
        self.name = name
        self.unit = unit
        self.precision = precision

    def __str__(self):
        return self.name

class SensorType(enum.Enum):
    TEMPERATURE = SensorSpec("Temperature", "C", 2)
    HUMIDITY = SensorSpec("Humidity", "%", 1)
    PRESSURE = SensorSpec("Pressure", "kPa", 3)

class MyConfig(config.Schema):
    def __init__(self):
        self.sensor = config.Enum(
            "Sensor",
            choices=SensorType,
            default=SensorType.TEMPERATURE
        )

    @property
    def sensor_unit(self):
        return self.sensor.value.unit  # Access custom attribute

Array

Represents a JSON array type. Contains a list of elements of the same type.

config.Array(
    display_name: str,
    *,
    element: ConfigElement = None,
    min_items: int = None,
    max_items: int = None,
    unique_items: bool = None,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None
)

Note: default values are not allowed for Array elements.

Array Parameters

ParameterDescription
elementThe type of items in the array
min_itemsMinimum number of items required
max_itemsMaximum number of items allowed
unique_itemsWhether items must be unique

Array Examples

# Array of strings
tags = config.Array(
    "Tags",
    element=config.String("Tag"),
    min_items=1,
    max_items=10,
    unique_items=True,
    description="List of tags for categorization"
)

# Array of integers
sensor_pins = config.Array(
    "Sensor Pins",
    element=config.Integer("Pin", minimum=0, maximum=40),
    min_items=1,
    description="GPIO pins connected to sensors"
)

# Accessing array values
for element in tags.elements:
    print(element.value)

Array Value Access

Use the elements property to iterate over loaded values:

class MyConfig(config.Schema):
    def __init__(self):
        self.ports = config.Array(
            "Ports",
            element=config.Integer("Port", minimum=1, maximum=65535)
        )

# After configuration injection:
for port_element in self.config.ports.elements:
    print(port_element.value)

Object

Represents a JSON object type with nested properties. Rendered as a collapsible form section in the UI.

config.Object(
    display_name: str,
    *,
    additional_elements: bool | dict = True,
    collapsible: bool = True,
    default_collapsed: bool = False,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None
)

Note: default values are not allowed for Object elements.

Object Parameters

ParameterDescription
additional_elementsAllow properties not defined in schema
collapsibleWhether the section can be collapsed in UI
default_collapsedWhether to start collapsed

Adding Elements to Object

Use add_elements() or attribute assignment:

# Using add_elements()
pump_settings = config.Object("Pump Settings")
pump_settings.add_elements(
    config.Integer("Pin", description="GPIO pin number"),
    config.Number("On Time", default=5.0),
)

# Using attribute assignment
pump_settings = config.Object("Pump Settings")
pump_settings.pin = config.Integer("Pin")
pump_settings.on_time = config.Number("On Time", default=5.0)

Object Example

class MyConfig(config.Schema):
    def __init__(self):
        self.pump = config.Object(
            "Pump Settings",
            description="Configure the pump output"
        )
        self.pump.add_elements(
            config.Integer(
                "Digital Output Number",
                description="The digital output pin"
            ),
            config.Number(
                "On Time",
                default=5.2,
                description="Run time in seconds"
            ),
        )

# Access nested values
pin = self.config.pump.digital_output_number.value
on_time = self.config.pump.on_time.value

Variable

A special element that creates dynamic references to other configuration values. Variables are resolved at deployment time.

config.Variable(scope: str, name: str)

Variable Parameters

ParameterDescription
scopeThe application or context name
nameThe configuration key to reference

Variable Usage

Variables are typically used as default values:

class MyConfig(config.Schema):
    def __init__(self):
        # Reference a value from another app's config
        self.device_id = config.String(
            "Device ID",
            default=config.Variable("device_manager", "primary_device_id")
        )

The variable serializes to a string format: $scope.name

var = config.Variable("app", "setting")
str(var)  # Returns "$app.setting"

Application

A special element that references other Doover applications. Rendered as a dropdown of installed applications in the UI.

config.Application(
    display_name: str,
    *,
    default: str = NotSet,
    description: str = None,
    hidden: bool = False,
    deprecated: bool = None
)

Application Example

class MyConfig(config.Schema):
    def __init__(self):
        self.data_source = config.Application(
            "Data Source",
            description="Select the application to receive data from"
        )

# The value is the application identifier string
source_app_id = self.config.data_source.value

The Application element generates JSON Schema with format: "doover-application", which the Doover UI uses to render an application selector.

Element Summary

ElementJSON TypePython TypeConstraints
Integerintegerintmin, max, multipleOf
Numbernumberfloatmin, max, multipleOf
BooleanbooleanboolNone
Stringstringstrlength, pattern
Enumstring or numbervarieschoices
ArrayarraylistminItems, maxItems, uniqueItems
ObjectobjectnestedadditionalElements
VariableN/Areferencescope, name
Applicationstringstrformat: doover-application

Related