Package: typix
TypixAn advanced module to hide type handling code behind type annotationsVersion: 1.0.0ByJulien BERTHETGitHubThis module adds:Dynamic Types: types that can check or modify the annotated values at runtimetypingsupportUtility functions to improve type handlingInstallingPyPIpip install typixQuickstartThis section will describe some of the useful features of the module to easely get started with it.Using Dynamic Types on a functionfromtypiximportprocessor,Strict# The `@processor` decorator will allow# dynamic type support on this function@processordeftest(my_arg:Strict(int)):# Here, we annotate `my_arg` with the `Strict` dynamic typeprint("test:",my_arg)TheStrictdynamic type is a built-in dynamic type that allow strong
typing on function arguments. To use it, it must wrap a child type.>>>test(1)test:1>>>test('a')Traceback(mostrecentcalllast):...typix.error.TypixError:StrictconstraintfailedWe can also use other dynamic types likeConvert. This type will automatically convert the value to the given type. Here is an examplefromtypiximportprocessor,Strict,Convert@processordeftest(my_arg:Strict(int),my_other_arg:Convert(float)):print("test:",my_arg,my_other_arg)>>>test(1,5)test:15.0Finally a dynamic type can wrap another dynamic type to create aCompound Dynamic Type. In the following example we use strong typing withStricton the type conversion withConvert.Convertwon't raise any error by itself, soStrictwill implement that.fromtypiximportprocessor,Strict,Convert@processordeftest(my_arg:Strict(Convert(int))):print("test:",my_arg)>>>test(1.0)test:1>>>test("Hello World!")Traceback(mostrecentcalllast):...typix.error.TypixError:Strictconstraintfailed:Cannotconvert'str'to'int'Type checking with thetypecheckfunctionIn a non-function context, type checking a value is often needed. This module provides thetypecheckfunction that allow dynamic type checking
with some extra features.The function takes is defined like this:typecheck(value, type_, context = None)It works like theisinstancebuilt-in function but it supportsGenericAliaseslikelist[int]and dynamic types. The function will return aCheckResultobject containing data about the typecheck but it can be used as a boolean value. Hence, it can be used in anifstatement directly. The context parameter is needed when the dynamic type needs argument data. In this case, thetypecheckfunction shouldn't be used or argument data should be passed with the context argument using aContextobject. Thus, theContextobject is not meant to be used directly, but for edge cases.Here is an example of the usage of thetypecheckfunction:>>>typecheck(0,int)# Simple use case with static types<CheckResult:True>>>>typecheck([1,2,3],list[int])# GenericAlias support<CheckResult:True>>>>typecheck(0.0,Strict(int))# In this case an error can be raised by typecheckTraceback(mostrecentcalllast):...typix.error.TypixError:StrictconstraintfailedCustom Dynamic TypesIn this final section we will see how to create dynamic types. The process is
very easy.fromtypiximportTypix,typecheckclassGreeting(Typix):defprocess(self,greeting_type,person):ifnottypecheck(self.value,str):returnself.error("The argument value should be a 'str'")returnf"{greeting_type}{person}! Here is the argument value:{self.value}"We create a class with the name of the type that inheritsTypix. Then we overload theprocessmethod, and we define the parameters of the type.selfwill contain context information if needed.The return value of the function will become the new value of the annotated argument.If an unwanted value goes into the argument, we should return an error. Not with araisestatement but by returningself.errorwith the error message as
the argument. The error also takes a optional argumentfatal. If an error is fatal, this error will be raised at runtime, else, it won't be raised at all but it will be written in the context and a parent type likeStrictcan access it and raise it as a fatal error. That is how contexts works. Every typecheck, either in a function or not: context contains returned errors, the current value and argument and function data to be accessed by parent types. ACheckResultobject returned by thetypecheckfunction can also be used as context.In real conditions, we can use the newly made type like this:fromtypiximportprocessor@processordeftest(my_arg:Greeting("Hello","Paul")):print(my_arg)>>>test("I like berries")HelloPaul!Hereistheargumentvalue:Ilikeberries>>>test(5)# This returns an non-fatal error. Thus, it will return the default value.5