Skip to main content

fresh-bakery

🍰 The little DI framework that tastes like a cake. 🍰


Documentation: https://fresh-bakery.readthedocs.io/en/latest/


Fresh Bakery

Fresh bakery is a lightweight [Dependency Injection][DI] framework/toolkit, which is ideal for building object dependencies in Python.

It is [fully] production-ready, and gives you the following:

  • A lightweight, stupidly simple DI framework.
  • Fully asynchronous, no synchronous mode.
  • Any async backends compatible (asyncio, trio).
  • Zero dependencies.
  • Mypy compatible (no probably need for # type: ignore).
  • FastAPI fully compatible.
  • Litestar compatible.
  • Pytest fully compatible (Fresh Bakery encourages the use of pytest).
  • Ease of testing.
  • Easily extended (contribution is welcome).

Requirements

Python 3.8+

Installation

$ pip3 install fresh-bakery

Examples

Quickstart

This example is intended to show the nature of Dependency Injection and the ease of use the library. Many of us work 8 hours per day on average, 5 days a week, i.e. ~ 40 hours per week. Let's describe it using DI and bakery:

from bakery import Bakery, Cake


def full_days_in(hours: int) -> float:
    return hours / 24


def average(total: int, num: int) -> float:
    return total / num


class WorkingBakery(Bakery):
    average_hours: int = Cake(8)
    week_hours: int = Cake(sum, [average_hours, average_hours, 7, 9, average_hours])
    full_days: float = Cake(full_days_in, week_hours)


async def main() -> None:
    async with WorkingBakery() as bakery:
        assert bakery.week_hours == 40
        assert bakery.full_days - 0.00001 < full_days_in(40)
        assert int(bakery.average_hours) == 8

You can see it's as simple as it can be.

One more example

Let's suppose we have a thin wrapper around file object.

from typing import ClassVar, Final

from typing_extensions import Self


class FileWrapper:
    file_opened: bool = False
    write_lines: ClassVar[list[str]] = []

    def __init__(self, filename: str) -> None:
        self.filename: Final = filename

    def write(self, line: str) -> int:
        type(self).write_lines.append(line)
        return len(line)

    def __enter__(self) -> Self:
        type(self).file_opened = True
        return self

    def __exit__(self, *_args: object) -> None:
        type(self).file_opened = False
        type(self).write_lines.clear()

This wrapper acts exactly like a file object: it can be opened, closed, and can write line to file. Let's open file hello.txt, write 2 lines into it and close it. Let's do all this with the bakery syntax:

from bakery import Bakery, Cake


class FileBakery(Bakery):
    _file_obj: FileWrapper = Cake(FileWrapper, "hello.txt")
    file_obj: FileWrapper = Cake(_file_obj)
    write_1_bytes: int = Cake(file_obj.write, "hello, ")
    write_2_bytes: int = Cake(file_obj.write, "world")


async def main() -> None:
    assert FileWrapper.file_opened is False
    assert FileWrapper.write_lines == []
    async with FileBakery() as bakery:
        assert bakery.file_obj.filename == "hello.txt"
        assert FileWrapper.file_opened is True
        assert FileWrapper.write_lines == ["hello, ", "world"]

    assert FileWrapper.file_opened is False
    assert FileWrapper.write_lines == []

Maybe you noticed some strange things concerning FileBakery bakery:

  1. _file_obj and file_obj objects. Do we need them both?
  2. Unused write_1_bytes and write_2_bytes objects. Do we need them?

Let's try to fix both cases. First, let's figure out why do we need _file_obj and file_obj objects?

  • The first Cake for _file_obj initiates FileWrapper object, i.e. calls __init__ method;
  • the second Cake for file_obj calls context-manager, i.e. calls __enter__ method on enter and __exit__ method on exit.

Actually, we can merge these two statements into single one:

# class FileBakery(Bakery):
    file_obj: FileWrapper = Cake(Cake(FileWrapper, "hello.txt"))

So, what about unused arguments? OK, let's re-write this gist a little bit. First, let's declare the list of strings we want to write:

# class FileBakery(Bakery):
    strs_to_write: list[str] = Cake(["hello, ", "world"])

How to apply function to every string in this list? There are several ways to do it. One of them is built-in map function.

map_cake = Cake(map, file_obj.write, strs_to_write)

But map function returns iterator and we need to get elements from it. Built-in list function will do the job.

list_cake = Cake(list, map_cake)

In the same manner as we did for file_obj let's merge these two statements into one. The final FileBakery will look like this:

class FileBakeryMap(Bakery):
    file_obj: FileWrapper = Cake(Cake(FileWrapper, "hello.txt"))
    strs_to_write: list[str] = Cake(["hello, ", "world"])
    _: list[int] = Cake(list, Cake(map, file_obj.write, strs_to_write))

The last thing nobody likes is hard-coded strings! In this case such strings are:

  • the name of the file hello.txt
  • list of strings to write: hello, and world

What if we've got another filename or other strings to write? Let's define filename and list of strings as FileBakery parameters:

from bakery import Bakery, Cake, __Cake__


class FileBakery(Bakery):
    filename: str = __Cake__()
    strs_to_write: list[str] = __Cake__()
    file_obj: FileWrapper = Cake(Cake(FileWrapper, filename))
    _: list[int] = Cake(list, Cake(map, file_obj.write, strs_to_write))

To define parameters you can use dunder-cake construction: __Cake__().
To pass arguments into FileBakery you can use native python syntax:

# async def main() -> None:
    async with FileBakeryMapWithParams(
        filename="hello.txt", strs_to_write=["hello, ", "world"]
    ) as bakery:
        ...

And the whole example will look like this:

from typing import ClassVar, Final

from typing_extensions import Self

from bakery import Bakery, Cake, __Cake__


# class FileWrapper: ...


class FileBakery(Bakery):
    filename: str = __Cake__()
    strs_to_write: list[str] = __Cake__()
    file_obj: FileWrapper = Cake(Cake(FileWrapper, filename))
    _: list[int] = Cake(list, Cake(map, file_obj.write, strs_to_write))


async def main() -> None:
    assert FileWrapper.file_opened is False
    assert FileWrapper.write_lines == []
    async with FileBakeryMapWithParams(
        filename="hello.txt", strs_to_write=["hello, ", "world"]
    ) as bakery:
        assert bakery.file_obj.filename == "hello.txt"
        assert FileWrapper.file_opened is True
        assert FileWrapper.write_lines == ["hello, ", "world"]

    assert FileWrapper.file_opened is False
    assert FileWrapper.write_lines == []

More examples are presented in section bakery examples.

Dependencies

No dependencies ;)

Changelog

You can see the release history here: https://github.com/Mityuha/fresh-bakery/releases/


Fresh Bakery is MIT licensed code.

Release files for fresh-bakery 0.4.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fresh-bakery 0.4.4
File Size Uploaded
fresh_bakery-0.4.4.tar.gz 17.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fresh-bakery 0.4.4
File Interpreter ABI Platform
fresh_bakery-0.4.4-py3-none-any.whl Python 3 none any Details

Total release size: 37.6 kB

Release files / fresh_bakery-0.4.4.tar.gz

Download URL fresh_bakery-0.4.4.tar.gz
Size 17.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b151eb6ddbb86996fc86b6dc5d91d44604218ec1b6b620b4c4221be1dcad844b
BLAKE2b-256 checksum
How to use checksums
91eb11542a5119957566a2c6c9b90e34648b01c43c63502f160c08122dbf17e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.14.3 Linux/6.14.0-1017-azure

Release files / fresh_bakery-0.4.4-py3-none-any.whl

Download URL fresh_bakery-0.4.4-py3-none-any.whl
Size 19.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
276b6655313690cd2b8376fc447849f27a730359fdaa5d4de54f21bc5667af07
BLAKE2b-256 checksum
How to use checksums
6dd918d314bbe194cab9bfb5f253ac36655dc44dbb4680001b23f0a32a9f167a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.14.3 Linux/6.14.0-1017-azure

Release history Release notifications | RSS feed

This release

0.4.4 This release

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page