API Reference
pydase.data_service
¶
DataService
¶
Bases: AbstractDataService
Source code in src/pydase/data_service/data_service.py
serialize
¶
serialize() -> SerializedObject
Serializes the instance into a dictionary, preserving the structure of the instance.
For each attribute, method, and property, the method includes its name, type, value, readonly status, and documentation if any in the resulting dictionary. Attributes and methods starting with an underscore are ignored.
For nested DataService instances, the method serializes recursively. For attributes of type list, each item in the list is serialized individually. If an item in the list is an instance of DataService, it is serialized recursively.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
SerializedObject
|
The serialized instance. |
Source code in src/pydase/data_service/data_service.py
pydase.data_service.data_service_cache
¶
DataServiceCache
¶
DataServiceCache(service: DataService)
Maintains a serialized cache of the current state of a DataService instance.
This class is responsible for storing and updating a representation of the service’s public attributes and properties. It is primarily used by the StateManager and the web server to serve consistent state to clients without accessing the DataService attributes directly.
The cache is initialized once upon construction by serializing the full state of
the service. After that, it can be incrementally updated using attribute paths and
values as notified by the
DataServiceObserver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service |
DataService
|
The DataService instance whose state should be cached. |
required |
Source code in src/pydase/data_service/data_service_cache.py
pydase.data_service.data_service_observer
¶
DataServiceObserver
¶
DataServiceObserver(state_manager: StateManager)
Bases: PropertyObserver
Source code in src/pydase/data_service/data_service_observer.py
add_notification_callback
¶
add_notification_callback(callback: Callable[[str, Any, SerializedObject], None]) -> None
Registers a callback function to be invoked upon attribute changes in the observed object.
This method allows for the addition of custom callback functions that will be executed whenever there is a change in the value of an observed attribute. The callback function is called with detailed information about the change, enabling external logic to respond to specific state changes within the observable object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback |
Callable[[str, Any, SerializedObject], None]
|
The callback function to be registered. The function should have the following signature:
|
required |
Source code in src/pydase/data_service/data_service_observer.py
pydase.data_service.state_manager
¶
StateManager
¶
StateManager(service: DataService, filename: str | Path | None = None, autosave_interval: float | None = None)
Manages the state of a DataService instance, serving as both a cache and a persistence layer. It provides fast access to the most recently known state of the service and ensures consistent state updates across connected clients and service restarts.
The StateManager is used by the web server to apply updates to service attributes
and to serve the current state to newly connected clients. Internally, it creates a
DataServiceCache
instance to track the state of public attributes and properties.
The StateManager also handles state persistence: it can load a previously saved state from disk at startup and periodically autosave the current state to a file during runtime.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service |
DataService
|
The DataService instance whose state is being managed. |
required |
filename |
str | Path | None
|
The file name used for loading and storing the DataService’s state. If provided, the state is loaded from this file at startup and saved to it on shutdown or at regular intervals. |
None
|
autosave_interval |
float | None
|
Interval in seconds between automatic state save events.
If set to |
None
|
Note
The StateManager does not autonomously poll hardware state. It relies on the
service to perform such updates. The cache maintained by
DataServiceCache
reflects the last known state as notified by the DataServiceObserver, and is
used by the web interface to provide fast and accurate state rendering for
connected clients.
Source code in src/pydase/data_service/state_manager.py
cache_value
property
¶
cache_value: dict[str, SerializedObject]
Returns the “value” value of the DataService serialization.
__is_loadable_state_attribute
¶
Checks if an attribute defined by a dot-separated path should be loaded from storage.
For properties, it verifies the presence of the ‘@load_state’ decorator. Regular attributes default to being loadable.
Source code in src/pydase/data_service/state_manager.py
autosave
async
¶
Periodically saves the current service state to the configured file.
This coroutine is automatically started by the pydase.Server
when a filename is provided. It runs in the background and writes the latest
known state of the service to disk every autosave_interval seconds.
If autosave_interval is set to None, autosaving is disabled and this
coroutine exits immediately.
Source code in src/pydase/data_service/state_manager.py
load_state
¶
Loads the DataService’s state from a JSON file defined by self.filename.
Updates the service’s attributes, respecting type and read-only constraints.
Source code in src/pydase/data_service/state_manager.py
save_state
¶
Saves the DataService’s current state to a JSON file defined by
self.filename.
Source code in src/pydase/data_service/state_manager.py
set_service_attribute_value_by_path
¶
set_service_attribute_value_by_path(path: str, serialized_value: SerializedObject) -> None
Sets the value of an attribute in the service managed by the StateManager
given its path as a dot-separated string.
This method updates the attribute specified by ‘path’ with ‘value’ only if the attribute is not read-only and the new value differs from the current one. It also handles type-specific conversions for the new value before setting it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path |
str
|
A dot-separated string indicating the hierarchical path to the attribute. |
required |
serialized_value |
SerializedObject
|
The serialized representation of the new value to set for the attribute. |
required |
Source code in src/pydase/data_service/state_manager.py
has_load_state_decorator
¶
Determines if the property’s setter method is decorated with the @load_state
decorator.
Source code in src/pydase/data_service/state_manager.py
load_state
¶
This function should be used as a decorator on property setters to indicate that the value should be loaded from the JSON file.
Example
Source code in src/pydase/data_service/state_manager.py
pydase.server.server
¶
AdditionalServer
¶
Bases: TypedDict
A TypedDict that represents the configuration for an additional server to be run alongside the main server.
kwargs
instance-attribute
¶
Additional keyword arguments that will be passed to the server’s constructor
server
instance-attribute
¶
server: type[AdditionalServerProtocol]
Server adhering to the
AdditionalServerProtocol.
AdditionalServerProtocol
¶
AdditionalServerProtocol(data_service_observer: DataServiceObserver, host: str, port: int, **kwargs: Any)
Bases: Protocol
A Protocol that defines the interface for additional servers.
This protocol sets the standard for how additional servers should be implemented to ensure compatibility with the main Server class. The protocol requires that any server implementing it should have an init method for initialization and a serve method for starting the server.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_service_observer |
DataServiceObserver
|
Observer for the DataService, handling state updates and communication to connected clients through injected callbacks. Can be utilized to access the service and state manager, and to add custom state-update callbacks. |
required |
host |
str
|
Hostname or IP address where the server is accessible. Commonly ‘0.0.0.0’ to bind to all network interfaces. |
required |
port |
int
|
Port number on which the server listens. Typically in the range 1024-65535 (non-standard ports). |
required |
**kwargs |
Any
|
Any additional parameters required for initializing the server. These parameters are specific to the server’s implementation. |
{}
|
Source code in src/pydase/server/server.py
serve
async
¶
Starts the server. This method should be implemented as an asynchronous method, which means that it should be able to run concurrently with other tasks.
Server
¶
Server(service: DataService, host: str = '0.0.0.0', web_port: int | None = None, enable_web: bool = True, filename: str | Path | None = None, additional_servers: list[AdditionalServer] | None = None, autosave_interval: float = 30.0, **kwargs: Any)
The Server class provides a flexible server implementation for the DataService.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service |
DataService
|
The DataService instance that this server will manage. |
required |
host |
str
|
The host address for the server. Defaults to |
'0.0.0.0'
|
web_port |
int | None
|
The port number for the web server. If set to None, it will use the
port defined in
|
None
|
enable_web |
bool
|
Whether to enable the web server. |
True
|
filename |
str | Path | None
|
Filename of the file managing the service state persistence. |
None
|
additional_servers |
list[AdditionalServer] | None
|
A list of additional servers to run alongside the main server. Here’s an example of how you might define an additional server: And here’s how you might add it to the |
None
|
autosave_interval |
float
|
Interval in seconds between automatic state save events.
If set to |
30.0
|
**kwargs |
Any
|
Additional keyword arguments. |
{}
|
Advanced¶
-
post_startuphook:This method is intended to be overridden in subclasses. It runs immediately after all servers (web and additional) are initialized and before entering the main event loop. You can use this hook to register custom logic after the server is fully started.
Source code in src/pydase/server/server.py
pydase.server.web_server
¶
WebServer
¶
WebServer(data_service_observer: DataServiceObserver, host: str, port: int, *, enable_frontend: bool = True, css: str | Path | None = None, favicon_path: str | Path | None = None, enable_cors: bool = True, config_dir: Path = ServiceConfig().config_dir, generate_web_settings: bool = WebServerConfig().generate_web_settings, frontend_src: Path = Path(__file__).parent.parent.parent / 'frontend')
Represents a web server that adheres to the
AdditionalServerProtocol,
designed to work with a DataService instance. This server
facilitates client-server communication and state management through web protocols
and socket connections.
The WebServer class initializes and manages a web server environment aiohttp and Socket.IO, allowing for HTTP and Socket.IO communications. It incorporates CORS (Cross-Origin Resource Sharing) support, custom CSS, and serves a static files directory. It also initializes web server settings based on configuration files or generates default settings if necessary.
Configuration for the web server (like service configuration directory and whether to generate new web settings) is determined in the following order of precedence:
- Values provided directly to the constructor.
- Environment variable settings (via configuration classes like
ServiceConfigandWebServerConfig). - Default values defined in the configuration classes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_service_observer |
DataServiceObserver
|
Observer for the |
required |
host |
str
|
Hostname or IP address where the server is accessible. Commonly ‘0.0.0.0’ to bind to all network interfaces. |
required |
port |
int
|
Port number on which the server listens. Typically in the range 1024-65535 (non-standard ports). |
required |
css |
str | Path | None
|
Path to a custom CSS file for styling the frontend. If None, no custom styles are applied. Defaults to None. |
None
|
favicon_path |
str | Path | None
|
Path to a custom favicon.ico file. Defaults to None. |
None
|
enable_cors |
bool
|
Flag to enable or disable CORS policy. When True, CORS is enabled, allowing cross-origin requests. Defaults to True. |
True
|
config_dir |
Path
|
Path to the configuration directory where the web settings will be stored.
Defaults to
|
config_dir
|
generate_web_settings |
bool
|
Flag to enable or disable generation of new web settings if the
configuration file is missing. Defaults to
|
generate_web_settings
|
Source code in src/pydase/server/web_server/web_server.py
pydase.client
¶
Client
¶
Client(*, url: str, block_until_connected: bool = True, sio_client_kwargs: dict[str, Any] = {}, client_id: str | None = None, proxy_url: str | None = None, auto_update_proxy: bool = True)
A client for connecting to a remote pydase service using Socket.IO. This client handles asynchronous communication with a service, manages events such as connection, disconnection, and updates, and ensures that the proxy object is up-to-date with the server state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
url |
str
|
The URL of the pydase Socket.IO server. This should always contain the
protocol (e.g., |
required |
block_until_connected |
bool
|
If set to True, the constructor will block until the connection to the service has been established. This is useful for ensuring the client is ready to use immediately after instantiation. Default is True. |
True
|
sio_client_kwargs |
dict[str, Any]
|
Additional keyword arguments passed to the underlying
[ |
{}
|
client_id |
str | None
|
An optional client identifier. This ID is sent to the server as the
|
None
|
proxy_url |
str | None
|
An optional proxy URL to route the connection through. This is useful
if the service is only reachable via an SSH tunnel or behind a firewall
(e.g., |
None
|
auto_update_proxy |
bool
|
If False, disables automatic updates from the server. Useful for request-only clients where real-time synchronization is not needed. |
True
|
Example
Connect to a service directly:
Connect over a secure connection:
Connect using a SOCKS5 proxy (e.g., through an SSH tunnel):
Source code in src/pydase/client/client.py
proxy
instance-attribute
¶
A proxy object representing the remote service, facilitating interaction as if it were local.
get_value
¶
Retrieve the current value of a remote attribute.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
access_path |
str
|
The dot-separated path to the attribute in the remote service. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The deserialized value of the remote attribute, or None if the client is not |
Any
|
connected. |
Source code in src/pydase/client/client.py
trigger_method
¶
Trigger a remote method with optional arguments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
access_path |
str
|
The dot-separated path to the method in the remote service. |
required |
*args |
Any
|
Positional arguments to pass to the method. |
()
|
**kwargs |
Any
|
Keyword arguments to pass to the method. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
The return value of the method call, if any. |
Source code in src/pydase/client/client.py
update_value
¶
Set a new value for a remote attribute.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
access_path |
str
|
The dot-separated path to the attribute in the remote service. |
required |
new_value |
Any
|
The new value to assign to the attribute. |
required |
Source code in src/pydase/client/client.py
pydase.components
¶
The components module is a collection of specialized subclasses of the DataService
class that are designed to model different types of user interface components. These
classes can be used to represent the state of various UI elements in a data interface,
and provide a simple way to interact with these elements programmatically.
Each class in the components module corresponds to a specific type of UI element, such
as a slider, a file upload, a graph, etc. The state of these UI elements is maintained
by the instance variables of the respective classes. This allows you to keep track of
the user’s interactions with the UI elements and update your application’s state
accordingly.
You can use the classes in the components module as attributes of a DataService
subclass to model the state of your application’s UI. Here is an example of how to use
the NumberSlider class:
from components import NumberSlider
class MyService(DataService):
voltage = NumberSlider(1, 0, 10, 0.1)
# Then, you can modify or access the voltage value like this:
my_service = MyService()
my_service.voltage.value = 5
print(my_service.voltage.value) # Output: 5
ColouredEnum
¶
Bases: Enum
Represents a UI element that can display colour-coded text based on its value.
This class extends the standard Enum but requires its values to be valid CSS colour codes. Supported colour formats include:
- Hexadecimal colours
- Hexadecimal colours with transparency
- RGB colours
- RGBA colours
- HSL colours
- HSLA colours
- Predefined/Cross-browser colour names
Refer to the this website for more details on colour formats: (https://www.w3schools.com/cssref/css_colours_legal.php)
The behavior of this component in the UI depends on how it’s defined in the data service:
- As property with a setter or as attribute: Renders as a dropdown menu, allowing users to select and change its value from the frontend.
- As property without a setter: Displays as a coloured box with the key of the
ColouredEnumas text inside, serving as a visual indicator without user interaction.
Example
import pydase.components as pyc
import pydase
class MyStatus(pyc.ColouredEnum):
PENDING = "#FFA500" # Orange
RUNNING = "#0000FF80" # Transparent Blue
PAUSED = "rgb(169, 169, 169)" # Dark Gray
RETRYING = "rgba(255, 255, 0, 0.3)" # Transparent Yellow
COMPLETED = "hsl(120, 100%, 50%)" # Green
FAILED = "hsla(0, 100%, 50%, 0.7)" # Transparent Red
CANCELLED = "SlateGray" # Slate Gray
class StatusExample(pydase.DataService):
_status = MyStatus.RUNNING
@property
def status(self) -> MyStatus:
return self._status
@status.setter
def status(self, value: MyStatus) -> None:
# Custom logic here...
self._status = value
# Example usage:
my_service = StatusExample()
my_service.status = MyStatus.FAILED
Note
Each enumeration name and value must be unique. This means that you should use different colour formats when you want to use a colour multiple times.
DeviceConnection
¶
Bases: DataService
Base class for device connection management within the pydase framework.
This class serves as the foundation for subclasses that manage connections to
specific devices. It implements automatic reconnection logic that periodically
checks the device’s availability and attempts to reconnect if the connection is
lost. The frequency of these checks is controlled by the _reconnection_wait_time
attribute.
Subclassing¶
Users should primarily override the connect method to establish a connection
to the device. This method should update the self._connected attribute to reflect
the connection status:
class MyDeviceConnection(DeviceConnection):
def connect(self) -> None:
# Implementation to connect to the device
# Update self._connected to `True` if connection is successful,
# `False` otherwise
...
Optionally, if additional logic is needed to determine the connection status,
the connected property can also be overridden:
class MyDeviceConnection(DeviceConnection):
@property
def connected(self) -> bool:
# Custom logic to determine connection status
return some_custom_condition
Frontend Representation¶
In the frontend, this class is represented without directly exposing the connect
method and connected attribute. Instead, user-defined attributes, methods, and
properties are displayed. When self.connected is False, the frontend component
shows an overlay that allows manual triggering of the connect() method. This
overlay disappears once the connection is successfully re-established.
Source code in src/pydase/components/device_connection.py
connected
property
¶
Indicates if the device is currently connected or was recently connected. Users may override this property to incorporate custom logic for determining the connection status.
connect
¶
Tries connecting to the device and changes self._connected status
accordingly. This method is called every self._reconnection_wait_time seconds
when self.connected is False. Users should override this method to implement
device-specific connection logic.
Source code in src/pydase/components/device_connection.py
serialize
¶
serialize() -> SerializedObject
Serializes the instance into a dictionary, preserving the structure of the instance.
For each attribute, method, and property, the method includes its name, type, value, readonly status, and documentation if any in the resulting dictionary. Attributes and methods starting with an underscore are ignored.
For nested DataService instances, the method serializes recursively. For attributes of type list, each item in the list is serialized individually. If an item in the list is an instance of DataService, it is serialized recursively.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
SerializedObject
|
The serialized instance. |
Source code in src/pydase/data_service/data_service.py
NumberSlider
¶
Bases: DataService
This class models a UI slider for a data service, allowing for adjustments of a parameter within a specified range and increments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value |
Any
|
The initial value of the slider. Defaults to 0.0. |
0.0
|
min_ |
Any
|
The minimum value of the slider. Defaults to 0.0. |
0.0
|
max_ |
Any
|
The maximum value of the slider. Defaults to 100.0. |
100.0
|
step_size |
Any
|
The increment/decrement step size of the slider. Defaults to 1.0. |
1.0
|
Example
class MySlider(pydase.components.NumberSlider):
def __init__(
self,
value: float = 0.0,
min_: float = 0.0,
max_: float = 100.0,
step_size: float = 1.0,
) -> None:
super().__init__(value, min_, max_, step_size)
@property
def min(self) -> float:
return self._min
@min.setter
def min(self, value: float) -> None:
self._min = value
@property
def max(self) -> float:
return self._max
@max.setter
def max(self, value: float) -> None:
self._max = value
@property
def step_size(self) -> float:
return self._step_size
@step_size.setter
def step_size(self, value: float) -> None:
self._step_size = value
@property
def value(self) -> float:
return self._value
@value.setter
def value(self, value: float) -> None:
if value < self._min or value > self._max:
raise ValueError(
"Value is either below allowed min or above max value."
)
self._value = value
class MyService(pydase.DataService):
def __init__(self) -> None:
self.voltage = MyService()
# Modifying or accessing the voltage value:
my_service = MyService()
my_service.voltage.value = 5
print(my_service.voltage.value) # Output: 5
Source code in src/pydase/components/number_slider.py
serialize
¶
serialize() -> SerializedObject
Serializes the instance into a dictionary, preserving the structure of the instance.
For each attribute, method, and property, the method includes its name, type, value, readonly status, and documentation if any in the resulting dictionary. Attributes and methods starting with an underscore are ignored.
For nested DataService instances, the method serializes recursively. For attributes of type list, each item in the list is serialized individually. If an item in the list is an instance of DataService, it is serialized recursively.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
SerializedObject
|
The serialized instance. |
Source code in src/pydase/data_service/data_service.py
pydase.task
¶
autostart
¶
autostart_service_tasks
¶
autostart_service_tasks(service: DataService) -> None
Starts the service tasks defined with the autostart keyword argument.
This method goes through the attributes of the passed service and its nested
DataService instances and calls the start method on
autostart-tasks.
Source code in src/pydase/task/autostart.py
decorator
¶
PerInstanceTaskDescriptor
¶
PerInstanceTaskDescriptor(func: Callable[[Any], Coroutine[None, None, R]] | Callable[[], Coroutine[None, None, R]], autostart: bool, restart_on_exception: bool, restart_sec: float, start_limit_interval_sec: float | None, start_limit_burst: int, exit_on_failure: bool)
Bases: Generic[R]
A descriptor class that provides a unique Task object
for each instance of a DataService
class.
The PerInstanceTaskDescriptor is used to transform an asynchronous function into a
task that is managed independently for each instance of a DataService subclass.
This allows tasks to be initialized, started, and stopped on a per-instance basis,
providing better control over task execution within the service.
The PerInstanceTaskDescriptor is not intended to be used directly. Instead, it is
used internally by the @task decorator to manage task objects for each instance of
the service class.
Source code in src/pydase/task/decorator.py
__set_name__
¶
__set_name__(owner: type[DataService], name: str) -> None
Stores the name of the task within the owning class. This method is called automatically when the descriptor is assigned to a class attribute.
Source code in src/pydase/task/decorator.py
task
¶
task(*, autostart: bool = False, restart_on_exception: bool = True, restart_sec: float = 1.0, start_limit_interval_sec: float | None = None, start_limit_burst: int = 3, exit_on_failure: bool = False) -> Callable[[Callable[[Any], Coroutine[None, None, R]] | Callable[[], Coroutine[None, None, R]]], PerInstanceTaskDescriptor[R]]
A decorator to define an asynchronous function as a per-instance task within a
DataService class.
This decorator transforms an asynchronous function into a
Task object that is unique to each instance of the
DataService class. The resulting Task object provides methods like start()
and stop() to control the execution of the task, and manages the task’s lifecycle
independently for each instance of the service.
The decorator is particularly useful for defining tasks that need to run
periodically or perform asynchronous operations, such as polling data sources,
updating databases, or any recurring job that should be managed within the context
of a DataService.
The keyword arguments that can be passed to this decorator are inspired by systemd unit services.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
autostart |
bool
|
If set to True, the task will automatically start when the service is initialized. Defaults to False. |
False
|
restart_on_exception |
bool
|
Configures whether the task shall be restarted when it exits with an
exception other than [ |
True
|
restart_sec |
float
|
Configures the time to sleep before restarting a task. Defaults to 1.0. |
1.0
|
start_limit_interval_sec |
float | None
|
Configures start rate limiting. Tasks which are started more than
|
None
|
start_limit_burst |
int
|
Configures unit start rate limiting. Tasks which are started more than
|
3
|
exit_on_failure |
bool
|
If True, exit the service if the task fails and restart_on_exception is False or burst limits are exceeded. |
False
|
Returns:
A decorator that wraps an asynchronous function in a
PerInstanceTaskDescriptor
object, which, when accessed, provides an instance-specific
Task object.
Example
import asyncio
import pydase
from pydase.task.decorator import task
class MyService(pydase.DataService):
@task(autostart=True)
async def my_task(self) -> None:
while True:
# Perform some periodic work
await asyncio.sleep(1)
if __name__ == "__main__":
service = MyService()
pydase.Server(service=service).run()
In this example, my_task is defined as a task using the @task decorator, and
it will start automatically when the service is initialized because
autostart=True is set. You can manually start or stop the task using
service.my_task.start() and service.my_task.stop(), respectively.
Source code in src/pydase/task/decorator.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
task
¶
Task
¶
Task(func: Callable[[], Coroutine[None, None, R | None]], *, autostart: bool, restart_on_exception: bool, restart_sec: float, start_limit_interval_sec: float | None, start_limit_burst: int, exit_on_failure: bool)
Bases: DataService, Generic[R]
A class representing a task within the pydase framework.
The Task class wraps an asynchronous function and provides methods to manage its
lifecycle, such as start() and stop(). It is typically used to perform periodic
or recurring jobs in a DataService, like reading
sensor data, updating databases, or executing other background tasks.
When a function is decorated with the @task
decorator, it is replaced by a Task instance that controls the execution of the
original function.
The keyword arguments that can be passed to this class are inspired by systemd unit services.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func |
Callable[[], Coroutine[None, None, R | None]]
|
The asynchronous function that this task wraps. It must be a coroutine without arguments. |
required |
autostart |
bool
|
If set to True, the task will automatically start when the service is initialized. Defaults to False. |
required |
restart_on_exception |
bool
|
Configures whether the task shall be restarted when it exits with an
exception other than [ |
required |
restart_sec |
float
|
Configures the time to sleep before restarting a task. Defaults to 1.0. |
required |
start_limit_interval_sec |
float | None
|
Configures start rate limiting. Tasks which are started more than
|
required |
start_limit_burst |
int
|
Configures unit start rate limiting. Tasks which are started more than
|
required |
exit_on_failure |
bool
|
If True, exit the service if the task fails and restart_on_exception is False or burst limits are exceeded. |
required |
Example
import asyncio
import pydase
from pydase.task.decorator import task
class MyService(pydase.DataService):
@task(autostart=True)
async def my_task(self) -> None:
while True:
# Perform some periodic work
await asyncio.sleep(1)
if __name__ == "__main__":
service = MyService()
pydase.Server(service=service).run()
In this example, my_task is defined as a task using the @task decorator, and
it will start automatically when the service is initialized because
autostart=True is set. You can manually start or stop the task using
service.my_task.start() and service.my_task.stop(), respectively.
Source code in src/pydase/task/task.py
start
¶
Starts the asynchronous task if it is not already running.
Source code in src/pydase/task/task.py
pydase.utils.serialization.serializer
¶
Serializer
¶
Serializes objects into
SerializedObject
representations.
serialize_object
classmethod
¶
serialize_object(obj: Any, access_path: str = '') -> SerializedObject
Serialize obj to a
SerializedObject.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj |
Any
|
Object to be serialized. |
required |
access_path |
str
|
String corresponding to the full access path of the object. This will be prepended to the full_access_path in the SerializedObject entries. |
''
|
Returns:
| Type | Description |
|---|---|
SerializedObject
|
Dictionary representation of |
Source code in src/pydase/utils/serialization/serializer.py
add_prefix_to_full_access_path
¶
add_prefix_to_full_access_path(serialized_obj: SerializedObject, prefix: str) -> Any
Recursively adds a specified prefix to all full access paths of the serialized object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serialized_obj |
SerializedObject
|
The serialized object to process. |
required |
prefix |
str
|
The prefix string to prepend to each full access path. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The modified serialized object with the prefix added to all full access paths. |
Example
>>> serialized_obj = {
... "full_access_path": "",
... "value": {
... "item": {
... "full_access_path": "some_item_path",
... "value": 1.0
... }
... }
... }
...
... modified_data = add_prefix_to_full_access_path(serialized_obj, 'prefix')
{"full_access_path": "prefix", "value": {"item": {"full_access_path":
"prefix.some_item_path", "value": 1.0}}}
Source code in src/pydase/utils/serialization/serializer.py
create_empty_serialized_object
¶
create_empty_serialized_object() -> SerializedObject
Create a new empty serialized object.
dump
¶
dump(obj: Any) -> SerializedObject
Serialize obj to a
SerializedObject.
The Serializer is used for
encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj |
Any
|
Object to be serialized. |
required |
Returns:
| Type | Description |
|---|---|
SerializedObject
|
Dictionary representation of |
Source code in src/pydase/utils/serialization/serializer.py
generate_serialized_data_paths
¶
generate_serialized_data_paths(data: dict[str, SerializedObject]) -> list[str]
Recursively extracts full access paths from a serialized DataService class instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
dict[str, SerializedObject]
|
The value of the “value” key of a serialized DataService class instance. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
A list of strings, each representing a full access path in the serialized object. |
Source code in src/pydase/utils/serialization/serializer.py
get_container_item_by_key
¶
get_container_item_by_key(container: dict[Any, SerializedObject] | list[SerializedObject], key: str, *, allow_append: bool = False) -> SerializedObject
Retrieve an item from a container specified by the passed key. Add an item to the
container if allow_append is set to True.
If specified keys or indexes do not exist, the function can append new elements to
dictionaries and to lists if allow_append is True and the missing element is
exactly the next sequential index (for lists).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
container |
dict[Any, SerializedObject] | list[SerializedObject]
|
The container representing serialized data. |
required |
key |
str
|
The key name representing the attribute in the dictionary, which may include direct keys or indexes (e.g., ‘attr_name’, ‘[“key”]’ or ‘[0]’). |
required |
allow_append |
bool
|
Flag to allow appending a new entry if the specified index is out of range by exactly one position. |
False
|
Returns:
| Type | Description |
|---|---|
SerializedObject
|
The dictionary or list item corresponding to the specified attribute and index. |
Raises:
| Type | Description |
|---|---|
SerializationPathError
|
If the path composed of |
Source code in src/pydase/utils/serialization/serializer.py
get_data_paths_from_serialized_object
¶
get_data_paths_from_serialized_object(serialized_obj: SerializedObject, parent_path: str = '') -> list[str]
Recursively extracts full access paths from a serialized object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serialized_obj |
SerializedObject
|
The dictionary representing the serialization of an object. Produced by
|
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
A list of strings, each representing a full access path in the serialized object. |
Source code in src/pydase/utils/serialization/serializer.py
get_or_create_item_in_container
¶
get_or_create_item_in_container(container: dict[Any, SerializedObject] | list[SerializedObject], key: Any, *, allow_add_key: bool) -> SerializedObject
Ensure the key exists in the dictionary, append if necessary and allowed.
Source code in src/pydase/utils/serialization/serializer.py
set_nested_value_by_path
¶
set_nested_value_by_path(serialization_dict: dict[Any, SerializedObject], path: str, value: Any) -> None
Set a value in a nested dictionary structure, which conforms to the serialization
format used by Serializer,
using a dot-notation path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serialization_dict |
dict[Any, SerializedObject]
|
The base dictionary representing data serialized with
|
required |
path |
str
|
The dot-notation path (e.g., ‘attr1.attr2[0].attr3’) indicating where to set the value. |
required |
value |
Any
|
The new value to set at the specified path. |
required |
Note
If the index equals the length of the list, the function will append the serialized representation of the ‘value’ to the list.
Source code in src/pydase/utils/serialization/serializer.py
pydase.utils.serialization.deserializer
¶
Deserializer
¶
deserialize
classmethod
¶
deserialize(serialized_object: SerializedObject) -> Any
Deserialize serialized_object (a dict) to a Python object.
Source code in src/pydase/utils/serialization/deserializer.py
loads
¶
loads(serialized_object: SerializedObject) -> Any
Deserialize serialized_object (a dict) to a Python object.
pydase.utils.serialization.types
¶
SerializedObject
module-attribute
¶
SerializedObject = SerializedBool | SerializedFloat | SerializedInteger | SerializedString | SerializedDatetime | SerializedList | SerializedDict | SerializedNoneType | SerializedMethod | SerializedException | SerializedDataService | SerializedEnum | SerializedQuantity | SerializedNoValue
This type can be any of the following:
- SerializedBool
- SerializedFloat
- SerializedInteger
- SerializedString
- SerializedDatetime
- SerializedList
- SerializedDict
- SerializedNoneType
- SerializedMethod
- SerializedException
- SerializedDataService
- SerializedEnum
- SerializedQuantity
- SerializedNoValue
pydase.utils.decorators
¶
frontend
¶
Decorator to mark a DataService method for frontend
rendering. Ensures that the method does not contain arguments, as they are not
supported for frontend rendering.
Source code in src/pydase/utils/decorators.py
pydase.utils.logging
¶
DefaultFormatter
¶
DefaultFormatter(fmt: str | None = None, datefmt: str | None = None, style: Literal['%', '{', '$'] = '%', use_colors: bool | None = None)
Bases: Formatter
A custom log formatter class that:
- Outputs the LOG_LEVEL with an appropriate color.
- If a log call includes an
extras={"color_message": ...}it will be used for formatting the output, instead of the plain text message.
Source code in src/pydase/utils/logging.py
NameFilter
¶
SocketIOHandler
¶
Bases: Handler
Custom logging handler that emits ERROR and CRITICAL log records to a Socket.IO server, allowing for real-time logging in applications that use Socket.IO for communication.
Source code in src/pydase/utils/logging.py
configure_logging_with_pydase_formatter
¶
configure_logging_with_pydase_formatter(name: str | None = None, level: int = logging.INFO, stream: TextIO | None = None) -> None
Configure a logger with the pydase DefaultFormatter.
This sets up a StreamHandler with the custom DefaultFormatter, which includes
timestamp, log level with color (if supported), logger name, function, and line
number. It can be used to configure the root logger or any named logger.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name |
str | None
|
The name of the logger to configure. If None, the root logger is used. |
None
|
level |
int
|
The logging level to set on the logger (e.g., logging.DEBUG, logging.INFO). Defaults to logging.INFO. |
INFO
|
stream |
TextIO | None
|
The output stream for the log messages (e.g., sys.stdout or sys.stderr). If None, defaults to sys.stderr. |
None
|
Example
Configure logging in your service:
import sys
from pydase.utils.logging import configure_logging_with_pydase_formatter
configure_logging_with_pydase_formatter(
name="my_service", # Use the package/module name or None for the root logger
level=logging.DEBUG, # Set the desired logging level (defaults to INFO)
stream=sys.stdout # Set the output stream (stderr by default)
)
Notes
- This function adds a new handler each time it’s called. Use carefully to avoid duplicate logs.
- Colors are enabled if the stream supports TTY (e.g., in terminal).
Source code in src/pydase/utils/logging.py
setup_logging
¶
Configures the logging settings for the application.
This function sets up logging with specific formatting and colorization of log messages. The log level is determined based on the application’s operation mode. By default, in a development environment, the log level is set to DEBUG, whereas in other environments, it is set to INFO.
Source code in src/pydase/utils/logging.py
pydase.units
¶
convert_to_quantity
¶
Convert a given value into a pint.Quantity object with the specified unit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value |
QuantityDict | float | Quantity
|
The value to be converted into a Quantity object.
|
required |
unit |
str
|
The target unit for conversion. If empty and value is not a Quantity object, it will assume a unitless quantity. |
''
|
Returns:
| Type | Description |
|---|---|
Quantity
|
The converted value as a pint.Quantity object with the specified unit. |
Examples:
>>> convert_to_quantity(5, 'm')
<Quantity(5.0, 'meters')>
>>> convert_to_quantity({'magnitude': 10, 'unit': 'mV'})
<Quantity(10.0, 'millivolt')>
>>> convert_to_quantity(10.0 * u.units.V)
<Quantity(10.0, 'volt')>
Note
If unit is not provided and value is a float or int, the resulting Quantity will be unitless.