Skip to content

Implementation of python generic builder class for use in projects

License

Notifications You must be signed in to change notification settings

ChrisW-priv/python-builder

Repository files navigation

Python Builder

Simple implementation of a builder pattern for Python. This library is done to be as small and simple as possible. I wanted an easy wrapper around any class.

In my tests, I explicitly check if my library works with:

  • base python class
  • python dataclass
  • python "slotted" class (using __slots__)
  • pydantic BaseModel

But because of how simple the code is, I expect it to work with all classes.

Usage

To use the Python Builder, decorate your classes with @add_builder and utilize the generated builder() method to construct instances fluently.

Example with a Regular Python Class

from python_builder import add_builder

@add_builder
class RegularClass:
    def __init__(self, a: int, b: str, c: bool):
        self.a = a
        self.b = b
        self.c = c

# Building an instance
builder = RegularClass.builder()
instance = (
    builder
    .set("a", 10)
    .set("b", "test")
    .set("c", True)
    .build()
)

print(instance.a)  # Output: 10
print(instance.b)  # Output: test
print(instance.c)  # Output: True

Example with a Dataclass

from dataclasses import dataclass
from python_builder import add_builder

@add_builder
@dataclass
class DataClass:
    x: float = None
    y: str = None
    z: int = None

# Building an instance
instance = (
    DataClass.builder()
    .set("x", 3.14)
    .set("y", "pi")
    .set("z", 42)
    .build()
)

print(instance.x)  # Output: 3.14
print(instance.y)  # Output: pi
print(instance.z)  # Output: 42

Example with a Pydantic Model

from pydantic import BaseModel
from python_builder import add_builder

@add_builder
class PydanticModel(BaseModel):
    foo: str
    bar: int
    baz: bool

# Building an instance
instance = (
    PydanticModel.builder()
    .set("foo", "hello")
    .set("bar", 123)
    .set("baz", False)
    .build()
)

print(instance.foo)  # Output: hello
print(instance.bar)  # Output: 123
print(instance.baz)  # Output: False

Example with a Slotted Class

from python_builder import add_builder

@add_builder
class SlotClass:
    __slots__ = ["x", "y", "z"]

    def __init__(self, x: int, y: str, z: bool):
        self.x = x
        self.y = y
        self.z = z

# Building an instance
instance = (
    SlotClass.builder()
    .set("x", 100)
    .set("y", "slot test")
    .set("z", True)
    .build()
)

print(instance.x)  # Output: 100
print(instance.y)  # Output: slot test
print(instance.z)  # Output: True

Merging Builders

You can merge multiple builder instances using the | operator. The resulting builder inherits properties from both builders. In cases of conflicting properties, the values from the builder on the right take precedence.

builder1 = RegularClass.builder().set("a", 1).set("b", "initial")
builder2 = RegularClass.builder().set("b", "overridden").set("c", True)
merged_builder = builder1 | builder2  # Merges builder1 and builder2; 'b' from builder2 takes precedence
instance = merged_builder.build()

print(instance.a)  # Output: 1       # Inherited from builder1
print(instance.b)  # Output: overridden  # Overridden by builder2
print(instance.c)  # Output: True    # Inherited from builder2

When merging builders using the | operator, the resulting builder combines the properties from both builders. If both builders set the same property, the value from the builder on the right side of the | operator overrides the one from the left.

Handling Errors

If you set an invalid property or omit required properties, the builder will raise appropriate errors.

# Setting an invalid property
builder = RegularClass.builder().set("d", "invalid")
instance = builder.build()  # Raises TypeError

# Building with missing required properties
builder = RegularClass.builder().set("a", 100)
instance = builder.build()  # Raises TypeError

These examples demonstrate how to utilize the Python Builder with different types of classes, handle merging of builders, and manage potential errors during the building process.

Developement

I use uv so I expect you have it installed too. After cloning the repo, run:

uv sync

That should install all dev dependencies. After that, activate venv and run:

pre-commit install

That will auto format your code on each commit.

About

Implementation of python generic builder class for use in projects

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages