Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

strict is a module, that addresses the frequent need for type checking in Python.

Quick Example

Function Constraints

Add type constraints to the function signature:

from __future__ import print_function
from strict.functions import *

@expects(arg(float), arg(float), message=arg(str))
def multiply_and_print(a, b, message="You've got {result}"):
    print(message.format(result=(a * b)))

# This works just fine
multiply_and_print(2.0, 3.0)

# This raises a TypeConstraintError
multiply_and_print(int(2.0), 3.0)

Add type constraint to a method:

from __future__ import print_function
from strict.functions import *

class Foo(object):

    @expects(self, arg(str))
    def __init__(self, name):
        self.name = name

    def say_hello(self):
        print(", ".join(["Hello", self.name]))

# This works
f = Foo("Jim")
f.say_hello()

# This doesn't
f = Foo(123)
f.say_hello()

Add a constraint on the return value of a function:

from strict.functions import *

@returns(int)
def return_two():
    return 2

@returns(int)
def return_half():
    return 0.5

# This works fine
return_two()

# This raises an exception
return_half()

Add a subject matter constraint, as well as a type constraint to a function:

@expects(arg(float), arg(float, lambda x: x != 0))
def divide(a, b):
    "We need to make sure, that b isn't zero..."
    return a / b

# This works
divide(4.0, 2.0)

# This all fails with a TypeConstraintError
divide(4, 2.0)
divide(4.0, "poop")

# This fails with a SubjectConstraintError
divide(4.0, 0.0)

Structures

Define a structure:

from strict.structures import *

class Point(Structure):
    """
    Let's have a point, that can fit only on a certain area.
    """
    x = Field(float, lambda x: 0.0 < x < 1000.0)
    y = Field(float, lambda y: 0.0 < y < 1000.0)

    def __init__(self, x, y):
        self.x = x
        self.y = y

# This works
a = Point(10.0, 15.0)

# This all fails with the correct exception
Point(10, 15)
Point(10.0, 1001.0)
Point(-2.0, 50.0)

Serialize your structure:

from strict.structures import *

class Point(Structure):
    """
    Let's have a point, that can fit only on a certain area.
    """
    x = Field(float, lambda x: 0.0 < x < 1000.0)
    y = Field(float, lambda y: 0.0 < y < 1000.0)

    def __init__(self, x, y):
        self.x = x
        self.y = y

a = Point(10.0, 15.0)

# This outputs a dictionary
a.to_dict()

# This outputs a list
a.to_list()

Why Would I Type Check?

Although, the common idiom to deal with type compatibility issues in Python is duck typing, in some cases it is not adequate.

Quite often the information about the usage context is implicitly encoded in the class name, which duck typing would usually fail to handle, unless you introduce wildly differing class interfaces or just kludge.

Consider the following class tree of a financial application:

                    +--------------------------+
                    |                          |
                    |   BaseVolatilitySurface  |
                    |                          |
                    +-------------+------------+
                                  |
                                  |
                                  |
                                  |
+---------------------------+     |     +-------------------------+
|                           |     |     |                         |
|  EquityVolatilitySurface  <-----+----->  RateVolatilitySurface  |
|                           |           |                         |
+---------------------------+           +-------------------------+

Volatility of some value (usually of an asset price) is the key input of valuation models for financial derivatives. In this case, we try to model in our application the volatility of equity and interest rates, implied by market prices.

Both classes would have mostly the same interface. If we rely on duck typing and accidentaly pass a RateVolatilitySurface to value an equity option, no exception would be raised, since techically the input would satisfy the constraint expressed through duck typing. However, the result would be wrong and we’d get a typical example of a SH*T IN, SH*T OUT program.

The obvious solution is to sprinkle your code with a liberal amount of isinstance checks. This, however, quickly leads to your business code being dominated by boilerplate checks and error handling. To avoid this I tried to put the most useful and simple patterns in a module:

  • Assigning constraints to function arguments and return values

  • Creating a class with strict type checking of its properties and the correctly filled __slots__ variable.

2014, Jevgeni Tarasov (jevgeni@tarasov.ch)

Metadata

Release files for strict 0.1alpha

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

Source distribution (sdist)

Source distribution for strict 0.1alpha
File Size Uploaded
strict-0.1alpha.tar.gz 7.4 kB Details

Release files / strict-0.1alpha.tar.gz

Download URL strict-0.1alpha.tar.gz
Size 7.4 kB
Tags Source
SHA-256 checksum
How to use checksums
caad92ee5f9e825c5d9e0d0eab4b14051efa867987eefc44e52964337ccad1d4
BLAKE2b-256 checksum
How to use checksums
1a479e66c2e593abfce27dff7d97b593c7b9c55d37bcd5a02458553f1763ef59
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

0.1alpha 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