Repository navigation
very minor changes to support Functional units in CDS tables - #9971
Conversation
pllim
left a comment
There was a problem hiding this comment.
Thanks, @DShivansh ! I have some minor comments below but you can wait for a review from the io.ascii maintainers. I am thinking maybe a change log under 4.1 under "API change" but I can be overruled.
In the meantime, please add test(s).
| if unit == '---': | ||
| col.unit = None # "---" is the marker for no unit in CDS table | ||
| elif unit[0] == '[' and unit[-1] == ']': | ||
| temp = re.compile(r'\[(?P<un>.*?)\]') |
There was a problem hiding this comment.
Maybe the compile can be done once at the module level or is that premature optimization?
There was a problem hiding this comment.
Yes, I think I should do the compile at the module level because each time it sees the functional unit it will recompile.
| unit = match.group('units') | ||
| if unit == '---': | ||
| col.unit = None # "---" is the marker for no unit in CDS table | ||
| elif unit[0] == '[' and unit[-1] == ']': |
There was a problem hiding this comment.
Is this comparison going to catch other non-CDS stuff and cause unintended side effects?
There was a problem hiding this comment.
No because this function is only run when the program guesses that the provided format is CDS.
hamogu
left a comment
There was a problem hiding this comment.
I think this looks good, thanks a lot for working on this. Let's give it a test drive. Can you add a test?
You could just modify https://github.com/astropy/astropy/blob/master/astropy/io/ascii/tests/data/cds.dat so that one column has a logarithmic unit. Alternatively, it might be worthwhile to have a separate test case for that (see the existing cds tests to see how to do that) using a real CDS table with logarithmic units (but shorten the table to only have one line of data to save time on running the test).
|
Hmm, while this works, I think it is more logically done inside the parser/lexer in |
|
@mhvk parser and lexer have no role when making the table when provided with the data. |
|
@DShivansh : @mhvk is right. The Units are parsed here: https://github.com/astropy/astropy/blob/master/astropy/io/ascii/cds.py#L123 That line parses a string to the |
|
@hamogu yes, sorry while debugging I stepped over that function 😅, I'll move my code inside |
|
@hamogu I still think that although all the work is done inside the units/format/cds.py but while converting the column info to units to units there is no use of parser astropy/astropy/units/format/cds.py Line 81 in 72728ef and lexer astropy/astropy/units/format/cds.py Line 142 in 72728ef Please correct me if I am wrong. |
|
@DShivansh - I will have to correct you, sorry! The line So, I think you'll need to define p.s. So far, only the |
|
@mhvk can you please suggest whether the current implementation is correct or not? Should I now implement the test cases? |
|
@DShivansh - this looks OK, but I must admit that with the parser, I just never know... So, yes, do add test cases, both in Plus an entry under new features for 4.1. And of course be sure to remove the |
|
@mhvk can you please check whether my |
| raise ValueError("Function units cannot be written in {} format. " | ||
| "Only 'generic', 'unscaled' and 'latex' are " | ||
| "supported.".format(format)) | ||
| if format == 'cds': |
There was a problem hiding this comment.
I think this is the right idea, but it should not be here, but rather in DexUnit (which is the only one that is allowed to be overridden; CDS cannot reproduce mag and dB function units). I.e., create a new method to_string there which has your special case for CDS, but otherwise just does return super().to_string(....)
There was a problem hiding this comment.
Inside UnitDex what should I do if the format is not cds?
There was a problem hiding this comment.
return super().to_string(....)
There was a problem hiding this comment.
This comment still stands. We should be sure that, say, u.mag(u.Jy).to_string(format='cds') still raises an error - right now, I think it would incorrectly lead to [Jy]. Indeed, could you add a test that checks that this example continues raises ValueError? (Clearly, I should have done that myself when I introduced the functional units!)
|
@DShivansh - quick comment in-line. Please do add the test cases even if the code is not working yet, it makes thinking about changes much easier (and will tell you whether you got it right!). p.s. I'll be traveling the coming week, so responses may be slow. |
|
@mhvk can you please provide the readme with glob_header and multi_header that have the functional unit. |
|
@DShivansh - sorry, very quickly only: there are examples scattered throughout this PR and the original issue. The latter also has a link to a Vizier table which has them, might as well use the corresponding |
|
Hello @DShivansh 👋! It looks like you've made some changes in your pull request, so I've checked the code again for style. There are no PEP8 style issues with this pull request - thanks! 🎉 Comment last updated at 2020-03-03 20:04:58 UTC |
There was a problem hiding this comment.
@DShivansh - now had a chance to review in a bit more detail. Main comment is about the location of to_string; others are small but might as well address these too.
EDIT: Also needs a changelog entry! Also needs moving the changelog entry to the right section (4.1).
| raise ValueError("Function units cannot be written in {} format. " | ||
| "Only 'generic', 'unscaled' and 'latex' are " | ||
| "supported.".format(format)) | ||
| if format == 'cds': |
There was a problem hiding this comment.
This comment still stands. We should be sure that, say, u.mag(u.Jy).to_string(format='cds') still raises an error - right now, I think it would incorrectly lead to [Jy]. Indeed, could you add a test that checks that this example continues raises ValueError? (Clearly, I should have done that myself when I introduced the functional units!)
|
|
||
| # NOTE THE ORDERING OF THESE RULES IS IMPORTANT!! | ||
| # Regular expression rules for simple tokens | ||
| def t_OPEN_BRACKET(t): |
There was a problem hiding this comment.
Looking at format/generic.py for the definition of regular parentheses, I think these two can just be
t_OPEN_BRACKET = r'\['
t_CLOSE_BRACKET = r'\]'
I think we don't need the trailing $ either since the grammar rules only put these at the start and end anyway.
| data_and_readme = 'data/cdsFunctional.dat' | ||
| reader = ascii.get_reader(ascii.Cds) | ||
| table = reader.read(data_and_readme) | ||
| assert isinstance(table['logg'].unit, type(dex())) |
There was a problem hiding this comment.
I'd prefer to test explicitly that it is the right unit, so assert table['logg'].unit == u.dex(u.cm/u.s**2).
And might as well test the other units in the table too.
| if len(p) == 3: | ||
| p[0] = Unit(p[1] * p[2]) | ||
| elif len(p) == 4: | ||
| p[0] = dex(Unit(p[2])) |
There was a problem hiding this comment.
It doesn't matter too much but I think this can just be p[0] = dex(p[2]) (combined_unit is guaranteed to be a unit instance already).
mhvk
left a comment
There was a problem hiding this comment.
Looks OK, but two remaining little things.
| if format == 'cds': | ||
| return "[{}]".format(self.physical_unit.to_string(format=format)) | ||
| else: | ||
| self_str = self.function_unit.to_string(format) |
There was a problem hiding this comment.
No need to repeat code from above; as I noted in the original comment, you can just do
return super().to_string(format=format)
| def _quantity_class(self): | ||
| return Dex | ||
|
|
||
| def to_string(self, format = 'generic'): |
There was a problem hiding this comment.
No spaces around = for argument defaults.
Works by changing the parser to recognize the square brackets signature used by CDS for Dex. Also adjust Dex.to_string() to be able to output in that format.
mhvk
left a comment
There was a problem hiding this comment.
@DShivansh - looks all OK now, so approving! Note that I saw one left-over import and a missing CR, so I took the liberty to just fetching your PR, fixing those two items, and squashing all commits together (so the edits to io/ascii/cds.py do not enter the history). I also added one further commit with a few round-trip tests (something I had asked for but which slipped through the cracks before) - this ensures the to_string method is properly tested.
|
@mhvk thank you for correcting my PR. Can you please tell what is CR? sorry I forgot about the round-trip test case. |
|
@DShivansh - CR=carriage return (was one missing at the end of the data file; really didn't matter much at all). As tests pass, I'll merge this. Thanks again! |
Description
changes to support functional units in CDS tables.
Fixes #9946