About
Here you will find some important changelogs for the library {typed}. For the full list of tags, see here.
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.
from
typing
:Union
,List
,Tuple
,Dict
,Set
, …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:
Ordered: Validates data with respect to the ordering of entries.
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 typeY
, then every instance ofX
should be an instance ofY
.
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 entitiesBuiltin
: builtin functionsLambda
: lambda functionsFunction
(orFuncType
): user defined functionsCompFuncType
: composable functionsHintedDomFuncType
: user defined functions that have type hint in domainHintedCodFuncType
: user defined functions that have type hint in codomainHintedFuncType
: user defined functions that have type hint in both domain and codomainTypedDomFuncType
: user defined functions with type hints in domain, which is checked at runtimeTypedCodFuncType
: user defined functions with type hints in codomain, which is checked at runtimeTypedFuncType
: user defined functions with type hints in domain and codomain, which are checked at runtimeBoolFuncType
: user defined typed functions whose codomain isBool
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:
Models (the standard type, where the instance must contain at least the defined attributes)
Exact Models (where the instance must contain exactly the defined attributes)
Ordered Models (where the instance must contain at least the defined attributes, but in the order they were defined)
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:
MyModel.is_model
MyModel.is_exact
MyModel.is_ordered
MyModel.is_rigid
Attributes that return optional and mandatory attributes have also been added:
MyModel.attrs
: returns all attributes, with name, type, default value, and whether it is optional or not.MyModel.optional_attrs
: returns only the optional attributes.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:
error messages are now more descriptive
unification of function types with function factories
BoolFunc
has now the nameCondition
So, for example:
CompType
is nowComposable
which can be applied to both a function or to a pair of integersTypedFuncType
andTypedFunc
are now justTyped
, which can be applied to functions, types or pair of integers: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:
predefined builtin nullable types
types with a
__null__
defined.
Also, all factories were reviewed to include a __null__
attribute to the type they construct.