Developer Interface

This package defines the following functions and decorators:

typeable.cast(typ: typing.Type[_T], val: object, *, ctx: Context = None)_T

Cast a value to a type.

This returns the value converted to the designated type. typ can be anything that can be used in type annotation.

The conversion rules try to mimic the standard Python rules as much as possible. But you can use ctx to change the rules.

If the conversion rules do not allow conversion, various standard exceptions such as TypeError and ValueError can be thrown. If you wish, you can use ctx to locate the error position on val.

@cast.function(user_function)
@cast.function(*, ctx_name: str = 'ctx', cast_return: bool = False, keep_async: bool = True)

A decorator that types-casts the arguments of a function.

When a decorated function is called, the original function is called by type-casted values for the annotated arguments. Arguments without the annotation are passed as it is.

The default behavior is to not type-cast the return value even if there is a annotation of the return value. If cast_return is true and there is a annotation of the return value, the return value is also type casted.

When tracking the error location with Context.capture(), the location attribute is given the name of the argument. If an error occurred in the return value, "return" is used. If annotation is supplied to an argument of the form *args or **kwargs, the name of the argument is supplied first, followed by the index or keyword name.

The decorated function has an additional ctx argument that takes a Context instance. It raises TypeError, if the original function already has an argument named ctx. To change this name, specify name with the ctx_name argument. If the original function wants to receive ctx arguments directly, it must provide Context type annotation. In this case, when None is passed to ctx, a new instance is created and passed.

This decorator can also be used for methods. When cast.function() is applied in combination with other method descriptors, it should be applied as the innermost decorator.

This decorator can also be used with coroutine function. In this case, the decorated function is also coroutine function. However, if the keep_async parameter is False, the decorated function becomes a synchronous function that immediately calls the original function and returns awaitable. It is used for the purpose of generating an error due to type casting early.

@typeable.cast.register(impl)
typeable.declare(name: str)

A context manager that allows you to define recursive type aliases using forward references.

Provides an instance of typing.ForwardRef with the name provided as the name argument as the target of as of the with statement. If you use this value for a type parameter of a generic type, forward references are automatically evaluated when exiting the with statement.

It can be used for local aliases as well as global aliases.

typeable.dump(obj: JsonValue, fp, *, ensure_ascii=False, separators=(',', ':'), **kw)

A function that wraps the standard library json.dump() function so that obj arguments are automatically converted to JsonValue.

This function has changed the default values for the ensure_ascii and separators arguments.

typeable.dumps(obj: JsonValue, *, ensure_ascii=False, separators=(',', ':'), **kw)

A function that wraps the standard library json.dumps() function so that obj arguments are automatically converted to JsonValue.

This function has changed the default values for the ensure_ascii and separators arguments.

typeable.field(*, key=None, default=dataclasses.MISSING, default_factory=None, nullable=None, required=False, kind=False)
typeable.fields(class_or_instance)

This package defines a number of classes, which are detailed in the sections below.

class typeable.AllOf(arg: Constraint, *args: Constraint)

Constraint that must satisfy all constraints passed as arguments.

class typeable.AnyOf(arg: Constraint, *args: Constraint)

Constraint that must satisfy at least one of the constraints passed as arguments.

class typeable.Constraint

Base class of constraints checked at runtime.

Used as metadata provided to typing.Annotated.

Other than this purpose, the user does not have to deal with instances of Constraint directly. The following interface is only needed if you want to define a new constraint by creating a subclass of Constraint.

annotate(root: JsonSchema, schema: JsonSchema)

Add the constraint to the JSON Schema passed as the schema argument.

root is a JSON Schema instance of type defined as typing.Annotated.

compile()

Returns a callable that evaluates the constraint.

The callable takes the value after casting by cast(). If the callable’s return value evaluates to true, it is interpreted as satisfying the constraint. Returning false or raising an exception is interpreted as not satisfying the constraint.

emit()

Returns a string expressing the constraint.

The expression must assume that the argument to be tested is provided as a variable called x. For example, "(x > 0)".

If the expression refers to a module, emit() can return a 2-tuple (expr, ns). expr is an expression, ns is a mapping where the key is the module name, and the value is the module instance.

class typeable.Context(**policies)

By passing the Context object to the cast() you can change the default conversion rules or find the location of the error that occurred during conversion.

Keyword-only parameters passed to policies are used to change conversion rules. These parameters are provided as attributes of the Context instance. You can also subclass Context to change the default values of parameters, or add new parameters. The currently defined parameters are:

bool_is_int: bool = True

If this attribute is False, then bool is not treated as int.

bool_strings: dict[str, bool] = {'0': False, '1': True, 'f': False, 'false': False, 'n': False, 'no': False, 'off': False, 'on': True, 't': True, 'true': True, 'y': True, 'yes': True}

Defines strings that can be converted to bool and the corresponding bool value. All keys should be lowercase. When looking up a dictionary, the value converted to lowercase is used as a key.

bytes_encoding: str = 'utf-8'
date_format: str = 'iso'
datetime_format: str = 'iso'
encoding_errors: str = 'strict'
lossy_conversion: bool = True

If this attribute is False, no conversion with information loss is performed. For example, cast(int, 1.2) is not allowed.

naive_timestamp: bool = False
strict_str: bool = True
time_format: str = 'iso'
union_prefers_same_type: bool = True
union_prefers_base_type: bool = True
union_prefers_super_type: bool = True
union_prefers_nearest_type: bool = True

The location of the error that occurred during conversion can be found using capture().

Context instances are neither thread-safe nor coroutine-safe. Make sure that an instance is not used by multiple threads or coroutines simultaneously. But it’s safe to use it repeatedly for successive cast() calls.

capture()

Tracks the location of errors that occur during conversion. Since it is a context manager, it must be used with the with statement. The error object is passed to the as target of the with statement. This error object provides the location attribute which is a tuple when an error occurs, and is None if no error occurs. location is a tuple of keys or indices needed to reach the error position. For example:

>>> from typing import Dict, List
>>> from typeable import *
>>> ctx = Context()
>>> with ctx.capture() as error:
...     data = cast(Dict[str,List[int]], {"a":[], "b":[0,"1",None,3]}, ctx=ctx)
Traceback (most recent call last):
    ...
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
>>> error.location
('b', 2)
traverse(key)
class typeable.IsFinite

Constraint which allows only finite numbers.

Applies only to int, float, and complex types, and does not allow NaN or infinity.

Standard JSON does not allow NaN or infinite, so it is not reflected in JSON Schema.

class typeable.IsGreaterThan(exclusive_minimum)

Constraint that only allows values greater than exclusive_minimum.

It is expressed as exclusiveMinimum in JSON Schema.

class typeable.IsGreaterThanOrEqual(minimum)

Constraint that only allows values greater than or equal to minimum.

It is expressed as minimum in JSON Schema.

class typeable.IsLessThan(exclusive_maximum)

Constraint that only allows values less than exclusive_maximum.

It is expressed as exclusiveMaximum in JSON Schema.

class typeable.IsLessThanOrEqual(maximum)

Constraint that only allows values less than or equal to maximum.

It is expressed as maximum in JSON Schema.

class typeable.IsLongerThanOrEqual(minimum)

Constraint that only allows values longer than or equal to minimum.

In JSON Schema, it is expressed as minLength, minProperties, minItems depending on the type.

class typeable.IsMatched(pattern)

Constraint that only allows strings that match the regular expression pattern.

Regular expressions are not implicitly anchored. That is, matches are checked with re.search().

It is expressed as pattern in JSON Schema.

class typeable.IsMultipleOf(value)

Constraint that allows only numbers that are integer multiples of value.

Raises ValueError if value is not positive.

It is expressed as multipleOf in JSON Schema.

class typeable.IsShorterThanOrEqual(maximum)

Constraint that only allows values shorter than or equal to maximum.

In JSON Schema, it is expressed as maxLength, maxProperties, maxItems depending on the type.

class typeable.JsonSchema(value_or_type=dataclasses.MISSING, *, ctx: Context = None)

A subclass of Object representing JSON Schema.

The constructor takes a JSON Schema representation or type as the value_or_type parameter. Passing a type gives you a JSON Schema representation of that type.

classmethod register(type)
class typeable.JsonValue

This is a type that represents a JSON value recursively.

You cannot create an instance, you can only type cast with cast().

Values converted to this type can be passed directly to json.dumps() and json.dump() in the standard library.

class typeable.NoneOf(arg: Constraint, *args: Constraint)

Constraint which must not satisfy any of the constraints passed as arguments.

class typeable.Object(value = dataclasses.MISSING, /, *, ctx: Context = None, **kwargs)

Represents an object model with typed fields.

When a value is passed as value, Object(value, ctx=ctx) is equivalent to cast(Object, value, ctx=ctx).

If no value is passed as value, no type checking is performed, and only fields with default_factory are created as instance attributes.

By design, it mimics dataclasses.dataclass(). However, there are several differences: