gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
34.01k stars 2.58k forks source link

[Custom Components] Support `BlockContext` to include `Component` features #8870

Open Col0ring opened 3 months ago

Col0ring commented 3 months ago

Is your feature request related to a problem? Please describe.
I'm creating a custom component which can both hold other components and handle the data_model. But currently the classes BlockContext or Component provided by Gradio cannot resolve it. Custom components inherit from BlockContext will not run the callback functions preprocess and postprocess and handle the data_model. On the other hand, components inherit from Component cannot use with the with statement. I wonder if gradio can combine the features of both, or is there any other way to do this :)

Describe the solution you'd like
Support BlockContext to include Component features.

Additional context
Add any other context or screenshots about the feature request here.

abidlabs commented 3 months ago

Very interesting idea, I think this makes sense down the line to unify BlocksContext and Component. In particular, I think BlocksContext should be a subclass of Component since rows, columns, etc can already be used as output components

Col0ring commented 3 months ago

Thanks for your reply, I'm looking forward to it. BTW, I created a new base component class to combine both in gradio v4.38.1. I'm not sure if it‘s a correct way, but it works for me.

class LayoutComponent(Component, BlockContext, metaclass=ComponentMeta):
    """
    """
    EVENTS = []

    # fix gradio’s bug
    @property
    def component_class_id(self):
        return self.get_component_class_id()

    @component_class_id.setter
    def component_class_id(self, value):
        pass

    @property
    def skip_api(self):
        return False

    def __init__(
        self,
        value: Any = None,
        *,
        visible: bool = True,
        elem_id: str | None = None,
        elem_classes: list[str] | str | None = None,
        elem_style: dict | None = None,
        key: int | str | None = None,
        every: Timer | float | None = None,
        inputs: Component | list[Component] | set[Component] | None = None,
        render: bool = True,
    ):
        super().__init__(
            visible=visible,
            value=value,
            elem_id=elem_id,
            elem_classes=elem_classes,
            key=key,
            every=every,
            inputs=inputs,
            # it's important to set `render=False` here to disable the component render twice
            render=False)

        BlockContext.__init__(self,
                              visible=visible,
                              elem_id=elem_id,
                              elem_classes=elem_classes,
                              render=render)
freddyaboulton commented 3 months ago

Looking forward to seeing your component when it's launched!