Open keckler opened 2 years ago
Hm. This is an interesting edge case, though I believe it is consistent with the standard. YAML is typed. For example, null
is not equal to "null"
. Also, if I remember correctly, yes
for some crazy reason used to be a boolean.
The excerpt of the error message from your comment is missing the start.
Coerced `<class 'int'>` to `<class 'str'>`
Comments:
I suppose my confusion lies at the fact that sometimes the data can be casted from one type to another using the type=
parameter, while other times it cannot. For instance, in your README you give the example:
>>> from yamlize import Object, Attribute
>>>
>>> class StronglyTypedThing(Object):
...
... my_int = Attribute(type=int)
... my_float = Attribute(type=float)
... my_str = Attribute(type=str)
...
>>>
>>> stt2 = StronglyTypedThing.load(u'''
... my_int: 81.0 # this will be cast to an integer
... my_float: 92.1
... my_str: another boring message
... ''')
>>> stt2.my_int
81
In that case, a float is cast into an integer. So the type=int
is not used as a validator, it is used to cast.
But in the case that I provided in my initial comment, type=str
is used as a validator, not to cast. I guess this behavior is a little confusing because it seems arbitrary. It is confusing because it conflicts with the casting behavior that I just showed. According to the logic of the error message that is printed in my original comment, I would expect the example that I show in this comment to print an error like:
YamlizingError: Coerced `<class 'float'>` to `<class 'int'>`, but the new value `81` is not equal to old `81.0`.
But instead, in my original example, the casting takes place and you get an error message that shows two values which look exactly the same. It does not make it clear that the error resulted because the casting cannot be performed in this particular case, and this is not obvious otherwise because sometimes the casting can be performed without error.
Does that make sense?
With my use case right now, I can get around this easily enough just by using quotes. I just wanted to report the confusing behavior.
Yup.. that's a good point.
I think I lean more toward being strict than lenient. YAML is nice because it is mostly human maintainable. I believe I originally added the cast for int -> float conversion, because humans don't care about decimals when the float is a round number, and writing !!float 1
is not helpful.
So.... Now you've got me thinking. Is the right approach to create a yamlize.FloatLike object? I think we might be able to get rid of the cast validation which I believe would help reduce the inconsistency which you've pointed out. Are you working with ARMI friends? I'd have to bump the version for sure.
I think what you propose could be a good approach, but I'm not exactly clear on what you were thinking. My interpretation is that this would allow a user to do something like this without ambiguity:
>>> import yamlize
>>> from yamlize import Object, Attribute
>>>
>>> class Thing(Object):
...
... my_float1 = Attribute(type=yamlize.FloatLike)
... my_float2 = Attribute(type=yamlize.FloatLike)
...
>>>
>>> t = Thing.load(u'''
... my_float1: 81.0 # this is a float and will be interpreted as such
... my_float2: 92 # this is an int but will be interpreted as a float
... ''')
>>> t.my_float1
81.0
>>> t.my_float2
92.0
If that is indeed what you were thinking, perhaps also a yamlize.StrLike
object which would enable the following to be done unambiguously:
>>> import yamlize
>>> from yamlize import Object, Attribute
>>>
>>> class Thing(Object):
...
... my_str1 = Attribute(type=yamlize.StrLike)
... my_str2 = Attribute(type=yamlize.StrLike)
... my_str3 = Attribute(type=yamlize.StrLike)
...
>>>
>>> t = Thing.load(u'''
... my_str1: abcd # this looks like a str and will be treated as such
... my_str2: 92.1 # this is a float but will be interpreted as a str
... my_str3: 666 # this is an int but will be interpreted as a str
... ''')
>>> t.my_str1
'abcd'
>>> t.my_str2
'92.1'
>>> t.my_str3
'666'
I might be misunderstanding what you are suggesting, though, so please let me know if my interpretation is off.
But now that I type that out... I doubt that is what you were thinking because it moves further away from the underlying assumptions of YAML (i.e. that 1
is an int
, '1'
is a str
, and '1.0'
is a float
). So maybe you could explain in a little more detail what you had in mind? Are you suggesting to get rid of the type=...
option in the Attribute
class entirely?
So, maybe you could explain a little more detail what you had in mind?
Um. I think I like the StrLike implementation you're describing. Off hand, I'm not sure how to do it. It would be pretty confusing for another YAML interpreter to read, but I guess that's not our problem.
I doubt that is what you were thinking because it moves further away from the underlying assumptions of YAML ...
The *Like
classes have special behavior. The underlying int
, float
, str
classes behave normally. That makes it explicit, and I like explicit. This follows the Open/Closed principle.
Are you suggesting to get rid of the type=... option in the Attribute class entirely?
No. Definitely want to keep that. It's been so long, but I'm pretty sure this is with regard to "I think we might be able to get rid of the cast validation which I believe would help reduce the inconsistency which you've pointed out." That statement is talking about the check that exists to ensure that after casting from the yaml interpreted type to the Attribute's specified type, the objects are equivalent.
If one specifies an attribute to be of type
str
, they cannot then enter a valid string that looks like an integer to that attribute in their stream.For example:
Instead, if the user wants to supply (what is ostensibly) an
int
to a string attribute, they have to use quotes around the value. But this is strange, because quotes are not needed in other cases. For instance, if a user supplies something that obviously looks like a string to a string attribute, quotes are not needed:It would be nice if Yamlize would fully recognize that the
type=str
parameter being passed toAttribute
means that whatever the user provides, even if it looks like anint
or anything else, it should be coerced to astr
.At the least, the printed error could be changed to be more meaningful. Right now it says:
and this is confusing because the two printed values look exactly the same.