For #391, set a very low bar for satellite names

Hopefully not too many users will get nonsense text as a result, and
hopefully those that do will see the option letting them avoid it.
This commit is contained in:
Brandon Rhodes 2020-06-15 22:46:37 -04:00
parent 9fe659a280
commit 94a307a9fa
3 changed files with 43 additions and 25 deletions

View File

@ -18,3 +18,5 @@ to download and open the data files they need in order to operate.
The directory where this loader looks when trying to open a file,
and where it downloads files that have not been downloaded yet.
.. autofunction:: parse_tle_file

View File

@ -37,9 +37,11 @@ for artificial satellites in Earth orbit:
the date on which an element set is most accurate —
of every TLE element set you use.
Elements are only useful for a week or two
on either side of the epoch date,
and for dates outside of that range
on either side of the epoch date.
For later dates,
you will want to download a fresh set of elements.
For earlier dates,
you will want to pull an old TLE from the archives.
4. Expect a satellites orbit to constantly change
as the SGP4 propagation routine models effects

View File

@ -244,7 +244,8 @@ class Loader(object):
d[name] = sat
return d
def tle_file(self, url, reload=False, filename=None, ts=None):
def tle_file(self, url, reload=False, filename=None,
ts=None, skip_names=False):
"""Load and parse a TLE file, returning a list of Earth satellites.
Given a URL or local path to an ASCII text file, this loads a
@ -252,12 +253,15 @@ class Loader(object):
:class:`~skyfield.sgp4lib.EarthSatellite` objects for them.
See :doc:`earth-satellites`.
See the :meth:`~skyfield.iokit.Loader.open()` documentation for
the meaning of the ``reload`` and ``filename`` parameters.
See the :meth:`~skyfield.iokit.Loader.open()` method for the
meaning of the ``reload`` and ``filename`` parameters.
See the :meth:`parse_tle_file()` function for the meaning of the
``ts`` and ``skip_names`` parameters.
"""
with self.open(url, reload=reload, filename=filename) as f:
return list(parse_tle_file(f, ts))
return list(parse_tle_file(f, ts, skip_names))
def open(self, url, mode='rb', reload=False, filename=None):
"""Open a file, downloading it first if it does not yet exist.
@ -421,30 +425,38 @@ def parse_tle(fileobj):
b0 = b1
b1 = b2
def parse_tle_file(lines, ts=None):
"""Parse TLE satellite elements, yielding a sequence of satellites.
def parse_tle_file(lines, ts=None, skip_names=False):
"""Parse lines of TLE satellite data, yielding a sequence of satellites.
Given a sequence ``lines`` of byte strings that contain TLE
Two-Line Element sets of satellite orbital elements, yields an
:class:`~skyfield.sgp4lib.EarthSatellite` for each pair of adjacent
lines that start with ``b"1 "`` and ``b"2 "`` and have 69 or more
characters each. If the preceding line looks like a name, it is set
as the satellites ``.name``. See :doc:`earth-satellites`.
Given a sequence ``lines`` of byte strings (which can be an open
binary file, which acts like a sequence of lines in Python), this
routine yields an :class:`~skyfield.sgp4lib.EarthSatellite` for each
pair of adjacent lines that start with ``"1 "`` and ``"2 "`` and
have 69 or more characters each. If the line preceding a TLE is not
part of another TLE, it is used as the satellites ``.name``.
An exception is raised if the attempt to parse a pair of candidate
lines as TLE elements fails.
If you pass a ``ts`` timescale, Skyfield will use it to build the
``.epoch`` date attribute on each satellite; otherwise a timescale
derived from Skyfields built-in leap second files will be used.
If for a particular file you see random lines of text being
interpreted as satellite names, set ``skip_names`` to ``True`` and
Skyfield will not try to store satellite names.
See :doc:`earth-satellites` for details. An exception is raised if
the attempt to parse a pair of candidate lines as TLE lines fails.
"""
b0 = b1 = b''
for b2 in lines:
if (b1.startswith(b'1 ') and len(b1) >= 69 and
b2.startswith(b'2 ') and len(b2) >= 69):
if (b2.startswith(b'2 ') and len(b2) >= 69 and
b1.startswith(b'1 ') and len(b1) >= 69):
b0 = b0.rstrip(b'\n\r')
if len(b0) == 24: # Celestrak
name = b0.decode('ascii').rstrip()
elif b0.startswith(b'0 '): # Spacetrack 3-line format
name = b0[2:].decode('ascii').rstrip()
if not skip_names and b0:
b0 = b0.rstrip(b' \n\r')
if b0.startswith(b'0 '):
b0 = b0[2:] # Spacetrack 3-line format
name = b0.decode('ascii')
else:
name = None
@ -452,8 +464,10 @@ def parse_tle_file(lines, ts=None):
line2 = b2.decode('ascii')
yield EarthSatellite(line1, line2, name, ts)
b0 = b1
b1 = b2
b0 = b1 = b''
else:
b0 = b1
b1 = b2
def download(url, path, verbose=None, blocksize=128*1024):
"""Download a file from a URL, possibly displaying a progress bar.