Skip to content

Blocks

A Block is a collection of options defined as a class.

Blocks are useful for grouping related options, as they can then be passed to the Engin in one go helping manage complex applications.

Blocks are preferred over other data structures such as a list of options as they integrate with other functionality in the rest of the framework.

Defining an empty Block

A Block is just a class that inherits from Block:

from engin import Engin, Block, provide, invoke


class ExampleBlock(Block):
    ...

Adding options to the Block

Blocks have a class attribute named options which can be used to include existing options.

import asyncio
from engin import Engin, Block, Invoke, Provide, Supply


def print_string(string: str) -> None:
   print(string)


class ExampleBlock(Block):
   options = [
      Supply("hello"),
      Invoke(print_string)
   ]


# register it as a provider with the Engin
engin = Engin(ExampleBlock())

asyncio.run(engin.run())  # prints 'hello'

Tip

Blocks are themselves valid options, so Blocks can include other Blocks as options. This compositional approach can help you build and manage larger applications.

Defining Providers, Modifiers & Invocations in the Block

Engin ships three decorators: @provide, @modify & @invoke that can be used to define providers, modifiers and invocations within a Block as methods. These decorators mirror the signature of their respective classes Provide, Modify & Invoke.

from engin import Engin, Block, provide, modify, invoke


# this block is equivalent to the one in the example above
class ExampleBlock(Block):
    @provide
    def string_factory(self) -> str:
        return "hello"

    @modify
    def add_prefix(self, value: str) -> str:
        return f"[INFO] {value}"

    @invoke
    def print_string(self, string: str) -> None:
       print(string)

Note

The self parameter in these methods is replaced with an empty object at runtime so should not be used. Blocks do not need to be instantiated to be passed to Engin as an option.