Skip to content

htmy.function_component

_AsyncFunctionComponent = Callable[[TProps, Context], Coroutine[Any, Any, Component]] module-attribute

Protocol definition for async function components that have both a properties and a context argument.

_AsyncMethodComponent = Callable[[TSelf, TProps, Context], Coroutine[Any, Any, Component]] module-attribute

Protocol definition for async method components that have both a properties and a context argument.

_ContextOnlyAsyncFunctionComponent = Callable[[Context], Coroutine[Any, Any, Component]] module-attribute

Protocol definition for async function components that only have a context argument.

_ContextOnlySyncFunctionComponent = Callable[[Context], Component] module-attribute

Protocol definition for sync function components that only have a context argument.

_SyncFunctionComponent = Callable[[TProps, Context], Component] module-attribute

Protocol definition for sync function components that have both a properties and a context argument.

_SyncMethodComponent = Callable[[TSelf, TProps, Context], Component] module-attribute

Protocol definition for sync method components that have both a properties and a context argument.

component = ComponentDecorators() module-attribute

Decorators for converting functions into components

This is an instance of ComponentDecorators.

ComponentDecorators

Function component decorators.

Source code in htmy/function_component.py
class ComponentDecorators:
    """
    Function component decorators.
    """

    __slots__ = ()

    # -- Function component decorator.

    @overload
    def __call__(self, func: _SyncFunctionComponent[TProps]) -> Callable[[TProps], SyncComponent]: ...

    @overload
    def __call__(self, func: _AsyncFunctionComponent[TProps]) -> Callable[[TProps], AsyncComponent]: ...

    def __call__(
        self,
        func: _SyncFunctionComponent[TProps] | _AsyncFunctionComponent[TProps],
    ) -> Callable[[TProps], SyncComponent] | Callable[[TProps], AsyncComponent]:
        """
        Decorator that converts the decorated function into one that must be called with
        the function component's properties and returns a component instance.

        If used on an async function, the resulting component will also be async;
        otherwise it will be sync.

        Example:

        ```python
        @component
        def my_component(props: int, context: Context) -> Component:
            return html.p(f"Value: {props}")

        async def render() -> str:
           return await Renderer().render(
               my_component(42)
           )
        ```

        Arguments:
            func: The decorated function.

        Returns:
            A function that must be called with the function component's properties and
            returns a component instance. (Or loosly speaking, an `HTMYComponentType` which
            can be "instantiated" with the function component's properties.)
        """

        if asyncio.iscoroutinefunction(func):

            def async_wrapper(props: TProps) -> AsyncComponent:
                # This function must be async, in case the renderer inspects it to decide how to handle it.
                async def component(context: Context) -> Component:
                    return await func(props, context)  # type: ignore[no-any-return]

                component.htmy = component  # type: ignore[attr-defined]
                return component  # type: ignore[return-value]

            return async_wrapper
        else:

            def sync_wrapper(props: TProps) -> SyncComponent:
                def component(context: Context) -> Component:
                    return func(props, context)  # type: ignore[return-value]

                component.htmy = component  # type: ignore[attr-defined]
                return component  # type: ignore[return-value]

            return sync_wrapper

    @overload
    def function(self, func: _SyncFunctionComponent[TProps]) -> Callable[[TProps], SyncComponent]: ...

    @overload
    def function(self, func: _AsyncFunctionComponent[TProps]) -> Callable[[TProps], AsyncComponent]: ...

    def function(
        self,
        func: _SyncFunctionComponent[TProps] | _AsyncFunctionComponent[TProps],
    ) -> Callable[[TProps], SyncComponent] | Callable[[TProps], AsyncComponent]:
        """
        Decorator that converts the decorated function into one that must be called with
        the function component's properties and returns a component instance.

        If used on an async function, the resulting component will also be async;
        otherwise it will be sync.

        This function is just an alias for `__call__()`.

        Example:

        ```python
        @component.function
        def my_component(props: int, context: Context) -> Component:
            return html.p(f"Value: {props}")

        async def render() -> str:
           return await Renderer().render(
               my_component(42)
           )

        Arguments:
            func: The decorated function.

        Returns:
            A function that must be called with the function component's properties and
            returns a component instance. (Or loosly speaking, an `HTMYComponentType` which
            can be "instantiated" with the function component's properties.)
        """
        return self(func)

    # -- Context-only function component decorator.

    @overload
    def context_only(
        self, func: _ContextOnlySyncFunctionComponent
    ) -> _DecoratedContextOnlySyncFunctionComponent: ...

    @overload
    def context_only(
        self, func: _ContextOnlyAsyncFunctionComponent
    ) -> _DecoratedContextOnlyAsyncFunctionComponent: ...

    def context_only(
        self,
        func: _ContextOnlySyncFunctionComponent | _ContextOnlyAsyncFunctionComponent,
    ) -> _DecoratedContextOnlySyncFunctionComponent | _DecoratedContextOnlyAsyncFunctionComponent:
        """
        Decorator that converts the decorated function into a component.

        If used on an async function, the resulting component will also be async;
        otherwise it will be sync.

        Example:

        ```python
        @component.context_only
        def my_component(ctx):
            return "Context only function component."

        async def render() -> str:
           return await Renderer().render(
               my_component()
           )
        ```

        Arguments:
            func: The decorated function.

        Returns:
            The created component.
        """

        def wrapper() -> SyncComponent | AsyncComponent:
            func.htmy = func  # type: ignore[union-attr]
            return func  # type: ignore[return-value]

        # This assignment adds support for context-only function components without call signature.
        wrapper.htmy = func  # type: ignore[attr-defined]
        return wrapper  # type: ignore[return-value]

    # -- Method component decorator.

    @overload
    def method(
        self, func: _SyncMethodComponent[TSelf, TProps]
    ) -> Callable[[TSelf, TProps], SyncComponent]: ...

    @overload
    def method(
        self, func: _AsyncMethodComponent[TSelf, TProps]
    ) -> Callable[[TSelf, TProps], AsyncComponent]: ...

    def method(
        self,
        func: _SyncMethodComponent[TSelf, TProps] | _AsyncMethodComponent[TSelf, TProps],
    ) -> Callable[[TSelf, TProps], SyncComponent] | Callable[[TSelf, TProps], AsyncComponent]:
        """
        Decorator that converts the decorated method into one that must be called with
        the method component's properties and returns a component instance.

        If used on an async method, the resulting component will also be async;
        otherwise it will be sync.

        Example:

        ```python
        @dataclass
        class MyBusinessObject:
            message: str

            @component.method
            def paragraph(self, props: int, context: Context) -> Component:
                return html.p(f"{self.message} {props}")


        async def render() -> str:
            return await Renderer().render(
                MyBusinessObject("Hi!").paragraph(42)
            )
        ```

        Arguments:
            func: The decorated method.

        Returns:
            A method that must be called with the method component's properties and
            returns a component instance. (Or loosly speaking, an `HTMYComponentType` which
            can be "instantiated" with the method component's properties.)
        """
        if asyncio.iscoroutinefunction(func):

            def async_wrapper(self: TSelf, props: TProps) -> AsyncComponent:
                # This function must be async, in case the renderer inspects it to decide how to handle it.
                async def component(context: Context) -> Component:
                    return await func(self, props, context)  # type: ignore[no-any-return]

                component.htmy = component  # type: ignore[attr-defined]
                return component  # type: ignore[return-value]

            return async_wrapper
        else:

            def sync_wrapper(self: TSelf, props: TProps) -> SyncComponent:
                def component(context: Context) -> Component:
                    return func(self, props, context)  # type: ignore[return-value]

                component.htmy = component  # type: ignore[attr-defined]
                return component  # type: ignore[return-value]

            return sync_wrapper

    # -- Context-only function component decorator.

    @overload
    def context_only_method(
        self, func: _SyncFunctionComponent[TSelf]
    ) -> Callable[[TSelf], SyncComponent]: ...

    @overload
    def context_only_method(
        self, func: _AsyncFunctionComponent[TSelf]
    ) -> Callable[[TSelf], AsyncComponent]: ...

    def context_only_method(
        self,
        func: _SyncFunctionComponent[TSelf] | _AsyncFunctionComponent[TSelf],
    ) -> Callable[[TSelf], SyncComponent] | Callable[[TSelf], AsyncComponent]:
        """
        Decorator that converts the decorated method into one that must be called
        without any arguments and returns a component instance.

        If used on an async method, the resulting component will also be async;
        otherwise it will be sync.

        Example:

        ```python
        @dataclass
        class MyBusinessObject:
            message: str

            @component.context_only_method
            def paragraph(self, context: Context) -> Component:
                return html.p(f"{self.message} Goodbye!")


        async def render() -> str:
            return await Renderer().render(
                MyBusinessObject("Hello!").paragraph()
            )
        ```

        Arguments:
            func: The decorated method.

        Returns:
            A method that must be called without any arguments and returns a component instance.
            (Or loosly speaking, an `HTMYComponentType` which can be "instantiated" by calling
            the method.)
        """
        # A context only method component must be implemented in the same way as
        # a function component. The self argument replaces the props argument
        # and it is added automatically by Python when the method is called.
        # Even the type hint must be the same.
        # This implementation doesn't make the function itself a component though,
        # so the call signature is always necessary (unlike for context-only function
        # components).
        return self(func)

__call__(func)

__call__(func: _SyncFunctionComponent[TProps]) -> Callable[[TProps], SyncComponent]
__call__(func: _AsyncFunctionComponent[TProps]) -> Callable[[TProps], AsyncComponent]

Decorator that converts the decorated function into one that must be called with the function component's properties and returns a component instance.

If used on an async function, the resulting component will also be async; otherwise it will be sync.

Example:

@component
def my_component(props: int, context: Context) -> Component:
    return html.p(f"Value: {props}")

async def render() -> str:
   return await Renderer().render(
       my_component(42)
   )

Parameters:

Name Type Description Default
func _SyncFunctionComponent[T] | _AsyncFunctionComponent[T]

The decorated function.

required

Returns:

Type Description
Callable[[T], SyncComponent] | Callable[[T], AsyncComponent]

A function that must be called with the function component's properties and

Callable[[T], SyncComponent] | Callable[[T], AsyncComponent]

returns a component instance. (Or loosly speaking, an HTMYComponentType which

Callable[[T], SyncComponent] | Callable[[T], AsyncComponent]

can be "instantiated" with the function component's properties.)

Source code in htmy/function_component.py
def __call__(
    self,
    func: _SyncFunctionComponent[TProps] | _AsyncFunctionComponent[TProps],
) -> Callable[[TProps], SyncComponent] | Callable[[TProps], AsyncComponent]:
    """
    Decorator that converts the decorated function into one that must be called with
    the function component's properties and returns a component instance.

    If used on an async function, the resulting component will also be async;
    otherwise it will be sync.

    Example:

    ```python
    @component
    def my_component(props: int, context: Context) -> Component:
        return html.p(f"Value: {props}")

    async def render() -> str:
       return await Renderer().render(
           my_component(42)
       )
    ```

    Arguments:
        func: The decorated function.

    Returns:
        A function that must be called with the function component's properties and
        returns a component instance. (Or loosly speaking, an `HTMYComponentType` which
        can be "instantiated" with the function component's properties.)
    """

    if asyncio.iscoroutinefunction(func):

        def async_wrapper(props: TProps) -> AsyncComponent:
            # This function must be async, in case the renderer inspects it to decide how to handle it.
            async def component(context: Context) -> Component:
                return await func(props, context)  # type: ignore[no-any-return]

            component.htmy = component  # type: ignore[attr-defined]
            return component  # type: ignore[return-value]

        return async_wrapper
    else:

        def sync_wrapper(props: TProps) -> SyncComponent:
            def component(context: Context) -> Component:
                return func(props, context)  # type: ignore[return-value]

            component.htmy = component  # type: ignore[attr-defined]
            return component  # type: ignore[return-value]

        return sync_wrapper

context_only(func)

context_only(func: _ContextOnlySyncFunctionComponent) -> _DecoratedContextOnlySyncFunctionComponent
context_only(func: _ContextOnlyAsyncFunctionComponent) -> _DecoratedContextOnlyAsyncFunctionComponent

Decorator that converts the decorated function into a component.

If used on an async function, the resulting component will also be async; otherwise it will be sync.

Example:

@component.context_only
def my_component(ctx):
    return "Context only function component."

async def render() -> str:
   return await Renderer().render(
       my_component()
   )

Parameters:

Name Type Description Default
func _ContextOnlySyncFunctionComponent | _ContextOnlyAsyncFunctionComponent

The decorated function.

required

Returns:

Type Description
_DecoratedContextOnlySyncFunctionComponent | _DecoratedContextOnlyAsyncFunctionComponent

The created component.

Source code in htmy/function_component.py
def context_only(
    self,
    func: _ContextOnlySyncFunctionComponent | _ContextOnlyAsyncFunctionComponent,
) -> _DecoratedContextOnlySyncFunctionComponent | _DecoratedContextOnlyAsyncFunctionComponent:
    """
    Decorator that converts the decorated function into a component.

    If used on an async function, the resulting component will also be async;
    otherwise it will be sync.

    Example:

    ```python
    @component.context_only
    def my_component(ctx):
        return "Context only function component."

    async def render() -> str:
       return await Renderer().render(
           my_component()
       )
    ```

    Arguments:
        func: The decorated function.

    Returns:
        The created component.
    """

    def wrapper() -> SyncComponent | AsyncComponent:
        func.htmy = func  # type: ignore[union-attr]
        return func  # type: ignore[return-value]

    # This assignment adds support for context-only function components without call signature.
    wrapper.htmy = func  # type: ignore[attr-defined]
    return wrapper  # type: ignore[return-value]

context_only_method(func)

context_only_method(func: _SyncFunctionComponent[TSelf]) -> Callable[[TSelf], SyncComponent]
context_only_method(func: _AsyncFunctionComponent[TSelf]) -> Callable[[TSelf], AsyncComponent]

Decorator that converts the decorated method into one that must be called without any arguments and returns a component instance.

If used on an async method, the resulting component will also be async; otherwise it will be sync.

Example:

@dataclass
class MyBusinessObject:
    message: str

    @component.context_only_method
    def paragraph(self, context: Context) -> Component:
        return html.p(f"{self.message} Goodbye!")


async def render() -> str:
    return await Renderer().render(
        MyBusinessObject("Hello!").paragraph()
    )

Parameters:

Name Type Description Default
func _SyncFunctionComponent[U] | _AsyncFunctionComponent[U]

The decorated method.

required

Returns:

Type Description
Callable[[U], SyncComponent] | Callable[[U], AsyncComponent]

A method that must be called without any arguments and returns a component instance.

Callable[[U], SyncComponent] | Callable[[U], AsyncComponent]

(Or loosly speaking, an HTMYComponentType which can be "instantiated" by calling

Callable[[U], SyncComponent] | Callable[[U], AsyncComponent]

the method.)

Source code in htmy/function_component.py
def context_only_method(
    self,
    func: _SyncFunctionComponent[TSelf] | _AsyncFunctionComponent[TSelf],
) -> Callable[[TSelf], SyncComponent] | Callable[[TSelf], AsyncComponent]:
    """
    Decorator that converts the decorated method into one that must be called
    without any arguments and returns a component instance.

    If used on an async method, the resulting component will also be async;
    otherwise it will be sync.

    Example:

    ```python
    @dataclass
    class MyBusinessObject:
        message: str

        @component.context_only_method
        def paragraph(self, context: Context) -> Component:
            return html.p(f"{self.message} Goodbye!")


    async def render() -> str:
        return await Renderer().render(
            MyBusinessObject("Hello!").paragraph()
        )
    ```

    Arguments:
        func: The decorated method.

    Returns:
        A method that must be called without any arguments and returns a component instance.
        (Or loosly speaking, an `HTMYComponentType` which can be "instantiated" by calling
        the method.)
    """
    # A context only method component must be implemented in the same way as
    # a function component. The self argument replaces the props argument
    # and it is added automatically by Python when the method is called.
    # Even the type hint must be the same.
    # This implementation doesn't make the function itself a component though,
    # so the call signature is always necessary (unlike for context-only function
    # components).
    return self(func)

function(func)

function(func: _SyncFunctionComponent[TProps]) -> Callable[[TProps], SyncComponent]
function(func: _AsyncFunctionComponent[TProps]) -> Callable[[TProps], AsyncComponent]

Decorator that converts the decorated function into one that must be called with the function component's properties and returns a component instance.

If used on an async function, the resulting component will also be async; otherwise it will be sync.

This function is just an alias for __call__().

Example:

```python @component.function def my_component(props: int, context: Context) -> Component: return html.p(f"Value: {props}")

async def render() -> str: return await Renderer().render( my_component(42) )

Arguments: func: The decorated function.

Returns: A function that must be called with the function component's properties and returns a component instance. (Or loosly speaking, an HTMYComponentType which can be "instantiated" with the function component's properties.)

Source code in htmy/function_component.py
def function(
    self,
    func: _SyncFunctionComponent[TProps] | _AsyncFunctionComponent[TProps],
) -> Callable[[TProps], SyncComponent] | Callable[[TProps], AsyncComponent]:
    """
    Decorator that converts the decorated function into one that must be called with
    the function component's properties and returns a component instance.

    If used on an async function, the resulting component will also be async;
    otherwise it will be sync.

    This function is just an alias for `__call__()`.

    Example:

    ```python
    @component.function
    def my_component(props: int, context: Context) -> Component:
        return html.p(f"Value: {props}")

    async def render() -> str:
       return await Renderer().render(
           my_component(42)
       )

    Arguments:
        func: The decorated function.

    Returns:
        A function that must be called with the function component's properties and
        returns a component instance. (Or loosly speaking, an `HTMYComponentType` which
        can be "instantiated" with the function component's properties.)
    """
    return self(func)

method(func)

method(func: _SyncMethodComponent[TSelf, TProps]) -> Callable[[TSelf, TProps], SyncComponent]
method(func: _AsyncMethodComponent[TSelf, TProps]) -> Callable[[TSelf, TProps], AsyncComponent]

Decorator that converts the decorated method into one that must be called with the method component's properties and returns a component instance.

If used on an async method, the resulting component will also be async; otherwise it will be sync.

Example:

@dataclass
class MyBusinessObject:
    message: str

    @component.method
    def paragraph(self, props: int, context: Context) -> Component:
        return html.p(f"{self.message} {props}")


async def render() -> str:
    return await Renderer().render(
        MyBusinessObject("Hi!").paragraph(42)
    )

Parameters:

Name Type Description Default
func _SyncMethodComponent[U, T] | _AsyncMethodComponent[U, T]

The decorated method.

required

Returns:

Type Description
Callable[[U, T], SyncComponent] | Callable[[U, T], AsyncComponent]

A method that must be called with the method component's properties and

Callable[[U, T], SyncComponent] | Callable[[U, T], AsyncComponent]

returns a component instance. (Or loosly speaking, an HTMYComponentType which

Callable[[U, T], SyncComponent] | Callable[[U, T], AsyncComponent]

can be "instantiated" with the method component's properties.)

Source code in htmy/function_component.py
def method(
    self,
    func: _SyncMethodComponent[TSelf, TProps] | _AsyncMethodComponent[TSelf, TProps],
) -> Callable[[TSelf, TProps], SyncComponent] | Callable[[TSelf, TProps], AsyncComponent]:
    """
    Decorator that converts the decorated method into one that must be called with
    the method component's properties and returns a component instance.

    If used on an async method, the resulting component will also be async;
    otherwise it will be sync.

    Example:

    ```python
    @dataclass
    class MyBusinessObject:
        message: str

        @component.method
        def paragraph(self, props: int, context: Context) -> Component:
            return html.p(f"{self.message} {props}")


    async def render() -> str:
        return await Renderer().render(
            MyBusinessObject("Hi!").paragraph(42)
        )
    ```

    Arguments:
        func: The decorated method.

    Returns:
        A method that must be called with the method component's properties and
        returns a component instance. (Or loosly speaking, an `HTMYComponentType` which
        can be "instantiated" with the method component's properties.)
    """
    if asyncio.iscoroutinefunction(func):

        def async_wrapper(self: TSelf, props: TProps) -> AsyncComponent:
            # This function must be async, in case the renderer inspects it to decide how to handle it.
            async def component(context: Context) -> Component:
                return await func(self, props, context)  # type: ignore[no-any-return]

            component.htmy = component  # type: ignore[attr-defined]
            return component  # type: ignore[return-value]

        return async_wrapper
    else:

        def sync_wrapper(self: TSelf, props: TProps) -> SyncComponent:
            def component(context: Context) -> Component:
                return func(self, props, context)  # type: ignore[return-value]

            component.htmy = component  # type: ignore[attr-defined]
            return component  # type: ignore[return-value]

        return sync_wrapper

_DecoratedContextOnlyAsyncFunctionComponent

Bases: SyncComponent, Protocol

Protocol definition for async components that are also callable, and return an async component when called.

Source code in htmy/function_component.py
class _DecoratedContextOnlyAsyncFunctionComponent(SyncComponent, Protocol):
    """
    Protocol definition for async components that are also callable, and return an async
    component when called.
    """

    def __call__(self) -> SyncComponent: ...

_DecoratedContextOnlySyncFunctionComponent

Bases: SyncComponent, Protocol

Protocol definition for sync components that are also callable, and return a sync component when called.

Source code in htmy/function_component.py
class _DecoratedContextOnlySyncFunctionComponent(SyncComponent, Protocol):
    """
    Protocol definition for sync components that are also callable, and return a sync
    component when called.
    """

    def __call__(self) -> SyncComponent: ...