Skip to main content

A simple python implementation of Specification pattern.

Project description

Sutoppu

Pypi Version Python Version CI Coverage Status Project license Code Style

Sutoppu (ストップ - Japanese from English Stop) is a simple python implementation of Specification pattern.

What is Specification Pattern?

See Wikipedia.

In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic. The pattern is frequently used in the context of domain-driven design.

More information: Eric Evans and Martin Fowler article about Specifications

Basic usage

Installation

$ pip install sutoppu

Usage

from sutoppu import Specification


class Fruit:
    def __init__(self, color: str, sweet: bool, bitter: bool) -> None:
        self.color = color
        self.sweet = sweet
        self.bitter = bitter


class FruitIsBitter(Specification[Fruit]):
    description = 'The given fruit must be bitter.'

    def is_satisfied_by(self, fruit: Fruit) -> bool:
        return fruit.bitter is True


class FruitIsSweet(Specification[Fruit]):
    description = 'The given fruit must be sweet.'

    def is_satisfied_by(self, fruit: Fruit) -> bool:
        return fruit.sweet is True


class FruitIsYellow(Specification[Fruit]):
    description = 'The given fruit must be yellow.'

    def is_satisfied_by(self, fruit: Fruit) -> bool:
        return fruit.color == 'yellow'
>>> lemon = Fruit(color='yellow', sweet=False, bitter=True)
>>> is_a_lemon = FruitIsYellow() & FruitIsBitter() & ~FruitIsSweet()
>>> is_a_lemon.is_satisfied_by(lemon)
True

Operators

Sutoppu uses bitwise operator overloading to provide simplified syntax.

And:

>>> my_spec = SpecificationA() & SpecificationB()

Or:

>>> my_spec = SpecificationA() | SpecificationB()

Not:

>>> my_spec = ~SpecificationA()

Lighter syntax

If you find the is_satisfied_by method inconvenient you can alternatively call the specification as shown below.

>>> lemon = Fruit(color='yellow', sweet=False, bitter=True)
>>> is_a_lime = FruitIsGreen() & FruitIsBitter() & ~FruitIsSweet()
>>> is_a_lime(lemon)
False

Error reporting

It can be difficult to know which specification failed in complex concatenated rules. Sutoppu allows to list all the failed specifications by getting the errors attribute after use. The errors attribute is reset each time the specification is used. For each failed specification, it returns a dict with the name of the specification class as key and the description provided in the class as value. In the case where the specification failed with a not condition, the description is prefixed with Not ~.

>>> apple = Fruit(color='red', sweet=True, bitter=False)
>>> is_a_lemon = FruitIsYellow() & FruitIsBitter() & ~ FruitIsSweet()
>>> is_a_lemon.is_satisfied_by(apple)
False
>>> is_a_lemon.errors
{
    'FruitIsColored': 'The given fruit must be yellow.',
    'FruitIsBitter': 'The given fruit must be bitter.',
    'FruitIsSweet': 'Not ~ The given fruit must be sweet.'
}

Project details


Download files

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

Source Distribution

sutoppu-1.1.0.tar.gz (5.2 kB view hashes)

Uploaded Source

Built Distribution

sutoppu-1.1.0-py3-none-any.whl (7.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page