Closed aendie closed 2 years ago
In many cases, Python libraries are designed to allow errors through un-edited, since that gives the programmer the most information possible about the network error. Generally it's the application designer who knows better about how a transient error should be processed (displayed? replaced with another message? timeout and retry?). So my guess is that Skyfield should continue to let the real-life error through?
I can implement a ping test that I can trap myself, however I expected that a try ... except block (as above) should give me some kind of error message that I can test for. So, I'm not aware of of the best practices ... it's up to you. Thanks for the prompt response.
As these errors are operating-system dependent — it's error 11001 on Windows, but would be a different error with a different number or message on other operating systems — I think that applications should make their own plans about how to handle I/O rather than having Skyfield try to (probably imperfectly) catch and recognize the different errors from at least 3 different operating systems.
I'll try adding a note to the documentation reminding folks that they may want to do their own downloading if they want to be in full control of the process, and noting that their operating system might raise any kind of network error during the download.
Permit me to add my "simple" solution, in case it may help another user. I just didn't want the Python code to spew out that "unfriendly" message for users that just want to run my code (maybe in the middle of an ocean). I have tested this on Windows 10 and Ubuntu Desktop 20.04 LTS (and I think it should also work on MacOS).
It has a simple network connection test - the subject of network (or internet) connection testing is quite deep in fact. I deliberately only test for http://www.iers.org on port 80 (no SSL test; no test on the actual IERS download site, which is different to the URL I chose). My code calls ts = init_sf()
to initialize the Timescale object. I have slightly reduced the code here to form a MWE.
from skyfield import VERSION
from os import path
from skyfield.api import load
def compareVersion(versions1, version2):
#versions1 = [int(v) for v in version1.split(".")]
versions2 = [int(v) for v in version2.split(".")]
for i in range(max(len(versions1),len(versions2))):
v1 = versions1[i] if i < len(versions1) else 0
v2 = versions2[i] if i < len(versions2) else 0
if v1 > v2:
return 1
elif v1 < v2:
return -1
return 0
def isConnected():
try:
# connect to the host -- tells us if the host is actually reachable
sock = socket.create_connection(("www.iers.org", 80))
if sock is not None: sock.close
return True
except OSError:
pass
return False
def init_sf():
EOPdf = "finals2000A.all" # Earth Orientation Parameters data file
if compareVersion(VERSION, "1.31") >= 0:
if path.isfile(EOPdf):
if load.days_old(EOPdf) > 30.0: # > float(config.ageIERS)
if isConnected(): load.download(EOPdf)
else: print("NOTE: no Internet connection... using existing '{}'".format(EOPdf))
ts = load.timescale(builtin=False) # timescale object
else:
if isConnected():
load.download(EOPdf)
ts = load.timescale(builtin=False) # timescale object
else:
print("NOTE: no Internet connection... using built-in UT1-tables")
ts = load.timescale() # timescale object with built-in UT1-tables
else:
ts = load.timescale() # timescale object with built-in UT1-tables
return ts
Code is provided "as is", without a guarantee, and I am not responsible for any damage it may cause. (I know I don't need the compareVersion()
function, but what works I leave.)
Thanks for sharing example code! Hopefully it will help another user with a similar problem. I agree with you completely that “the subject of network (or internet) connection testing is quite deep in fact” — which makes me almost regret adding download()
in the first place, instead of showing people how to use a Python networking library themselves and avoid having Skyfield deal with the issue. Alas! What is done in an API cannot be undone.
When I have no network connection and the following code executes ...
I get the following console message (with Skyfield 1.37 and 1.39):![Error 11001](https://user-images.githubusercontent.com/13238632/138334764-33e016ae-5718-4ba8-86aa-96b8eaaca262.JPG)
Using the following try - except block didn't make the console message friendlier:
I only came across this by accident (while trying to code while charging my E-car a few blocks away), and the code works fine when I have a WiFi connection. Maybe the error handling can be improved in the case that one is offline? (Fortunately my car still reached maximum charge ... :-) I'm using Python 3.9.5, by the way.