Skip to content

Handle missing or stale IERS-A better - #13052

Merged
taldcroft merged 10 commits into
astropy:mainfrom
taldcroft:iers-b-more-robust
Apr 22, 2022
Merged

taldcroft merged 10 commits into
astropy:mainfrom
taldcroft:iers-b-more-robust

Conversation

@taldcroft

@taldcroft taldcroft commented Apr 3, 2022 •

Copy link
Copy Markdown
Member

Description

This pull request is to partially address #9227 and #12998. I'm not sure this is a perfect solution but it is an idea. In particular:

  • Make a new config item conf.iers_degraded_accuracy which specifies the behavior when times are outside the range of IERS table, possible resulting in degraded time accuracy when converting scales.
  • The options are
    • 'error' (default)
    • 'warn' (issue a IERSDegradedAccuracyWarning)
    • 'ignore' (ignore the problem)

Independent of the above discussion, this PR changes the logic for auto-downloads to guarantee that no matter what happens with the IERS download operations, only warnings will be issued.

Fixes #12998

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.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see "When to rebase and squash commits".
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the Extra CI label.
  • Is a change log needed? If yes, did the change log check pass? If no, add the no-changelog-entry-needed label. If this is a manual backport, use the skip-changelog-checks label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • Is a milestone set? Milestone must be set but astropy-bot check might be missing; do not let the green checkmark fool you.
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate backport-X.Y.x label(s) before merge.

cc: @mhvk @bjweiner

@taldcroft taldcroft added this to the v5.1 milestone Apr 3, 2022
@github-actions

github-actions Bot commented Apr 3, 2022

Copy link
Copy Markdown
Contributor

👋 Thank you for your draft pull request! Do you know that you can use [ci skip] or [skip ci] in your commit messages to skip running continuous integration tests until you are ready?

@taldcroft
taldcroft force-pushed the iers-b-more-robust branch from cb6c4c8 to d041b0e Compare April 4, 2022 12:58
@adrn

adrn commented Apr 14, 2022

Copy link
Copy Markdown
Member

I think this is a sensible idea and would hopefully cause minimal pain for people who just want things to work and don't care about extreme precision. We can also have the exceptions point people to a docs page or note that explains how to disable the auto-download, and explains the risk and implications of doing this. I also think that this is sufficiently urgent that we should try to get something in to address this before the next release. I don't have a strong opinion on whether this should be a new configuration keyword or whether we should overload auto_download.

@eteq

eteq commented Apr 14, 2022 •

Copy link
Copy Markdown
Member

Broad brush I think this is a good idea, but I'm a bit worried about the questionable accuracy of " if the user explicitly opts out of getting the latest IERS data, then they understand what they are doing" 😉... That is, I think this is the sort of thing someone wouldn't necessarily recognize as having the stated effect because it seems like it's about downloading instead of time/coordinates accuracy. So something like either a different name than overloading auto_download or having the "False" in this PR instead be a special sentinal string like conf.auto_download = 'allow_degraded_accuracy'.

Will try to give a more thorough review ASAP - I agree with @adrn this is a high priority to try to get into next release

@eteq

eteq commented Apr 14, 2022

Copy link
Copy Markdown
Member

(and to clarify, I think this in particularly addresses the concern @bjweiner brought up in #12998 (comment), to tie things together a bit more )

@taldcroft
taldcroft force-pushed the iers-b-more-robust branch from d041b0e to 492b69b Compare April 19, 2022 19:02
@taldcroft

Copy link
Copy Markdown
Member Author

@adrn @eteq @mhvk - I updated this PR to add a new config parameter iers_degraded_accuracy. If this looks basically acceptable code-wise then I can work on finishing this up with supporting docs. If you have a better idea for the config parameter name then let me know.

I'm not sure the tests are written in the best way, I honestly have forgotten the details of making sure that there is no IERS data cached somewhere.

@taldcroft taldcroft changed the title WIP: Handle missing or stale IERS-B better Handle missing or stale IERS-B better Apr 19, 2022
@taldcroft

Copy link
Copy Markdown
Member Author

One failing test right now is a doctest that is complaining because it is trying to access network resources without +REMOTE_DATA:

044     >>> t = Time('J2010')
045     >>> obj = EarthLocation(-1*u.deg, 52*u.deg, height=10.*u.km)
046     >>> home = EarthLocation(-1*u.deg, 52*u.deg, height=0.*u.km)
047     >>> altaz_frame = AltAz(obstime=t, location=home)
048     >>> obj.get_itrs(t).transform_to(altaz_frame).alt # doctest: +FLOAT_CMP
UNEXPECTED EXCEPTION: IERSWarning('failed to download https://maia.usno.navy.mil/ser7/finals2000A.all: <urlopen error An attempt was made to connect to the internet by a test that was not marked `remote_data`. The requested host was: maia.usno.navy.mil>')
Traceback (most recent call last):

What I don't understand is why this was ever working. If I turn off the network on my laptop and run the doctest example, I get warnings saying that the code is trying to access the IERS site to get finals2000A.all. (And actually I don't quite understand why that is needed for a time of 2010.0, but never mind that).

The only thing I can think is that in my unit test I clear the download cache and maybe it was there before? But that doesn't make sense, I thought the tests are running in a clean (no cache files) environment.

Would it be OK to just add the +REMOTE_DATA doctest flag?

Astropy 5.0

In [1]:     >>> from astropy.coordinates import EarthLocation, AltAz
   ...:     >>> from astropy.time import Time
   ...:     >>> from astropy import units as u
   ...: 
   ...:     >>> t = Time('J2010')
   ...:     >>> obj = EarthLocation(-1*u.deg, 52*u.deg, height=10.*u.km)
   ...:     >>> home = EarthLocation(-1*u.deg, 52*u.deg, height=0.*u.km)
   ...:     >>> altaz_frame = AltAz(obstime=t, location=home)
   ...:     >>> obj.get_itrs(t).transform_to(altaz_frame).alt
WARNING: failed to download ftp://anonymous:mail%[email protected]/pub/products/iers/finals2000A.all and https://datacenter.iers.org/data/9/finals2000A.all, using local IERS-B: <urlopen error Unable to open any source! Exceptions were {'ftp://anonymous:mail%[email protected]/pub/products/iers/finals2000A.all': URLError(gaierror(8, 'nodename nor servname provided, or not known. requested URL: ftp://anonymous:mail%[email protected]/pub/products/iers/finals2000A.all')), 'https://datacenter.iers.org/data/9/finals2000A.all': URLError(gaierror(8, 'nodename nor servname provided, or not known. requested URL: ftp://anonymous:mail%[email protected]/pub/products/iers/finals2000A.all'))}> [astropy.utils.iers.iers]
Out[1]: <Latitude 86.32878441 deg>

In [2]: import astropy

In [3]: astropy.__version__
Out[3]: '5.0'

Thoughts @pllim?

@taldcroft
taldcroft marked this pull request as ready for review April 20, 2022 13:37
@eerovaher

Copy link
Copy Markdown
Member

Adding a new configuration item changed the example output at

Exploring Configuration
-----------------------
To see what configuration parameters are defined for a given ``conf``::
>>> from astropy.utils.iers import conf
>>> list(conf)
['auto_download',
'auto_max_age',
...,
'ietf_leap_second_auto_url']

The failure of that test means that the cleanup code is not executed, which causes more failures:
.. testcleanup::
>>> from astropy import config
>>> config.reload_config()
>>> from astropy.utils.iers import conf
>>> conf.auto_download = False

Updating the aforementioned example should be enough to ensure the doctests pass, there should be no need for any new +REMORE_DATA flags.

@taldcroft

Copy link
Copy Markdown
Member Author

Awesome @eerovaher thanks! I'll revert the changes I just made.

@taldcroft
taldcroft force-pushed the iers-b-more-robust branch from 28b739f to 572f0b0 Compare April 20, 2022 13:56
10.0,
'Remote timeout downloading IERS file data (seconds).')
iers_degraded_accuracy = _config.ConfigItem(
['error', 'warn', 'ignore'],

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.

The io.votable.verify configuration item accepts analogous values, but instead of 'error' it uses 'exception':

verify = _config.ConfigItem(
'ignore',
"Can be 'exception' (treat fixable violations of the VOTable spec as "
"exceptions), 'warn' (show warnings for VOTable spec violations), or "
"'ignore' (silently ignore VOTable spec violations)",

For the sake of consistency it would be better if 'exception' is used here too.

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.

Well there is metadata_conflicts with 'error', 'warn', and 'silent', and parse_strict with 'raise', 'warn', and 'silent'. I don't think there is any one answer that will get us to being "consistent". I came to 'error' and 'ignore' in part being consistent with Python warnings filter terminology.

Anyway, I don't feel too strongly since there is no right answer. @eerovaher - let me know if you still would like a change.

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.

It would be better to be consistent, but if the values used here are the same as the ones from Python warnings filtering then it looks like we should rather change the other values to match what is used here.

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.

OK, I'm just going to leave this.

@taldcroft

Copy link
Copy Markdown
Member Author

It looks like the diff code coverage is not running with remote_data. Is that right? The missing coverage it notes is definitely covered by the new tests that require remote data.

@taldcroft
taldcroft force-pushed the iers-b-more-robust branch from 572f0b0 to 6e8b6a0 Compare April 21, 2022 13:00
@taldcroft

Copy link
Copy Markdown
Member Author

@adrn @eteq @mhvk - I think this is fully ready now and should get into the release. Comments welcome.

@eerovaher eerovaher 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.

The code changes look good to me, but I have a couple of suggestions regarding the change log and what's new entries.

Comment thread docs/whatsnew/5.1.rst Resolved
Comment thread docs/changes/utils/13052.feature.rst Resolved
@adrn

adrn commented Apr 21, 2022

Copy link
Copy Markdown
Member

Thanks @taldcroft - I'll take a look over lunch today. (BTW: @eerovaher is a coordinates maintainer as well, so I also trust his eyes here!)

Comment thread astropy/utils/iers/iers.py Resolved
Comment thread astropy/utils/iers/iers.py Resolved
try:
filename = download_file(url, cache=True)
except Exception as err:
warn(f'failed to download {url}: {err}', IERSWarning)

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.

Suggested change
warn(f'failed to download {url}: {err}', IERSWarning)
warn(f'failed to download {url}: {repr(err)}', IERSWarning)

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.

@pllim - are you sure about wanting repr() here? I don't think that is common for exception messages since it turns newlines into the \n character and can otherwise make the output messy.

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.

Oh, I thought repr(err) was recommended in one of the PyCon talks a few years back. If you prefer not to use it, that is fine too.

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.

If you have a reference I'd be interested to look but for now let's leave it.

@pllim pllim Apr 21, 2022 •

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.

I don't feel like watching the talk right now but I remember ejeschke/ginga#767 that points to https://www.youtube.com/watch?v=V2fGAv2R5j8 , FWIW.

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 watched it and this is an interesting question:

In [3]: try:
   ...:     raise ValueError('blah\nblah\nblah\n')
   ...: except Exception as exc:
   ...:     print(f'failed to download: {repr(exc)}')
   ...: 
failed to download: ValueError('blah\nblah\nblah\n')

In [4]: try:
   ...:     raise ValueError('blah\nblah\nblah\n')
   ...: except Exception as exc:
   ...:     print(f'failed to download: {exc}')
   ...: 
failed to download: blah
blah
blah

I'm not sure about this, but I am definitely sure that I am tired of this PR.. 😄

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.

Let's leave it then. 😉

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd actually add !r for the repr (i.e., {exc!r}) - it is useful to know what the type of the exception was!

Comment thread astropy/utils/iers/iers.py Resolved
Comment thread astropy/utils/iers/tests/test_iers.py Resolved
Comment thread astropy/utils/iers/tests/test_iers.py Resolved
Comment thread astropy/utils/iers/tests/test_iers.py Resolved
Comment thread docs/changes/utils/13052.feature.rst Resolved

@pllim pllim 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.

Do these pages need updating too?

p.s. Sorry for the comment spam. I should have commented as part of a review but when I started, I didn't think I would have this many comments and then halfway through I thought it would be confusing to only have half the comments attached to the review... 😅

@taldcroft taldcroft changed the title Handle missing or stale IERS-B better Handle missing or stale IERS-A better Apr 21, 2022
@pep8speaks

pep8speaks commented Apr 21, 2022 •

Copy link
Copy Markdown

Hello @taldcroft 👋! 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 2022-04-21 21:58:52 UTC

Co-authored-by: P. L. Lim <[email protected]>
Co-authored-by: Eero Vaher <[email protected]>
@taldcroft

Copy link
Copy Markdown
Member Author

@pllim - yup, those narrative docs page need some attention too. Sigh, it's always the docs and testing that take so long!

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks like an excellent solution! One question/one nitpick.

try:
filename = download_file(all_urls[0], sources=all_urls, cache=True)
except Exception as err:
for url in all_urls:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why the loop? I thought the idea of sources in dowload_url is exactly to give different possible sources, but still count them as "the same file" for download purposes. Or is this to guard against a mirror providing a bad file? If it is not essential to the PR, I'd recommend not changing it here.

@taldcroft taldcroft Apr 21, 2022 •

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.

Probably needs an upstream fix but that was out of scope. If the first provided URL is not a valid URL then download_file raises an exception, even if one of the backup URL's can download successfully.

download_file('junk', sources=['junk', 'https://google.com'])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's bad and would seem a real bug in download_file. But maybe best not to try to work around it here?

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.

Actually the other reason (maybe more important) is that part of the point here is to not only ensure that some HTML page content got downloaded (which is all that download_file cares about), but that it is correct. That was one of the original problems with a site returning some text that was not the expected IERS table content and crashing later.

In short, we really do need a loop that tries each URL in turn, both downloading and validating the content.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OK, let's keep this as is then!

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.

If you want to pursue the download_file bug, we need to ping @aarchiba on the original intent of that implementation. FYI.

Comment thread docs/whatsnew/5.1.rst Resolved

@adrn adrn 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.

Thanks @taldcroft for this idea and PR! I had some other minor nitpicks/suggestions but overall think this is great and should get in to the next release.

Comment thread astropy/utils/iers/iers.py Resolved
Comment thread docs/whatsnew/5.1.rst Resolved
Comment thread docs/whatsnew/5.1.rst Outdated
desired or possible. Examples include an application where full accuracy is not
required, running on a cluster, or the rare instances when the IERS server and
mirror are not available. For these cases there is a new config item
`iers.conf.iers_degraded_accuracy <astropy.utils.iers.Conf.iers_degraded_accuracy>` which specifies the behavior when times are

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.

Suggested change
`iers.conf.iers_degraded_accuracy <astropy.utils.iers.Conf.iers_degraded_accuracy>` which specifies the behavior when times are
`iers.conf.iers_degraded_accuracy <astropy.utils.iers.Conf.iers_degraded_accuracy>`__ that specifies the behavior when times are

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.

Done.

@taldcroft
taldcroft force-pushed the iers-b-more-robust branch from 85d2bf0 to e5c9d06 Compare April 21, 2022 21:04
@taldcroft

Copy link
Copy Markdown
Member Author

Thanks for all the feedback all! 🤞 on tests and mostly RTD, but I think that I got all the suggestions in one way or another. @mhvk the 5.1.rst has a straggler long line again from @adrn, someone can fix it in another PR! 😄.

@pllim

This comment was marked as resolved.

@taldcroft
taldcroft force-pushed the iers-b-more-robust branch from e5c9d06 to 405ef42 Compare April 21, 2022 21:11
@taldcroft
taldcroft force-pushed the iers-b-more-robust branch from 405ef42 to b32e6aa Compare April 21, 2022 21:58
@taldcroft
taldcroft requested review from eerovaher and mhvk April 22, 2022 09:36
@taldcroft

Copy link
Copy Markdown
Member Author

CI is passing now!

@taldcroft
taldcroft merged commit 907047c into astropy:main Apr 22, 2022
@taldcroft
taldcroft deleted the iers-b-more-robust branch April 22, 2022 12:39
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.

datacenter.iers.org SSL: CERTIFICATE_VERIFY_FAILED (Column year failed to convert: invalid literal for int() with base 10: '<!')

7 participants