haystack icon indicating copy to clipboard operation
haystack copied to clipboard

feat: Enhance Component registry to update with init and support shortened import paths

Open Amnah199 opened this issue 9 months ago • 0 comments

Is your feature request related to a problem? Please describe. Currently, the component registry in Haystack only stores the complete module path of components. When users create init files to re-export components with shorter paths (a common Python pattern), the registry isn't updated. This forces users to always use the complete path during serialization and deserialization. For example, if a user has:

# haystack/components/retrievers/memory.py
@component
class MemoryRetriever:

And __init__ file:

# haystack/components/__init__.py
from .retrievers.memory import MemoryRetriever

They still need to use haystack.components.retrievers.memory.MemoryRetriever in serialized pipelines instead of the shorter haystack.components.MemoryRetriever as it wont work.

Describe the solution you'd like Enhance the component registry to track both original paths and re-exported paths (aliases). Below is one possible solution.

Dynamic Registry Update During Import: Update the registry when components are re-exported through init files. We could modify the _component decorator to track both the original and re-exported paths. A quick implementation suggest by cursor for reference:

class _Component:
    def __init__(self):
        # Map of original path -> list of alias paths
        self.registry = {}
        self.alias_registry = {}  # alias -> original path

    def _component(self, cls: Any):
        logger.debug("Registering {component} as a component", component=cls)

        if not hasattr(cls, "run"):
            raise ComponentError(f"{cls.__name__} must have a 'run()' method. See the docs for more information.")

        # Create the new class with metaclass as before
        new_cls = new_class(cls.__name__, cls.__bases__, {"metaclass": ComponentMeta}, copy_class_namespace)

        # Get both the original path and current import path
        original_path = f"{cls.__module__}.{cls.__name__}"
        current_path = f"{new_cls.__module__}.{new_cls.__name__}"

        # Register both paths
        if original_path not in self.registry:
            self.registry[original_path] = new_cls
            
        # Add alias if this is a re-export
        if current_path != original_path:
            self.alias_registry[current_path] = original_path
            logger.debug(
                "Added alias {alias} for component {original}",
                alias=current_path,
                original=original_path
            )

        return new_cls

Alternate Solutions We could maintain a separate index by class name to help with resolution.

Amnah199 avatar Mar 30 '25 23:03 Amnah199