About

Here you will find some important changelogs for the library {typed}. For the full list of tags, see here.

  1. v0.1.9: extendable models and exact models

  2. v0.1.13: base type factories as functors

  3. v0.1.15: type safety for variables

  4. v0.3.0: compatibility with pydantic and dataclasses

  5. v0.4.0: inclusion of new model types

  6. v0.4.1: optional without default value

  7. v0.4.2: refactoring function types

  8. v0.4.3: introduction of @optional decorator

  9. v0.4.4: introduction of model attributes

  10. v0.4.5: optional and mandatory models

  11. v0.5.0: refactor of factories

  12. v0.5.1: introduce __null__ in factories

v0.1.9: extendable models and exact models

The possibility of creating a Model or an ExactModel that inherits all components from previously constructed models has been introduced.

 1from typed import *
 2from typed.models import Model
 3
 4Model1 = Model(
 5    arg1=Str,
 6    arg2=List(Dict(Int)),
 7    # ...
 8)
 9
10Model2 = Model(
11    argA=Float,
12    argB=Union(Null(Dict(Str)), Str)
13    # ....
14)
15
16Model3 = Model(
17    __extends__=[Model1, Model2],
18    other_arg=SomeType,
19    # ....
20)

Fully compatible with typed functions.

v0.1.13: base type factories as functors

In {typed}, there are various type factories, which operate between types to construct new types.

Among these factories are the “base factories,” which essentially correspond to implementations as concrete types of annotations from the typing library, along with a few more factories.

Example.

  1. from typing: Union, List, Tuple, Dict, Set, …

  2. additional: Prod, UProd, Null, …

Types have a semantics given by a certain class of sets. Among the types, we have typed functions, so we can think of the category TYPE, where objects are types and morphisms are typed functions.

In this sense, type factories operate at the level of TYPE objects, and it would be natural to try to extend them to functors F: TYPE -> TYPE.

In version {typed} v0.1.13, this was done for the base type factories listed above.

This means, for example, that we can now take a function: f: SomeType -> OtherType and apply the List, Tuple, etc. operations to it:

List(f): List(f.domain) -> List(f.codomain).

Furthermore, such a construction is done in a way that compositions are respected:

List(g*f) == List(g)*List(f)

Naturally, operations at the function level can be concatenated (just as they were at the type level).

This brings {typed} closer to providing not only a “typed approach” to Python, but also a truly functional approach.

v0.1.15: type safety for variables

Previously, typed was limited to providing factories (and models) to create new types and to check types passed as type hints to typed functions calls.

Now, it’s also possible to use typed to check values assigned to variables.

Instead of:

1my_var = some_value

use:

1my_var = typed(ExpectedType)(some_value)

At runtime, the interpreter will check if the variable my_var has a value whose type is ExpectedType.

v0.3.0: compatibility with pydantic and dataclasses

It is now possible to transform any class into a model, exact model, or conditional model.

In version {typed} v0.3.0, the decorators @model, @exact, and @conditional were included. These decorators can be applied to any class, collecting its attributes and passing them as arguments to the Model, Exact, and Conditional type factories, respectively.

This, in particular, allows you to transform other types of model constructs (such as pydantic models and dataclasses) into models in the typed sense.

This also enables better integration with LSPs (type factories are dynamic by nature, while classes are static).

v0.4.0: inclusion of new model types

The {typed} models system has been completely refactored. It is now possible to create custom model factories from the ModelFactory metaclass.

Additionally, new model factories have been introduced:

  1. Ordered: Validates data with respect to the ordering of entries.

  2. Rigid: Validates data with respect to the exactness and ordering of entries.

The Conditional model factory has been removed. It is now possible to pass a __conditions__ variable to each of the model factories, which defines additional conditions for validation.

v0.4.1: optional without default value

In {typed}, you can create models by applying the @model decorator to a class. If you want an entry to be optional, you simply use the Optional type factory, passing the type with a default value:

1from typed import SomeType, OtherType
2from typed.models import model, Optional
3
4@model
5class MyModel:
6    x: SomeType
7    y: Optional(OtherType, some_value)

The vast majority of typed’s builtin types (and also those constructed by its type factories) are nullable, meaning that a “null object” is defined for them, which can be accessed via the null function.

In the new update, if a value is not passed along with a type in the Optional function, it attempts to take that value as the null object of the type in question:

1Optional(SomeType) = Optional(SomeType, null(SomeType))

Naturally, if the type in question is not nullable, an error is returned.

v0.4.2: refactoring function types

One of {typed} premisses is:

If a type X is a subtype of a type Y, then every instance of X should be an instance of Y.

This is not a natural behavior of Python, which completely distinguishes elements of a class from the elements of any of its extensions.

Mathematically, this is not the expected behavior, something we have “fixed” within {typed}’s builtin types and type factories.

To exhibit such behavior, classes need to be constructed from specific metaclasses, in which we specify (within the __instancecheck__ method) the necessary conditions to validate instantiation.

I noticed that some function types were not exhibiting the desired behavior. They were then refactored, and now there is a natural chain of function types, in which one is not only a subtype of the other but also preserves instantiation:

  • Callable: general callable entities

  • Builtin: builtin functions

  • Lambda: lambda functions

  • Function (or FuncType): user defined functions

  • CompFuncType: composable functions

  • HintedDomFuncType: user defined functions that have type hint in domain

  • HintedCodFuncType: user defined functions that have type hint in codomain

  • HintedFuncType: user defined functions that have type hint in both domain and codomain

  • TypedDomFuncType: user defined functions with type hints in domain, which is checked at runtime

  • TypedCodFuncType: user defined functions with type hints in codomain, which is checked at runtime

  • TypedFuncType: user defined functions with type hints in domain and codomain, which are checked at runtime

  • BoolFuncType: user defined typed functions whose codomain is Bool

v0.4.3: introduction of @optional decorator

In some cases, we need to build models where all inputs are optional. In the new version of {typed}, a decorator to facilitate the construction of this type of model:

1from typed.models import optional
2
3@optional
4class MyModel:
5    some_var: SomeType
6    other_var: OtherType = some_value
7    ...

The snippet above is equivalent to the following:

1from typed.models import model, Optional
2
3@model
4class MyModel:
5    some_var: Optional(Maybe(SomeType), None)
6    other_var: Optional(OtherType, some_value)
7    ...

Here, Maybe is the type factory that receives a type and returns Union(SomeType, None). This means that, by default, @optional assumes that if a default value is not provided, then None is taken as the default.

Instead of passing None as the default, you might want to pass the null object of the type (if it is nullable). To do this, simply use the nullable variable:

1from typed.models import optional
2
3@optional(nullable=True)
4class MyModel:
5    some_var: SomeType
6    other_var: OtherType = some_value
7    ...

In this case, the snippet above is equivalent to:

1from typed.models import model, Optional
2
3@model
4class MyModel:
5    some_var: Optional(SomeType, null(SomeType))
6    other_var: Optional(OtherType, some_value)
7    ...

v0.4.4: introduction of model attributes

In {typed} we have several types of models:

  1. Models (the standard type, where the instance must contain at least the defined attributes)

  2. Exact Models (where the instance must contain exactly the defined attributes)

  3. Ordered Models (where the instance must contain at least the defined attributes, but in the order they were defined)

  4. Rigid Models (where the instance must contain exactly the defined attributes, and in the same order they were defined)

There is a type whose instances are models of each of the above classes: MODEL, EXACT, ORDERED, and RIGID.

Now, such types come with attributes that allow identifying if a given model belongs to a specific class:

  1. MyModel.is_model

  2. MyModel.is_exact

  3. MyModel.is_ordered

  4. MyModel.is_rigid

Attributes that return optional and mandatory attributes have also been added:

  1. MyModel.attrs: returns all attributes, with name, type, default value, and whether it is optional or not.

  2. MyModel.optional_attrs: returns only the optional attributes.

  3. MyModel.mandatory_attrs: returns only the mandatory attributes.

v0.4.5: optional and mandatory models

In v0.4.3 it was introduced the @optional decorator, from which one can to quickly create optional models, which are models whose all attributes are optional.

In this new version, a type OPTIONAL of all optional models was created. Also, the @optional decorator was extended to be applied directory in already existing models, turning them into optional models.

Analogously, it was introduced the type MANDATORY of all mandatory models, i.e, models with none optional arguments. A decorator @mandatory was created, allowed to turn any model into a mandatory model.

If applied in already existing models, both @optional and @mandatory preserves the underlying model kind, i.e, exact models are mapped into exact models, and so on.

v0.5.0: refactor of factories

In v0.5.0 all factories were reviewed:

  1. error messages are now more descriptive

  2. unification of function types with function factories

  3. BoolFunc has now the name Condition

So, for example:

  1. CompType is now Composable which can be applied to both a function or to a pair of integers

  2. TypedFuncType and TypedFunc are now just Typed, which can be applied to functions, types or pair of integers:

  3. and so on

1from typed import Typed, SomeType, OtherType
2from some.where import some_function
3
4Typed # the same as the old TypedFuncType
5Typed(SomeType, cod=OtherType) # the same as the old TypedFunc(SomeType, cod=OtherType)
6Typed(some_function) # the same as the old TypedFunc(some_function)
7...

v0.5.1: introduce __null__ in factories

In {typed} we have nullable types. These are the types for which the null function is defined. In v0.5.1 the null function was revisited to look for two cases:

  1. predefined builtin nullable types

  2. types with a __null__ defined.

Also, all factories were reviewed to include a __null__ attribute to the type they construct.