Repository navigation
Time allow initialization with bytes or dtype='S' ndarray input - #6823
Conversation
|
Hi there @mhvk 👋 - thanks for the pull request! I'm just a friendly 🤖 that checks for issues related to the changelog and making sure that this pull request is milestoned and labeled correctly. This is mainly intended for the maintainers, so if you are not a maintainer you can ignore this, and a maintainer will let you know if any action is required on your part 😃. Everything looks good from my point of view! 👍 If there are any issues with this message, please report them here. |
|
Failures are the usual URL errors, plus numpy-dev formatting errors unrelated to this PR. |
|
Hrm I don't get why there are still URL errors. It's really unlikely that both data.astropy.org and the mirror don't work... I guess I'll have to investigate some more. |
taldcroft
left a comment
There was a problem hiding this comment.
Quick comments on the code here. Will try to think about this a little more, later.
| .format(timestr, self.name)) | ||
|
|
||
| @staticmethod | ||
| def _decode_if_needed(val, encoding='ascii'): |
There was a problem hiding this comment.
Right now this encoding kwarg is orphaned, in the sense that it is not actually used and is not exposed in any way to the public API. I'd rather hardwire for now and then add a kwarg IFF it is actually necessary.
| for val, iy, im, id, ihr, imin, dsec in iterator: | ||
| iy[...], im[...], id[...], ihr[...], imin[...], dsec[...] = ( | ||
| self.parse_string(val.item(), subfmts)) | ||
| self.parse_string(self._decode_if_needed(val.item()), subfmts)) |
There was a problem hiding this comment.
Is there a noticeable performance hit to adding this extra call within the inner loop?
There was a problem hiding this comment.
One point is that you know in advance from val1.dtype whether every value needs decoding or none need decoding, so there is some opportunity for optimization. But maybe that is truly in the noise and code clarity is more important.
taldcroft
left a comment
There was a problem hiding this comment.
Overall this is a good thing but has some issues. It seems the whole PR should be re-branded as bringing support for bytes inputs without reference to the column unicode sandwich.
| for val, iy, im, id, ihr, imin, dsec in iterator: | ||
| iy[...], im[...], id[...], ihr[...], imin[...], dsec[...] = ( | ||
| self.parse_string(val.item(), subfmts)) | ||
| self.parse_string(self._decode_if_needed(val.item()), subfmts)) |
There was a problem hiding this comment.
One point is that you know in advance from val1.dtype whether every value needs decoding or none need decoding, so there is some opportunity for optimization. But maybe that is truly in the noise and code clarity is more important.
| # Select subformats based on current self.in_subfmt | ||
| subfmts = self._select_subfmts(self.in_subfmt) | ||
|
|
||
| # We cannot just use the iterator over val1, since that effectively |
There was a problem hiding this comment.
This comment completely confuses me. Is it a leftover from previous implementation? Maybe below a comment to the effect that the Column unicode sandwich machinery doesn't work here because of how np.nditer works, hence the need to specifically decode each element in the case of a bytestring array val.dtype='S'.
(At least, that is my understanding of the situation..)
[EDIT] - re-reading the PR description it looks like this is a leftover from the multi-index idea.
| assert (t0 + 1 * u.second) == (t1 + 1 * u.second) | ||
|
|
||
|
|
||
| def test_string_valued_columns(): |
There was a problem hiding this comment.
Should probably be test_bytes_valued_inputs.
Since the implementation and scope now includes bytes inputs that are not Column, that should be tested.
| @staticmethod | ||
| def _decode_if_needed(val, encoding='ascii'): | ||
| """Decode ``vall`` if it is a bytes instance.""" | ||
| if type(result) is bytes: |
There was a problem hiding this comment.
Err, this should be val everywhere not result. This is preventing even import of astropy.
|
|
||
| @staticmethod | ||
| def _decode_if_needed(val, encoding='ascii'): | ||
| """Decode ``vall`` if it is a bytes instance.""" |
|
Dang, sorry to have uploaded a version that doesn't even work. With the advent of I'm still trying to think what is best, as I don't really like allowing bytes everywhere, but rather would just let |
|
I'm closing thsi in favour of #6832, which I think is better targeted. |
|
In this case I would tend toward Postel's law of being liberal on input. For instance I might use If someone provides a bytes string or array and it parses, then clearly the input was in fact ASCII-encoded and I don't see harm in letting this work. Making this case fail while a bytes Column succeeds doesn't make too much sense to me. |
|
OK, let me make at least make this PR work and then we can compare. |
Also add a test for direct bytes input.
9ab732a to
c73764f
Compare
88ad4b9 to
885c1b7
Compare
|
@taldcroft - OK, I revisted this one, now no longer using a staticmethod, but just creating a conversion function on the fly. For unicode arrays, this will now be faster than before (since for some reason |
|
circleci failure is unrelated (something with the sites not being up to date). |
|
@mhvk - excellent! The code change and tests look good to me. The CHANGES.rst entry needs to be updated, and there should be some updates of API / narrative docs to reflect that |
|
@taldcroft - am not sure we should update documentation - people should really be passing in strings; I see this as a work-around for |
|
@mhvk - I guess not updating the narrative docs is OK, but the API docs need to provide accurate information about the API! If the On the bigger picture, I see this as a workaround for the lack of a one-byte string dtype in numpy (remembering that Py2 is no longer part of our conversation). We've made an effort at a workaround with |
|
@taldcroft - before I had stuff: with "API", do you mean an addition to the |
|
@mhvk - about API docs, from what I can see it is just There is a question about what to do for |
|
@taldcroft - finally got around (end of term...) to wrapping up this PR; please have a look. p.s. It was amusing to see that some of the docstrings stated "Data to initialize table." |
|
@mhvk - what is your thinking in marking this as a Bug for backport? I think that the 2.0 behavior is not a really bug since the docs correctly state that only |
|
@taldcroft - I think it was a bug that one could not pass in string-valued But I don't feel strongly, so if this turns out to be a difficult backport, then I think it is fine to just not do it. |
|
If there is really a regression then definitely a bug fix. But I cannot reproduce that: |
| - Initialization of Time instances now is consistent for all formats to | ||
| ensure that ``-0.5 <= jd2 < 0.5``. [#6653] | ||
|
|
||
| - Initialization of ``Time`` instances with ``Column`` is now possible |
There was a problem hiding this comment.
Sorry for missing this, but this should reference the actual change here of generically allowing byte-type input (either bytes or dtype='S' ndarray objects).
In [2]: Time(Column(b'2001:001'))
Out[2]: <Time object: scale='utc' format='yday' value=2001:001:00:00:00.000>
In [3]: Time(b'2001:001')
Out[3]: <Time object: scale='utc' format='yday' value=2001:001:00:00:00.000>
In [4]: Time(np.array([b'2001:001']))
Out[4]: <Time object: scale='utc' format='yday' value=['2001:001:00:00:00.000']>
|
@taldcroft - I think the regression would be that one would have an ascii string column (say, from a fits file) which would be convertible to a |
Hmm, the table unicode sandwich PR #5700 did not touch FITS or the FITS table reader at all, and left this as a followup #6122. I haven't explicitly verified, but I don't think there is a regression there. If @astrofrog's #6821 had been part of 2.0 then indeed there could have been a regression (except that he had fixed it internally). Fortunately with this PR all will be well for 3.0! |
|
OK, let's change the milestone to 3.0; I'll update the changelog as well. |
Better changelog entry for gh-6823
Currently, if we pass a
Columnwithdtype='S'toTime, this raises an error even thoughColumnitself knows how to translate the bytes to strings. The problem is that in iterating over the column usingnp.nditer, the input is treated as a regular array. There are two possible solutions: use themulti_indexof the iterator to get the item, so thatColumn.__getitem__can return a string, or just being more generally accepting of bytes input, and treating it as ascii. In this PR, I took the latter approach, as it was simpler and I didn't really see a downside to it.This is helpful for #6821.