Skip to main content

A simple decorator used for parameter checking

Project description

Introduction

The following decorator can be used to provide parameter checking for regular and class methods.

This decorator would not be possible without the inspiration of the following:

The above inspired me to create this decorator to reduce the clutter of my code.

Even thou the accepts decorator already checks for the type. It is somewhat limited because it expects the exact number of parameters of the method. It forces the users to decorator all of the parameters instead of the ones that one wants checked. This limitation has been removed for this decorator.

Objective

To allow for a wide range of parameter checking that can be used by anyone without having to include the parameter checks within the calling method. This will allow someone to provide cleaner code for the implemented method while adding some complexity to the decorator.

Features

The contract decorator provides the ability for a user to check a parameter for type and/or value expectation. This also includes the option of checking the return value.

The contract decorator uses the following syntax:

    import contract

    @contract({
        'a': [checktype(float), closed(0.0, 1.0)],
        'b': [checktype(int), gteq(1)],
        'c': [checktype(int), gteq(1)]
    })
    def __init__(self,a, b, c, d):

The above contract will check that the a parameter is of type float and is between 0.0 and 1.0. While the b parameter is checked that is it an integer and is greater than of equal to 1. The same for parameter c. While parameter d does not required any special condition to be true.

As can be seen, the contract decorator expects you to pass it a dictionary. Where the key is the name of the parameter and the value is a tuple containing the different checks that will be called for each parameter value during run-time.

The following table contains the different options that the can be used with this decorator.

Name Parameters Type Description
validvalues tuple Value Check Checks that the parameter value is part of the tuple
checktype type Type Check Checks if the parameter is an instance of the expected type
closed a,b such that a <= b Closed Range Check Checks if the value is between two values a and b including a and b
opened a,b such that a < b Opened Range Check Checks if the value is between two values a and b excluding a and b
closedopened a,b such that a < b Closed/Opened Check Checks if the value is between two values a and b including a but excluding b
openedclosed a,b such that a < b Opened/Closed Check Checks if the value is between two values a and b including b but excluding a
gt a Value Check Checks that the parameter value is greater than a
lt a Value Check Checks that the parameter value is less than a
gteq a Value Check Checks that the parameter value is greater than or equal to a
lteq a Value Check Checks that the parameter value is less than or equal to a

Examples

The following example offers some ways that the contract decorator can be used within someone code.

Type Check.

The following code shows how you can check that a given parameter is of a given type.

    import contract

    @contract({
        'a': [checktype(float)]
    })
    def m(a):

The above will determine if the passed value a is a float type.

Range Checks

The following contains the different range checks that can be applied.

    import contract

    @contract({
        'a': [closed(0, 1)],
        'b': [gteq(2)],
        'c': [gt(3)],
        'd': [lt(4)],
        'e': [lteq(5)],
        'f': [opened(10.0, 11.0)],
        'g': [closedopened(12, 13)],
        'h': [openedclosed(14, 15)],
    })
    def range_check(self,a, b, c, d, e, f, g, h):

The above will then perform the expected checks for each of the referenced parameters.

Note that the above checks are not restricted to the primitive values but can be any class that implements the different range checks methods of the Data Model. You can then use the Range checks with a users defined class that implements the __lt__, __le__, __gt__, and __ge__ methods.

Tuple Check

    @contract({
        'a': [validvalues(set('blue','green','red'))]
    })
    def contains(a,b):

The above example will insure that the value of parameter a will be set to 'blue', 'green' or 'red'.

Return Value Check

    @contract({
        None: [gt(101)]
    })
    def contains(a,b):

The above check will determine that the return value is greater than 100. Note that you need to specify that the return parameter name as None. This is how we associate the check for the return value.

User Defined Checks

The contract decorator provides the ability for a user to create their own user defined checks. This will allow users to define checks that are not covered above. There are two different ways of creating user-defined checks. You can create a class that has a callable defined that expects a single parameter or you can define a method that expects a single parameter. Both implementations will be passed the value that was passed to the decorated method. The following section will give examples of each.

User Defined Class Check

Here is a simple example of how to create and use a user define class to check that the passed method parameter value agrees with the method contract.

class UserDefinedCheck(object):
    def __init__(self,cond):
        self.cond_ = cond
        ...

    def __call__(self, v):
        # Example of using a simple assert check
        assert v != None, "The value passed cannot be None"
        # Example of using a simple method or instance object.
        # The method or instance should raise an AssertionError whenever the condition is false
        cond(v) 
        ...

@contract({'a':[UserDefinedCheck()]})
def check_me(a,b):
    ...

The UserDefinedCheck class that was created above has a distinctive requirement.
The need for the class to implement the __call__ method with a single parameter. The callable method is called by the contract decorator and it expects the call to raise an AssertionError whenever the condition is not valid. Lastly, the class is used by passing an instance of the UserDefinedCheck class to the contract decorator.

In the example above, the parameter passed will be the value of the a parameter when the check_me function is called.

User Defined Method Check

Here is a simple example showing how a user-defined check method can be implemented and used by the contract decorator.

def user_defined_check(v):
    assert v != None, 'The value cannot be set to None'
    ...

@contract({'b':[user_defined_check]})
def check_me(a,b):
    ...

The user_defined_check method was created with a similar requirement as the user defined class. The method was defined with a simple parameter. The contract decorator will then pass the value of the checking parameter when the method that is being checked is called. Lastly, a reference to the user_defined_check method is passed to the contract decorator.

In the example above, the check_me method will use the user_defined_check method to check the contract of the b parameter.

Project details


Download files

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

Source Distribution

contract-decorator-2020.10.27.tar.gz (7.8 kB view details)

Uploaded Source

Built Distribution

contract_decorator-2020.10.27-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file contract-decorator-2020.10.27.tar.gz.

File metadata

  • Download URL: contract-decorator-2020.10.27.tar.gz
  • Upload date:
  • Size: 7.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.9.0

File hashes

Hashes for contract-decorator-2020.10.27.tar.gz
Algorithm Hash digest
SHA256 944fb352b30e736bb7a42c1c0802d64cda398f602c8673b5f502da79989e3e40
MD5 fa0841f4213ae6b2583473d06feb5670
BLAKE2b-256 4dbc28b886335d1a467160afb11d0796c98ba2c1df27d7f5e87ee0f834fafb13

See more details on using hashes here.

File details

Details for the file contract_decorator-2020.10.27-py3-none-any.whl.

File metadata

  • Download URL: contract_decorator-2020.10.27-py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.51.0 CPython/3.9.0

File hashes

Hashes for contract_decorator-2020.10.27-py3-none-any.whl
Algorithm Hash digest
SHA256 3abfd98b3037fc31dfed1e49f86eb998c0f73c6e90894c2b80c92c17405fa4c9
MD5 a05a6f86a9fa94ce4f0b7443c93a7b05
BLAKE2b-256 95bd6ec4a14b4943956f24e1db7087286fd37ebe7115978014e9a735970fa756

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page