diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a8db991..a1aae28 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,9 +1,7 @@ - + - [ ] Closes #xxxx - [ ] Tests added - - [ ] Tests passed - - [ ] Passes ``flake8 pyorbital`` - [ ] Fully documented diff --git a/pyorbital/tests/test_tlefile.py b/pyorbital/tests/test_tlefile.py index d0d53e9..9fe78c2 100644 --- a/pyorbital/tests/test_tlefile.py +++ b/pyorbital/tests/test_tlefile.py @@ -3,10 +3,6 @@ # # Copyright (c) 2014-2023 Pytroll Community # -# Author(s): -# -# Martin Raspaud -# Panu Lahtinen # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,6 +21,7 @@ from pyorbital.tlefile import Tle +from pyorbital import tlefile from pyorbital.tlefile import (_get_config_path, read_platform_numbers, _get_local_tle_path_from_env, @@ -34,18 +31,65 @@ import logging import datetime +import pytest import unittest from unittest.mock import patch from unittest import mock -import pytest import os from contextlib import suppress import time +from pathlib import Path + line0 = "ISS (ZARYA)" line1 = "1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927" line2 = "2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537" + +def _write_fake_platforms_txt_file(platforms_filename) -> None: + with open(platforms_filename, 'w') as platforms_file: + platforms_file.write("""NOAA-18 28654 +NOAA-19 33591 +NOAA-20 43013 +NOAA-21 54234 +# ISS 25544 +""") + + +# NOAA 18 +# 1 28654U 05018A 23045.48509621 .00000446 00000+0 26330-3 0 9998 +# 2 28654 98.9223 120.4228 0014233 11.3574 348.7916 14.12862494914152 + +def _write_fake_tle_file(tlefilename: Path) -> None: + with open(tlefilename, "w") as tle_file: + tle_file.write("""NOAA 20 +1 43013U 17073A 23045.54907786 .00000253 00000+0 14081-3 0 9995 +2 43013 98.7419 345.5839 0001610 80.3742 279.7616 14.19558274271576 +NOAA 21 (JPSS-2) +1 54234U 22150A 23045.56664999 .00000332 00000+0 17829-3 0 9993 +2 54234 98.7059 345.5113 0001226 81.6523 278.4792 14.19543871 13653 +ISS (ZARYA) +1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927 +2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537 +""") + + +@pytest.fixture +def fake_platforms_txt_file(tmp_path: Path) -> Path: + """Make fake platforms.txt file.""" + filename = tmp_path / 'platforms.txt' + _write_fake_platforms_txt_file(filename) + yield filename + + +@pytest.fixture +def fake_tlefile(tmp_path: Path) -> Path: + """Make fake tle file.""" + filename = tmp_path / 'sometlefile.txt' + _write_fake_tle_file(filename) + yield filename + + line1_2 = "1 38771U 12049A 21137.30264622 .00000000 00000+0 -49996-5 0 00017" line2_2 = "2 38771 98.7162 197.7716 0002383 106.1049 122.6344 14.21477797449453" @@ -78,6 +122,48 @@ '')) +def test_read_tlefile_standard_platform_name(monkeypatch, fake_platforms_txt_file, fake_tlefile): + """Test create a tle-object by reading tle data from file. + + Use Oscar naming matching name in platforms.txt. + """ + path_to_platforms_txt_file = fake_platforms_txt_file.parent + monkeypatch.setenv('PPP_CONFIG_DIR', str(path_to_platforms_txt_file)) + + tle_n21 = tlefile.read('NOAA-21', str(fake_tlefile)) + assert tle_n21.line1 == '1 54234U 22150A 23045.56664999 .00000332 00000+0 17829-3 0 9993' + assert tle_n21.line2 == '2 54234 98.7059 345.5113 0001226 81.6523 278.4792 14.19543871 13653' + + +def test_read_tlefile_non_standard_platform_name(monkeypatch, fake_platforms_txt_file, fake_tlefile): + """Test create a tle-object by reading tle data from file. + + Use naming matching what is in the TLE files, but non-standard (non Oscar) naming. + """ + path_to_platforms_txt_file = fake_platforms_txt_file.parent + monkeypatch.setenv('PPP_CONFIG_DIR', path_to_platforms_txt_file) + + tle_n20 = tlefile.read('NOAA 20', str(fake_tlefile)) + + assert tle_n20.line1 == '1 43013U 17073A 23045.54907786 .00000253 00000+0 14081-3 0 9995' + assert tle_n20.line2 == '2 43013 98.7419 345.5839 0001610 80.3742 279.7616 14.19558274271576' + + +def test_read_tlefile_non_standard_platform_name_matching_start_of_name_in_tlefile(monkeypatch, + fake_platforms_txt_file, + fake_tlefile): + """Test create a tle-object by reading tle data from file. + + Use non-standard naming matching only the beginning of what is in the TLE files. + """ + path_to_platforms_txt_file = fake_platforms_txt_file.parent + monkeypatch.setenv('PPP_CONFIG_DIR', path_to_platforms_txt_file) + with pytest.raises(KeyError) as exc_info: + _ = tlefile.read('NOAA 21', str(fake_tlefile)) + + assert str(exc_info.value) == '"Found no TLE entry for \'NOAA 21\'"' + + @pytest.fixture def fake_platforms_file(tmp_path): """Return file path to a fake platforms.txt file.""" @@ -537,6 +623,7 @@ def test_read_tle_files(self): fname = os.path.join(save_dir.name, 'tle_20200129_1600.txt') with open(fname, 'w') as fid: fid.write(tle_text) + # Add a non-existent file, it shouldn't cause a crash nonexistent = os.path.join(save_dir.name, 'not_here.txt') # Use a wildcard to collect files (passed to glob) diff --git a/pyorbital/tlefile.py b/pyorbital/tlefile.py index d44d7e1..f8c2806 100644 --- a/pyorbital/tlefile.py +++ b/pyorbital/tlefile.py @@ -3,12 +3,6 @@ # # Copyright (c) 2011-2023 Pytroll Community # -# Author(s): -# -# Esben S. Nielsen -# Martin Raspaud -# Panu Lahtinen -# Will Evonosky # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,20 +16,19 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - """Classes and functions for handling TLE files.""" -import io -import logging -import datetime as dt -from urllib.request import urlopen -import os -import glob -import numpy as np -import requests -import sqlite3 -from xml.etree import ElementTree as ET from itertools import zip_longest +from xml.etree import ElementTree as ET +import sqlite3 +import requests +import numpy as np +import glob +import os +from urllib.request import urlopen +import datetime as dt +import logging +import io TLE_URLS = ('https://celestrak.org/NORAD/elements/active.txt', @@ -341,22 +334,27 @@ def _get_first_tle(uris, open_func, platform=''): def _get_tles_from_uris(uris, open_func, platform='', only_first=True): tles = [] - designator = "1 " + SATELLITES.get(platform, '') + _satellites = read_platform_numbers(get_platforms_filepath(), in_upper=True, num_as_int=False) + + designator = "1 " + _satellites.get(platform, '') for url in uris: fid = open_func(url) for l_0 in fid: tle = "" l_0 = _decode(l_0) + # This will make the all the tests pass, but not prety! + # So, should the new test case that fails added in a draft PR, Feb 15, 2023, be removed? + # if l_0.strip() == platform or l_0.startswith(platform) and 'NOAA' in platform: if l_0.strip() == platform: l_1 = _decode(next(fid)) l_2 = _decode(next(fid)) tle = l_1.strip() + "\n" + l_2.strip() - elif (platform in SATELLITES or not only_first) and l_0.strip().startswith(designator): + elif (platform in _satellites or not only_first) and l_0.strip().startswith(designator): l_1 = l_0 l_2 = _decode(next(fid)) tle = l_1.strip() + "\n" + l_2.strip() if platform: - LOGGER.debug("Found platform %s, ID: %s", platform, SATELLITES[platform]) + LOGGER.debug("Found platform %s, ID: %s", platform, _satellites[platform]) elif open_func == _dummy_open_stringio and l_0.startswith(designator): l_1 = l_0 l_2 = _decode(next(fid)) @@ -487,8 +485,10 @@ def collect_filenames(paths): def read_tles_from_mmam_xml_files(paths): - """Read TLEs from EUMETSAT MMAM XML files.""" - # Collect filenames + """Read TLE data from a list of MMAM XMl file (EUMETSAT). + + MMAM = Multi-Mission Administration Message + """ fnames = collect_filenames(paths) tles = [] for fname in fnames: @@ -500,7 +500,7 @@ def read_tles_from_mmam_xml_files(paths): def read_tle_from_mmam_xml_file(fname): - """Read TLEs from a EUMETSAT MMAM XML file.""" + """Read TLE data from MMAM XMl file (EUMETSAT).""" tree = ET.parse(fname) root = tree.getroot() data = []