Skip to main content

preconditions

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.

Metadata

Release files for preconditions 0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for preconditions 0.1
File Size Uploaded
preconditions-0.1.tar.gz 5.2 kB Details

Release files / preconditions-0.1.tar.gz

Download URL preconditions-0.1.tar.gz
Size 5.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e783f97bee1e3302745a67575ce788fc98874968e1c9343b7e0cdfd5d4c13527
BLAKE2b-256 checksum
How to use checksums
5d19324c00d1399e5997c25d49ece9f9f68868621f06ea1f553671229d28601d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

0.1 This release

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page