Skip to main content

uType

Version Python Requires License CI Test Coverage Code style: black Downloads

utype is a data types declaration & parsing library based on Python type annotations, enforce types and constraints for classes and functions at runtime

Core Features

  • Enforce types, data classes, function params and result parsing at runtime based on Python type annotation
  • Support a variety of constraints, logical operators and flexible parsing options
  • Highly extensible, all type transformer can be register, extend and override

Installation

pip install -U utype

utype requires Python >= 3.7

Usage Example

Types and constraints

The utype support to add constraints on types, such as

from utype import Rule, exc

class PositiveInt(int, Rule):  
    gt = 0

assert PositiveInt(b'3') == 3

try:
    PositiveInt(-0.5)
except exc.ParseError as e:
    print(e)
    """
    Constraint: 0 violated
    """

Data that conforms to the type and constraints will complete the conversion, otherwise will throw a parse error indicating what went wrong

Parsing dataclasses

utype supports the "dataclass" usage that convert a dict or JSON to a class instance, similar to pydantic and attrs

from utype import Schema, Field, exc
from datetime import datetime

class UserSchema(Schema):
    username: str = Field(regex='[0-9a-zA-Z]{3,20}')
    signup_time: datetime

# 1. Valid input
data = {'username': 'bob', 'signup_time': '2022-10-11 10:11:12'}
print(UserSchema(**data))
#> UserSchema(username='bob', signup_time=datetime.datetime(2022, 10, 11, 10, 11, 12))

# 2. Invalid input
try:
    UserSchema(username='@invalid', signup_time='2022-10-11 10:11:12')
except exc.ParseError as e:
    print(e)
    """
    parse item: ['username'] failed: 
    Constraint: <regex>: '[0-9a-zA-Z]{3,20}' violated
    """

After a simple declaration, you can get

  • Automatic __init__ to take input data, perform validation and attribute assignment
  • Providing __repr__ and __str__ to get the clearly print output of the instance
  • parse and protect attribute assignment and deletion to avoid dirty data

Parsing functions

utype can also parse function params and result

import utype
from typing import Optional

class PositiveInt(int, utype.Rule):  
    gt = 0

class ArticleSchema(utype.Schema):
    id: Optional[PositiveInt]
    title: str = utype.Field(max_length=100)
    slug: str = utype.Field(regex=r"[a-z0-9]+(?:-[a-z0-9]+)*")

@utype.parse
def get_article(id: PositiveInt = None, title: str = '') -> ArticleSchema:
    return {
        'id': id,
        'title': title,
        'slug': '-'.join([''.join(
            filter(str.isalnum, v)) for v in title.split()]).lower()
    }

print(get_article('3', title=b'My Awesome Article!'))
#> ArticleSchema(id=3, title='My Awesome Article!', slug='my-awesome-article')

try:
    get_article('-1')
except utype.exc.ParseError as e:
    print(e)
    """
    parse item: ['id'] failed: Constraint: : 0 violated
    """

try:
    get_article(title='*' * 101)
except utype.exc.ParseError as e:
    print(e)
    """
    parse item: ['<return>'] failed: 
    parse item: ['title'] failed: 
    Constraint: <max_length>: 100 violated
    """

You can easily get type checking and code completion of IDEs (such as Pycharm, VS Code) during development

utype supports not only normal functions, but also generator functions, asynchronous functions, and asynchronous generator functions with the same usage

import utype  
import asyncio  
from typing import AsyncGenerator  

@utype.parse  
async def waiter(rounds: int = utype.Param(gt=0)) -> AsyncGenerator[int, float]:  
    assert isinstance(rounds, int)  
    i = rounds  
    while i:  
        wait = yield str(i)  
        if wait:  
            assert isinstance(wait, float)  
            print(f'sleep for: {wait} seconds')
            await asyncio.sleep(wait)  
        i -= 1  
  
async def wait():  
    wait_gen = waiter('2')  
    async for index in wait_gen:  
        assert isinstance(index, int)  
        try:  
            await wait_gen.asend(b'0.5')  
            # sleep for: 0.5 seconds  
        except StopAsyncIteration:  
            return  
  
if __name__ == '__main__':  
    asyncio.run(wait())

The AsyncGenerator type is used to annotate the return value of the asynchronous generator, which has two parameters: the type of the value output by yield, type of the value sent by asend

As you can see, the parameters passed to the function and the value received from yield were all converted to the expected type as declared

Logical operation of type

utype supports logical operations on types and data structures using Python-native logical operators

from utype import Schema, Field
from typing import Tuple

class User(Schema):  
    name: str = Field(max_length=10)  
    age: int

one_of_user = User ^ Tuple[str, int]

print(one_of_user({'name': 'test', 'age': '1'}))
# > User(name='test', age=1)

print(one_of_user([b'test', '1']))
# > ('test', 1)

The example uses the ^ exclusive or symbol to logically combine User and Tuple[str, int], and the new logical type gains the ability to convert data to one of those

Register transformer for type

Type transformation and validation strictness required by each project may be different, so in utype, all types support registraton, extension and override, such as

from utype import Rule, Schema, register_transformer
from typing import Type

class Slug(str, Rule):  
    regex = r"[a-z0-9]+(?:-[a-z0-9]+)*"

@register_transformer(Slug)
def to_slug(transformer, value, t: Type[Slug]):
    str_value = transformer(value, str)
    return t('-'.join([''.join(
    filter(str.isalnum, v)) for v in str_value.split()]).lower())


class ArticleSchema(Schema):
	slug: Slug

print(dict(ArticleSchema(slug=b'My Awesome Article!')))
# > {'slug': 'my-awesome-article'}

You can register transformers not only for custom types, but also for basic types (such as str, int, etc.) Or types in the standard library (such as datetime, Enum, etc.) To customize the conversion behavior

RoadMap and Contribution

utype is still growing, and the following features are planned for implementation in the new version

  • Improve the handling mechanism of parsing errors, including error handling hook functions, etc.
  • Support the declaration and parse command line parameters
  • Support for Python generics, type variables, and more type annotation syntax
  • Develop Pycharm/VS Code plugin that supports IDE detection and hints for constraints, logical types, and nested types

You are also welcome to contribute features or submit issues.

Applications

UtilMeta Python Framework

UtilMeta Python Framework is a progressive meta-framework for backend applications, which efficiently builds declarative APIs based on the Python type annotation standard, and supports the integration of mainstream Python frameworks as runtime backend

Community

utype is a project of UtilMeta, so you can join the community in

Release files for utype 0.6.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for utype 0.6.8
File Size Uploaded
utype-0.6.8.tar.gz 115.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for utype 0.6.8
File Interpreter ABI Platform
utype-0.6.8-py3-none-any.whl Python 3 none any Details

Total release size: 209.6 kB

Release files / utype-0.6.8.tar.gz

Download URL utype-0.6.8.tar.gz
Size 115.7 kB
Tags Source
SHA-256 checksum
How to use checksums
7b92c9fd2d62d36a9896570da562132bfd06a3971265d1da88c62b8239e502c2
BLAKE2b-256 checksum
How to use checksums
2288d7ad25b68ec8032e1dee3c175c0c85e4ea17fdeae220eae3c15f7a194a5e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.7

Release files / utype-0.6.8-py3-none-any.whl

Download URL utype-0.6.8-py3-none-any.whl
Size 93.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e4df5d0a63357f800285da534aca2c76f3b2cda5ebb4594115271e57373b6729
BLAKE2b-256 checksum
How to use checksums
f688539c106bd56da65ca4fc4ceda74eade40c25154660eb095b649e7c2c8be8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.7

Release history Release notifications | RSS feed

This release

0.6.8 This release

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page