OpenFactoryApp decorators#

openfactory.apps.decorators.ofa_method(name=None, description=None, param_description=None)[source]#

Decorator to mark an instance method as an OpenFactory callable method.

This decorator inspects the function signature and attaches structured metadata to the method object for later registration with OpenFactory inside a class derived from OpenFactoryApp.

Return type:

Callable

It enforces the following constraints on the decorated method:
  1. The first parameter must be self.

  2. Only named parameters are allowed (no positional-only parameters).

  3. No *args or **kwargs are allowed.

The attached metadata includes:
  • method_name: name of the method (defaults to the Python function name)

  • parameters: dictionary of parameter names with their description, type, default, and required flag

  • description: the method description

Parameters:
  • name (str | None) – External name to register the method under. Defaults to None, which uses the Python function name.

  • description (str | None) – Optional short description of the method. Defaults to the function docstring if not provided.

  • param_description (dict[str, str] | None) – Optional dict mapping parameter names to user-friendly descriptions. Takes precedence over Annotated types.

Raises:
  • TypeError – If the decorated function does not have self as the first parameter.

  • TypeError – If any parameter is positional-only, *args, or **kwargs.

Returns:

Callable – The original function with _ofa_method_metadata attached.

Decorator usage examples:

from typing import Annotated

class MyApp(OpenFactoryApp):

    # Decorator uses docstring
    @ofa_method()
    def home_axis(self):
        """Move to home position."""
        ...

    # Decorator overrides docstring with description argument
    @ofa_method(description="Move axis with optional speed.")
    def move_axis(self, x: float, y: float, speed: int = 100):
        """This docstring will be ignored."""
        ...

    # Using param_description dict
    @ofa_method(param_description={"x": "X coordinate", "y": "Y coordinate"})
    def move_axis_fast(self, x: float, y: float):
        ...

    # Using Annotated types
    @ofa_method()
    def move_z_axis(
        self,
        z: Annotated[float, "Z coordinate"],
        speed: Annotated[int, "Feed rate (optional; defaults to 100)"] = 100
    ):
        ...