Transaction Context

TransactionContext() is a core building block in lato. It’s main purpose is to inject dependencies into a handler function. When TransactionContext is calling a function using call method, it will inspect all its arguments and it will try to inject all matching dependencies into it. This greatly simplifies testing.

You can instantiate TransactionContext() with any args and kwargs. These arguments will be injected to a handler during a call. Any arguments passed to TransactionContext.call that match the function signature will be passed to the called function, and will replace the ones passed in the constructor.

from lato import TransactionContext

def greet(name, greeting):
    return f"{greeting}, {name}!"

ctx = TransactionContext()
result = ctx.call(greet, greeting="Hello", name="Alice")

assert result == "Hello, Alice!"

As you can see, greeting and name arguments in TransactionContext.call() are actually passed to the greet function. You can use both keyword and positional arguments:

ctx.call(greet, "Alice", "Hello")
ctx.call(greet, "Alice", greeting="Hello")

Instead of passing passing dependencies to TransactionContext.call(), it’s often more convenient to pass them to TransactionContext constructor:

from lato import TransactionContext

def greet(name, greeting):
    return f"{greeting}, {name}!"

ctx = TransactionContext(greeting="Hola")
print(ctx.call(greet, "Bob"))
print(ctx.call(greet, "Charlie"))

Note

Any arguments passed to TransactionContext.call() will override arguments passed to the TransactionContext constructor.

class FooService:
    ...

def do_something(foo_service):
    ...

def do_something_else(service: FooService):
    ...

ctx = TransactionContext(foo_service=FooService())
ctx.call(do_something)  # will inject an instance of FooService using name `foo_service`
ctx.call(do_something_else)  # will inject an instance of FooService using type `FooService`

TransactionContext is also a context manager, so you can use it with with statement:

from lato import TransactionContext

def greet(name, greeting):
    return f"{greeting}, {name}!"

with TransactionContext(greeting="Hola") as ctx:
    print(ctx.call(greet, "Bob"))
    print(ctx.call(greet, "Charlie"))

It is rarely needed to instantiate transaction context directly. In most cases, it is sufficient to call any of the Application methods: call(), execute(), or publish(), which creates the transaction context under the hood.