Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to simplify registering user defined type? #56

Open
xbanke opened this issue Apr 17, 2020 · 4 comments
Open

Is it possible to simplify registering user defined type? #56

xbanke opened this issue Apr 17, 2020 · 4 comments
Labels
enhancement New feature or request
Projects

Comments

@xbanke
Copy link

xbanke commented Apr 17, 2020

  • typical version: 2.0.1
  • Python version: 3.7
  • Operating System: CentOS 8

Description

Hi, I like typical and I think it's more lightweight than pydantic. But add user defined type by typic.register is something tedious or there's another convenient way I didn't found. If so, is it possible to simplify it like pydantic's __get_validators__ or some else?

@seandstewart seandstewart added the enhancement New feature or request label Apr 17, 2020
@seandstewart
Copy link
Owner

Hey, @xbanke!

Thanks for the input.

What sort of custom user-type are you thinking of? Most any type is supported. The only real exceptions are recursive types (a class definition which takes an instance of the class itself) and Unions of multiple types (e.g., Union[int, str]).

In the case of Unions, validation still works, but not conversion.

Ex:

from typing import Union
import typic

typic.validate(Union[int, str], b"foo")
#> typic.constraints.error.ConstraintValueError: Given value <b'foo'> fails constraints: (constraints=((type=int, nullable=False, coerce=False), (type=str, nullable=False, coerce=False)), nullable=False)

I do think there's some room for improvement here, but I'd like to understand your use-case.

@xbanke
Copy link
Author

xbanke commented Apr 18, 2020

Thanks for your quick reply @seandstewart .
In many cases, I want to define my own coercion method. e.g. there is an argument annotated by List[typic.Strict[str]], but should accept str and coerced by some user defined function.

class Columns(typing.List[typic.Strict[str]]):
    ...


def coerce_columns(v) -> typing.List[typic.Strict[str]]:
    if isinstance(v, str):
        v = v.replace(',', ' ').replace(';', ' ').split()
    return typic.transmute(typing.List[typic.Strict[str]], v)


def check_columns(ann) -> bool:
    return ann is Columns


typic.register(coerce_columns, check_columns)

As seen above, the code being splitted to several independent blocks and not straigthforward. I have temp solution by a decorator, still saying register, and two dunder class methods: __deserialize__ and __check__. Of course the name is not the point.

from functools imoprt wraps
import typic


def register(cls):
    if not hasattr(cls, '__check__'):
        @classmethod
        def __check__(c, a):
            return a is c
        setattr(cls, '__check__', __check__)
    typic.register(cls.__deserialize__, cls.__check__)
    return cls

And then we can rewrite the type Columns as follow:

@register
class Columns(typing.List[typic.Strict[str]]):
    @classmethod
    def __deserialize__(cls, v):
        if isinstance(v, str):
            v = v.replace(',', ' ').replace(';', ' ').split()
    return typic.transmute(typing.List[typic.Strict[str]], v)
    
    @classmethod
    def __check__(cls, ann):
        return ann is cls

If possible, we can define some protocal which can handle this with out decorator.

Thanks again.

@seandstewart
Copy link
Owner

Thanks for the clarification and examples! This is super helpful, and pretty straightforward.

The current registration system is a holdout from v1 and I’d love to make it more accessible. I’ll play with this and see what I can come up with!

@xbanke
Copy link
Author

xbanke commented Apr 18, 2020

My pleasure.

@seandstewart seandstewart added this to To do in v2.1 Apr 30, 2020
@seandstewart seandstewart added this to the Typic 2.1 milestone Apr 30, 2020
@seandstewart seandstewart removed this from To do in v2.1 Jan 5, 2021
@seandstewart seandstewart added this to To do in v2.6 via automation Jan 5, 2021
@seandstewart seandstewart removed this from the Typic 2.1 milestone Jan 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
v2.6
To do
Development

No branches or pull requests

2 participants