Runtype is a collection of run-time type utilities for Python.
It is:
🏃 Fast! Uses an internal typesystem for maximum performance.
🧠 Smart! Supports typing
, forward-references, constraints, auto-casting, and more.
⚙️ Configurative! Write your own type system, and use it with dataclass and dispatch.
⭐ validation - Provides a smarter alternative to isinstance
and issubclass
, with support for the typing
module, and type constraints.
⭐ dataclass - Adds run-time type validation to the built-in dataclass.
typing
and forward-references (foo: 'Bar'
).String(max_length=10)
)⭐ dispatch - Provides fast multiple-dispatch for functions and methods, via a decorator.
@overload
decorator⭐ type utilities - Provides a set of classes to implement your own type-system.
Read the docs here: https://runtype.readthedocs.io/
No dependencies.
Requires Python 3.8 or up.
Validation (Isa & Subclass)Use isa
and issubclass
as a smarter alternative to the builtin isinstance & issubclass -
from runtype import isa, issubclass assert isa({'a': 1}, dict[str, int]) # == True assert not isa({'a': 'b'}, dict[str, int]) # == False assert issubclass(dict[str, int], typing.Mapping[str, int]) # == True assert not issubclass(dict[str, int], typing.Mapping[int, str]) # == False
from runtype import dataclass @dataclass(check_types='cast') # Cast values to the target type, when applicable class Person: name: str birthday: datetime = None # Implicit optional interests: list[str] = [] # The list is copied for each instance print( Person("Beetlejuice") ) #> Person(name='Beetlejuice', birthday=None, interests=[]) print( Person("Albert", "1955-04-18T00:00", ['physics']) ) #> Person(name='Albert', birthday=datetime.datetime(1955, 4, 18, 0, 0), interests=['physics']) print( Person("Bad", interests=['a', 1]) ) # TypeError: [Person] Attribute 'interests' expected value of type list[str]. Instead got ['a', 1] # Failed on item: 1, expected type str
Runtype dispatches according to the most specific type match -
from runtype import multidispatch as md @md def mul(a: list, b: list): return [mul(i, j) for i, j in zip(a, b, strict=True)] @md def mul(a: list, b: Any): return [ai*b for ai in a] @md def mul(a: Any, b: list): return [bi*b for bi in b] @md def mul(a: Any, b: Any): return a * b assert mul("a", 4) == "aaaa" # Any, Any assert mul([1, 2, 3], 2) == [2, 4, 6] # list, Any assert mul([1, 2], [3, 4]) == [3, 8] # list, list
Dispatch can also be used for extending the dataclass builtin __init__
:
@dataclass class Point: x: int = 0 y: int = 0 @md def __init__(self, points: list | tuple): # Call default constructor self.__init__(*points) @md def __init__(self, points: dict): # Call default constructor self.__init__(points['x'], points['y']) # Test constructors p0 = Point() # Default constructor assert p0 == Point(0, 0) # Default constructor assert p0 == Point([0, 0]) # User constructor assert p0 == Point((0, 0)) # User constructor assert p0 == Point({"x": 0, "y": 0}) # User constructor
Runtype beats its competition handily. It is significantly faster than both beartype and plum, and in some cases is even faster than regular Python code.
See the benchmarks page in the documentation for detailed benchmarks.
Runtype uses the MIT license.
If you like Runtype and want to see it grow, you can help by:
Reporting bugs or suggesting features
Submitting pull requests (better to ask me first)
Writing about runtype in a blogpost or even a tweet
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4