{ "info": { "author": "u8slvn", "author_email": "u8slvn@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Build Tools", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing" ], "description": "# Sutoppu\n\n[![Pypi Version](https://img.shields.io/pypi/v/sutoppu.svg)](https://pypi.org/project/sutoppu/)\n[![Python Version](https://img.shields.io/pypi/pyversions/sutoppu)](https://pypi.org/project/sutoppu/)\n[![Build Status](https://travis-ci.org/u8slvn/sutoppu.svg?branch=master)](https://travis-ci.org/u8slvn/sutoppu)\n[![Coverage Status](https://coveralls.io/repos/github/u8slvn/sutoppu/badge.svg?branch=master)](https://coveralls.io/github/u8slvn/sutoppu?branch=master)\n[![Project license](https://img.shields.io/pypi/l/sutoppu)](https://pypi.org/project/sutoppu/)\n\n**Sutoppu** (\u30b9\u30c8\u30c3\u30d7 - Japanese from English *Stop*) is a simple python implementation of Specification pattern.\n\n## What is Specification Pattern?\n\nSee [Wikipedia](https://en.wikipedia.org/wiki/Specification_pattern).\n\n> 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.\n\nMore information: [Eric Evans and Martin Fowler article about Specifications](https://www.martinfowler.com/apsupp/spec.pdf)\n\n## Basic usage\n\n### Installation\n\n```sh\n$ pip install sutoppu\n```\n\n### Usage\n\n```python\nfrom sutoppu import Specification\n\n\nclass Fruit:\n def __init__(self, color: str, sweet: bool, bitter: bool):\n self.color = color\n self.sweet = sweet\n self.bitter = bitter\n\n\nclass FruitIsBitter(Specification):\n description = 'The given fruit must be bitter.'\n\n def is_satisfied_by(self, fruit: Fruit):\n return fruit.bitter is True\n\n\nclass FruitIsSweet(Specification):\n description = 'The given fruit must be sweet.'\n\n def is_satisfied_by(self, fruit: Fruit):\n return fruit.sweet is True\n\n\nclass FruitIsColored(Specification):\n description = 'The given fruit must be {color}.'\n\n def __init__(self, color):\n super().__init__()\n self.color = color\n self.description = self.description.format(color=color)\n\n def is_satisfied_by(self, fruit: Fruit):\n return self.color == fruit.color\n```\n\n```python\n>>> lemon = Fruit(color='yellow', sweet=False, bitter=True)\n>>> is_a_lemon = FruitIsColored('yellow') & FruitIsBitter() & ~FruitIsSweet()\n>>> is_a_lemon.is_satisfied_by(lemon)\nTrue\n```\n\n### Operators\n\nAnd:\n\n```python\n>>> my_spec = SpecificationA() & SpecificationB()\n```\n\nOr:\n\n```python\n>>> my_spec = SpecificationA() | SpecificationB()\n```\n\nNot:\n\n```python\n>>> my_spec = ~SpecificationA()\n```\n\n### Lighter syntax\n\nIf you do not find the `is_satisfied_by` method very convenient you can also directly call the specification as below.\n\n```python\n>>> lemon = Fruit(color='yellow', sweet=False, bitter=True)\n>>> is_a_lime = FruitIsColored('green') & FruitIsBitter() & ~FruitIsSweet()\n>>> is_a_lime(lemon)\nFalse\n```\n\n### Error reporting\n\nIt can be difficult to know which specification failed in a complex rule. Sutoppu allows to list all the failed specifications by getting the `errors` attribute after use.\nThe `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 for key and the description provide in the class for value. In the case where the specification failed with a `not` condition, the description are prefixed with `Not ~`.\n\n```python\n>>> apple = Fruit(color='red', sweet=True, bitter=False)\n>>> is_a_lemon = FruitIsColored('yellow') & FruitIsBitter() & ~ FruitIsSweet()\n>>> is_a_lemon.is_satisfied_by(apple)\nFalse\n>>> is_a_lemon.errors\n{\n 'FruitIsColored': 'The given fruit must be yellow.',\n 'FruitIsBitter': 'The given fruit must be bitter.',\n 'FruitIsSweet': 'Not ~ The given fruit must be sweet.'\n}\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/u8slvn/sutoppu/archive/0.1.0.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/u8slvn/sutoppu", "keywords": "specification,specification-patternDDD,domain-driven-designbusiness-rules,verification", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "sutoppu", "package_url": "https://pypi.org/project/sutoppu/", "platform": "all", "project_url": "https://pypi.org/project/sutoppu/", "project_urls": { "Download": "https://github.com/u8slvn/sutoppu/archive/0.1.0.tar.gz", "Homepage": "https://github.com/u8slvn/sutoppu" }, "release_url": "https://pypi.org/project/sutoppu/0.1.0/", "requires_dist": [ "pytest (>=5.0.1) ; extra == 'dev'", "pytest-cov (>=2.7.1) ; extra == 'dev'", "pytest-mock (>=1.10.4) ; extra == 'dev'", "coverage (>=4.5.3) ; extra == 'dev'", "flake8 (>=3.7.7) ; extra == 'dev'", "bandit (>=1.6.2) ; extra == 'dev'" ], "requires_python": ">=3.6", "summary": "A simple python implementation of Specification pattern.", "version": "0.1.0" }, "last_serial": 5636725, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "f3ff204660e026c5f8426580ffd3b122", "sha256": "11b9b7b612e5eb5261a4f24cb6e88e82fa1c01dc8de42a542481d6d3953733ba" }, "downloads": -1, "filename": "sutoppu-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "f3ff204660e026c5f8426580ffd3b122", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 5072, "upload_time": "2019-08-05T22:24:16", "url": "https://files.pythonhosted.org/packages/74/6e/fec2619b5cdda2a6c461a02ef1e1854be04f3c9363a8e0e17b5150e73936/sutoppu-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "885f8d5f3c7ea1ca10f9c7ba57389ced", "sha256": "2d5a6bf58abb85026a55640a64c8615b43694153f0e3717fc6d41422d9d233fa" }, "downloads": -1, "filename": "sutoppu-0.1.0.tar.gz", "has_sig": false, "md5_digest": "885f8d5f3c7ea1ca10f9c7ba57389ced", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5234, "upload_time": "2019-08-05T22:24:18", "url": "https://files.pythonhosted.org/packages/5f/2f/33bdca1d1a41fa08cf93ac836730b3e404eaf027aa8080f17961c6c41c45/sutoppu-0.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "f3ff204660e026c5f8426580ffd3b122", "sha256": "11b9b7b612e5eb5261a4f24cb6e88e82fa1c01dc8de42a542481d6d3953733ba" }, "downloads": -1, "filename": "sutoppu-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "f3ff204660e026c5f8426580ffd3b122", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 5072, "upload_time": "2019-08-05T22:24:16", "url": "https://files.pythonhosted.org/packages/74/6e/fec2619b5cdda2a6c461a02ef1e1854be04f3c9363a8e0e17b5150e73936/sutoppu-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "885f8d5f3c7ea1ca10f9c7ba57389ced", "sha256": "2d5a6bf58abb85026a55640a64c8615b43694153f0e3717fc6d41422d9d233fa" }, "downloads": -1, "filename": "sutoppu-0.1.0.tar.gz", "has_sig": false, "md5_digest": "885f8d5f3c7ea1ca10f9c7ba57389ced", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5234, "upload_time": "2019-08-05T22:24:18", "url": "https://files.pythonhosted.org/packages/5f/2f/33bdca1d1a41fa08cf93ac836730b3e404eaf027aa8080f17961c6c41c45/sutoppu-0.1.0.tar.gz" } ] }