Comments (8)
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.
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.
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.
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.
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.
You could call typic.coerce
on the nested type within your own coercer.
from typical.
@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.
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)
- Support new type union operator `|` in Python3.10
- Still not working with PEP 604 Union Operators HOT 5
- Unpredictable behavior with Union[pd.Series, pd.DataFrame] HOT 1
- float should not been converted to int with Union[float, int] HOT 3
- typic.field not compatible with old version, parameter `default` should be postional
- Wrong behavior when Union with constrained types HOT 8
- Couldn't evaluate type ForwardRef pandas DataFrame HOT 2
- callable instance should be the treated as a function or class? HOT 1
- Not compatible with pandas v1.3.3 HOT 2
- add parameter to typic.klass
- Transmute is broken with dicts of dataclasses with default values HOT 2
- TypeError if annotated typing.Deque[int]
- issubclass error after version 2.6.4
- tojson and primitive fails when class is derived
- Decimal serialization and deserialization HOT 2
- Use orjson for other libraries benchmark
- Version conflicts installed the pinned typing-extensions HOT 2
- Is there a way to use choices with values and labels when generating schemas? HOT 2
- Question on your approach to strict mode HOT 2
- When using my with typic.mypy plugin get error cannot import name 'TypingType' from 'mypy.typeops' HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typical.