Skip to content

3. Composite Classes

Action service — composite classes. Combine a function action, a class action, and a bound service method. The service can also define its own methods using these actions.

Source

"""Action service — composite classes.
Combine a function action, a class action, and a bound service method.
The service can also define its own methods using these actions."""

import asyncio
from typing import assert_type

from fastsprout.actions import Action, action
from fastsprout.core import BaseSchema, Field


class Document(BaseSchema):
    content: Field[str]


class RenderedDocument(BaseSchema):
    content: Field[bytes]


class SignedDocument(BaseSchema):
    content: Field[bytes]
    signature: Field[str]


@action
async def render_document(document: Document) -> RenderedDocument:
    return RenderedDocument(content=document.content.encode())


class SignDocument(Action[RenderedDocument, SignedDocument]):
    async def __call__(self, document: RenderedDocument) -> SignedDocument:
        return SignedDocument(
            content=document.content,
            signature=f"signed:{len(document.content)}",
        )


@action
class DocumentVerifier:
    async def verify(self, document: SignedDocument) -> bool:
        return document.signature == f"signed:{len(document.content)}"


verifier = DocumentVerifier()


@action
class DocumentService:
    render = render_document
    sign = SignDocument()
    verify = verifier.verify

    async def prepare(self, document: Document) -> SignedDocument:
        content = await self.render(document)
        return await self.sign(content)


async def main() -> None:
    documents = DocumentService()
    document = Document(content="FastSprout")

    content = await documents.render(document)
    assert_type(content, RenderedDocument)

    signed = await documents.sign(content)
    assert_type(signed, SignedDocument)

    verified = await documents.verify(signed)
    assert_type(verified, bool)

    prepared = await documents.prepare(document)
    assert_type(prepared, SignedDocument)
    print(prepared)
    print("Verified:", verified)


if __name__ == "__main__":
    asyncio.run(main())

Result

content=b'FastSprout' signature='signed:10'
Verified: True