From 09fa1a39feadfac92ff138aefc8bebc79626d65b Mon Sep 17 00:00:00 2001 From: Zach Date: Sun, 9 May 2021 07:56:10 -0400 Subject: [PATCH] move members into submodules --- examples/read_text_file.py | 2 +- packetraven/__main__.py | 31 ++- packetraven/connections/__init__.py | 9 + packetraven/{ => connections}/base.py | 9 + packetraven/connections/file.py | 164 +++++++++++++ .../internet.py} | 222 +----------------- packetraven/connections/serial.py | 59 +++++ packetraven/gui/__init__.py | 1 + packetraven/{gui.py => gui/base.py} | 11 +- packetraven/{ => gui}/plotting.py | 2 +- packetraven/packets/__init__.py | 1 + packetraven/{packets.py => packets/base.py} | 2 +- packetraven/{ => packets}/parsing.py | 4 +- packetraven/{ => packets}/structures.py | 0 packetraven/{ => packets}/tracks.py | 2 +- packetraven/{ => packets}/writer.py | 2 +- packetraven/predicts.py | 8 +- tests/test_database.py | 2 +- tests/test_packets.py | 2 +- tests/test_parser.py | 2 +- tests/test_structures.py | 2 +- tests/test_writer.py | 4 +- 22 files changed, 292 insertions(+), 249 deletions(-) create mode 100644 packetraven/connections/__init__.py rename packetraven/{ => connections}/base.py (92%) create mode 100644 packetraven/connections/file.py rename packetraven/{connections.py => connections/internet.py} (66%) create mode 100644 packetraven/connections/serial.py create mode 100644 packetraven/gui/__init__.py rename packetraven/{gui.py => gui/base.py} (99%) rename packetraven/{ => gui}/plotting.py (98%) create mode 100644 packetraven/packets/__init__.py rename packetraven/{packets.py => packets/base.py} (99%) rename packetraven/{ => packets}/parsing.py (98%) rename packetraven/{ => packets}/structures.py (100%) rename packetraven/{ => packets}/tracks.py (99%) rename packetraven/{ => packets}/writer.py (98%) diff --git a/examples/read_text_file.py b/examples/read_text_file.py index ae347d88..f81c5f20 100644 --- a/examples/read_text_file.py +++ b/examples/read_text_file.py @@ -1,5 +1,5 @@ from packetraven import RawAPRSTextFile -from packetraven.tracks import APRSTrack +from packetraven.packets.tracks import APRSTrack if __name__ == '__main__': filename = 'http://bpp.umd.edu/archives/Launches/NS-95_2020-11-07/APRS/W3EAX-11/W3EAX-11_raw_NS95.txt' diff --git a/packetraven/__main__.py b/packetraven/__main__.py index 435ee71e..6c4c6314 100644 --- a/packetraven/__main__.py +++ b/packetraven/__main__.py @@ -11,7 +11,6 @@ import humanize as humanize import numpy -from packetraven.base import PacketSource from packetraven.connections import ( APRSDatabaseTable, APRSfi, @@ -22,11 +21,12 @@ SerialTNC, TimeIntervalError, ) +from packetraven.connections.base import PacketSource from packetraven.packets import APRSPacket +from packetraven.packets.tracks import APRSTrack, LocationPacketTrack +from packetraven.packets.writer import write_packet_tracks from packetraven.predicts import PredictionAPIURL, PredictionError, get_predictions -from packetraven.tracks import APRSTrack, LocationPacketTrack from packetraven.utilities import get_logger, read_configuration, repository_root -from packetraven.writer import write_packet_tracks LOGGER = get_logger('packetraven', log_format='%(asctime)s | %(message)s') @@ -490,8 +490,9 @@ def retrieve_packets( ) packet_track.sort() try: - coordinate_string = ', '.join(f'{coordinate:.3f}°' - for coordinate in packet_track.coordinates[-1, :2]) + coordinate_string = ', '.join( + f'{coordinate:.3f}°' for coordinate in packet_track.coordinates[-1, :2] + ) logger.info( f'{callsign:8} - packet #{len(packet_track):<3} - ({coordinate_string}, {packet_track.coordinates[-1, 2]:9.2f}m)' f'; packet time is {packet_time} ({humanize.naturaltime(current_time - packet_time)}, {packet_track.intervals[-1]:6.1f} s interval)' @@ -508,18 +509,22 @@ def retrieve_packets( / numpy.timedelta64(1, 's') ) try: - message = f'{callsign:8} - ' \ - f'altitude: {packet_track.altitudes[-1]:6.1f} m' \ - f'; avg. ascent rate: {numpy.mean(packet_track.ascent_rates[packet_track.ascent_rates > 0]):5.1f} m/s' \ - f'; avg. descent rate: {numpy.mean(packet_track.ascent_rates[packet_track.ascent_rates < 0]):5.1f} m/s' \ - f'; avg. ground speed: {numpy.mean(packet_track.ground_speeds):5.1f} m/s' \ - f'; avg. packet interval: {numpy.mean(packet_track.intervals):6.1f} s' + message = ( + f'{callsign:8} - ' + f'altitude: {packet_track.altitudes[-1]:6.1f} m' + f'; avg. ascent rate: {numpy.mean(packet_track.ascent_rates[packet_track.ascent_rates > 0]):5.1f} m/s' + f'; avg. descent rate: {numpy.mean(packet_track.ascent_rates[packet_track.ascent_rates < 0]):5.1f} m/s' + f'; avg. ground speed: {numpy.mean(packet_track.ground_speeds):5.1f} m/s' + f'; avg. packet interval: {numpy.mean(packet_track.intervals):6.1f} s' + ) if packet_track.time_to_ground >= timedelta(seconds=0): landing_time = packet_time + packet_track.time_to_ground time_to_ground = current_time - landing_time - message += f'; estimated landing: {landing_time:%Y-%m-%d %H:%M:%S} ({humanize.naturaltime(time_to_ground)})' \ - f'; max altitude: {packet_track.coordinates[:, 2].max():.2f} m' + message += ( + f'; estimated landing: {landing_time:%Y-%m-%d %H:%M:%S} ({humanize.naturaltime(time_to_ground)})' + f'; max altitude: {packet_track.coordinates[:, 2].max():.2f} m' + ) logger.info(message) diff --git a/packetraven/connections/__init__.py b/packetraven/connections/__init__.py new file mode 100644 index 00000000..8f7ea275 --- /dev/null +++ b/packetraven/connections/__init__.py @@ -0,0 +1,9 @@ +from packetraven.connections.base import TimeIntervalError +from packetraven.connections.file import PacketGeoJSON, RawAPRSTextFile +from packetraven.connections.internet import ( + APRSDatabaseTable, + APRSfi, + APRSis, + PacketDatabaseTable, +) +from packetraven.connections.serial import SerialTNC diff --git a/packetraven/base.py b/packetraven/connections/base.py similarity index 92% rename from packetraven/base.py rename to packetraven/connections/base.py index 4533291a..6692e7ff 100644 --- a/packetraven/base.py +++ b/packetraven/connections/base.py @@ -5,6 +5,15 @@ from serial.tools import list_ports from packetraven.packets import APRSPacket, LocationPacket +from packetraven.utilities import get_logger, repository_root + +LOGGER = get_logger('connection') + +CREDENTIALS_FILENAME = repository_root() / 'credentials.config' + + +class TimeIntervalError(Exception): + pass class Connection(ABC): diff --git a/packetraven/connections/file.py b/packetraven/connections/file.py new file mode 100644 index 00000000..d2823120 --- /dev/null +++ b/packetraven/connections/file.py @@ -0,0 +1,164 @@ +from datetime import datetime +from os import PathLike +from pathlib import Path +from urllib.parse import urlparse + +from dateutil.parser import parse as parse_date +import geojson +import requests + +from packetraven.connections.base import ( + APRSPacketSource, + LOGGER, + PacketSource, + TimeIntervalError, +) +from packetraven.packets import APRSPacket, LocationPacket + + +class RawAPRSTextFile(APRSPacketSource): + def __init__(self, filename: PathLike = None, callsigns: str = None): + """ + read APRS packets from a given text file where each line consists of the time sent (`YYYY-MM-DDTHH:MM:SS`) followed by + a colon `:` and then the raw APRS string + + :param filename: path to text file + :param callsigns: list of callsigns to return from source + """ + + if not urlparse(str(filename)).scheme in ['http', 'https', 'ftp', 'sftp']: + if not isinstance(filename, Path): + if isinstance(filename, str): + filename = filename.strip('"') + filename = Path(filename) + filename = str(filename) + + super().__init__(filename, callsigns) + self.__last_access_time = None + self.__parsed_lines = [] + + @property + def packets(self) -> [APRSPacket]: + if self.__last_access_time is not None and self.interval is not None: + interval = datetime.now() - self.__last_access_time + if interval < self.interval: + raise TimeIntervalError( + f'interval {interval} less than minimum interval {self.interval}' + ) + + if Path(self.location).exists(): + file_connection = open(Path(self.location).expanduser().resolve()) + lines = file_connection.readlines() + else: + file_connection = requests.get(self.location, stream=True) + lines = file_connection.iter_lines() + + packets = [] + for line in lines: + if len(line) > 0: + if isinstance(line, bytes): + line = line.decode() + if line not in self.__parsed_lines: + self.__parsed_lines.append(line) + try: + packet_time, raw_aprs = line.split(': ', 1) + packet_time = parse_date(packet_time) + except: + raw_aprs = line + packet_time = datetime.now() + raw_aprs = raw_aprs.strip() + try: + packets.append( + APRSPacket.from_frame(raw_aprs, packet_time, source=self.location) + ) + except Exception as error: + LOGGER.error(f'{error.__class__.__name__} - {error}') + + file_connection.close() + + if self.callsigns is not None: + packets = [packet for packet in packets if packet.from_callsign in self.callsigns] + self.__last_access_time = datetime.now() + + return packets + + def close(self): + pass + + def __repr__(self): + return f'{self.__class__.__name__}({repr(self.location)}, {repr(self.callsigns)})' + + +class PacketGeoJSON(PacketSource): + def __init__(self, filename: PathLike = None): + """ + read location packets from a given GeoJSON file + + :param filename: path to GeoJSON file + """ + + if not urlparse(str(filename)).scheme in ['http', 'https', 'ftp', 'sftp']: + if not isinstance(filename, Path): + if isinstance(filename, str): + filename = filename.strip('"') + filename = Path(filename) + filename = str(filename) + + super().__init__(filename) + self.__last_access_time = None + + @property + def packets(self) -> [LocationPacket]: + if self.__last_access_time is not None and self.interval is not None: + interval = datetime.now() - self.__last_access_time + if interval < self.interval: + raise TimeIntervalError( + f'interval {interval} less than minimum interval {self.interval}' + ) + + if Path(self.location).exists(): + with open(Path(self.location).expanduser().resolve()) as file_connection: + features = geojson.load(file_connection) + else: + response = requests.get(self.location, stream=True) + features = geojson.loads(response.text) + + packets = [] + for feature in features['features']: + if feature['geometry']['type'] == 'Point': + properties = feature['properties'] + time = parse_date(properties['time']) + del properties['time'] + + if 'from' in properties: + from_callsign = properties['from'] + to_callsign = properties['to'] + del properties['from'], properties['to'] + + packet = APRSPacket( + from_callsign, + to_callsign, + time, + *feature['geometry']['coordinates'], + source=self.location, + **properties, + ) + else: + packet = LocationPacket( + time, + *feature['geometry']['coordinates'], + source=self.location, + **properties, + ) + + packets.append(packet) + + self.__last_access_time = datetime.now() + + return packets + + def close(self): + pass + + def __repr__(self): + return f'{self.__class__.__name__}({repr(self.location)})' diff --git a/packetraven/connections.py b/packetraven/connections/internet.py similarity index 66% rename from packetraven/connections.py rename to packetraven/connections/internet.py index 81ba0751..40977df9 100644 --- a/packetraven/connections.py +++ b/packetraven/connections/internet.py @@ -1,234 +1,26 @@ from datetime import datetime, timedelta -from os import PathLike -from pathlib import Path from time import sleep from typing import Any, Sequence -from urllib.parse import urlparse import aprslib -from dateutil.parser import parse as parse_date -import geojson import requests -from serial import Serial from shapely.geometry import Point from tablecrow import PostGresTable from tablecrow.utilities import split_hostname_port -from packetraven.packets import APRSPacket, LocationPacket -from packetraven.parsing import InvalidPacketError -from packetraven.utilities import get_logger, read_configuration, repository_root -from .base import ( +from packetraven.connections.base import ( APRSPacketSink, APRSPacketSource, + CREDENTIALS_FILENAME, + LOGGER, NetworkConnection, PacketSink, PacketSource, - next_open_serial_port, + TimeIntervalError, ) - -LOGGER = get_logger('connection') - -CREDENTIALS_FILENAME = repository_root() / 'credentials.config' - - -class TimeIntervalError(Exception): - pass - - -class SerialTNC(APRSPacketSource): - def __init__(self, serial_port: str = None, callsigns: [str] = None): - """ - Connect to TNC over given serial port. - - :param serial_port: port name - :param callsigns: list of callsigns to return from source - """ - - if serial_port is None or serial_port == '' or serial_port == 'auto': - try: - serial_port = next_open_serial_port() - except ConnectionError: - raise ConnectionError('could not find TNC connected to serial') - else: - serial_port = serial_port.strip('"') - - self.serial_connection = Serial(serial_port, baudrate=9600, timeout=1) - super().__init__(self.serial_connection.port, callsigns) - self.__last_access_time = None - - @property - def packets(self) -> [APRSPacket]: - if self.__last_access_time is not None and self.interval is not None: - interval = datetime.now() - self.__last_access_time - if interval < self.interval: - raise TimeIntervalError( - f'interval {interval} less than minimum interval {self.interval}' - ) - packets = [] - for line in self.serial_connection.readlines(): - try: - packet = APRSPacket.from_frame(line, source=self.location) - packets.append(packet) - except Exception as error: - LOGGER.error(f'{error.__class__.__name__} - {error}') - if self.callsigns is not None: - packets = [packet for packet in packets if packet.from_callsign in self.callsigns] - self.__last_access_time = datetime.now() - return packets - - def close(self): - self.serial_connection.close() - - def __repr__(self): - return f'{self.__class__.__name__}({repr(self.location)}, {repr(self.callsigns)})' - - -class RawAPRSTextFile(APRSPacketSource): - def __init__(self, filename: PathLike = None, callsigns: str = None): - """ - read APRS packets from a given text file where each line consists of the time sent (`YYYY-MM-DDTHH:MM:SS`) followed by - a colon `:` and then the raw APRS string - - :param filename: path to text file - :param callsigns: list of callsigns to return from source - """ - - if not urlparse(str(filename)).scheme in ['http', 'https', 'ftp', 'sftp']: - if not isinstance(filename, Path): - if isinstance(filename, str): - filename = filename.strip('"') - filename = Path(filename) - filename = str(filename) - - super().__init__(filename, callsigns) - self.__last_access_time = None - self.__parsed_lines = [] - - @property - def packets(self) -> [APRSPacket]: - if self.__last_access_time is not None and self.interval is not None: - interval = datetime.now() - self.__last_access_time - if interval < self.interval: - raise TimeIntervalError( - f'interval {interval} less than minimum interval {self.interval}' - ) - - if Path(self.location).exists(): - file_connection = open(Path(self.location).expanduser().resolve()) - lines = file_connection.readlines() - else: - file_connection = requests.get(self.location, stream=True) - lines = file_connection.iter_lines() - - packets = [] - for line in lines: - if len(line) > 0: - if isinstance(line, bytes): - line = line.decode() - if line not in self.__parsed_lines: - self.__parsed_lines.append(line) - try: - packet_time, raw_aprs = line.split(': ', 1) - packet_time = parse_date(packet_time) - except: - raw_aprs = line - packet_time = datetime.now() - raw_aprs = raw_aprs.strip() - try: - packets.append( - APRSPacket.from_frame(raw_aprs, packet_time, source=self.location) - ) - except Exception as error: - LOGGER.error(f'{error.__class__.__name__} - {error}') - - file_connection.close() - - if self.callsigns is not None: - packets = [packet for packet in packets if packet.from_callsign in self.callsigns] - self.__last_access_time = datetime.now() - - return packets - - def close(self): - pass - - def __repr__(self): - return f'{self.__class__.__name__}({repr(self.location)}, {repr(self.callsigns)})' - - -class PacketGeoJSON(PacketSource): - def __init__(self, filename: PathLike = None): - """ - read location packets from a given GeoJSON file - - :param filename: path to GeoJSON file - """ - - if not urlparse(str(filename)).scheme in ['http', 'https', 'ftp', 'sftp']: - if not isinstance(filename, Path): - if isinstance(filename, str): - filename = filename.strip('"') - filename = Path(filename) - filename = str(filename) - - super().__init__(filename) - self.__last_access_time = None - - @property - def packets(self) -> [LocationPacket]: - if self.__last_access_time is not None and self.interval is not None: - interval = datetime.now() - self.__last_access_time - if interval < self.interval: - raise TimeIntervalError( - f'interval {interval} less than minimum interval {self.interval}' - ) - - if Path(self.location).exists(): - with open(Path(self.location).expanduser().resolve()) as file_connection: - features = geojson.load(file_connection) - else: - response = requests.get(self.location, stream=True) - features = geojson.loads(response.text) - - packets = [] - for feature in features['features']: - if feature['geometry']['type'] == 'Point': - properties = feature['properties'] - time = parse_date(properties['time']) - del properties['time'] - - if 'from' in properties: - from_callsign = properties['from'] - to_callsign = properties['to'] - del properties['from'], properties['to'] - - packet = APRSPacket( - from_callsign, - to_callsign, - time, - *feature['geometry']['coordinates'], - source=self.location, - **properties, - ) - else: - packet = LocationPacket( - time, - *feature['geometry']['coordinates'], - source=self.location, - **properties, - ) - - packets.append(packet) - - self.__last_access_time = datetime.now() - - return packets - - def close(self): - pass - - def __repr__(self): - return f'{self.__class__.__name__}({repr(self.location)})' +from packetraven.packets import APRSPacket, LocationPacket +from packetraven.packets.parsing import InvalidPacketError +from packetraven.utilities import read_configuration class APRSfi(APRSPacketSource, NetworkConnection): diff --git a/packetraven/connections/serial.py b/packetraven/connections/serial.py new file mode 100644 index 00000000..0a0de7cf --- /dev/null +++ b/packetraven/connections/serial.py @@ -0,0 +1,59 @@ +from datetime import datetime + +from serial import Serial + +from packetraven.connections.base import ( + APRSPacketSource, + LOGGER, + TimeIntervalError, + next_open_serial_port, +) +from packetraven.packets import APRSPacket + + +class SerialTNC(APRSPacketSource): + def __init__(self, serial_port: str = None, callsigns: [str] = None): + """ + Connect to TNC over given serial port. + + :param serial_port: port name + :param callsigns: list of callsigns to return from source + """ + + if serial_port is None or serial_port == '' or serial_port == 'auto': + try: + serial_port = next_open_serial_port() + except ConnectionError: + raise ConnectionError('could not find TNC connected to serial') + else: + serial_port = serial_port.strip('"') + + self.serial_connection = Serial(serial_port, baudrate=9600, timeout=1) + super().__init__(self.serial_connection.port, callsigns) + self.__last_access_time = None + + @property + def packets(self) -> [APRSPacket]: + if self.__last_access_time is not None and self.interval is not None: + interval = datetime.now() - self.__last_access_time + if interval < self.interval: + raise TimeIntervalError( + f'interval {interval} less than minimum interval {self.interval}' + ) + packets = [] + for line in self.serial_connection.readlines(): + try: + packet = APRSPacket.from_frame(line, source=self.location) + packets.append(packet) + except Exception as error: + LOGGER.error(f'{error.__class__.__name__} - {error}') + if self.callsigns is not None: + packets = [packet for packet in packets if packet.from_callsign in self.callsigns] + self.__last_access_time = datetime.now() + return packets + + def close(self): + self.serial_connection.close() + + def __repr__(self): + return f'{self.__class__.__name__}({repr(self.location)}, {repr(self.callsigns)})' diff --git a/packetraven/gui/__init__.py b/packetraven/gui/__init__.py new file mode 100644 index 00000000..b22b650e --- /dev/null +++ b/packetraven/gui/__init__.py @@ -0,0 +1 @@ +from packetraven.gui.base import PacketRavenGUI diff --git a/packetraven/gui.py b/packetraven/gui/base.py similarity index 99% rename from packetraven/gui.py rename to packetraven/gui/base.py index 724c73a8..ef1ca112 100644 --- a/packetraven/gui.py +++ b/packetraven/gui/base.py @@ -14,14 +14,15 @@ from packetraven import APRSDatabaseTable, APRSfi, RawAPRSTextFile, SerialTNC from packetraven.__main__ import DEFAULT_INTERVAL_SECONDS, LOGGER, retrieve_packets -from packetraven.base import available_serial_ports, next_open_serial_port -from packetraven.connections import APRSis, PacketGeoJSON +from packetraven.connections.base import available_serial_ports, next_open_serial_port +from packetraven.connections.file import PacketGeoJSON +from packetraven.connections.internet import APRSis +from packetraven.gui.plotting import LivePlot from packetraven.packets import APRSPacket -from packetraven.plotting import LivePlot +from packetraven.packets.tracks import LocationPacketTrack, PredictedTrajectory +from packetraven.packets.writer import write_packet_tracks from packetraven.predicts import PredictionError, get_predictions -from packetraven.tracks import LocationPacketTrack, PredictedTrajectory from packetraven.utilities import get_logger -from packetraven.writer import write_packet_tracks class PacketRavenGUI: diff --git a/packetraven/plotting.py b/packetraven/gui/plotting.py similarity index 98% rename from packetraven/plotting.py rename to packetraven/gui/plotting.py index 034501f0..41f839dd 100644 --- a/packetraven/plotting.py +++ b/packetraven/gui/plotting.py @@ -4,7 +4,7 @@ from matplotlib.axes import Axes from matplotlib.figure import Figure -from packetraven.tracks import LocationPacketTrack, PredictedTrajectory +from packetraven.packets.tracks import LocationPacketTrack, PredictedTrajectory VARIABLES = { 'altitude': {'x': 'times', 'y': 'altitudes', 'xlabel': 'time', 'ylabel': 'altitude (m)'}, diff --git a/packetraven/packets/__init__.py b/packetraven/packets/__init__.py new file mode 100644 index 00000000..1e684766 --- /dev/null +++ b/packetraven/packets/__init__.py @@ -0,0 +1 @@ +from packetraven.packets.base import APRSPacket, DEFAULT_CRS, LocationPacket diff --git a/packetraven/packets.py b/packetraven/packets/base.py similarity index 99% rename from packetraven/packets.py rename to packetraven/packets/base.py index 3db1de51..1ea25775 100644 --- a/packetraven/packets.py +++ b/packetraven/packets/base.py @@ -5,7 +5,7 @@ import numpy from pyproj import CRS, Geod, Transformer -from packetraven.parsing import InvalidPacketError, parse_raw_aprs +from packetraven.packets.parsing import InvalidPacketError, parse_raw_aprs DEFAULT_CRS = CRS.from_epsg(4326) diff --git a/packetraven/parsing.py b/packetraven/packets/parsing.py similarity index 98% rename from packetraven/parsing.py rename to packetraven/packets/parsing.py index 68c50663..009ef6ce 100644 --- a/packetraven/parsing.py +++ b/packetraven/packets/parsing.py @@ -73,7 +73,7 @@ class InvalidPacketError(Exception): def decompress_longitude(compressed_longitude: str) -> float: """ - Decode longitude string from APRS compressed format (shifted ASCII in base 91) to a float. + Decode longitude string from APRS compressed format (shifted ASCII in model.py 91) to a float. :param compressed_longitude: compressed APRS longitude string :return: longitude @@ -91,7 +91,7 @@ def decompress_longitude(compressed_longitude: str) -> float: def decompress_latitude(compressed_latitude: str) -> float: """ - Decode latitude string from APRS compressed format (shifted ASCII in base 91) to a float. + Decode latitude string from APRS compressed format (shifted ASCII in model.py 91) to a float. :param compressed_latitude: compressed APRS latitude string :return: latitude diff --git a/packetraven/structures.py b/packetraven/packets/structures.py similarity index 100% rename from packetraven/structures.py rename to packetraven/packets/structures.py diff --git a/packetraven/tracks.py b/packetraven/packets/tracks.py similarity index 99% rename from packetraven/tracks.py rename to packetraven/packets/tracks.py index 0f150ad1..557ba2b8 100644 --- a/packetraven/tracks.py +++ b/packetraven/packets/tracks.py @@ -12,7 +12,7 @@ FREEFALL_SECONDS_TO_GROUND, ) from packetraven.packets import APRSPacket, DEFAULT_CRS, LocationPacket -from packetraven.structures import DoublyLinkedList +from packetraven.packets.structures import DoublyLinkedList class LocationPacketTrack: diff --git a/packetraven/writer.py b/packetraven/packets/writer.py similarity index 98% rename from packetraven/writer.py rename to packetraven/packets/writer.py index 949418a0..f6134a37 100644 --- a/packetraven/writer.py +++ b/packetraven/packets/writer.py @@ -7,7 +7,7 @@ from shapely.geometry import LineString from packetraven.packets import APRSPacket -from packetraven.tracks import APRSTrack, LocationPacketTrack +from packetraven.packets.tracks import APRSTrack, LocationPacketTrack KML_STANDARD = '{http://www.opengis.net/kml/2.2}' diff --git a/packetraven/predicts.py b/packetraven/predicts.py index 68b3a1d2..f3ff5731 100644 --- a/packetraven/predicts.py +++ b/packetraven/predicts.py @@ -10,7 +10,7 @@ from shapely.geometry import Point from packetraven.packets import LocationPacket -from packetraven.tracks import LocationPacketTrack, PredictedTrajectory +from packetraven.packets.tracks import LocationPacketTrack, PredictedTrajectory from packetraven.utilities import get_logger DEFAULT_ASCENT_RATE = 5.5 @@ -422,7 +422,7 @@ def get_predictions( if float_altitude is not None and not packet_track.falling: packets_at_float_altitude = packet_track[ numpy.abs(float_altitude - packet_track.altitudes) < float_altitude_uncertainty - ] + ] if ( len(packets_at_float_altitude) > 0 and packets_at_float_altitude[-1].time == packet_track.times[-1] @@ -461,7 +461,9 @@ def get_predictions( prediction = prediction_query.predict if packet_track.time_to_ground >= timedelta(seconds=0): - LOGGER.info(f'"{packet_track.name}" predicted landing location: {prediction.coordinates[-1]}') + LOGGER.info( + f'"{packet_track.name}" predicted landing location: {prediction.coordinates[-1]}' + ) prediction_tracks[name] = prediction diff --git a/tests/test_database.py b/tests/test_database.py index 68058cb3..9baf70df 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -9,7 +9,7 @@ from tablecrow.tables.postgres import PostGresTable, SSH_DEFAULT_PORT, database_has_table from tablecrow.utilities import split_hostname_port -from packetraven.connections import APRSDatabaseTable +from packetraven import APRSDatabaseTable from packetraven.packets import APRSPacket from packetraven.utilities import read_configuration, repository_root diff --git a/tests/test_packets.py b/tests/test_packets.py index 03c1dde4..cdd26dc1 100644 --- a/tests/test_packets.py +++ b/tests/test_packets.py @@ -4,7 +4,7 @@ import pytest from packetraven.packets import APRSPacket -from packetraven.tracks import APRSTrack +from packetraven.packets.tracks import APRSTrack def test_from_frame(): diff --git a/tests/test_parser.py b/tests/test_parser.py index 81583d0c..aecfe633 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1,6 +1,6 @@ import pytest -from packetraven.parsing import InvalidPacketError, parse_raw_aprs +from packetraven.packets.parsing import InvalidPacketError, parse_raw_aprs def test_parse_aprs_packet(): diff --git a/tests/test_structures.py b/tests/test_structures.py index 7b5e8bc9..fb28948a 100644 --- a/tests/test_structures.py +++ b/tests/test_structures.py @@ -1,4 +1,4 @@ -from packetraven.structures import DoublyLinkedList +from packetraven.packets.structures import DoublyLinkedList def test_index(): diff --git a/tests/test_writer.py b/tests/test_writer.py index a9f6c5f3..237b1d04 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -6,9 +6,9 @@ import pytz from packetraven.packets import APRSPacket -from packetraven.tracks import APRSTrack +from packetraven.packets.tracks import APRSTrack +from packetraven.packets.writer import write_packet_tracks from packetraven.utilities import repository_root -from packetraven.writer import write_packet_tracks REFERENCE_DIRECTORY = repository_root() / 'tests' / 'reference'