tortoise / tortoise-orm

Familiar asyncio ORM for python, built with relations in mind
https://tortoise.github.io
Apache License 2.0
4.68k stars 392 forks source link

Signals not working within classes #1061

Open Kyzegs opened 2 years ago

Kyzegs commented 2 years ago

Describe the bug You're unable to use signal decorators within classes.

To Reproduce

from tortoise.backends.base.client import BaseDBAsyncClient
from tortoise.signals import post_save
from typing import List, Optional, Type

from .models import Model

class Example:
    @post_save(Model)
    async def signal_post_save(
        self,
        sender: Type[Model],
        instance: Model,
        created: bool,
        using_db: Optional[BaseDBAsyncClient],
        update_fields: List[str],
    ) -> None:
        print(sender, instance, using_db, created, update_fields)
teschmitt commented 2 years ago

The post_save decorator takes the model class you want to define the signal for as an argument. This cannot be accessed during the class definition. You could get tricky with partial functions and own custom decorators to get this to work at runtime, or you could simply call the signal-creator after the class definition:

from tortoise.backends.base.client import BaseDBAsyncClient
from tortoise.signals import post_save, Signals
from typing import List, Optional, Type

class Example:

    async def signal_post_save(
        self,
        sender: Type[Model],
        instance: Model,
        created: bool,
        using_db: Optional[BaseDBAsyncClient],
        update_fields: List[str],
    ) -> None:
        print(sender, instance, using_db, created, update_fields)

Example.register_listener(Signals.post_save, Example.signal_post_save)

Although far from elegant, you get to keep the signal definition in the class.