Metadata-Version: 1.0
Name: strict
Version: 0.1alpha
Summary: UNKNOWN
Home-page: https://bitbucket.org/slenderboy/strict
Author: Jevgeni Tarassov
Author-email: jevgeni@tarasov.ch
License: MIT
Description: =======================================
        Strict Functions & Structures in Python
        =======================================
        
        ``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)
Platform: UNKNOWN
