backcall
backcall is a Python module designed to create backwards-compatible callback APIs. It enables developers to add new parameters to API calls without breaking existing third-party callback functions that may not be aware of these new parameters. The library is currently at version 0.2.0, last released on June 9, 2020, and appears to be in a maintenance state with infrequent updates.
Warnings
- gotcha Callback functions provided to `prototype.adapt()` cannot have *more* arguments than defined in the `callback_prototype`, even if those extra arguments have default values. Doing so will result in a `TypeError` when the callback is registered.
- gotcha Callback functions must have introspectable signatures. This means functions defined in compiled code (e.g., C extensions) cannot be directly used as callbacks unless they are wrapped in a Python function.
- gotcha The project appears to be in a maintenance state, with the last release in June 2020 and minimal recent activity on its GitHub repository. While widely used, be aware that active development and new features are unlikely.
Install
-
pip install backcall
Imports
- callback_prototype
from backcall import callback_prototype
Quickstart
from backcall import callback_prototype
@callback_prototype
def my_prototype_handler(sender, message, detail=None):
# This function defines the expected signature for callbacks.
# Positional parameters without defaults, keyword-only with defaults (Python 3).
pass
def register_event_handler(callback_func):
# The adapt method inspects the callback and wraps it if necessary
# to discard extra arguments not in the prototype.
adapted_callback = my_prototype_handler.adapt(callback_func)
print(f"Registered adapted callback: {adapted_callback.__name__}")
return adapted_callback
# Example callbacks
def simple_callback(sender, message):
print(f"Simple: {sender} says '{message}'")
def detailed_callback(sender, message, detail):
print(f"Detailed: {sender} says '{message}' with detail: {detail}")
def super_detailed_callback(sender, message, detail, extra_arg='default'):
print(f"Super Detailed: {sender} says '{message}' with detail: {detail} and extra: {extra_arg}")
# Registering and calling
print("--- Registering simple_callback ---")
adapted_simple = register_event_handler(simple_callback)
adapted_simple('System', 'Hello world!')
print("--- Registering detailed_callback ---")
adapted_detailed = register_event_handler(detailed_callback)
adapted_detailed('System', 'Another message', 'Important info')
# This would normally raise TypeError if passed to .adapt directly,
# but backcall will raise it because the callback has *more* arguments than prototype.
print("\n--- Attempting to register super_detailed_callback (expecting TypeError) ---")
try:
register_event_handler(super_detailed_callback)
except TypeError as e:
print(f"Caught expected error: {e}")