Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@component decorator on a class that inherits from another marked with the same breaks its init #7824

Closed
shadeMe opened this issue Jun 7, 2024 · 2 comments
Assignees
Labels
2.x Related to Haystack v2.0 P1 High priority, add to the next sprint type:bug Something isn't working

Comments

@shadeMe
Copy link
Collaborator

shadeMe commented Jun 7, 2024

Describe the bug
Adding the @component to a component class that already derives from another component class with the @component decorator breaks the former's initialization if its __init__ method calls super() or super().__init__.

Error message

TypeError: super(type, obj): obj must be an instance or subtype of type

To Reproduce
Add the decorator to FaithfulnessEvaluator, which derives from LLMEvaluator.

@shadeMe shadeMe added type:bug Something isn't working P2 Medium priority, add to the next sprint if no P1 available 2.x Related to Haystack v2.0 labels Jun 7, 2024
@shadeMe shadeMe added P1 High priority, add to the next sprint and removed P2 Medium priority, add to the next sprint if no P1 available labels Jun 14, 2024
@shadeMe shadeMe self-assigned this Jun 14, 2024
@masci
Copy link
Contributor

masci commented Jun 15, 2024

This is most likely due to something similar to python-attrs/attrs#1038, the way we reconstruct any decorated component class with new_class would trigger the same problem with method rewriting.

Closest example to our case to reproduce:

from types import new_class
from functools import partial


def copyns(cls, ns):
    """Copy the namespace of the original class"""
    for key, val in dict(cls.__dict__).items():
        ns[key] = val
    return ns


class MyMeta(type):
    pass


class BaseComponent:
    pass


# This is what the `@component` decorator would eventually do
BaseComponent = new_class(  # type:ignore
    BaseComponent.__name__,
    BaseComponent.__bases__,
    {"metaclass": MyMeta},
    partial(copyns, BaseComponent),
)  # type:ignore


class DerivedComponent(BaseComponent):
    def __init__(self):
        super().__init__()


DerivedComponent = new_class(  # type:ignore
    DerivedComponent.__name__,
    DerivedComponent.__bases__,
    {"metaclass": MyMeta},
    partial(copyns, DerivedComponent),
)  # type:ignore

dc = DerivedComponent()  # TypeError: super(type, obj): obj must be an instance or subtype of type

The workaround (that's also mentioned in the linked issue) is to "help" Python understand what's going on calling super() like this:

# ...

class DerivedComponent(BaseComponent):
    def __init__(self):
        super(DerivedComponent, self).__init__()

# ...

dc = DerivedComponent()  # ok

@shadeMe
Copy link
Collaborator Author

shadeMe commented Jun 19, 2024

Looks like the above workaround is the way forward.

@shadeMe shadeMe closed this as completed Jun 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.x Related to Haystack v2.0 P1 High priority, add to the next sprint type:bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants