Skip to main content

A non intrusive optional type checking for Python 3 using annotations

Project description

A non intrusive optional type checking for Python 3 using annotations

Now that Python 3 supports annotations many people are using the feature to describe the valid types for the input and output of functions and methods. This kind of usage turns the reading of code more easy besides simplifly the documentation.

Once types are listed in the annotations, why not use them to check the types? The type checking is especially valuable in the development phase.

This idea is not new and there are several implementations on the internet. Most of them using function decorators. The problem with this kind to implementation is that it pollutes the code and overloads the functions calls with type checking.

This package implements a non intrusive alternative for type checking in functions and methods. Once types are defined in annotations, no changes are required to make the verification of types. And, because it is completely optional, it can be used only in the desired environmens, like unit testings, for instance. This way, the performance of production code is not affected.

Installation

pip3 install optypecheck

Example

Create a python module, for instance utils.py

#!python
from typecheck import typecheck

def gencode(a: bytes, b: str) -> str:
    return '{}{}'.format(a[0], b)

assert typecheck(__name__)

Create a module to test, for instance test.py

#!python
from utils import gencode

def test1():
    return gencode('a', 'b') # raises TypeCheckError

def test2():
    return gencode(b'a', 'b') # no error

def test3():
    return gencode(b'a', b'b') # raises TypeCheckError

if __name__ == '__main__':
    import sys
    if len(sys.argv) == 2:
        test = getattr(sys.modules[__name__], sys.argv[1], None)
        if test:
            print(test())
            exit(0)
    print('Use: {} test1|test2|test3'.format(sys.argv[0]))

Testing with type checking:

Test1 - raises TypeCheckError for utils.test1()

#!bash
$python3 test.py test1
Traceback (most recent call last):
  File "test.py", line 21, in <module>
    test()
  File "test.py", line 8, in test1
    print(gencode('a', 'b')) # raises TypeCheckError
  File "/opt/python34/lib/python3.4/site-packages/typecheck/__init__.py", line 46, in decorated
    raise TypeCheckError(arg_error_fmt.format(name, argtype, args[i].__class__))
typecheck.TypeCheckError: Argument a expects an instance of <class 'bytes'>, <class 'str'> found

Test2 - no error for utils.test2()

#!bash
$python3 test.py test2
97b

Test3 - raises TypeCheckError for utils.test3()

#!bash
$python3 test.py test3
Traceback (most recent call last):
  File "test.py", line 21, in <module>
    test()
  File "test.py", line 14, in test3
    print(gencode(b'a', b'b')) # raises TypeCheckError
  File "/opt/python34/lib/python3.4/site-packages/typecheck/__init__.py", line 46, in decorated
    raise TypeCheckError(arg_error_fmt.format(name, argtype, args[i].__class__))
typecheck.TypeCheckError: Argument b expects an instance of <class 'str'>, <class 'bytes'> found

Testing with no type checking:

Because we use assert to call typecheck() if python is called with debug mode disabled, typecheck() is not called. This way we got rid of the overload of type checking in functions and methods.

Test1 - result of utils.test1() is wrong, but no error is reported!

#!bash
$python3 -O test.py test1
ab

Test2 - no error for utils.test2()

#!bash
$python3 -O test.py test2
97b

Test3 - result of utils.test3() is wrong, but no error is reported again!

#!bash
$python3 -O test.py test3
97b'b'

Cost of type checking

#!bash
$python3 -m timeit -s 'from test import test2' 'test2()' # with type checking
100000 loops, best of 3: 3.06 usec per loop

$python3 -O -m timeit -s 'from test import test2' 'test2()' # without type checking
1000000 loops, best of 3: 0.445 usec per loop

Type checked function is 6.87 times slower. That’s why it’s better to use it only for development and testing and, when the code is trusted, remove then with no penalties.

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

optypecheck-1.0.tar.gz (4.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

optypecheck-1.0.linux-x86_64.tar.gz (4.6 kB view details)

Uploaded Source

File details

Details for the file optypecheck-1.0.tar.gz.

File metadata

  • Download URL: optypecheck-1.0.tar.gz
  • Upload date:
  • Size: 4.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for optypecheck-1.0.tar.gz
Algorithm Hash digest
SHA256 cc9bc1df74fb8ec4664601a5f1bf4f073777b260c3514fed30f505fb87ca450b
MD5 b4277b61afc0a2b10b86fa64e50a9ab7
BLAKE2b-256 ab719afb04f8c0e75c9f1f0d7cf761defb3d9fe8c84160a2b6afc914127b09eb

See more details on using hashes here.

File details

Details for the file optypecheck-1.0.linux-x86_64.tar.gz.

File metadata

File hashes

Hashes for optypecheck-1.0.linux-x86_64.tar.gz
Algorithm Hash digest
SHA256 94c6a80904b5e15be5b2e873c33a70ad7f4306d681a17ad472d6925efbedef9c
MD5 4c2dc4201ff9f16922d6339cec576b29
BLAKE2b-256 ad981fd2391a4685d3f07d342b7c1ccd744cc0eadcb717f3f25e467ec791e22e

See more details on using hashes here.

Supported by

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