Skip to main content

Provides hierarchical factory

Project description

https://travis-ci.org/palankai/baluster.svg?branch=master

What is this package for

This package provides a simple way to build back structure of application. Can be used building composite root as acting a factory for resources, building a fixture factory for tests.

Features

  • Lazy initialisation
  • Simple composition and dependency handling

Example - composie root

from baluster import Baluster, placeholders
import psycopg2

class ApplicationRoot(Baluster):
    @placeholders.factory
    def db(self, root):
        # Will be called at the first use
        # Will be cached so won't be called again
        return psycopg2.connect("dbname=test user=postgres")

    @db.close
    def _close_db(self, root, db):
        db.close()

    @placeholders.factory
    def cr(self, root):
        return self.db.cursor()

    @cr.close
    def _close_cr(self, root, cr):
        cr.close()


def main():
    approot = ApplicationRoot()
    with approot:
        approot.cr.execute('SELECT * FROM user')

    # at this point the connection and the cursor has already been closed

Example - async composie root

from baluster import Baluster, placeholders

class AsyncApplicationRoot(Baluster):

    @placeholders.factory
    async def resource(self, root):
        # Will be called at the first use
        # Will be cached so won't be called again
        return await some_aync_resource()

    @db.close
    async def _close_resource(self, root, resource):
        await resource.close()


def main():
    approot = AsyncApplicationRoot()
    async with approot:
        conn = await approot.resource
        await conn.operation(...)

    # at this point the resource has already been closed

Example - fixture factory for tests

from baluster import Baluster, placeholders
import psycopg2

class Fixtures(Baluster):

    @placeholders.factory
    def cr(self, root):
        conn = psycopg2.connect("dbname=test user=postgres")
        return conn.cursor()

    class users(Baluster):

        @placeholders.factory
        def user(self, root):
            root.cr.execute('SELECT * FROM user WHERE id=1')
            return User(root.cr.fetchone())

        @placeholders.factory
        def customer(self, root):
            root.cr.execute('SELECT * FROM customer WHERE id=1')
            return Customer(root.cr.fetchone())

    class orders(Baluster):

        @placeholders.factory
        def amount(self, root):
            return 100

        @placeholders.factory
        def quantity(self, root):
            return 1

        @placeholders.factory
        def order(self, root):
            customer = root.users.customer
            created_by = root.users.user
            amount = self.amount
            # Fictive order object...
            return Order(
                customer=customer, created_by=created_by,
                amount=amount, quantity=quantity
            )

        @placeholders.factory
        def shipped_order(self, root):
            order = self.order
            order.mark_shipped()
            return order


def test_order():
    # Demonstrate a few use fictive usecase

    # Creating order with defaults
    f = Fixtures()
    assert f.order.calculated_total_value == 100
    assert f.order.shipping_address == f.users.customer.address

    # Create new fixtures, but keep some cached data
    f2 = f.copy('cr', 'users')

    # Set some value
    f2.order.amount = 50
    f2.order.quantity = 3
    assert f2.order.calculated_total_value == 150

    # Manage different stage of object life
    f3 = f.copy('cr', 'users')
    order = f3.shipped_order

    with pytest.raises(OrderException):
        order.cancel()
        # as it is shipped

Installation

Python target: >=3.6

$ pip install baluster

Dependencies

The package is independent, using only the python standard library.

Development

pip install -r requirements-dev.txt

This installs the package in development mode (setup.py develop) and the testing packages. I would like to achive nearly 100% test coverage.

Test

pytest

Contribution

I really welcome any comments! I would be happy if you fork my code and create pull requests. For an approved pull request flake8 have to pass just as all of tests.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Filename, size & hash SHA256 hash help File type Python version Upload date
Baluster-0.2.1.tar.gz (8.9 kB) Copy SHA256 hash SHA256 Source None

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN SignalFx SignalFx Supporter DigiCert DigiCert EV certificate StatusPage StatusPage Status page