-
Notifications
You must be signed in to change notification settings - Fork 3
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
Axis can be number (float or int) or str. CompactAxis can be number #15
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #15 +/- ##
=======================================
Coverage 93.90% 93.90%
=======================================
Files 9 9
Lines 279 279
=======================================
Hits 262 262
Misses 17 17
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
src/covjson_pydantic/domain.py
Outdated
x: Optional[Union[ValuesAxis[float], CompactAxis]] = None | ||
y: Optional[Union[ValuesAxis[float], CompactAxis]] = None | ||
z: Optional[Union[ValuesAxis[float], CompactAxis]] = None | ||
x: Optional[Union[ValuesAxis[int], ValuesAxis[float], ValuesAxis[str], CompactAxis]] = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Python float
is the correct representation of a JSON number
, so we don't need int
here.
There was originally a problem with Pydantic supporting this Union[ValuesAxis[X], ValuesAxis[Y]]
, is this fixed now?
It would be good to test mixed cases, where we have an array like 3.14, "red"
. This should fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this PR, this snippet will print
print(Axes.model_validate_json("""
{
"x": {
"values": [
1,
2
]
}
}
"""))
x=ValuesAxis[float](dataType=None, coordinates=None, values=[1.0, 2.0], bounds=None) y=None z=None t=None composite=None
With this PR it will print
x=ValuesAxis[int](dataType=None, coordinates=None, values=[1, 2], bounds=None) y=None z=None t=None composite=None
I don't see why the latter is not preferable. Why should the pristine int
s be converted to float
s, which may result in weird floating point arithmetic issues down the line? I realise JSON has no strict definition of number types, but Python does.
I've not seen an issue so far with this Union[]
, but haven't tested yet beyond the test cases in this repository.
I've added a test with mixed case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there will be issues with the floating point representation, as all 32 bits integers can be exactly represented in a double precision floating point number. See for example:
https://stackoverflow.com/a/43656339
Although I agree that values=[1, 2]
looks cleaner, the library is trying to represent a JSON format, and in JSON 1
is exactly the same as 1.0
.
BTW, it is not that JSON has no strict definition of number
, they are explicitly defined to be floating point numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think the problem with the Union types in the past was actually here:
https://github.com/KNMI/covjson-pydantic/blob/master/src/covjson_pydantic/ndarray.py#L22
The ValueAxis like in this PR is probably fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess in the current code, if you construct the Axes from Python, and the values
are Python int
's it will fail, because of the strict
validation? While with the proposed PR, this will work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two more interesting text cases are:
- values = [1, 2.1]
- values = [1.1, 2]
I guess the first one will fail, and the second will work fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was the issue I had with Pydantic v1:
https://docs.pydantic.dev/1.10/usage/model_config/#smart-union
Hopefully resolved in v2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both with and without this PR you can pass integers to a float Axis. Even with strict validation on. So this will work:
> print(Axes(x=ValuesAxis[float](values=[1])))
x=ValuesAxis[float](dataType=None, coordinates=None, values=[1.0], bounds=None) y=None z=None t=None composite=None
This will fail with strict mode on (and work with strict mode off).
print(Axes(x=ValuesAxis[float](values=[1])))
This matches what is described in this table: https://docs.pydantic.dev/latest/concepts/conversion_table/#__tabbed_1_5
However, strict mode for ValuesAxis
is turned off at the moment. See Issue #4.
I had tested the mixed cases before. They are interesting indeed. Some magic is happening here:
>print(Axes.model_validate_json('{"x": { "values": [ 1, 2.1 ] }}'))
x=ValuesAxis[float](dataType=None, coordinates=None, values=[1.0, 2.1], bounds=None) y=None z=None t=None composite=None
>print(Axes.model_validate_json('{"x": { "values": [ 1.1, 2 ] }}'))
x=ValuesAxis[float](dataType=None, coordinates=None, values=[1.1, 2.0], bounds=None) y=None z=None t=None composite=None
I think this magic is the smart_union
you linked to. So works as intended/expected.
src/covjson_pydantic/domain.py
Outdated
start: Union[int, float] | ||
stop: Union[int, float] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Python float is the correct representation of a JSON number, so we don't need int here.
tests/test_data/str-axes.json
Outdated
"1", | ||
"2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look "happy" to me. I don't think the intention of the spec is that numbers can be given as string, but instead that the axis is something like "red", "green", "blue".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Change to 'real' strings.
No description provided.