An advanced module to hide type handling code behind type annotations
Project description
Typix
An advanced module to hide type handling code behind type annotations
Version: 1.0.0
By Julien BERTHET
This module adds:
- Dynamic Types: types that can check or modify the annotated values at runtime
typingsupport- Utility functions to improve type handling
Installing
- PyPI
pip install typix
Quickstart
This section will describe some of the useful features of the module to easely get started with it.
Using Dynamic Types on a function
from typix import processor, Strict
# The `@processor` decorator will allow
# dynamic type support on this function
@processor
def test(my_arg: Strict(int)):
# Here, we annotate `my_arg` with the `Strict` dynamic type
print("test:", my_arg)
The Strict dynamic 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 (most recent call last):
...
typix.error.TypixError: Strict constraint failed
We can also use other dynamic types like Convert. This type will automatically convert the value to the given type. Here is an example
from typix import processor, Strict, Convert
@processor
def test(my_arg: Strict(int), my_other_arg: Convert(float)):
print("test:", my_arg, my_other_arg)
>>> test(1, 5)
test: 1 5.0
Finally a dynamic type can wrap another dynamic type to create a Compound Dynamic Type. In the following example we use strong typing with Strict on the type conversion with Convert.
Convert won't raise any error by itself, so Strict will implement that.
from typix import processor, Strict, Convert
@processor
def test(my_arg: Strict(Convert(int))):
print("test:", my_arg)
>>> test(1.0)
test: 1
>>> test("Hello World!")
Traceback (most recent call last):
...
typix.error.TypixError: Strict constraint failed: Cannot convert 'str' to 'int'
Type checking with the
typecheckfunction
In a non-function context, type checking a value is often needed. This module provides the typecheck function that allow dynamic type checking
with some extra features.
The function takes is defined like this:
typecheck(value, type_, context = None)
It works like the isinstance built-in function but it supports GenericAliases like list[int] and dynamic types. The function will return a CheckResult object containing data about the typecheck but it can be used as a boolean value. Hence, it can be used in an if statement directly. The context parameter is needed when the dynamic type needs argument data. In this case, the typecheck function shouldn't be used or argument data should be passed with the context argument using a Context object. Thus, the Context object is not meant to be used directly, but for edge cases.
Here is an example of the usage of the typecheck function:
>>> 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 typecheck
Traceback (most recent call last):
...
typix.error.TypixError: Strict constraint failed
Custom Dynamic Types
In this final section we will see how to create dynamic types. The process is very easy.
from typix import Typix, typecheck
class Greeting(Typix):
def process(self, greeting_type, person):
if not typecheck(self.value, str):
return self.error("The argument value should be a 'str'")
return f"{greeting_type} {person}! Here is the argument value: {self.value}"
We create a class with the name of the type that inherits Typix. Then we overload the process method, and we define the parameters of the type.
self will 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 a raise
statement but by returning self.error with the error message as
the argument. The error also takes a optional argument fatal. 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 like Strict can 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. A CheckResult object returned by the typecheck function can also be used as context.
In real conditions, we can use the newly made type like this:
from typix import processor
@processor
def test(my_arg: Greeting("Hello", "Paul")):
print(my_arg)
>>> test("I like berries")
Hello Paul! Here is the argument value: I like berries
>>> test(5) # This returns an non-fatal error. Thus, it will return the default value.
5
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file typix-1.0.0.tar.gz.
File metadata
- Download URL: typix-1.0.0.tar.gz
- Upload date:
- Size: 4.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d88d61c1f5a674c84827c90add9361aeb3f4f089b3d9354efbaae715606e0666
|
|
| MD5 |
2a1d37657f374d45779c845eb978b2a7
|
|
| BLAKE2b-256 |
7477070a8e7e87f46932df09eefee141373ec9956443f3d838ad2c6ef7b330d1
|