Skip to main content

Type dispatch and validation for run-time Python

Project description

Runtype

Runtype offers fast run-time type validation for Python, by providing utilities for multiple-dispatch and type-safe dataclasses.

Runtype's integration with the typing module allows users to invoke type signatures such as List[int], Dict[str, Optional[str]], or Union[str, Callable].

Multiple Dispatch

Multiple-dispatch is a state-of-the-art technique for structuring code, that complements object-oriented programming.

Unlike in OOP, where the type of the "object" (or: first argument) is always what determines the dispatch, in multiple-dispatch all the arguments decide together, according the idea of specificity: The more specific classes (i.e. subclasses) get picked before the more abstract ones (i.e. superclasses).

That means that when you need to define a logical operation that applies to several types, you can first solve the most abstract case, and then slowly add special handling for more specific types as required. If you ever found yourself writing several "isinstance" in a row, you could probably use multiple-dispatch to write better code!

Runtype's dispatcher is fast, and will never make an arbitrary choice: in ambiguous situations it will always throw an error.

As a side-effect, it also provides type-validation to functions. Trying to dispatch with types that don't match, will result in a dispatch-error.

Type-Safe Dataclasses

The ability to annotate dataclasses with types has spurred the creation of many great static type-validation tools (such as mypy). Unfortunately, they can't always predict what types your dataclasses will receive.

The trouble with storing the wrong data, is that it can just sit there for a while, and by time you get the error, it's hard to track which component or thread put it there.

Runtype provides a dataclass drop-in replacement to Python's native dataclass, that validates the types in runtime, and makes sure you'll see the error the moment something goes wrong, and in the right context.

While Runtype's validation can add a small runtime overhead, it's relatively light. And because it's a drop-in replacement, you can always just switch the import back once you're done debugging.

Docs

Read the docs here: https://runtype.readthedocs.io/

Install

$ pip install runtype

No dependencies.

Requires Python 3.6 or up.

Build Status codecov

Examples

Isa & Subclass

from typing import Dict
from runtype import isa, issubclass

isa({'a': 1}, Dict[str, int])      # True
isa({'a': 'b'}, Dict[str, int])    #  False

issubclass(Dict[str, int], Mapping[str, int])   # True
issubclass(Dict[str, int], Mapping[int, str])   # False

Multiple Dispatch

from runtype import Dispatch
dp = Dispatch()

@dp
def append(a: list, b):
    return a + [b]

@dp
def append(a: tuple, b):
    return a + (b,)

@dp
def append(a: str, b: str):
    return a + b


print( append([1, 2, 3], 4) )        # prints [1, 2, 3, 4]
print( append((1, 2, 3), 4) )        # prints (1, 2, 3, 4)
print( append('foo', 'bar') )        # prints foobar
print( append('foo', 4)     )        # raises DispatchError, no signature for (str, int)

Dataclasses

Basic usage:

>>> from runtype import dataclass

>>> @dataclass
>>> class Point:
...     x: int
...     y: int

>>> p = Point(2, 3)
>>> p
Point(x=2, y=3)
>>> dict(p)          # Maintains order
{'x': 2, 'y': 3}

>>> p.replace(x=30)  # New instance
Point(x=30, y=3)

>>> Point(10, 3.5)   # Actively validates types
Traceback (most recent call last):
    ...
TypeError: [Point] Attribute 'y' expected value of type <class 'int'>, instead got 3.5

Using advanced types:

>>> from typing import Optional, Callable
>>> from runtype import dataclass

>>> @dataclass
>>> class Animal:
...     name: str
...     make_sound: Optional[Callable] = None

>>> Animal("Ant")
Animal(name='Ant', make_sound=None)

>>> Animal("Cat", lambda: print("meow"))
Animal(name='Cat', make_sound=<function <lambda> at ...>)

>>> Animal("Dog", "woof")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
[Animal] Attribute 'make_sound' expected value of type typing.Union[typing.Callable, NoneType], instead got 'woof'

Performance

Type verification in classes introduces a slight run-time overhead. When running in production, it's recommended to use the -O switch for Python. It will skip all asserts, and also skip type verification on classes by default (use the check_types option to adjust it manually).

Multiple-dispatch caches call-signatures by default (disable at your own risk!), and should add a minimal overhead after the initial resolution. Dispatch is only 5 to 8 times slower than adding two numbers (see: examples/benchmark_dispatch), which is negligible.

Runtype is not recommended for use in functions that are called often in time-critical code (or classes that are created often).

License

Runtype uses the MIT license.

Donate

If you like Runtype and want to show your appreciation, you can do so at my patreon page, or ko-fi page.

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

runtype-0.1.14.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

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

runtype-0.1.14-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file runtype-0.1.14.tar.gz.

File metadata

  • Download URL: runtype-0.1.14.tar.gz
  • Upload date:
  • Size: 15.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.7 CPython/3.8.2 Windows/10

File hashes

Hashes for runtype-0.1.14.tar.gz
Algorithm Hash digest
SHA256 d2a8e5b88180f3a30ba71d19cd1e1ec09a4940af90cce3d90a731732c10bdd4b
MD5 d0b4ff15c8beb49d732f4c09f3da88c1
BLAKE2b-256 dc72192bdf5e0d208435a21fa25056b32b6395b567def40a33192e48db640041

See more details on using hashes here.

File details

Details for the file runtype-0.1.14-py3-none-any.whl.

File metadata

  • Download URL: runtype-0.1.14-py3-none-any.whl
  • Upload date:
  • Size: 14.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.7 CPython/3.8.2 Windows/10

File hashes

Hashes for runtype-0.1.14-py3-none-any.whl
Algorithm Hash digest
SHA256 b66ed8915315c92e846151174373cfba3c32f5ae8d6350839c8023f650b55f76
MD5 4d3ae7224f059cde4e1220a7eb7d02c6
BLAKE2b-256 afbfde8fefa8278955ccdd4d32d10cdebeeb9c9294bf4e6805e3cc72e442e924

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