Skip to main content

blok

Inspiration

Blok is designed to be intergrated into existing projects that want to programmatically created docker compose projects, suitable for development and production environments. The main goal is to allow the user to create a project with a high level of configurability and reusability. blok is following the principles of depencency injection and inversion of control to create a project from various "bloks" (i.e configurable services).

Installation

pip install blok

Quickstart

Create a new python file my_cli.py and add the following code:

from blok import blok, ExecutionContext, Option, service
from blok.cli import create_cli
from typing import Protocol


@service("io.blok.minio")
class MinioService(Protocol):

    def register_bucket(self, bucket: str):
        ...

@blok(MinioService, options=[Option("port", type=int, default=9000)])
class MinioBlok:
    buckets: list[str]

    def preflight(self, port: int):
        self.buckets = []
        self.port = port

    def register_bucket(self, bucket: str):
        self.buckets.append(bucket)
        return bucket

    def build(self, context: ExecutionContext):
        service = {
            "image": "minio/minio",
            "command": ["server", "/data"],
            "volumes": [],
        }

        for bucket in self.buckets:
            context.file_tree.set_nested("mounts", bucket, {})
            service["command"].append(f"/data/{bucket}")
            service["volumes"].append(f"./mounts/{bucket}:/data/{bucket}")

        context.docker_compose.set_nested("services", "minio", service)


@blok("io.blok.data", options=[Option("port", type=int, default=8080)])
class DataBlok:
    port: int


    def preflight(self, minio: MinioBlok, port: int):
        self.port = port
        minio.register_bucket("data")
        minio.register_bucket("logs")

    def build(self, context: ExecutionContext):
        image = {
            "image": "dependend",
            "command": ["web-service", "--port", self.port],
        }
        context.docker_compose.set_nested("services", "data", image)


cli = create_cli(MinioBlok(), DataBlok())

if __name__ == "__main__":
    cli()

And now you can run the script to generate the docker-compose file

python my_cli.py build data .

This will starting from the data blok, resolve all dependencies and build the docker-compose setup in the directory creating a docker-compose.yml file and the necessary mounts.

- my_cli.py
- docker-compose.yml
- mounts
    - data
    - logs

Pass arguments to the bloks

All bloks can register options that can be passed to the blok via the cli (or in the future other renderers). The options are passed to the blok by prepending the blok name (or the blok class name) with -- and the option name. For example to pass the port to the data blok you can run:

python my_cli.py build data --data-port 8080

Diffable Projects

The blok project is designed to be diffable. This means that you can run the script multiple times and the output will be the same. This is achieved by using a file tree to store the state of the project and only writing the changes to the file system once you confirm it. Also if you run the script with one argument it will only show the changes that will be made to the project.

python my_cli.py build data --data-port 8080

Wil Resulst in:

Differences                                                                          
├── Will Modify: /docker-compose.yml/services/data/command/2/a                       
│     Old: 7000                                                                      
│     New: 8080                                                                      
└── Will Modify: /__blok__.yml/data_port                                             
      Old: 7000                                                                      
      New: 8080   

You can then choose to apply the changes.

Blok Dependencies

Bloks can define dependencies on other bloks by adding them as arguments to the preflight method. The blok will then be resolved and passed to the blok. For example the DataBlok has a dependency on the MinioService and can access it via the minio argument in the preflight method.

Depedency Resolution

One of the core ideas is that services that bloks can depend on have various implementations. For example you could create a custom implemention of the MinioService and other bloks that depend on the MinioService could on dependency resolution choose the custom implementation.

You can force a specific blok by passing the -b flag to the cli. For example to force the MinioService

python my_cli.py build data -b minio

Metadata

Release files for blok 0.1.0

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

Source distribution (sdist)

Source distribution for blok 0.1.0
File Size Uploaded Provenance
blok-0.1.0.tar.gz 22.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for blok 0.1.0
File Interpreter ABI Platform
blok-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 54.8 kB

Release files / blok-0.1.0.tar.gz

Download URL blok-0.1.0.tar.gz
Size 22.9 kB
Tags Source
SHA-256 checksum
How to use checksums
0ae92799a5a7611aa284be108dc4a0912131c91cfbf7dbcb38ea2cf9086ab514
BLAKE2b-256 checksum
How to use checksums
d1434439497c6bf89052efa571c02a78218c90d92e23eed2deb3f34684512d5b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.12.3 Linux/6.11.0-21-generic

Release files / blok-0.1.0-py3-none-any.whl

Download URL blok-0.1.0-py3-none-any.whl
Size 31.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1e55f349dc6d2a9edbe8fd29b99f1d0a2f48876a2b4c378eaf81d0cc6d741185
BLAKE2b-256 checksum
How to use checksums
4cbd74db47d957cc787042952ba1159830ad12b20209a7c1d1e76fab45b43b88
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.12.3 Linux/6.11.0-21-generic

Security for blok 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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