Skip to main content

preconditions - A precondition decorator utility which relies on parameter-name equivalence for conciseness and consistency.

Examples

First let’s take a tour of examples. All examples assume the preconditions decorator has been imported:

from preconditions import preconditions

Basic type checking

The double application function requires that the i parameter is an int, which is verified by a single predicate (the lambda expression):

@preconditions(lambda i: isinstance(i, int))
def double(i):
    return 2*i

Multiple predicates

Multiple predicates may be specified:

@preconditions(
    lambda i: isinstance(i, int),
    lambda i: i > 0,
    )
def double(i):
    return 2*i

Note that this is functionally equivalent to this single predicate version:

@preconditions(
    lambda i: isinstance(i, int) and i > 0,
    )
def double(i):
    return 2*i

The multi-predicate version should (eventually) have more specific error reporting for a failure, while the single predicate version may be more efficient.

Multiple arguments

Multiple predicates can express preconditions for multiple arguments:

@preconditions(
    lambda s: isinstance(s, unicode),
    lambda n: isinstance(n, int) and n >= 0,
    )
def repeat(s, n):
    return s*n

However, a single predicate can express preconditions for multiple arguments. This allows relational preconditions:

@preconditions(
    lambda a, b: a <= b
    )
def strict_range(a, b):
    return range(a, b)

Method preconditions

Predicates can be expressed for methods, including relations to self. For example, a Monotonic instance ensures that each call to .set must pass a value larger than any previous call:

class Monotonic (object):
    def __init__(self):
        self.v = 0

    @preconditions(lambda self, v: v > self.v)
    def set(self, v):
        self.v = v

Preconditions can be applied to special methods, such as __new__, __init__, __call__, etc…

class LinearRange (tuple):
    @preconditions(
           lambda a: isinstance(a, float),
           lambda b: isinstance(b, float),
           lambda a, b: a < b,
           )
    def __new__(cls, a, b):
        return super(OrderedTuple, cls).__new__(cls, (a, b))

    @preconditions(lambda w: 0 <= w < 1.0)
    def __call__(self, w):
        lo, hi = self
        return w * (hi - lo) + lo

    @preconditions(lambda x: self[0] <= x < self[1])
    def invert(self, x):
        lo, hi = self
        return (x - lo) / (hi - lo)

Concepts

An application function may be guarded with precondition predicates. These predicates are callables passed to the preconditions decorator. Consider this code:

@preconditions(
    lambda a: isinstance(a, float) and a >= 0,
    lambda b: isinstance(b, float) and b >= 0,
    )
def area(a, b):
    return a*b

The application function is area, and it has two predicates defined with lambda, each of which ensures one of the arguments is a non-negative float.

Parameter Name Equivalence

The parameter names in a predicate must match parameter names in the application function. This is known as parameter name equivalence [1].

One exception to this rule is for default parameters within predicates. Default parameters may be used to associate some state at predicate definition time. For example:

scores = {}

@preconditions(
    lambda color, _colors=['RED', 'GREEN', 'BLUE']: color in _colors
    )
def get_color_score(color):
    return scores[color]

This feature may be most convenient when there’s a need to remember a local loop variable.

Similar Projects

covenant - Code contracts for Python 3.

Download files

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

Source Distribution

preconditions-0.1.tar.gz (5.2 kB view details)

Uploaded Source

File details

Details for the file preconditions-0.1.tar.gz.

File metadata

  • Download URL: preconditions-0.1.tar.gz
  • Upload date:
  • Size: 5.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for preconditions-0.1.tar.gz
Algorithm Hash digest
SHA256 e783f97bee1e3302745a67575ce788fc98874968e1c9343b7e0cdfd5d4c13527
MD5 c61bf4e2f5052ea8ff6903fa656a2e23
BLAKE2b-256 5d19324c00d1399e5997c25d49ece9f9f68868621f06ea1f553671229d28601d

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1 This release

1 file

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page