Skip to content

Table no longer access variable length VO table as bytes string - #8745

Closed
pllim wants to merge 2 commits into
astropy:masterfrom
pllim:vo-uni-sandwich
Closed

pllim wants to merge 2 commits into
astropy:masterfrom
pllim:vo-uni-sandwich

Conversation

@pllim

@pllim pllim commented May 22, 2019 •

Copy link
Copy Markdown
Member

Fix #8716 . This does change a subtle behavior, so it should only go into a major release.

I suspect it would affect packages downstream, e.g., astroquery.vo_conesearch or whoever is parsing VO table using Table.read() and then decoding bytes to UTF-8 themselves.

Fun fact: Incidentally, I have just tagged all four Toms for review!

TODO:

  • Discuss whether this is the correct approach and the possible side effects (breaking behavior, memory usage, performance).
  • Add PR number to change log.

assert table is not None

tt = table.to_table()
assert tt['access_url'][0] == (

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, without this patch, it returns a b'http://...'.


field_types = [
('string_test', {'datatype': 'char', 'arraysize': '*'}),
('string_test', {'datatype': 'unicodeChar', 'arraysize': '*'}),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Behavior change in existing test.

@taldcroft taldcroft left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs dedicated table tests in test_column.py to test the change. The potential breakage extends to users that are putting bytes objects into a column, e.g. like c = Column([b'asdf', None]) and then expecting c[0] to be bytes.

Comment thread astropy/table/_column_mixins.pyx Resolved
Comment thread CHANGES.rst Outdated
astropy.table
^^^^^^^^^^^^^

- Accessing variable length columns from VO table no longer returns bytes

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the API changes section. The more fundamental change is to the table item access behavior of a Column of object dtype whenever the object is bytes. So in fact the VO table does still return a column of bytes objects, but it looks like str whenever they get accessed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I solidified the change log entry.

@astropy astropy deleted a comment from codecov Bot Jun 28, 2019
@astropy astropy deleted a comment from codecov Bot Jun 28, 2019
@pllim pllim removed this from the v4.0 milestone Jul 17, 2019
@codecov

codecov Bot commented Jul 17, 2019 •

Copy link
Copy Markdown

Codecov Report

Merging #8745 into master will decrease coverage by 0.01%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #8745      +/-   ##
==========================================
- Coverage   86.96%   86.94%   -0.02%     
==========================================
  Files         408      399       -9     
  Lines       61437    59355    -2082     
  Branches     1096     1100       +4     
==========================================
- Hits        53429    51607    -1822     
+ Misses       7385     7107     -278     
- Partials      623      641      +18
Impacted Files Coverage Δ
astropy/visualization/wcsaxes/coordinates_map.py 86.88% <0%> (-10.18%) ⬇️
astropy/modeling/mappings.py 84.31% <0%> (-8.79%) ⬇️
astropy/convolution/src/convolve.c 80.68% <0%> (-8.34%) ⬇️
astropy/wcs/src/unit_list_proxy.c 54.92% <0%> (-5.94%) ⬇️
astropy/stats/histogram.py 92% <0%> (-5.85%) ⬇️
astropy/visualization/units.py 68.08% <0%> (-5.5%) ⬇️
astropy/modeling/separable.py 90.62% <0%> (-5.26%) ⬇️
astropy/constants/__init__.py 94.87% <0%> (-5.13%) ⬇️
astropy/coordinates/solar_system.py 70.06% <0%> (-4.94%) ⬇️
...coordinates/builtin_frames/icrs_cirs_transforms.py 78.1% <0%> (-4.76%) ⬇️
... and 186 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b96c6f3...2196ad0. Read the comment docs.

@pllim

This comment has been minimized.

@bsipocz

bsipocz commented Jul 17, 2019

Copy link
Copy Markdown
Member

Until I hear back from @tomdonaldson , this is not going forward, so removing milestone for now.

but surely having a decision by 4.0 is feasible?

@bsipocz bsipocz added this to the v4.0 milestone Oct 21, 2019
@taldcroft

Copy link
Copy Markdown
Member

I have locally rebased this on master and changed the Cython code update to below, and see tests passing for Table and io.votable:

    try:
        if value.dtype.char == 'S' and not value.shape:
            value = value.decode('utf-8', errors='replace')
    except AttributeError:
        if isinstance(value, bytes):
            value = value.decode('utf-8', errors='replace')
    return value

With this new flow, I don't see any performance change for Column item access. That is expected because it never gets to the if isinstance() code in this case (no attribute error since value will be a numpy object with dtype and shape attributes).

I confirmed that there is an API change for table access to an Object column that has a Python bytes object inside. In release it returns bytes, with this it will return str. At some level that is more consistent with Table behavior, but in any case that seems like a relatively rare situation.

Takeaway: this is good from my perspective for Table, but would definitely need an API changelog entry.

@pllim

pllim commented Oct 23, 2019

Copy link
Copy Markdown
Member Author

Re: #8745 (comment)

@taldcroft , regarding the code change that you posted above -- Do you want me to actually change it to that logic or was it just for your personal testing?

I am not sure what you mean by "it never gets to the if isinstance() code in this case" because the reason I added it was to handle the VO use case, so I would think the logic flow would actually get there, since you said you noticed a change in behavior. I'd rather not have the check in except block because if I remember correctly, except is computationally "expensive" and VO already has its own performance issues without adding more to it.

Hope you can clarify!

p.s. I updated the change log and will push it out shortly.

Comment on lines +691 to +693
assert c[1] == 'def' # Was b'def' before PR 8745
assert isinstance(c[1], str) # Was bytes before PR 8745
assert not isinstance(c[1], bytes) # Was str before PR 8745

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noted the behavior change in comments here when compared to astropy 3.2.2. Is this behavior change acceptable?

Comment on lines +695 to +696
assert np.all(c[:2] == np.array([None, b'def']))
assert not np.all(c[:2] == np.array([None, 'def']))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comparison to np.array remains unchanged, unlike above.

@taldcroft

Copy link
Copy Markdown
Member

@taldcroft , regarding the code change that you posted above -- Do you want me to actually change it to that logic or was it just for your personal testing?

I did want you to change it to maintain table performance. Yesterday I thought I found a noticeable hit on column access speed with the `isinstance() in there up front. But trying to reproduce today I don't see it. E.g.:

col = Column([1, 2, 3])
timeit col[1]

or

col = Column(np.arange(1e6))
timeit l = [c for c in col]

Can you verify that the timing in this branch compared to master is the same? I'm surprised / confused because it has to do the isinstance first and then do the original test as well. In my testing isinstance() takes about 100 ns compared to the column access time of 300 ns in master. So I would have expected to get about 100 ns more in this branch vs. master, but it came out just the same. Don't forget the Cython needs to be recompiled in different versions.

If there is no noticeable performance difference then I agree avoiding the except: is a good thing.

I am not sure what you mean by "it never gets to the if isinstance() code in this case"

Sorry, I just meant for normal Table column access of some type like float or int.

@tomdonaldson

Copy link
Copy Markdown
Contributor

This change has a side effect on write() that FIELDs with string values now default to an IVOA datatype of "unicodeChar" instead of "char". This change was noted and accounted for in the unit tests, but it turns out it is not benign.

The output() method of the UnicodeChar converter is different than that for Char. One impact of this is that when a VOTable with a char FIELD is read, then written, the FIELD is output as a unicodeChar with it original value wrapped by b''. So when input is:
...
<FIELD ID="mydata" arraysize="*" datatype="char" name="mydata"/>
<DATA>
<TABLEDATA><TR><TD>My Data Value</TD></TR></TABLEDATA>
...

the output is:

...
<FIELD ID="mydata" arraysize="*" datatype="unicodeChar" name="mydata"/>
<DATA>
<TABLEDATA><TR><TD>b'My Data Value'</TD></TR></TABLEDATA>
...

With this complication, and the lingering concerns about performance and Table impacts beyond VOTable reading, @pllim and I decided we should table this for 4.0 and revisit it for 4.1.

@pllim

pllim commented Oct 29, 2019

Copy link
Copy Markdown
Member Author

Trying to see if we can do this without touching the Table code and end up deep in 🐰 🕳

@pllim pllim mentioned this pull request Oct 29, 2019
2 tasks done
@pllim

pllim commented Oct 29, 2019

Copy link
Copy Markdown
Member Author

Closing in favor of #9505 . If we want to come back to this solution, I'd rather open a new PR.

@pllim pllim closed this Oct 29, 2019
@pllim
pllim deleted the vo-uni-sandwich branch October 29, 2019 17:47
@bsipocz bsipocz removed this from the v4.1 milestone Nov 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extended Table unicode sandwich for varchar data access from votable

4 participants