Source code for python_project_template_AS.operations
"""Operation container and a few example math operations.
The :class:`Operation` is a tiny callable wrapper that validates arity and
delegates to the underlying function. A small set of convenience
instances (ADD, SUB, MUL, DIV, NEG, SQR) are provided for tests/examples.
"""
from dataclasses import dataclass
from typing import Callable, Any
from .exceptions import OperationError
[docs]
@dataclass
class Operation:
"""Named callable with arity check.
Attributes:
name (str): Operation name.
func (Callable): Operation function.
arity (int): Expected argument count.
"""
name: str
func: Callable[..., Any]
arity: int = 1
def __call__(self, *args):
"""Call operation, checking argument count.
Args:
*args: Arguments for the operation.
Raises:
OperationError: If argument count is wrong.
"""
if len(args) != self.arity:
raise OperationError(
f"Operation '{self.name}' expects {self.arity} arguments, got {len(args)}"
)
return self.func(*args)
# --- Example operations -------------------------------------------------
[docs]
def add(a, b):
"""Return the sum of two numbers."""
return a + b
[docs]
def sub(a, b):
"""Return the difference of two numbers."""
return a - b
[docs]
def mul(a, b):
"""Return the product of two numbers."""
return a * b
[docs]
def safe_div(a, b):
"""Divide a by b, raising :class:`OperationError` on zero division."""
try:
return a / b
except ZeroDivisionError as e:
raise OperationError("Division by zero") from e
[docs]
def neg(a):
"""Return the numeric negation of a value."""
return -a
[docs]
def square(a):
"""Return the square of a value."""
return a * a
# Convenience instances
ADD = Operation("add", add, arity=2)
SUB = Operation("sub", sub, arity=2)
MUL = Operation("mul", mul, arity=2)
DIV = Operation("div", safe_div, arity=2)
NEG = Operation("neg", neg, arity=1)
SQR = Operation("sqr", square, arity=1)