Repository navigation
Support structured quantity, including scalars. - #12509
Conversation
|
Looks good, but hard to tell with the CI. #12511 is merged. |
08e51ea to
4594632
Compare
|
OK, thanks. I rebased now - so we can actually see all the tests! |
taldcroft
left a comment
There was a problem hiding this comment.
Looks generally good and non-controversial.
|
|
||
| def _ndarray_constructor(loader, node): | ||
| map = loader.construct_mapping(node) | ||
| map = loader.construct_mapping(node, deep=True) |
There was a problem hiding this comment.
Can you add a comment about what the deep=True is doing? I see the comment below about deep but it wasn't enough to make me understand.
There was a problem hiding this comment.
Without deep=True, the list produced by the structured dtype is not interpreted. It took me a while to figure out why I got dtype=[], so I should indeed have added a comment!
Actually, might as well ask: my first attempt kept just str(dtype) in the dumper, which means a structured dtype looks something like:
import numpy as np
dt = np.dtype('f8,f8')
str(dt)
# "[('f0', '<f8'), ('f1', '<f8')]"
But to interpret this in the loader, one would have to eval the string, which seemed less good than just letting yaml take care of the lists and tuples, even though that is substantially longer,
from astropy.io.misc.yaml import dump
print(dump(dt.descr))
- !!python/tuple [f0, <f8]
- !!python/tuple [f1, <f8]
If you think keeping just the string is better (and ideally have a better suggestion that eval!), I can do that too.
There was a problem hiding this comment.
Can ast's safe eval work here?
There was a problem hiding this comment.
Even though the ast.literal_eval is totally safe, I still prefer representing the dtype with "native" YAML lists and tuples.
There was a problem hiding this comment.
ast.literal_eval works indeed:
np.dtype(ast.literal_eval(str(np.dtype('f8, f8'))))
dtype([('f0', '<f8'), ('f1', '<f8')])
and implementing it would mean adding the following to the constructor:
if map['dtype'].startswith('['):
map['dtype'] = ast.literal_eval(map['dtype'])
So, it seems it would be mostly a matter of preference:
print(dump([(1., 2.)] * u.Unit('m, m/s')))
# this PR
!astropy.units.Quantity
unit: !astropy.units.Unit {unit: '(m, m / s)'}
value: !numpy.ndarray
buffer: !!binary |
QUFBQUFBQUE4RDhBQUFBQUFBQUFRQT09
dtype:
- !!python/tuple [f0, <f8]
- !!python/tuple [f1, <f8]
order: C
shape: !!python/tuple [1]
# with str(dtype)
!astropy.units.Quantity
unit: !astropy.units.Unit {unit: '(m, m / s)'}
value: !numpy.ndarray
buffer: !!binary |
QUFBQUFBQUE4RDhBQUFBQUFBQUFRQT09
dtype: '[(''f0'', ''<f8''), (''f1'', ''<f8'')]'
order: C
shape: !!python/tuple [1]
The literal_eval has the advantage of keeping the strings shorter and being closer to what one would see by just looking at the dtype, but what I have here is nicer in that one can just put the contents in np.dtype directly. I end up being torn.
But since you both seem to prefer the yaml list option, I just made some updates to that, so this should then be ready for final review. Obviously, if you change your mind, I'm happy to change.
p.s. Yet another option is to register the dtype with the dumper/loader, but the yaml then becomes even longer... Indeed, just for fun, if one just let's yaml.dump itself do it, one gets the following rather hopeless output:
In [6]: print(yaml.dump(np.dtype('f8,f8')))
!!python/object/apply:numpy.dtype
args:
- V16
- false
- true
state: !!python/tuple
- 3
- '|'
- null
- !!python/tuple
- f0
- f1
- f0: !!python/tuple
- &id001 !!python/object/apply:numpy.dtype
args:
- f8
- false
- true
state: !!python/tuple
- 3
- <
- null
- null
- null
- -1
- -1
- 0
- 0
f1: !!python/tuple
- *id001
- 8
- 16
- 1
- 16
There was a problem hiding this comment.
Agreed that registering the dtype is a mess!
Right now either the ast.literal_eval or the YAML look fine.
dtype can store metadata in a dictionary, for which the YAML option might be more suited...
There was a problem hiding this comment.
@mhvk. Is this comment resolved and/or the PR ready for a review?
There was a problem hiding this comment.
@nstarman - in my last comment I just thought I'd give you and @taldcroft a last look at how the two options of serializing the dtype look in practice. I think you both preferred to stick to native yaml as much as possible, so that is the version currently there. If after having a look, that is still the preference, then yes, this should be good to go. If not, and we go with literal_eval after all, then it is a very quick extra commit to change it to that.
4594632 to
04b2b30
Compare
nstarman
left a comment
There was a problem hiding this comment.
@mhvk, looks great. I think sticking to the YAML is best both for simplicity and also general robustness. Features like https://numpy.org/devdocs/reference/generated/numpy.dtype.metadata.html are better supported with YAML than ast.literal_eval.
|
I think the hanging tests are just a product of the branch requirements changing. A rebase should fix this. |
04b2b30 to
bc3b050
Compare
|
OK, thanks. Am quite happy to stick with this. I now rebased; hopefully all the tests will now run. |
|
#12535 should fix the py3.8w/dev test. As @taldcroft agrees with the YAML representation... I'm good to merge this. |
|
Thanks @mhvk! This will also be very useful for Cosmology. I'm trying to turn |
|
Great! Hopefully it will indeed work well! |
|
@meeseeksdev backport to v5.0.x |
|
Retry backport once #12559 is merged |
|
@meeseeksdev backport to v5.0.x |
…509-on-v5.0.x Backport PR #12509 on branch v5.0.x (Support structured quantity, including scalars.)
Description
As the title indicates, this allows structured quantities, including scalars, to be saved to yaml. This is independent of whether the unit is structured. I ended up deciding not to try to represent the void as a tuple, but rather as an opaque binary blob, since in principle the structure can be quite large and include arrays.
Fixes #12497
Checklist for package maintainer(s)
This checklist is meant to remind the package maintainer(s) who will review this pull request of some common things to look for. This list is not exhaustive.
Extra CIlabel.no-changelog-entry-neededlabel. If this is a manual backport, use theskip-changelog-checkslabel unless special changelog handling is necessary.astropy-botcheck might be missing; do not let the green checkmark fool you.backport-X.Y.xlabel(s) before merge.