Coder Social home page Coder Social logo

Comments (8)

seandstewart avatar seandstewart commented on May 16, 2024

Thank you for the well-thought-out discussion on Unions. It's a bit of a weird case, since as I note in the documentation, the resolution path for a Union-type is unclear when it comes to coercion, since we don't actually know what the user wants. You do bring up a good point about the runtime validation of Union-types.

We don't currently do any actual runtime validation beyond the attempt to coerce a type and I feel that this logic bleeds into validation logic rather than coercion logic, but I'll have to think about this a bit more.

from typical.

syastrov avatar syastrov commented on May 16, 2024

You're welcome. I certainly understand the concern about not wanting to guess what the user wants and about adding validation logic.
I already see there is a potential issue in my proposal: In case C1, where you check if the type isinstance of one of the types in the Union, you could get multiple matches, due to subclassing: therefore that should also raise an error in the case of multiple valid coercions.

Still, I think ignoring coercion of Unions is not a good idea, because, as far as I understand the idea behind coercion, is that you are guaranteed that you get the target type back or an error is thrown. That's not the case right now for typic.coerce("foo", Union[float, int]). I'd prefer some error (e.g. TypeError) to be thrown there.

I wonder if we could make everyone happy by allowing to register a custom Union coercer, with the default being that an error is thrown? (unless it's this special case of Optional?)
Currently, it's possible to register a custom coercer for Union using typic.register (typic.register(union_coercer, lambda typ: getattr(typ, "__origin__", typ) == Union)), but it's not very useful... the coercer function does not get passed the type it's coercing to, so there would be no way to decide which type to coerce to. Therefore, I wouldn't be able to implement the kind of coercion that I outlined. Maybe you'd be willing to add an extra parameter to the coercer, passing the target type? Or maybe it should be a separate register_union_coercer function or somesuch...

So, if you don't feel inclined to make the library opinionated about this, maybe opening it up for the user to decide is a good choice.

from typical.

syastrov avatar syastrov commented on May 16, 2024

By the way, my original use case was that I have a sentinel value that I default for all values in a class to indicate missing values, e.g.:

class Missing:
    pass


MISSING = Missing()
@typic.al
@dataclass
class PartialBlogEntity:
    title: Union[Optional[str], Missing] = MISSING

In that case, I never want typical to coerce to the Missing type.

from typical.

seandstewart avatar seandstewart commented on May 16, 2024

Here’s a complete example of registering a custom coercer from my library iambic which makes use of Unions.

In your case, I would probably write a check which looks for a Union as the origin and your Missing sentinel as an arg.

from typical.

syastrov avatar syastrov commented on May 16, 2024

Thanks for the example. I can see how it works in this case where you essentially have a discriminated union (e.g. you can check the "type" field of the value to know what to coerce to). But I don't see how I could make this in a generic way, without registering a coercer for each possible Union combination.

For example, if I have more fields, like this:

@typic.al
@dataclass
class PartialBlogEntity:
    title: Union[Optional[str], Missing] = MISSING
    created_at: Union[datetime, Missing] = MISSING

I would have to register a coercer with a check function that looked for Union[Optional[str], Missing], which always coerced to Optional[str]; then, register another coercer with a check function that looked for Union[datetime, Missing] and always coerced to datetime.
Am I missing something?

from typical.

seandstewart avatar seandstewart commented on May 16, 2024

You could call typic.coerce on the nested type within your own coercer.

from typical.

seandstewart avatar seandstewart commented on May 16, 2024

@syastrov I believe I've provided a path for something like what you're asking for here in v2.0.0b8. That version should be released today.

from typical.

seandstewart avatar seandstewart commented on May 16, 2024

I've been noodling on this a bit and decided it's a good thing to add to the library. We added support for "tagged unions" a while back, which solves the main use-case of custom type registration, but there are real cases where it may be useful to allow for this.

from typical.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.