Module i2pp.core.user_function_transformer.user_function_transformer

Transform pixel values according to user-defined transformation function.

Classes

class UserFunctionTransformer (normalize: bool = False, pixel_range: numpy.ndarray = None)
Expand source code
class UserFunctionTransformer:
    """Handles the application of user-defined transformation functions."""

    def __init__(
        self, normalize: bool = False, pixel_range: np.ndarray = None
    ):
        self.normalize = normalize
        self.pixel_range = pixel_range

    def load_user_function(
        self, script_path: Path, function_name: str
    ) -> Callable:
        """Dynamically loads a user-defined function from a script file.

        This function attempts to import a Python script as a module and
        retrieve a specified function from it. If the script or function is
        not found, an error is raised.

        Arguments:
            script_path (str): The file path to the user script.
            function_name (str): The name of the function to load.

        Returns:
            Callable: The loaded user-defined function.

        Raises:
            RuntimeError: If the script file does not exist.
            RuntimeError: If the script cannot be loaded as a module.
            RuntimeError: If the function is not found or is not callable.
        """
        if not Path(script_path).is_file():
            raise RuntimeError(f"User script '{script_path}' not found!")

        spec = importlib.util.spec_from_file_location(
            "user_module", script_path
        )
        if spec is None or spec.loader is None:
            raise RuntimeError(f"Failed to load module spec for {script_path}")

        user_module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(user_module)

        user_function = getattr(user_module, function_name, None)
        if not callable(user_function):
            raise RuntimeError(
                f"User function {function_name} not found or not callable"
            )

        # check that the function accepts two arguments
        if user_function.__code__.co_argcount != 2:
            raise RuntimeError(
                f"User function {function_name} must accept two arguments"
            )

        # check that the user function returns a numpy array
        # Use test data that simulates realistic element data structure
        test_ids = np.array([1, 2])  # Two element IDs
        test_data = np.array([[0.5, 0.3, 0.2], [0.4, 0.4, 0.2]])  # 2D data
        result = user_function(test_ids, test_data)
        if not isinstance(result, np.ndarray):
            raise RuntimeError(
                f"User function {function_name} must return a numpy array"
            )

        return user_function

    def apply_transformation(
        self, elements: list[Element], script_path: Path, function_name: str
    ) -> Any:
        """Applies user-defined transformation to element data."""
        element_ids = np.array([ele.id + 1 for ele in elements])
        element_data = np.array([ele.data for ele in elements])

        if self.normalize:
            element_data = normalize_values(element_data, self.pixel_range)

        user_function = self.load_user_function(script_path, function_name)
        return user_function(element_ids, element_data)

Handles the application of user-defined transformation functions.

Methods

def apply_transformation(self,
elements: list[Element],
script_path: pathlib.Path,
function_name: str) ‑> Any
Expand source code
def apply_transformation(
    self, elements: list[Element], script_path: Path, function_name: str
) -> Any:
    """Applies user-defined transformation to element data."""
    element_ids = np.array([ele.id + 1 for ele in elements])
    element_data = np.array([ele.data for ele in elements])

    if self.normalize:
        element_data = normalize_values(element_data, self.pixel_range)

    user_function = self.load_user_function(script_path, function_name)
    return user_function(element_ids, element_data)

Applies user-defined transformation to element data.

def load_user_function(self, script_path: pathlib.Path, function_name: str) ‑> Callable
Expand source code
def load_user_function(
    self, script_path: Path, function_name: str
) -> Callable:
    """Dynamically loads a user-defined function from a script file.

    This function attempts to import a Python script as a module and
    retrieve a specified function from it. If the script or function is
    not found, an error is raised.

    Arguments:
        script_path (str): The file path to the user script.
        function_name (str): The name of the function to load.

    Returns:
        Callable: The loaded user-defined function.

    Raises:
        RuntimeError: If the script file does not exist.
        RuntimeError: If the script cannot be loaded as a module.
        RuntimeError: If the function is not found or is not callable.
    """
    if not Path(script_path).is_file():
        raise RuntimeError(f"User script '{script_path}' not found!")

    spec = importlib.util.spec_from_file_location(
        "user_module", script_path
    )
    if spec is None or spec.loader is None:
        raise RuntimeError(f"Failed to load module spec for {script_path}")

    user_module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(user_module)

    user_function = getattr(user_module, function_name, None)
    if not callable(user_function):
        raise RuntimeError(
            f"User function {function_name} not found or not callable"
        )

    # check that the function accepts two arguments
    if user_function.__code__.co_argcount != 2:
        raise RuntimeError(
            f"User function {function_name} must accept two arguments"
        )

    # check that the user function returns a numpy array
    # Use test data that simulates realistic element data structure
    test_ids = np.array([1, 2])  # Two element IDs
    test_data = np.array([[0.5, 0.3, 0.2], [0.4, 0.4, 0.2]])  # 2D data
    result = user_function(test_ids, test_data)
    if not isinstance(result, np.ndarray):
        raise RuntimeError(
            f"User function {function_name} must return a numpy array"
        )

    return user_function

Dynamically loads a user-defined function from a script file.

This function attempts to import a Python script as a module and retrieve a specified function from it. If the script or function is not found, an error is raised.

Arguments

script_path (str): The file path to the user script. function_name (str): The name of the function to load.

Returns

Callable
The loaded user-defined function.

Raises

RuntimeError
If the script file does not exist.
RuntimeError
If the script cannot be loaded as a module.
RuntimeError
If the function is not found or is not callable.