Update the remaining docstrings, update pre-commit hook, add docstring formatting CI, update CONTRIBUTING with formatting guidance (#2089)

This commit is contained in:
Mark Backman
2025-07-01 00:37:04 -04:00
committed by GitHub
parent 224d2cedc8
commit fd570b0377
122 changed files with 6858 additions and 1281 deletions

View File

@@ -4,6 +4,13 @@
# SPDX-License-Identifier: BSD 2-Clause License
#
"""Base object class providing event handling and lifecycle management.
This module provides the foundational BaseObject class that offers common
functionality including unique identification, naming, event handling,
and async cleanup for all Pipecat components.
"""
import asyncio
import inspect
from abc import ABC
@@ -15,7 +22,20 @@ from pipecat.utils.utils import obj_count, obj_id
class BaseObject(ABC):
"""Abstract base class providing common functionality for Pipecat objects.
Provides unique identification, naming, event handling capabilities,
and async lifecycle management for all Pipecat components. All major
classes in the framework should inherit from this base class.
"""
def __init__(self, *, name: Optional[str] = None):
"""Initialize the base object.
Args:
name: Optional custom name for the object. If not provided,
generates a name using the class name and instance count.
"""
self._id: int = obj_id()
self._name = name or f"{self.__class__.__name__}#{obj_count(self)}"
@@ -29,19 +49,44 @@ class BaseObject(ABC):
@property
def id(self) -> int:
"""Get the unique identifier for this object.
Returns:
The unique integer ID assigned to this object instance.
"""
return self._id
@property
def name(self) -> str:
"""Get the name of this object.
Returns:
The object's name, either custom-provided or auto-generated.
"""
return self._name
async def cleanup(self):
"""Clean up resources and wait for running event handlers to complete.
This method should be called when the object is no longer needed.
It waits for all currently executing event handler tasks to finish
before returning.
"""
if self._event_tasks:
event_names, tasks = zip(*self._event_tasks)
logger.debug(f"{self} waiting on event handlers to finish {list(event_names)}...")
await asyncio.wait(tasks)
def event_handler(self, event_name: str):
"""Decorator for registering event handlers.
Args:
event_name: The name of the event to handle.
Returns:
The decorator function that registers the handler.
"""
def decorator(handler):
self.add_event_handler(event_name, handler)
return handler
@@ -49,18 +94,37 @@ class BaseObject(ABC):
return decorator
def add_event_handler(self, event_name: str, handler):
"""Add an event handler for the specified event.
Args:
event_name: The name of the event to handle.
handler: The function to call when the event occurs.
Can be sync or async.
"""
if event_name in self._event_handlers:
self._event_handlers[event_name].append(handler)
else:
logger.warning(f"Event handler {event_name} not registered")
def _register_event_handler(self, event_name: str):
"""Register an event handler type.
Args:
event_name: The name of the event type to register.
"""
if event_name not in self._event_handlers:
self._event_handlers[event_name] = []
else:
logger.warning(f"Event handler {event_name} not registered")
async def _call_event_handler(self, event_name: str, *args, **kwargs):
"""Call all registered handlers for the specified event.
Args:
event_name: The name of the event to trigger.
*args: Positional arguments to pass to event handlers.
**kwargs: Keyword arguments to pass to event handlers.
"""
# If we haven't registered an event handler, we don't need to do
# anything.
if not self._event_handlers.get(event_name):
@@ -76,6 +140,13 @@ class BaseObject(ABC):
task.add_done_callback(self._event_task_finished)
async def _run_task(self, event_name: str, *args, **kwargs):
"""Execute all handlers for an event.
Args:
event_name: The name of the event being handled.
*args: Positional arguments to pass to handlers.
**kwargs: Keyword arguments to pass to handlers.
"""
try:
for handler in self._event_handlers[event_name]:
if inspect.iscoroutinefunction(handler):
@@ -86,9 +157,19 @@ class BaseObject(ABC):
logger.exception(f"Exception in event handler {event_name}: {e}")
def _event_task_finished(self, task: asyncio.Task):
"""Clean up completed event handler tasks.
Args:
task: The completed asyncio Task to remove from tracking.
"""
tuple_to_remove = next((t for t in self._event_tasks if t[1] == task), None)
if tuple_to_remove:
self._event_tasks.discard(tuple_to_remove)
def __str__(self):
"""Return the string representation of this object.
Returns:
The object's name as its string representation.
"""
return self.name