skyfielders / python-skyfield

Elegant astronomy for Python
MIT License
1.38k stars 208 forks source link

[Suggestion]: Open TLE file from URL as Memory File #884

Closed gabriel-russo closed 5 months ago

gabriel-russo commented 11 months ago

Hello! I would like to know if there is a particular reason why the library cannot load a URL with TLEs in memory (without having to download it)

My need came from this piece of code in docs:

from skyfield.api import load, wgs84

stations_url = 'http://celestrak.org/NORAD/elements/stations.txt'
satellites = load.tle_file(stations_url)
print('Loaded', len(satellites), 'satellites')

After some reads and search in source code, i saw that it download the data everytime...

If i just want to make an operation with this data using tle_file without writing in disk?

So, i came up with this solution:

from skyfield.iokit import parse_tle_file
from requests import get
from io import BytesIO

def tle_file(url, ts=None, skip_names=False):
    req = get(
        url,
        stream=True,
    )

    with BytesIO(req.content) as f:
        return list(parse_tle_file(f, ts, skip_names))

if __name__ == "__main__":
    file = tle_file(
        "https://celestrak.org/NORAD/elements/gp.php?GROUP=active&FORMAT=tle"
    )

    print(file)

Output: [<EarthSatellite CALSPHERE 1 catalog #900 epoch 2023-08-06 12:47:27 UTC>, ...]

This code reuse the logic from parse_tle_file that expects an open binary file

I ask the community's opinion on this suggestion, and feel free to use this piece of code i made.

Regards,

PeterS-mBryonics commented 8 months ago

I've tested this, replacing load.tle in my code and it works just fine. My application doesn't need to store the TLE for any length of time so this is perfect. I'm loading one TLE at a time.

brandon-rhodes commented 7 months ago

Thank you for the example code, @gabriel-russo! Apologies that I have not replied quickly—but since it sounded like you had already put together a good solution, I assumed there was no urgency and that your project was not blocked waiting for me to reply.

Now that I have read over your example in detail, and re-read Skyfield's code, my first thoughts are:

  1. Yes, the design of parse_tle_file() was intended to allow an in-memory file to be read; that is why it takes a file object, without having any opinion about where the file comes from, or whether it really exists on disk.
  2. Was it difficult to find the parse_tle_file() function? It is documented in the Skyfield documentation in one of the API sections — but, if you instead found it by reading code, then maybe that section of the documentation is too hard to find?
  3. I am a bit confused by your statement that you “saw that it download the data everytime”. Unless the code has become broken, load.tle_file() should only download the file the first time, because its default is reload=False. Have you observed the opposite behavior, that the file downloads more than once? If so, we should try to get that fixed for you.
  4. If I am correct, isn’t it your copy of the code that does a download every time? It looks like your code would require a fresh download every single time the program runs, possibly putting strain on the servers at celestrak.org (which is why Skyfield avoids extra downloads when it can). But maybe not, since that is what you were complaining that load.tle_file() does? Please clarify whether your code does a download every time.
  5. Given that it was difficult for you to find, would you recommend that the documentation show both load.tle_file() and parse_tle_file() examples on the main page about satellites, instead of only describing parse_tle_file() over in the API documentation? Would that have helped you solve your problem faster?

Again, thanks for including example code with your question!

brandon-rhodes commented 5 months ago

I have added a BytesIO example to the docs. It should appear on the website with the next release.