Add a showtable script - #6859
Conversation
|
Hi there @saimn 👋 - 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. |
|
Missing:
Note that I created the file inside a new directory |
|
c/c @SaraOgaz in case this is of interest for STAK. |
| try: | ||
| table = Table.read(filename, **read_kwargs) | ||
| table.pprint(max_lines=args.max_lines, max_width=args.max_width, | ||
| show_unit=not args.hide_unit, show_dtype=args.show_dtype) |
There was a problem hiding this comment.
What about using table.more? Or maybe we could have a flag to switch between 'cat' mode (pprint) and 'more' mode?
There was a problem hiding this comment.
I never use Table.more so I had a look and yes it could useful to have an option. I prefer the "cat mode " as default as personally I'm used to pipe the output to less (or more) which allows to search (not possible with Table.more).
| def main(args=None): | ||
| """The main function called by the `showtable` script.""" | ||
| parser = argparse.ArgumentParser( | ||
| description=('Print tables from ASCII, FITS, HDF5, VOTable file(s).')) |
There was a problem hiding this comment.
I'd suggest putting some description here of the default output width / lines and how to control it. I think the fact that long/wide tables get clipped can be initially confusing. Something along the lines of:
The default behavior is make the table output fit onto a single screen page. For a
long and wide table this will mean cutting out inner rows and columns. To print
**all** the rows or columns use ``--max-lines=-1`` or ``max-width=-1``, respectively.
| addarg('--more', action='store_true', | ||
| help='Use the pager mode from Table.more.') | ||
| addarg('--max-lines', type=int, | ||
| help='Maximum number of lines in table output.') |
There was a problem hiding this comment.
Suggest help='Max number of lines in table output (default=screen length, -1 for no limit).'
Same idea for --max-width. (I replaced "Maximum" with "Max" so it will format slightly better, but maybe that's not necessary.)
There was a problem hiding this comment.
Thanks for the suggestions, I have done the changes (using Maximum as it will use 2 lines anyway).
| help='Include a header row for column dtypes.') | ||
|
|
||
| # ASCII-specific arguments | ||
| # FIXME: add more args ? (delimiter, guess ?) |
There was a problem hiding this comment.
I wonder if it would make sense to generalize this so that all the reader-specific kwargs are not initially pre-defined in the argparse parser. See e.g. for a hackish way to do this (which BTW doesn't totally work...)
https://stackoverflow.com/questions/37367331/is-it-possible-to-use-argparse-to-capture-an-arbitrary-set-of-optional-arguments
Probably a better option is to pre-code allowed options but use subparsers to keep them tidy and compartmentalized. E.g.
showtable ascii filename.dat --delimiter='|' --quotechar='"' --data-start=5
showtable ascii --help . # shows ascii subparser options
There was a problem hiding this comment.
I'm not sure it's useful to add all possible parameters, my idea was to add only the most frequent ones (delimiter is certainly useful). The issue with subparsers is that it prevents a more generic use where you don't have to know the file type in advance, Table.read is able to guess many formats. Also having to specify always a subparser is cumbersome !
|
Also, you could probably use this interface to print the results of |
|
Updated |
|
@saimn - About the subparser, or else generalized support for sub-format options, I think you need to think about this as a high-visibility script that will be around for 15 or 20 years. Pretty quickly we will add support for reading ASDF files, so that will result in at least one (if not more) new params. And with the mem-mapping in FITS it would make sense to add support in the API for reading in only some of the columns. Then a user will want the So I think that it is worth thinking hard about this script and future-proofing the UI, even if it means typing |
|
@taldcroft , your arguments make perfectly sense, (and I agree it's good to think about this now before the is widely used), despite that I would prefer to avoid subparsers. I think subparsers makes the command more complicated than what it should be, you can read a table with |
|
@saimn - agreed that we need to find a balance between overdesigning and getting into a mess down the road. I too am interested in other opinions. If you put in a general mechanism for handling any kwargs that are not parsed by argparse, then you get back to the simplicity but full generality of |
|
I have used argument groups to group arguments for each filetype, which gives a much better output I think (see below) and would allow to add a few more arguments while not being too messy. What do you think, compared to the sub-parsers option mentioned above, @taldcroft (and others - @astrofrog , @pllim , ... ? 😉 ) |
|
Ah, I didn't know about argument groups. That works for me and looks nice. I wonder if |
|
@taldcroft - Is it possible to force the Reader class used by the registry with a 'format' keyword ? Also there is a test error with end of lines on appveyor, with Table.info's output. Why is it different from Table.pprint ? |
|
@saimn , I like the grouping -- very nice! 👍 |
Are you talking about the Reader class in |
|
I mean for the general case, if I have an exotic fits extension is it possible to use |
|
Also the appveyor issue is fixed, so all tests pass, and argument groups seems to have the consensus. Anything else that should be added/modified ? |
taldcroft
left a comment
There was a problem hiding this comment.
More changes, but now I've looked through everything in some detail.
|
|
||
| - Allowed to remove table rows through the ``__delitem__`` method. [#5839] | ||
|
|
||
| - Added a new ``showtable`` command-line script to view binary tables. [#6859] |
There was a problem hiding this comment.
to view binary or ASCII table files.
| # ASCII-specific arguments | ||
| ascii_args = parser.add_argument_group('ASCII arguments') | ||
| addarg = ascii_args.add_argument | ||
| addarg('--format', help='input table format') |
There was a problem hiding this comment.
This should be moved out of the ASCII-specific args, since indeed one can specify format='fits' or 'hdf5' or 'ascii.ipac' etc.
| table output fit onto a single screen page. For a long and wide | ||
| table this will mean cutting out inner rows and columns. To print | ||
| **all** the rows or columns use ``--max-lines=-1`` or | ||
| ``max-width=-1``, respectively. |
There was a problem hiding this comment.
It would be useful for users to have a link to the complete list of available format values: http://astropy.readthedocs.io/en/latest/io/unified.html#built-in-table-readers-writers
| if args.info: | ||
| print(table.info) | ||
| elif args.stats: | ||
| table.info('stats') |
There was a problem hiding this comment.
For consistency you can write:
if args.info:
table.info('attributes')
elif args.stats:
table.info('stats')
else:
...
| def test_info(capsys): | ||
| showtable.main([os.path.join(FITS_ROOT, 'data/table.fits'), '--info']) | ||
| out, err = capsys.readouterr() | ||
| assert out == ('<Table length=3>{0}' |
There was a problem hiding this comment.
For reference one can do out.splitlines() == ['line 1', 'line2', etc..] to get around the OS-dependence. This is a bit easier for writing tests because you can write failing tests, run in the debugger, and then print out.splitlines() to get the right answer to paste into code (after verifying by hand that it seems right!).
There was a problem hiding this comment.
Yep, it's probably more handy for debugging, I will change.
| def test_fits(capsys): | ||
| showtable.main([os.path.join(FITS_ROOT, 'data/table.fits')]) | ||
| out, err = capsys.readouterr() | ||
| assert out == (' target V_mag\n' |
There was a problem hiding this comment.
I see tests are passing, but why don't these need the os.linesep fix? Is this a bug in Table.pprint that it isn't using os.linesep?
There was a problem hiding this comment.
The behavior differs (pprint just prints each line, whereas info writes to stdout using os.linesep explicitly) but I don't know what behavior is expected for terminal output (as far as I know the convention differs for files ?).
| NGC1002 12.3 | ||
| NGC1003 15.2 | ||
|
|
||
|
|
There was a problem hiding this comment.
Add something like
To get full documentation on the usage and available options do ``showtable --help``.
| @@ -0,0 +1,112 @@ | |||
| # -*- coding: utf-8 -*- | |||
|
|
|||
There was a problem hiding this comment.
On testing, I don't see tests for -max-lines, -hide-unit, and -show-dtype. Note that max_lines cannot be less than 7, and it applies to the header lines as well.
| else: | ||
| formatter = table.more if args.more else table.pprint | ||
| formatter(max_lines=args.max_lines, max_width=args.max_width, | ||
| show_unit=not args.hide_unit, show_dtype=args.show_dtype) |
There was a problem hiding this comment.
The show_unit arg is actually a 3-state argument:
- True: always put in a line for the unit
- False: never put in a line for the unit
- None (default): put in a line for the unit if any of the columns has a unit
What is probably wanted here for default is None, so you don't get those blank lines in many of the typical cases (like in most of the tests). So show_unit=(False if args.hide_unit else None). This doesn't allow for forcing a line for units no matter what, but I think that is fine.
There was a problem hiding this comment.
Indeed, I wanted None as default, thanks.
|
And now circleci fails because pytest-astropy requires pytest-mpl which installs matplotlib from source, oups! ping @drdavella (I think you already mentioned this issue somewhere?) |
|
Tests are passing now, good for you @taldcroft ? |
|
Thanks @saimn ! |
|
This breaks my work on numpy 1.14 style changes (#6959), since it explicitly tests output - which depends on numpy version, with no allowance for floats being Are such tests this really needed? Obviously I can make the tests numpy-version dependent, but it is not for nothing that in our doctests we use p.s. It took me a while to figure out why a |
|
See #6959 (comment) (which says): I think this is a case where we should be testing non-nice floating point values. The whole point of showtable is creating human-readable output that is informative and "pleasant". So using real-world values is important to catch formatting issues that our users will end up seeing. |
|
Hey @taldcroft, shouldn't we add this to the http://docs.astropy.org/en/stable/io/fits/usage/scripts.html doc page? |
|
Minor correction: http://docs.astropy.org/en/latest/io/fits/usage/scripts.html (but I don't see it there either) |
|
This page is for |
|
👍 on adding to the FITS page for scripts, since it is definitely applicable there. Unlike with code, I think it's generally OK to repeat yourself in docs to help with discoverability. (Of course there is an issue of maintaining all the docs to be accurate, but these scripts don't change that much.) I agree that having a top-level page with all scripts would be a fine thing as well. |

Closes #3022. I often miss such a script and there was an agreement in #3022. Basically it is just a wrapper around
Table.readandTable.pprintso it supports printing ascii, fits, votable and hdf5. I also added options specific to each format (see the script help below), suggestions welcome if you think some option is missing.