kopia lustrzana https://github.com/glidernet/python-ogn-client
switch from regex to rust parser
rodzic
082798870e
commit
ecd02840a0
|
@ -1,5 +1,8 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 2.0.0: unreleased
|
||||
- parser: use rust parser as default
|
||||
|
||||
## 1.3.3: - 2025-05-21
|
||||
- parser: use rust parser with option "use_rust_parser=True" (default for v2.0.0)
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
from ogn.parser import parse as parse_module # noqa: F40 --- only for test functions. Without this a mock of parse would mock the function instead of the module
|
||||
from ogn.parser.parse import parse, parse_aprs, parse_comment # noqa: F401
|
||||
from ogn.parser.parse import parse # noqa: F401
|
||||
from ogn.parser.exceptions import ParseError, AprsParseError, OgnParseError # noqa: F401
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
class BaseParser():
|
||||
def __init__(self):
|
||||
self.beacon_type = 'unknown'
|
||||
|
||||
def parse(self, aprs_comment, aprs_type):
|
||||
if aprs_type.startswith('position'):
|
||||
data = self.parse_position(aprs_comment)
|
||||
elif aprs_type.startswith('status'):
|
||||
data = self.parse_status(aprs_comment)
|
||||
else:
|
||||
raise ValueError(f"aprs_type '{aprs_type}' unknown")
|
||||
data.update({'beacon_type': self.beacon_type})
|
||||
return data
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
raise NotImplementedError(f"Position parser for parser '{self.beacon_type}' not yet implemented")
|
||||
|
||||
def parse_status(self, aprs_comment):
|
||||
raise NotImplementedError(f"Status parser for parser '{self.beacon_type}' not yet implemented")
|
|
@ -1,34 +0,0 @@
|
|||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.pattern import PATTERN_FANET_POSITION_COMMENT, PATTERN_FANET_STATUS_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class FanetParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'fanet'
|
||||
self.position_pattern = PATTERN_FANET_POSITION_COMMENT
|
||||
self.status_pattern = PATTERN_FANET_STATUS_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
result = {}
|
||||
if match.group('details'):
|
||||
result.update({
|
||||
'address_type': int(match.group('details'), 16) & 0b00000011,
|
||||
'aircraft_type': (int(match.group('details'), 16) & 0b01111100) >> 2,
|
||||
'stealth': (int(match.group('details'), 16) & 0b10000000) >> 7 == 1,
|
||||
'address': match.group('address')
|
||||
})
|
||||
if match.group('climb_rate'): result['climb_rate'] = int(match.group('climb_rate')) * FPM_TO_MS
|
||||
return result
|
||||
|
||||
def parse_status(self, aprs_comment):
|
||||
match = self.status_pattern.match(aprs_comment)
|
||||
result = {}
|
||||
if match.group('fanet_name'): result['fanet_name'] = match.group('fanet_name')
|
||||
if match.group('signal_quality'): result['signal_quality'] = float(match.group('signal_quality'))
|
||||
if match.group('frequency_offset'): result['frequency_offset'] = float(match.group('frequency_offset'))
|
||||
if match.group('error_count'): result['error_count'] = int(match.group('error_count'))
|
||||
|
||||
return result
|
|
@ -1,40 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_FLARM_POSITION_COMMENT
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class FlarmParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'flarm'
|
||||
self.position_pattern = PATTERN_FLARM_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
|
||||
result = {}
|
||||
if match.group('details'):
|
||||
result.update({
|
||||
'address_type': int(match.group('details'), 16) & 0b00000011,
|
||||
'aircraft_type': (int(match.group('details'), 16) & 0b00111100) >> 2,
|
||||
'no-tracking': (int(match.group('details'), 16) & 0b01000000) >> 6 == 1,
|
||||
'stealth': (int(match.group('details'), 16) & 0b10000000) >> 7 == 1,
|
||||
'address': match.group('address'),
|
||||
})
|
||||
if match.group('climb_rate'): result['climb_rate'] = int(match.group('climb_rate')) * FPM_TO_MS
|
||||
if match.group('turn_rate'): result['turn_rate'] = float(match.group('turn_rate')) * HPM_TO_DEGS
|
||||
if match.group('signal_quality'): result['signal_quality'] = float(match.group('signal_quality'))
|
||||
if match.group('error_count'): result['error_count'] = int(match.group('error_count'))
|
||||
if match.group('frequency_offset'): result['frequency_offset'] = float(match.group('frequency_offset'))
|
||||
if match.group('gps_quality'):
|
||||
result.update({
|
||||
'gps_quality': {
|
||||
'horizontal': int(match.group('gps_quality_horizontal')),
|
||||
'vertical': int(match.group('gps_quality_vertical'))
|
||||
}
|
||||
})
|
||||
if match.group('software_version'): result['software_version'] = float(match.group('software_version'))
|
||||
if match.group('hardware_version'): result['hardware_version'] = int(match.group('hardware_version'), 16)
|
||||
if match.group('real_address'): result['real_address'] = match.group('real_address')
|
||||
if match.group('signal_power'): result['signal_power'] = float(match.group('signal_power'))
|
||||
return result
|
|
@ -1,12 +0,0 @@
|
|||
from .base import BaseParser
|
||||
|
||||
|
||||
class GenericParser(BaseParser):
|
||||
def __init__(self, beacon_type='unknown'):
|
||||
self.beacon_type = beacon_type
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
return {'comment': aprs_comment}
|
||||
|
||||
def parse_status(self, aprs_comment):
|
||||
return {'comment': aprs_comment}
|
|
@ -1,16 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_INREACH_POSITION_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class InreachParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'inreach'
|
||||
self.position_pattern = PATTERN_INREACH_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
return {'address': match.group('id'),
|
||||
'model': match.group('model') if match.group('model') else None,
|
||||
'status': match.group('status') == 'True' if match.group('status') else None,
|
||||
'pilot_name': match.group('pilot_name') if match.group('pilot_name') else None}
|
|
@ -1,16 +0,0 @@
|
|||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.pattern import PATTERN_LT24_POSITION_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class LT24Parser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'lt24'
|
||||
self.position_pattern = PATTERN_LT24_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
return {'lt24_id': match.group('lt24_id'),
|
||||
'climb_rate': int(match.group('climb_rate')) * FPM_TO_MS if match.group('climb_rate') else None,
|
||||
'source': match.group('source') if match.group('source') else None}
|
|
@ -1,23 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_MICROTRAK_POSITION_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class MicrotrakParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'microtrak'
|
||||
self.position_pattern = PATTERN_MICROTRAK_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
|
||||
result = {}
|
||||
if match.group('details'):
|
||||
result.update({
|
||||
'address_type': int(match.group('details'), 16) & 0b00000011,
|
||||
'aircraft_type': (int(match.group('details'), 16) & 0b00111100) >> 2,
|
||||
'no-tracking': (int(match.group('details'), 16) & 0b01000000) >> 6 == 1,
|
||||
'stealth': (int(match.group('details'), 16) & 0b10000000) >> 7 == 1,
|
||||
'address': match.group('address'),
|
||||
})
|
||||
return result
|
|
@ -1,21 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_NAVITER_POSITION_COMMENT
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class NaviterParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'naviter'
|
||||
self.position_pattern = PATTERN_NAVITER_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
return {'stealth': (int(match.group('details'), 16) & 0b1000000000000000) >> 15 == 1,
|
||||
'do_not_track': (int(match.group('details'), 16) & 0b0100000000000000) >> 14 == 1,
|
||||
'aircraft_type': (int(match.group('details'), 16) & 0b0011110000000000) >> 10,
|
||||
'address_type': (int(match.group('details'), 16) & 0b0000001111110000) >> 4,
|
||||
'reserved': (int(match.group('details'), 16) & 0b0000000000001111),
|
||||
'address': match.group('address'),
|
||||
'climb_rate': int(match.group('climb_rate')) * FPM_TO_MS if match.group('climb_rate') else None,
|
||||
'turn_rate': float(match.group('turn_rate')) * HPM_TO_DEGS if match.group('turn_rate') else None}
|
|
@ -1,92 +0,0 @@
|
|||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
from ogn.parser.pattern import PATTERN_RECEIVER_BEACON, PATTERN_AIRCRAFT_BEACON
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class OgnParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = None
|
||||
self.aircraft_pattern = PATTERN_AIRCRAFT_BEACON
|
||||
self.receiver_pattern = PATTERN_RECEIVER_BEACON
|
||||
|
||||
def parse(self, aprs_comment, aprs_type):
|
||||
if not aprs_comment:
|
||||
return {'beacon_type': 'aprs_receiver'}
|
||||
|
||||
ab_data = self.parse_aircraft_beacon(aprs_comment)
|
||||
if ab_data:
|
||||
ab_data.update({'beacon_type': 'aprs_aircraft'})
|
||||
return ab_data
|
||||
|
||||
rb_data = self.parse_receiver_beacon(aprs_comment)
|
||||
if rb_data:
|
||||
rb_data.update({'beacon_type': 'aprs_receiver'})
|
||||
return rb_data
|
||||
else:
|
||||
return {'user_comment': aprs_comment,
|
||||
'beacon_type': 'aprs_receiver'}
|
||||
|
||||
def parse_aircraft_beacon(self, aprs_comment):
|
||||
match = self.aircraft_pattern.match(aprs_comment)
|
||||
if match:
|
||||
result = {}
|
||||
if match.group('details'):
|
||||
result.update({
|
||||
'address_type': int(match.group('details'), 16) & 0b00000011,
|
||||
'aircraft_type': (int(match.group('details'), 16) & 0b00111100) >> 2,
|
||||
'no-tracking': (int(match.group('details'), 16) & 0b01000000) >> 6 == 1,
|
||||
'stealth': (int(match.group('details'), 16) & 0b10000000) >> 7 == 1,
|
||||
'address': match.group('address'),
|
||||
})
|
||||
if match.group('climb_rate'): result['climb_rate'] = int(match.group('climb_rate')) * FPM_TO_MS
|
||||
if match.group('turn_rate'): result['turn_rate'] = float(match.group('turn_rate')) * HPM_TO_DEGS
|
||||
if match.group('flight_level'): result['flightlevel'] = float(match.group('flight_level'))
|
||||
if match.group('signal_quality'): result['signal_quality'] = float(match.group('signal_quality'))
|
||||
if match.group('errors'): result['error_count'] = int(match.group('errors'))
|
||||
if match.group('frequency_offset'): result['frequency_offset'] = float(match.group('frequency_offset'))
|
||||
if match.group('gps_quality'):
|
||||
result.update({
|
||||
'gps_quality': {
|
||||
'horizontal': int(match.group('gps_quality_horizontal')),
|
||||
'vertical': int(match.group('gps_quality_vertical'))
|
||||
}
|
||||
})
|
||||
if match.group('flarm_software_version'): result['software_version'] = float(match.group('flarm_software_version'))
|
||||
if match.group('flarm_hardware_version'): result['hardware_version'] = int(match.group('flarm_hardware_version'), 16)
|
||||
if match.group('flarm_id'): result['real_address'] = match.group('flarm_id')
|
||||
if match.group('signal_power'): result['signal_power'] = float(match.group('signal_power'))
|
||||
if match.group('proximity'): result['proximity'] = [hear[4:] for hear in match.group('proximity').split(' ')]
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
def parse_receiver_beacon(self, aprs_comment):
|
||||
match = self.receiver_pattern.match(aprs_comment)
|
||||
if match:
|
||||
result = {
|
||||
'version': match.group('version'),
|
||||
'platform': match.group('platform'),
|
||||
'cpu_load': float(match.group('cpu_load')),
|
||||
'free_ram': float(match.group('ram_free')),
|
||||
'total_ram': float(match.group('ram_total')),
|
||||
'ntp_error': float(match.group('ntp_offset')),
|
||||
'rt_crystal_correction': float(match.group('ntp_correction'))
|
||||
}
|
||||
if match.group('voltage'): result['voltage'] = float(match.group('voltage'))
|
||||
if match.group('amperage'): result['amperage'] = float(match.group('amperage'))
|
||||
if match.group('cpu_temperature'): result['cpu_temp'] = float(match.group('cpu_temperature'))
|
||||
if match.group('visible_senders'): result['senders_visible'] = int(match.group('visible_senders'))
|
||||
if match.group('senders'): result['senders_total'] = int(match.group('senders'))
|
||||
if match.group('latency'): result['latency'] = float(match.group('latency'))
|
||||
if match.group('rf_correction_manual'): result['rec_crystal_correction'] = int(match.group('rf_correction_manual'))
|
||||
if match.group('rf_correction_automatic'): result['rec_crystal_correction_fine'] = float(match.group('rf_correction_automatic'))
|
||||
if match.group('signal_quality'): result['rec_input_noise'] = float(match.group('signal_quality'))
|
||||
if match.group('senders_signal_quality'): result['senders_signal'] = float(match.group('senders_signal_quality'))
|
||||
if match.group('senders_messages'): result['senders_messages'] = float(match.group('senders_messages'))
|
||||
if match.group('good_senders_signal_quality'): result['good_senders_signal'] = float(match.group('good_senders_signal_quality'))
|
||||
if match.group('good_senders'): result['good_senders'] = float(match.group('good_senders'))
|
||||
if match.group('good_and_bad_senders'): result['good_and_bad_senders'] = float(match.group('good_and_bad_senders'))
|
||||
return result
|
||||
else:
|
||||
return None
|
|
@ -1,45 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_RECEIVER_POSITION_COMMENT, PATTERN_RECEIVER_STATUS_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class ReceiverParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'receiver'
|
||||
self.position_pattern = PATTERN_RECEIVER_POSITION_COMMENT
|
||||
self.status_pattern = PATTERN_RECEIVER_STATUS_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
if aprs_comment is None:
|
||||
return {}
|
||||
else:
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
return {'user_comment': match.group('user_comment') if match.group('user_comment') else None}
|
||||
|
||||
def parse_status(self, aprs_comment):
|
||||
match = self.status_pattern.match(aprs_comment)
|
||||
result = {
|
||||
'version': match.group('version'),
|
||||
'platform': match.group('platform'),
|
||||
'cpu_load': float(match.group('cpu_load')),
|
||||
'free_ram': float(match.group('ram_free')),
|
||||
'total_ram': float(match.group('ram_total')),
|
||||
'ntp_error': float(match.group('ntp_offset')),
|
||||
}
|
||||
|
||||
if match.group('ntp_correction'): result['rt_crystal_correction'] = float(match.group('ntp_correction'))
|
||||
if match.group('voltage'): result['voltage'] = float(match.group('voltage'))
|
||||
if match.group('amperage'): result['amperage'] = float(match.group('amperage'))
|
||||
if match.group('cpu_temperature'): result['cpu_temp'] = float(match.group('cpu_temperature'))
|
||||
if match.group('visible_senders'): result['senders_visible'] = int(match.group('visible_senders'))
|
||||
if match.group('senders'): result['senders_total'] = int(match.group('senders'))
|
||||
if match.group('rf_correction_manual'): result['rec_crystal_correction'] = int(match.group('rf_correction_manual'))
|
||||
if match.group('rf_correction_automatic'): result['rec_crystal_correction_fine'] = float(match.group('rf_correction_automatic'))
|
||||
if match.group('signal_quality'): result['rec_input_noise'] = float(match.group('signal_quality'))
|
||||
if match.group('senders_signal_quality'): result['senders_signal'] = float(match.group('senders_signal_quality'))
|
||||
if match.group('senders_messages'): result['senders_messages'] = float(match.group('senders_messages'))
|
||||
if match.group('good_senders_signal_quality'): result['good_senders_signal'] = float(match.group('good_senders_signal_quality'))
|
||||
if match.group('good_senders'): result['good_senders'] = float(match.group('good_senders'))
|
||||
if match.group('good_and_bad_senders'): result['good_and_bad_senders'] = float(match.group('good_and_bad_senders'))
|
||||
|
||||
return result
|
|
@ -1,32 +0,0 @@
|
|||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.pattern import PATTERN_SAFESKY_POSITION_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class SafeskyParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'safesky'
|
||||
self.position_pattern = PATTERN_SAFESKY_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
result = dict()
|
||||
if match.group('details'):
|
||||
result.update({
|
||||
'address_type': int(match.group('details'), 16) & 0b00000011,
|
||||
'aircraft_type': (int(match.group('details'), 16) & 0b00111100) >> 2,
|
||||
'no-tracking': (int(match.group('details'), 16) & 0b01000000) >> 6 == 1,
|
||||
'stealth': (int(match.group('details'), 16) & 0b10000000) >> 7 == 1,
|
||||
'address': match.group('address'),
|
||||
})
|
||||
result.update(
|
||||
{'climb_rate': int(match.group('climb_rate')) * FPM_TO_MS if match.group('climb_rate') else None})
|
||||
if match.group('gps_quality'):
|
||||
result.update({
|
||||
'gps_quality': {
|
||||
'horizontal': int(match.group('gps_quality_horizontal')),
|
||||
'vertical': int(match.group('gps_quality_vertical'))
|
||||
}
|
||||
})
|
||||
return result
|
|
@ -1,15 +0,0 @@
|
|||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.pattern import PATTERN_SKYLINES_POSITION_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class SkylinesParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'skylines'
|
||||
self.position_pattern = PATTERN_SKYLINES_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
return {'skylines_id': match.group('skylines_id'),
|
||||
'climb_rate': int(match.group('climb_rate')) * FPM_TO_MS if match.group('climb_rate') else None}
|
|
@ -1,16 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_SPIDER_POSITION_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class SpiderParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'spider'
|
||||
self.position_pattern = PATTERN_SPIDER_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
return {'spider_id': match.group('spider_id'),
|
||||
'signal_power': int(match.group('signal_power')) if match.group('signal_power') else None,
|
||||
'spider_registration': match.group('spider_registration') if match.group('spider_registration') else None,
|
||||
'gps_quality': match.group('gps_quality') if match.group('gps_quality') else None}
|
|
@ -1,15 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_SPOT_POSITION_COMMENT
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class SpotParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'spot'
|
||||
self.position_pattern = PATTERN_SPOT_POSITION_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
return {'spot_id': match.group('spot_id'),
|
||||
'model': match.group('model') if match.group('model') else None,
|
||||
'status': match.group('status') if match.group('status') else None}
|
|
@ -1,59 +0,0 @@
|
|||
from ogn.parser.pattern import PATTERN_TRACKER_POSITION_COMMENT, PATTERN_TRACKER_STATUS_COMMENT
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
|
||||
from .base import BaseParser
|
||||
|
||||
|
||||
class TrackerParser(BaseParser):
|
||||
def __init__(self):
|
||||
self.beacon_type = 'tracker'
|
||||
self.position_pattern = PATTERN_TRACKER_POSITION_COMMENT
|
||||
self.status_pattern = PATTERN_TRACKER_STATUS_COMMENT
|
||||
|
||||
def parse_position(self, aprs_comment):
|
||||
match = self.position_pattern.match(aprs_comment)
|
||||
|
||||
result = {}
|
||||
if match.group('details'):
|
||||
result.update({
|
||||
'address_type': int(match.group('details'), 16) & 0b00000011,
|
||||
'aircraft_type': (int(match.group('details'), 16) & 0b01111100) >> 2,
|
||||
'stealth': (int(match.group('details'), 16) & 0b10000000) >> 7 == 1,
|
||||
'address': match.group('address'),
|
||||
})
|
||||
if match.group('climb_rate'): result['climb_rate'] = int(match.group('climb_rate')) * FPM_TO_MS
|
||||
if match.group('turn_rate'): result['turn_rate'] = float(match.group('turn_rate')) * HPM_TO_DEGS
|
||||
if match.group('flight_level'): result['flightlevel'] = float(match.group('flight_level'))
|
||||
if match.group('signal_quality'): result['signal_quality'] = float(match.group('signal_quality'))
|
||||
if match.group('error_count'): result['error_count'] = int(match.group('error_count'))
|
||||
if match.group('frequency_offset'): result['frequency_offset'] = float(match.group('frequency_offset'))
|
||||
if match.group('gps_quality'):
|
||||
result.update({
|
||||
'gps_quality': {
|
||||
'horizontal': int(match.group('gps_quality_horizontal')),
|
||||
'vertical': int(match.group('gps_quality_vertical'))
|
||||
}
|
||||
})
|
||||
if match.group('signal_power'): result['signal_power'] = float(match.group('signal_power'))
|
||||
return result
|
||||
|
||||
def parse_status(self, aprs_comment):
|
||||
match = self.status_pattern.match(aprs_comment)
|
||||
if match:
|
||||
result = {}
|
||||
|
||||
if match.group('hardware_version'): result['hardware_version'] = int(match.group('hardware_version'))
|
||||
if match.group('software_version'): result['software_version'] = int(match.group('software_version'))
|
||||
if match.group('gps_satellites'): result['gps_satellites'] = int(match.group('gps_satellites'))
|
||||
if match.group('gps_quality'): result['gps_quality'] = int(match.group('gps_quality'))
|
||||
if match.group('gps_altitude'): result['gps_altitude'] = int(match.group('gps_altitude'))
|
||||
if match.group('pressure'): result['pressure'] = float(match.group('pressure'))
|
||||
if match.group('temperature'): result['temperature'] = float(match.group('temperature'))
|
||||
if match.group('humidity'): result['humidity'] = int(match.group('humidity'))
|
||||
if match.group('voltage'): result['voltage'] = float(match.group('voltage'))
|
||||
if match.group('transmitter_power'): result['transmitter_power'] = int(match.group('transmitter_power'))
|
||||
if match.group('noise_level'): result['noise_level'] = float(match.group('noise_level'))
|
||||
if match.group('relays'): result['relays'] = int(match.group('relays'))
|
||||
return result
|
||||
else:
|
||||
return {'comment': aprs_comment}
|
|
@ -1,23 +1,7 @@
|
|||
from datetime import datetime, timezone
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS, createTimestamp, parseAngle, KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER, INCH_TO_MM, fahrenheit_to_celsius, CheapRuler, normalized_quality
|
||||
from ogn.parser.pattern import PATTERN_APRS, PATTERN_APRS_POSITION, PATTERN_APRS_POSITION_WEATHER, PATTERN_APRS_STATUS, PATTERN_SERVER
|
||||
from ogn.parser.exceptions import AprsParseError, OgnParseError
|
||||
|
||||
from ogn.parser.aprs_comment.ogn_parser import OgnParser
|
||||
from ogn.parser.aprs_comment.fanet_parser import FanetParser
|
||||
from ogn.parser.aprs_comment.lt24_parser import LT24Parser
|
||||
from ogn.parser.aprs_comment.naviter_parser import NaviterParser
|
||||
from ogn.parser.aprs_comment.flarm_parser import FlarmParser
|
||||
from ogn.parser.aprs_comment.tracker_parser import TrackerParser
|
||||
from ogn.parser.aprs_comment.receiver_parser import ReceiverParser
|
||||
from ogn.parser.aprs_comment.skylines_parser import SkylinesParser
|
||||
from ogn.parser.aprs_comment.spider_parser import SpiderParser
|
||||
from ogn.parser.aprs_comment.spot_parser import SpotParser
|
||||
from ogn.parser.aprs_comment.inreach_parser import InreachParser
|
||||
from ogn.parser.aprs_comment.safesky_parser import SafeskyParser
|
||||
from ogn.parser.aprs_comment.microtrak_parser import MicrotrakParser
|
||||
from ogn.parser.aprs_comment.generic_parser import GenericParser
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS, createTimestamp, KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER, INCH_TO_MM, fahrenheit_to_celsius, CheapRuler, normalized_quality
|
||||
from ogn.parser.exceptions import AprsParseError
|
||||
|
||||
from ogn_parser import parse as rust_parse
|
||||
|
||||
|
@ -45,7 +29,7 @@ mapping = {
|
|||
}
|
||||
|
||||
|
||||
def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use_server_timestamp=True, use_rust_parser=False):
|
||||
def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use_server_timestamp=True):
|
||||
global server_timestamp
|
||||
|
||||
if use_server_timestamp is True:
|
||||
|
@ -53,13 +37,16 @@ def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use
|
|||
elif reference_timestamp is None:
|
||||
reference_timestamp = datetime.now(timezone.utc)
|
||||
|
||||
if use_rust_parser:
|
||||
rust_response = rust_parse(aprs_message)[0]
|
||||
rust_messages = rust_parse(aprs_message)
|
||||
if rust_messages:
|
||||
rust_message = rust_messages[0]
|
||||
else:
|
||||
raise AprsParseError("Empty message")
|
||||
|
||||
message = {'raw_message': aprs_message, 'reference_timestamp': reference_timestamp}
|
||||
if parser_error := rust_response.get('parser_error'):
|
||||
message['aprs_type'] = 'comment'
|
||||
message['comment'] = str(parser_error)
|
||||
elif aprs_packet := rust_response.get('aprs_packet'):
|
||||
if parser_error := rust_message.get('parser_error'):
|
||||
raise AprsParseError(f"Parser error: {parser_error}")
|
||||
elif aprs_packet := rust_message.get('aprs_packet'):
|
||||
message.update({
|
||||
'aprs_type': 'position',
|
||||
'beacon_type': mapping.get(aprs_packet['to'], 'unknown'),
|
||||
|
@ -143,29 +130,21 @@ def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use
|
|||
if 'unparsed' in status: message["user_comment"] = status['unparsed']
|
||||
else:
|
||||
raise ValueError("WTF")
|
||||
elif server_comment := rust_response.get('servercomment'):
|
||||
elif server_comment := rust_message.get('server_comment'):
|
||||
message.update({
|
||||
'version': server_comment['version'],
|
||||
'timestamp': datetime.strptime(server_comment['timestamp'], "%d %b %Y %H:%M:%S %Z"),
|
||||
'timestamp': datetime.fromisoformat(server_comment['timestamp']),
|
||||
'server': server_comment['server'],
|
||||
'ip_address': server_comment['ip_address'],
|
||||
'port': server_comment['port'],
|
||||
'aprs_type': 'server'})
|
||||
elif comment := rust_response.get('comment'):
|
||||
elif comment := rust_message.get('comment'):
|
||||
message.update({
|
||||
'comment': comment['comment'],
|
||||
'aprs_type': 'comment'})
|
||||
else:
|
||||
raise ValueError("WTF")
|
||||
|
||||
else:
|
||||
message = parse_aprs(aprs_message, reference_timestamp=reference_timestamp)
|
||||
if message['aprs_type'] == 'position' or message['aprs_type'] == 'status':
|
||||
try:
|
||||
message.update(parse_comment(message['comment'], dstcall=message['dstcall'], aprs_type=message['aprs_type']))
|
||||
except Exception:
|
||||
raise OgnParseError(f"dstcall: {message['dstcall']}, aprs_type: {message['aprs_type']}, comment: {message['comment']}")
|
||||
|
||||
if message['aprs_type'].startswith('position') and calculate_relations is True:
|
||||
positions[message['name']] = (message['longitude'], message['latitude'])
|
||||
if message['receiver_name'] in positions:
|
||||
|
@ -178,132 +157,3 @@ def parse(aprs_message, reference_timestamp=None, calculate_relations=False, use
|
|||
server_timestamp = message['timestamp']
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def parse_aprs(message, reference_timestamp=None):
|
||||
if reference_timestamp is None:
|
||||
reference_timestamp = datetime.now(timezone.utc)
|
||||
|
||||
result = {'raw_message': message,
|
||||
'reference_timestamp': reference_timestamp}
|
||||
|
||||
if message and message[0] == '#':
|
||||
match_server = PATTERN_SERVER.search(message)
|
||||
if match_server:
|
||||
result.update({
|
||||
'version': match_server.group('version'),
|
||||
'timestamp': datetime.strptime(match_server.group('timestamp'), "%d %b %Y %H:%M:%S %Z"),
|
||||
'server': match_server.group('server'),
|
||||
'ip_address': match_server.group('ip_address'),
|
||||
'port': match_server.group('port'),
|
||||
'aprs_type': 'server'})
|
||||
else:
|
||||
result.update({
|
||||
'comment': message,
|
||||
'aprs_type': 'comment'})
|
||||
else:
|
||||
match = PATTERN_APRS.search(message)
|
||||
if match:
|
||||
aprs_type = 'position' if match.group('aprs_type') == '/' else 'status' if match.group('aprs_type') == '>' else 'unknown'
|
||||
result.update({'aprs_type': aprs_type})
|
||||
aprs_body = match.group('aprs_body')
|
||||
if aprs_type == 'position':
|
||||
match_position = PATTERN_APRS_POSITION.search(aprs_body)
|
||||
if match_position:
|
||||
result.update({
|
||||
'name': match.group('callsign'),
|
||||
'dstcall': match.group('dstcall'),
|
||||
'relay': match.group('relay'),
|
||||
'receiver_name': match.group('receiver'),
|
||||
'timestamp': createTimestamp(match_position.group('time'), reference_timestamp),
|
||||
'latitude': parseAngle('0' + match_position.group('latitude') + (match_position.group('latitude_enhancement') or '0')) * # noqa: W504
|
||||
(-1 if match_position.group('latitude_sign') == 'S' else 1),
|
||||
'symboltable': match_position.group('symbol_table'),
|
||||
'longitude': parseAngle(match_position.group('longitude') + (match_position.group('longitude_enhancement') or '0')) * # noqa: W504
|
||||
(-1 if match_position.group('longitude_sign') == 'W' else 1),
|
||||
'symbolcode': match_position.group('symbol'),
|
||||
|
||||
'track': int(match_position.group('course')) if match_position.group('course_extension') else None,
|
||||
'ground_speed': int(match_position.group('ground_speed')) * KNOTS_TO_MS / KPH_TO_MS if match_position.group('ground_speed') else None,
|
||||
'altitude': int(match_position.group('altitude')) * FEETS_TO_METER if match_position.group('altitude') else None,
|
||||
|
||||
'comment': match_position.group('comment') if match_position.group('comment') else "",
|
||||
})
|
||||
return result
|
||||
|
||||
match_position_weather = PATTERN_APRS_POSITION_WEATHER.search(aprs_body)
|
||||
if match_position_weather:
|
||||
result.update({
|
||||
'aprs_type': 'position_weather',
|
||||
|
||||
'name': match.group('callsign'),
|
||||
'dstcall': match.group('dstcall'),
|
||||
'relay': match.group('relay'),
|
||||
'receiver_name': match.group('receiver'),
|
||||
'timestamp': createTimestamp(match_position_weather.group('time'), reference_timestamp),
|
||||
'latitude': parseAngle('0' + match_position_weather.group('latitude')) * # noqa: W504
|
||||
(-1 if match_position_weather.group('latitude_sign') == 'S' else 1),
|
||||
'symboltable': match_position_weather.group('symbol_table'),
|
||||
'longitude': parseAngle(match_position_weather.group('longitude')) * # noqa: W504
|
||||
(-1 if match_position_weather.group('longitude_sign') == 'W' else 1),
|
||||
'symbolcode': match_position_weather.group('symbol'),
|
||||
|
||||
'wind_direction': int(match_position_weather.group('wind_direction')) if match_position_weather.group('wind_direction') != '...' else None,
|
||||
'wind_speed': int(match_position_weather.group('wind_speed')) * KNOTS_TO_MS / KPH_TO_MS if match_position_weather.group('wind_speed') != '...' else None,
|
||||
'wind_speed_peak': int(match_position_weather.group('wind_speed_peak')) * KNOTS_TO_MS / KPH_TO_MS if match_position_weather.group('wind_speed_peak') != '...' else None,
|
||||
'temperature': fahrenheit_to_celsius(float(match_position_weather.group('temperature'))) if match_position_weather.group('temperature') != '...' else None,
|
||||
'rainfall_1h': int(match_position_weather.group('rainfall_1h')) / 100.0 * INCH_TO_MM if match_position_weather.group('rainfall_1h') else None,
|
||||
'rainfall_24h': int(match_position_weather.group('rainfall_24h')) / 100.0 * INCH_TO_MM if match_position_weather.group('rainfall_24h') else None,
|
||||
'humidity': int(match_position_weather.group('humidity')) * 0.01 if match_position_weather.group('humidity') else None,
|
||||
'barometric_pressure': int(match_position_weather.group('barometric_pressure')) if match_position_weather.group('barometric_pressure') else None,
|
||||
|
||||
'comment': match_position_weather.group('comment') if match_position_weather.group('comment') else "",
|
||||
})
|
||||
return result
|
||||
|
||||
raise AprsParseError(message)
|
||||
elif aprs_type == 'status':
|
||||
match_status = PATTERN_APRS_STATUS.search(aprs_body)
|
||||
if match_status:
|
||||
result.update({
|
||||
'name': match.group('callsign'),
|
||||
'dstcall': match.group('dstcall'),
|
||||
'receiver_name': match.group('receiver'),
|
||||
'timestamp': createTimestamp(match_status.group('time'), reference_timestamp),
|
||||
'comment': match_status.group('comment') if match_status.group('comment') else ""})
|
||||
else:
|
||||
raise NotImplementedError(message)
|
||||
else:
|
||||
raise AprsParseError(message)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
dstcall_parser_mapping = {'APRS': OgnParser(),
|
||||
'OGNFNT': FanetParser(),
|
||||
'OGFLR': FlarmParser(),
|
||||
'OGFLR6': FlarmParser(),
|
||||
'OGFLR7': FlarmParser(),
|
||||
'OGNTRK': TrackerParser(),
|
||||
'OGNSDR': ReceiverParser(),
|
||||
'OGCAPT': GenericParser(beacon_type='capturs'),
|
||||
'OGFLYM': GenericParser(beacon_type='flymaster'),
|
||||
'OGNINRE': InreachParser(),
|
||||
'OGLT24': LT24Parser(),
|
||||
'OGNAVI': NaviterParser(),
|
||||
'OGPAW': GenericParser(beacon_type='pilot_aware'),
|
||||
'OGSKYL': SkylinesParser(),
|
||||
'OGSPID': SpiderParser(),
|
||||
'OGSPOT': SpotParser(),
|
||||
'OGNSKY': SafeskyParser(),
|
||||
'OGNMTK': MicrotrakParser(),
|
||||
'GENERIC': GenericParser(beacon_type='unknown'),
|
||||
}
|
||||
|
||||
|
||||
def parse_comment(aprs_comment, dstcall='APRS', aprs_type="position"):
|
||||
parser = dstcall_parser_mapping.get(dstcall)
|
||||
if parser:
|
||||
return parser.parse(aprs_comment, aprs_type)
|
||||
else:
|
||||
return dstcall_parser_mapping.get('GENERIC').parse(aprs_comment, aprs_type)
|
||||
|
|
|
@ -1,136 +1,5 @@
|
|||
import re
|
||||
|
||||
PATTERN_APRS = re.compile(r"^(?P<callsign>.+?)>(?P<dstcall>[A-Z0-9]+)(,((?P<relay>[A-Za-z0-9]+)\*)?.*,(?P<receiver>.+?))?:(?P<aprs_type>(.))(?P<aprs_body>.*)$")
|
||||
PATTERN_APRS_POSITION = re.compile(r"^(?P<time>(([0-1]\d|2[0-3])[0-5]\d[0-5]\dh|([0-2]\d|3[0-1])([0-1]\d|2[0-3])[0-5]\dz))(?P<latitude>9000\.00|[0-8]\d{3}\.\d{2})(?P<latitude_sign>N|S)(?P<symbol_table>.)(?P<longitude>18000\.00|1[0-7]\d{3}\.\d{2}|0\d{4}\.\d{2})(?P<longitude_sign>E|W)(?P<symbol>.)(?P<course_extension>(?P<course>\d{3})/(?P<ground_speed>\d{3}))?(/A=(?P<altitude>(-\d{5}|\d{6})))?(?P<pos_extension>\s!W((?P<latitude_enhancement>\d)(?P<longitude_enhancement>\d))!)?(?:\s(?P<comment>.*))?$")
|
||||
PATTERN_APRS_POSITION_WEATHER = re.compile(r"^(?P<time>(([0-1]\d|2[0-3])[0-5]\d[0-5]\dh|([0-2]\d|3[0-1])([0-1]\d|2[0-3])[0-5]\dz))(?P<latitude>9000\.00|[0-8]\d{3}\.\d{2})(?P<latitude_sign>N|S)(?P<symbol_table>.)(?P<longitude>18000\.00|1[0-7]\d{3}\.\d{2}|0\d{4}\.\d{2})(?P<longitude_sign>E|W)(?P<symbol>.)(?P<wind_direction>(\d{3}|\.{3}))/(?P<wind_speed>(\d{3}|\.{3}))g(?P<wind_speed_peak>(\d{3}|\.{3}))t(?P<temperature>(\d{3}|\.{3}))(r(?P<rainfall_1h>\d{3}))?(p(?P<rainfall_24h>\d{3}))?(h(?P<humidity>\d{2}))?(b(?P<barometric_pressure>\d{5}))?(?:\s(?P<comment>.*))?$")
|
||||
PATTERN_APRS_STATUS = re.compile(r"^(?P<time>(([0-1]\d|2[0-3])[0-5]\d[0-5]\dh|([0-2]\d|3[0-1])([0-1]\d|2[0-3])[0-5]\dz))\s(?P<comment>.*)$")
|
||||
|
||||
PATTERN_SERVER = re.compile(r"^# aprsc (?P<version>[a-z0-9\.\-]+) (?P<timestamp>\d+ [A-Za-z]+ \d+ \d{2}:\d{2}:\d{2} GMT) (?P<server>[A-Z0-9]+) (?P<ip_address>\d+\.\d+\.\d+\.\d+):(?P<port>\d+)$")
|
||||
|
||||
PATTERN_FANET_POSITION_COMMENT = re.compile(r"""
|
||||
(id(?P<details>[\dA-F]{2})(?P<address>[\dA-F]{6}?)\s?)?
|
||||
(?:(?P<climb_rate>[+-]\d+)fpm)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_FANET_STATUS_COMMENT = re.compile(r"""
|
||||
(?:(Name=\"(?P<fanet_name>[^\"]*)\")\s?)?
|
||||
(?:(?P<signal_quality>[\d.]+?)dB\s?)?
|
||||
(?:(?P<frequency_offset>[+-][\d.]+?)kHz\s?)?
|
||||
(?:(?P<error_count>\d+)e\s?)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_FLARM_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<details>[\dA-F]{2})(?P<address>[\dA-F]{6}?)\s?
|
||||
(?:(?P<climb_rate>[+-]\d+?)fpm\s)?
|
||||
(?:(?P<turn_rate>[+-][\d.]+?)rot\s)?
|
||||
(?:(?P<signal_quality>[\d.]+?)dB\s)?
|
||||
(?:(?P<error_count>\d+)e\s)?
|
||||
(?:(?P<frequency_offset>[+-][\d.]+?)kHz\s?)?
|
||||
(?:gps(?P<gps_quality>(?P<gps_quality_horizontal>(\d+))x(?P<gps_quality_vertical>(\d+)))\s?)?
|
||||
(?:s(?P<software_version>[\d.]+)\s?)?
|
||||
(?:h(?P<hardware_version>[\dA-F]{2})\s?)?
|
||||
(?:r(?P<real_address>[\dA-F]+)\s?)?
|
||||
(?:(?P<signal_power>[+-][\d.]+)dBm\s?)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_LT24_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<lt24_id>\d+)\s
|
||||
(?P<climb_rate>[+-]\d+)fpm\s
|
||||
(?P<source>.+)
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_NAVITER_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<details>[\dA-F]{4})(?P<address>[\dA-F]{6})\s
|
||||
(?P<climb_rate>[+-]\d+)fpm\s
|
||||
(?P<turn_rate>[+-][\d.]+)rot
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_SKYLINES_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<skylines_id>\d+)\s
|
||||
(?P<climb_rate>[+-]\d+)fpm
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_SPIDER_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<spider_id>[\d-]+)\s
|
||||
(?P<signal_power>[+-]\d+)dB\s
|
||||
(?P<spider_registration>[A-Z0-9]+)\s
|
||||
(?P<gps_quality>.+)
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_SPOT_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<spot_id>[\d-]+)\s
|
||||
(?P<model>SPOT[A-Z\d]+)\s
|
||||
(?P<status>[A-Z]+)
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_INREACH_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<id>[\d]+)\s
|
||||
(?P<model>inReac[A-Za-z\d]*)\s
|
||||
(?P<status>[A-Za-z]+)\s?
|
||||
(?P<pilot_name>.+)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_TRACKER_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<details>[\dA-F]{2})(?P<address>[\dA-F]{6}?)\s?
|
||||
(?:(?P<climb_rate>[+-]\d+?)fpm\s)?
|
||||
(?:(?P<turn_rate>[+-][\d.]+?)rot\s)?
|
||||
(?:FL(?P<flight_level>[\d.]+)\s)?
|
||||
(?:(?P<signal_quality>[\d.]+?)dB\s)?
|
||||
(?:(?P<error_count>\d+)e\s)?
|
||||
(?:(?P<frequency_offset>[+-][\d.]+?)kHz\s?)?
|
||||
(?:gps(?P<gps_quality>(?P<gps_quality_horizontal>(\d+))x(?P<gps_quality_vertical>(\d+)))\s?)?
|
||||
(?:(?P<signal_power>[+-][\d.]+)dBm\s?)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_SAFESKY_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<details>[\dA-F]{2})(?P<address>[\dA-F]{6}?)\s?
|
||||
(?:(?P<climb_rate>[+-]\d+?)fpm\s)?
|
||||
(?:gps(?P<gps_quality>(?P<gps_quality_horizontal>(\d+))x(?P<gps_quality_vertical>(\d+)))?)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_MICROTRAK_POSITION_COMMENT = re.compile(r"""
|
||||
id(?P<details>[\dA-F]{2})(?P<address>[\dA-F]{6}?)\s?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_TRACKER_STATUS_COMMENT = re.compile(r"""
|
||||
h(?P<hardware_version>[\d]{2})\s
|
||||
v(?P<software_version>[\d]{2})\s?
|
||||
(?:(?P<gps_satellites>[\d]+)sat/(?P<gps_quality>\d)\s?)?
|
||||
(?:(?P<gps_altitude>\d+)m\s?)?
|
||||
(?:(?P<pressure>[\d.]+)hPa\s?)?
|
||||
(?:(?P<temperature>[+-][\d.]+)degC\s?)?
|
||||
(?:(?P<humidity>\d+)%\s?)?
|
||||
(?:(?P<voltage>[\d.]+)V\s?)?
|
||||
(?:(?P<transmitter_power>\d+)/(?P<noise_level>[+-][\d.]+)dBm\s?)?
|
||||
(?:(?P<relays>\d+)/min)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_RECEIVER_POSITION_COMMENT = re.compile(r"""
|
||||
(?:(?P<user_comment>.+))?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_RECEIVER_STATUS_COMMENT = re.compile(r"""
|
||||
(?:
|
||||
v(?P<version>\d+\.\d+\.\d+)
|
||||
(?:\.(?P<platform>.+?))?
|
||||
\s)?
|
||||
CPU:(?P<cpu_load>[\d.]+)\s
|
||||
RAM:(?P<ram_free>[\d.]+)/(?P<ram_total>[\d.]+)MB\s
|
||||
NTP:(?P<ntp_offset>[\d.]+)ms/(?P<ntp_correction>[+-][\d.]+)ppm\s
|
||||
(?:(?P<voltage>[\d.]+)V\s)?
|
||||
(?:(?P<amperage>[\d.]+)A\s)?
|
||||
(?:(?P<cpu_temperature>[+-][\d.]+)C\s*)?
|
||||
(?:(?P<visible_senders>\d+)/(?P<senders>\d+)Acfts\[1h\]\s*)?
|
||||
(?:RF:
|
||||
(?:
|
||||
(?P<rf_correction_manual>[+-][\d]+)
|
||||
(?P<rf_correction_automatic>[+-][\d.]+)ppm/
|
||||
)?
|
||||
(?P<signal_quality>[+-][\d.]+)dB
|
||||
(?:/(?P<senders_signal_quality>[+-][\d.]+)dB@10km\[(?P<senders_messages>\d+)\])?
|
||||
(?:/(?P<good_senders_signal_quality>[+-][\d.]+)dB@10km\[(?P<good_senders>\d+)/(?P<good_and_bad_senders>\d+)\])?
|
||||
)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
PATTERN_TELNET_50001 = re.compile(r"""
|
||||
(?P<pps_offset>\d\.\d+)sec:(?P<frequency>\d+\.\d+)MHz:\s+
|
||||
|
@ -156,69 +25,3 @@ PATTERN_TELNET_50001 = re.compile(r"""
|
|||
R?\s*
|
||||
(B(?P<baro_altitude>\d+))?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
# The following regexp patterns are part of the ruby ogn-client.
|
||||
# source: https://github.com/svoop/ogn_client-ruby
|
||||
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2015-2017 Sven Schwyn
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
PATTERN_RECEIVER_BEACON = re.compile(r"""
|
||||
(?:
|
||||
v(?P<version>\d+\.\d+\.\d+)
|
||||
(?:\.(?P<platform>.+?))?
|
||||
\s)?
|
||||
CPU:(?P<cpu_load>[\d.]+)\s
|
||||
RAM:(?P<ram_free>[\d.]+)/(?P<ram_total>[\d.]+)MB\s
|
||||
NTP:(?P<ntp_offset>[\d.]+)ms/(?P<ntp_correction>[+-][\d.]+)ppm\s?
|
||||
(?:(?P<voltage>[\d.]+)V\s)?
|
||||
(?:(?P<amperage>[\d.]+)A\s)?
|
||||
(?:(?P<cpu_temperature>[+-][\d.]+)C\s*)?
|
||||
(?:(?P<visible_senders>\d+)/(?P<senders>\d+)Acfts\[1h\]\s*)?
|
||||
(Lat\:(?P<latency>\d+\.\d+)s\s*)?
|
||||
(?:RF:
|
||||
(?:
|
||||
(?P<rf_correction_manual>[+-][\d]+)
|
||||
(?P<rf_correction_automatic>[+-][\d.]+)ppm/
|
||||
)?
|
||||
(?P<signal_quality>[+-][\d.]+)dB
|
||||
(?:/(?P<senders_signal_quality>[+-][\d.]+)dB@10km\[(?P<senders_messages>\d+)\])?
|
||||
(?:/(?P<good_senders_signal_quality>[+-][\d.]+)dB@10km\[(?P<good_senders>\d+)/(?P<good_and_bad_senders>\d+)\])?
|
||||
)?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
||||
|
||||
PATTERN_AIRCRAFT_BEACON = re.compile(r"""
|
||||
id(?P<details>[\dA-F]{2})(?P<address>[\dA-F]{6}?)\s?
|
||||
(?:(?P<climb_rate>[+-]\d+?)fpm\s)?
|
||||
(?:(?P<turn_rate>[+-][\d.]+?)rot\s)?
|
||||
(?:FL(?P<flight_level>[\d.]+)\s)?
|
||||
(?:(?P<signal_quality>[\d.]+?)dB\s)?
|
||||
(?:(?P<errors>\d+)e\s)?
|
||||
(?:(?P<frequency_offset>[+-][\d.]+?)kHz\s?)?
|
||||
(?:gps(?P<gps_quality>(?P<gps_quality_horizontal>(\d+))x(?P<gps_quality_vertical>(\d+)))\s?)?
|
||||
(?:s(?P<flarm_software_version>[\d.]+)\s?)?
|
||||
(?:h(?P<flarm_hardware_version>[\dA-F]{2})\s?)?
|
||||
(?:r(?P<flarm_id>[\dA-F]+)\s?)?
|
||||
(?:(?P<signal_power>[+-][\d.]+)dBm\s?)?
|
||||
(?:(?P<proximity>(hear[\dA-F]{4}\s?)+))?
|
||||
""", re.VERBOSE | re.MULTILINE)
|
||||
|
|
|
@ -283,115 +283,115 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "ogn-parser"
|
||||
version = "0.3.12"
|
||||
version = "0.3.13"
|
||||
description = "OGN message parser for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7afd232e5f0e335a6099145faca13f794e1482e706750c3ab4ad010ae629424"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe99f1024510752c160ac71650daeabe9c83fdf821dac26f5945603e9dec15cc"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa3e072e371e3288573b22fbeb1d27f1cba90c6a9381e67dbc7601a3232c705"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2dabe0417895c7b7b3390b842c08b12f73f7334595e0891d5d1756d7aa80889"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f2778332e896861028d751251579bda619adf9905209e24cfcf68854bd0866f"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89dc453975ad53db4f6986bb50f77eac20a02539698bc948f4d73a45e6256c64"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5272e9fe6c5519839b853aff6d2458caeaab72ca0fc69a55f1a4c1e100e7e5fe"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:66c02cf230090b4dd63b47fc276f65c8b0f48458aafa7aedf0dcf277d7f2b493"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9d6277bd3aaf2fcdd430c07975022b48e11aade46d05a798ccc8e35d52b7046a"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b7a6aa7508a61f96879e68a5eeb53184e39aaa6df3c78b941126fcc82f8abc4"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-win32.whl", hash = "sha256:8c8e57f89700c88ad34cc77d5b9683031ea94dc91f74150161ccdda2752a7d0a"},
|
||||
{file = "ogn_parser-0.3.12-cp310-cp310-win_amd64.whl", hash = "sha256:16c84cfa579c5cb347cc1e2f01dec37b88eaaaf09e1e91b0af1fe6040fee13c6"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c0220353bf0c49a9f28d3c2321240802f0fb5abddc3af891254d8d7c7f50650b"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f1332ad9cc966e87fce08610d1ddfce300fc51c9704c099d76c8e5151ddf7900"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c46559171711f91121fd0fb91c7c6926988e0ec22363b6ff96d37585161d9ba5"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd73b3644f653df05fe348eed0a2c1893823f23c594bad0b8dbc689c9984c3ed"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86acbb9756980d8f91790315aada4031c4bf7c3f25b561ff6fa152795f22e520"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb8ae10284ecbea29b004484c0266c47b96cd10b2cc73ad06c5c9ad2c96e411b"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da1a8186f9b2712179d48a49199f74b848836e624522066492eb9df5384ff104"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cb3a5f4be6ee3ca4b394890285eb5fa9bdae71f281a6da6159abc9ef478fb4f"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e6c92c9ebffefa724062957ef5c273e6e9f6c4e85e9540db56976e3e50bc634"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ff6552f7f423a970c2b281e441732650d7b16cea6894bb27ac4a25e106a55587"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2cf262565242d7e7017b29b7b6a1cbf6a85ed35320ee66b7b60429a46917a5bd"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9d0c8187c3a48f66a0df95c6459f4aefe1bd5314953e36f3020b9c67f0892335"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-win32.whl", hash = "sha256:6f2a9dcdc92d7b24fdaea3bdec21ea185ebba4a23b3dada42263ff000b244388"},
|
||||
{file = "ogn_parser-0.3.12-cp311-cp311-win_amd64.whl", hash = "sha256:b1db1e7629af85e62839fc2603b0ea1a7cc06bc89e66b29cb45a5304252c3d54"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b8376794e058ae747926ef633aaf0279972de11e89b44669c8f3d571b6d3e90d"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:548989f9c4a715cd281e6794994af68efe727f865713f24ed836ddb7198782c7"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713589c8cf94be8296fe381712542f58e5ad1e469342798f5eb6b67ce9c8f496"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7159503aa312dd65fa13a2d28d8e6fcc73e4ea074236cfbac8835a750b29f1a9"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49674fbf731ddfc2847fcee9f2187ac2a9b0eecc2a021a078771612a75532d29"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e786bb428ebe544a9a00675e8338b9c3e07b90b9179d192a62918148a3b54fa"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b67b91521af52fab703593efc212ff1d0aa72af20d23843b0d9ba7f97e31673c"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6816ccd0456db6911a618556786eb50ea50b09696daab15deb74bc9bcd7d2be8"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b1822a9c78af7a83c1eb6721da383191c071a745a45c69bbd66401bb77b5c25"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5e141984b33993b8c5e81bc1e0415f8628f4d115f4e8ea3e029b7c796f68398c"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:314f4e6ff8b2cc0ec98fab58e93fd5cab3c14dafaf9d1e37db40168cb615c4e7"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1c6e2e28dd81982db9516d81a4d50b7afd52a25d9883b7165b3e4a71d979dea"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-win32.whl", hash = "sha256:b2a70b920b3eb914ba78b939793a70cec503e25c693dd5db459ffa8bbebd3a64"},
|
||||
{file = "ogn_parser-0.3.12-cp312-cp312-win_amd64.whl", hash = "sha256:6c841f09bf936ac1bf11d65440347bfd9722c5363010a2029c8be05c91eaa8f6"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:57caf5d2e718892d4d7e9b4b4b622b0374d63519a773dc494cd655ae0269fcc7"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3a49d926adb29a2fd450f8e489a3809dd448df0fe192daf53047be2e5b1ccfd9"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36c4fa0f3c497dc88e3024b6ebbce9f86e4f74d991c32752cd7c0b8b5c2b9e3d"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:476c0bb808f99f52cf12b591aabdca325e8645a6fb04622162f2e2db775d9c64"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55a70405ca1469035ca5497abfb879ede6849f679cd841ed0e268d57a0881458"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7efac92916e7537860f08995e2ea1cc0a4403384db4052bde60974cccc5b5c8a"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a721ea31db822746afd2c3a1b0f71bec7548a34c5c5312763d33e94baf8d3ec7"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3711a46b269ee51b9c55dd485fbe50805aeb23d9381037deddafb5f5bc8b4e07"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc6d23e091a1c32bb3e1d2cd5a17eb555e08a97ebe1c7c5950d4e4d39a6ee996"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:306aec983f555403121eddeac5fa2d3e7512cf4014fb107749bbf6da6ddaec75"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7b7cb8354a727d7c8d4c000b7c1f36a063cc3595815db1df7394b6e910523991"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:46ba22ce23e409e67292afbdc35e523b21587782ff34a8e2cd3d0f4e3854a7aa"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-win32.whl", hash = "sha256:8bd259b21579638e963ebb96c3101b6d66e360418cf4f9b3faa94f6767058a34"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313-win_amd64.whl", hash = "sha256:24f5ddf2933a94e3ca1c1edc4d85657445cc3f4281a86f1df8acfc1f4ac0db6f"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5c450592195d75cd00bc40cd8a89d2dd1374949dcd6879345d3aee5bcb257e2"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e50a86a598e9ea13642ffb1b281195ed9f1dad1dbd53e92ed8fe4aa391267691"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2940a2d05b72659e02b79737866254387ab82602f1a0a1a538f75d9ab2ea5bc"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f4afa2e8138307ebbd81f5571851cbd6c132b0cf97df6eb007d5f673fef6a8"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f98fa7362a08661b7619226fd5f08b635d4dd080d559491fbeb963732062fd1"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:9ffc87e4387346e85d40dad7c0d429e2a43888794f507d7c135f1078be50e87b"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4561496b6eb5a4c1cecd85c52ca68f50717b9ef21c98f4751210b7b70488b7d2"},
|
||||
{file = "ogn_parser-0.3.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5ef896e7166d41c4ae3e71a8d5427fd88dbef28ec20b6b587aab088d9b33c667"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:844bbc0b6250f8f42ffbf81555623f50c2f85554a77326019084269ccee182d3"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:45181ce44c8afef73ad25f91edfc70473f511513e4271be7a3740b7fc03ce092"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab55ae52edf0b8f085fed2f468c7575cab3479d77d3647f41e66a7bde302d9e"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f46e87d4ac9a113a0dc13bc1cd9164f7de4bc98ece8a0df806ab9b8188facc0b"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:395c2b23ea269d9622b73985df462d8aa8faa0e380857b9177b365e8f7316449"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b55688bc5fcc39b80ae49e84b0341eb201b9b9140b302cec307b87bf4d885c0c"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9a4345d6a8ab8fd7930e68e9491f15f9dce3046f0d7ed656c057478523b4f5d0"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:65d265a5ffacdf53ebf3867441ede2626bd902caaf790dbcc0f67f18dbb2222b"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0be51b8d723a4d845ab61046cc3788e00a5245bec05e424c008215e1e50fe6ca"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7fbff3f82a4d35d98658d875e13f3e73d71283b9d7e42611752c64f8ae804854"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-win32.whl", hash = "sha256:ad22911915fd742997aac92ec1cf3d9b04f0b1a2c3ef359288dc57d22f16a1df"},
|
||||
{file = "ogn_parser-0.3.12-cp39-cp39-win_amd64.whl", hash = "sha256:bf453245e82a028b71bf46b3be5c78f960222a6e53e8c3152b72a2cac22354b3"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7db14ace01e0133f107bd840b48b51d685525d42182499b2851ae517e1d7eef2"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c19c2b8f02a24cbc13170ec7a2b9e70a928abcfad9d88cf6f62f6d5c8ba39931"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5de1b7d11b5f61f6eebc25c3a65ea66161b1ff09bda49b0362521f6cd478bf11"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13e32673d331424e6aeffe3b8e3958cc172538372379f1d0a4641882185e959f"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12cc1f79872efaccedfcc00cdefa80fcc4f0ff44d4132950dfe7c1542ac83e00"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1e8c616057cac59644d6b29b94e033d64498b7f8c211b20e7c4aa3b19fb32b"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:628084b9e395a34dca905dda0cf1e441fb2d374d36d499a02968f68b6c2e0a39"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:8d7aae78739667dd232ed19ec2679ae0c10637ec1bf1fbbb4a0de685608d44c1"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:c035a39abeb180c7e86b2cb593eeda9d34b166056f92a7260d4626368cb2791f"},
|
||||
{file = "ogn_parser-0.3.12-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:b586c955ca73414a02160917f6631c36ee58308d09548561d5d14da8e2b0ce06"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a19132e92290feab8008829436f8c54ed55904eb4487c065eca8bf959c10c25"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a93dcd3a779a3d33d82e99f3910bcc565758ccd8a5b6a1a046b3f0d72df76e1f"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6ba712830bf1a2a8c3764058e114eb82f8954f8887e08ef240ec0f8a50b785d"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7bd1ecb6e1dd49c97f76d8abc8753f32896503cff1a3d29a0917b2eae61a108"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12c73f73dbd80859422b2db70977431f4808e105c739d65f74e1e122af6bdcbc"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3e99efab326f95ab754e2a6bfdf15ca5cb23a2f05cc46c4fa6c026efb80ef6"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4c5e42605bb7be8853fea0465d0ee4b1283f9608ce49eb93d1de9e274d5d1587"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:5ba3c660bc1ffdd88092157cdef0eee54bc728314b9ad0c6c2828f0e4df1ac1f"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:70ee1743c28c2e0e04afeb217ddcf249631d4016eccc788ebad4f7cd7b75207d"},
|
||||
{file = "ogn_parser-0.3.12-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4bdedfa07178e0f9955eb76d69eec1d89c29eae04cd0af47bb62212f80bc12f1"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e879139b92508b3d6bb5ce292bc5796068209165e65ff65128b4d3a7a08e21ce"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:687614cedf9533d37835a7d05f10621f0a5a409bd104d438199584ebee1c4e73"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:166a9c5f110772ddd554fc946620908f7304b7185e9fb73ab51f129fcc0bd7b1"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e2774a9ce952764925b181bb447742a03f4f1f27167043848bd77c5bcc9f8c8"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:0419c0a503bee84ec0de3a18c29c52b6b6f27d6dbfc6fdb37cd7b42a4f0b581a"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:57138159a9448cec16d617fccef5679adb65e65a14cc87fcd4c8df5212f1d501"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:17bf108d8a4ae31a0e53e440abfe79f195fdbd17e360e8ede9b6ed177016e5b7"},
|
||||
{file = "ogn_parser-0.3.12-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:a3e86cda7f6b4a34ed056c89db8dd6b9100c73483fa6b2ced4035b643491d516"},
|
||||
{file = "ogn_parser-0.3.12.tar.gz", hash = "sha256:c7d89ef6b3daf0931c18df8f071b75951fcf5ae00d787dfd49c142fdf1305982"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d50b08130675a8bcef022e9551f516a2b7a8170f88b1e23f0d61df33da8534"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c194d6146663e79cc1edc9063a564ed0fdd8be8ea1aa3ca187161c69f1852e8"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39d7930083825ee1b024b398c4fc74bb255dca0b7d9493bce659c42ec227606a"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbd0d8b8451b64579f5db43e542085557778139504a6f3c8783c577800a41ca2"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68ade7e496618f78635c508f85235f4d1ec2b0223d5a2e392923d2eea3d262fc"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda81e04dbfa7b80ce4bd28c78779eb170b811ef035bf32cd7ef7fe72e60e258"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a67055324fe93b1c54e1c50eea778a26842bf0028ea8049db99e586526b63667"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8c35e95cb462fbeaf7a0a823005e62a133e803d979de3ced38349f57f40c0a19"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c7314d6f1ef053983b8e12ca6b30bc99f52ba69c8a6390d26a10c502c2bcd480"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5cd56be8345368de71cb8e184b5f1b8a8ee4f7c3d8ab8e0656abde8033b492be"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-win32.whl", hash = "sha256:9c317b9f34095b31582bda2b29d39394ca93fdd06ab79f728295733c0d7c0a8c"},
|
||||
{file = "ogn_parser-0.3.13-cp310-cp310-win_amd64.whl", hash = "sha256:f3e132b980ea8215171739bb0a3ff77e6079e9ac16d5b599351f14460c82614e"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e1021785428f793537bc6ba34ed624d6669bbeaa5db26af430fac37bb5c23010"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:39a34b6b5837c90863f46a4e4a6b000e0e08501a664a263b63dc611253ca5edc"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cdbdbb7ecfb45ae98f8052e9b5c540dbe4a22a826457b6473bb665d89dc8e03"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c569d327fee3916491c5162590b2ab57e33999ba42b27b403f6ba233262caf86"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:039be58972d390d86f171631678739b2d6209c98b0fe095b9860e116c160cda6"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0234ae94c41e9ba5aca7f55f77a9826704470d19bc1ff45a9cd865f007353a8e"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21d6fd5f363f7846bc9d2483becc643e389c22464b99ca00cf22d6b118840c5b"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee1abc6db25e5c8d3da5c78509250a38458db9e43d2e27f07a84fef5e5989e5"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8adc3d5869c2380707aadfca8d523b2b76428e14ecbeac6226f6ae14781e6fc4"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:53bea6e9aa83f2aeed5a064067af5e42b52e66849c8211e7149200c38ca7caee"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:96b7525d08559e216774576ad2009bacc64a3297b26222808147ec014ed99a96"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6616af93fef79a2aa711a764b6d8723fdc93a56c3aa34a684e60fda21b12e348"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-win32.whl", hash = "sha256:febdd8b56178745e68078eb5c8d1e1d11fec8a5cacb04a87cc021f50f3585ab0"},
|
||||
{file = "ogn_parser-0.3.13-cp311-cp311-win_amd64.whl", hash = "sha256:ec596e676560210f67972a3ccb39fb06cc981ca2bd8c3ad5b7f72ab12a7cb15d"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7a9c6b817955e6667468234c34e2b1ca0fcaded24d859a9771b80156e1f43277"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b3986fe3162f123af87e8371c9edcd9dbd79fd02923f5da55e0913863933a33c"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66b654714c63499e9fa42d33c92cb52e5631fafa67d8572f1edc686107481e22"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfc7e211f51d94653d3ef3632e1e79fb7e6e0f4621576efb89586f5e003ec79d"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f0a19d56a222bbe7979190c330cb4a7838255b14357d97a2555c46ffe763893"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5829c9c4fc80713c5343eefd0fc2ed1703137577394e8d557064be1c0900d7ae"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39ad2158d1284ecb9574a659c22456a03bfa0691f4c971628d9666dc814c9203"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f523058f2d3e318370ab22839de734c3857344e64ef130ac617eb7272134951b"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:32de949dd34c3641ec82aa1fd1d826cdaed196761c574d2970521768ca8bce3f"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab396fbea01dae4f6191c807bf6290d15ce7085fe2c3a3fff959b476cccb879c"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0ced3677764cc3509fde01607557ecef6b041d23b8cc175f9e404298d81d8020"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d89cb305f64935c0c239ecb0016b2302fb22745d521a69e7640cbebadeb0bb44"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-win32.whl", hash = "sha256:8cd4d8b9de3d208bad51e1a7071b9626f2dae9322f646968c9aa8e14273622d3"},
|
||||
{file = "ogn_parser-0.3.13-cp312-cp312-win_amd64.whl", hash = "sha256:a1ae098d4ea76e4bf2452211f029b61656b866972725a3c4a28f8372c671fef9"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e1fd34de69b21456736a2f52bf227615f1d7ae422e69502f4714bc73821bc08c"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdf171f22f2ec8b1771db3ca1b872ee8a973e9ac5ec8114ecc9199493c63ea31"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28ee291f509c9c94b5e3c2b6509938ae7f4ff9a40da063bb63513ee5326ed21f"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb6ef82a7f9c71575eef5f7f29d4db5f3a8b9e4a4e6e95e1d4b77d2a7d2ad7dd"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc26c702de600edcfd18b4524f2a2bd5b5cfdc86fc7f028ade1f110cba7afc59"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ead0fe172a8ea9db652c9168c3f513d159e0dbba31278163bf10544b6aeef2c"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb29fe94a2c336cbb114dbd83991d56593799f8d751f0a7bdb2c2ddea3273cc"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d77106b0b9fe958ec41d6c841690836e53fe7331cf0024959ccac07384196f42"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c27941e94d2417d002c9d51d48ff7d8a8897b783313587c593c0b64dd4f9ba66"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2f000536f3d64c274cf2af4ee6aeff4dbd53addd883cb423da0975df913ea2e3"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c329989b1c12d3f24fbb6f3256ac3aabddb5a22e204062097ceee333d58daeb6"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:218c8bec2aaa7b6f6f58584710c60a0aed44f636a62bd2fdbfcc59740f4ef8ba"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-win32.whl", hash = "sha256:b804a974a4d5243100abbd24007faf322443c65740c233989c3140bb2297d822"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313-win_amd64.whl", hash = "sha256:f640bf34d69ccd1c20d245a1231c9ea9f11ceacc4eadffc4ec5e76250a96479e"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96c8fe0e97825ef13615e3cfd268bc2ff214308f621a183cf736a2682109733e"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11f55f16252117c438a715529ed6d11fa8739b0b6537b782629d605ccdb39f90"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:663b44f8c3f74331ee48279824357cd7d9207ae59bc078efff44a14987238a11"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64d8ebe402007a85c750bda8a314660b8d7ca79a7946e51d35bc733952254e42"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3012484d4d56d47b2d4c73e9f4cf4bea9a4305603f9bf0957aaed3bd1967a54e"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:5238f0cc76b3b41d3c2ae5f0862b3946d968e5217a08d1e72cfb131c2873cc1a"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:35eebb2fbdd79a7e2fe1f27d3633d49bb346dacfdfb23b989f13ac971c90c9a8"},
|
||||
{file = "ogn_parser-0.3.13-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7fc20b288a9663ca7eb3afbd2e2d68c9139a51b6e47c4221861b8721476e59a0"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b644ea28a96f59911ae0f14c2ad87dd9b15778fbfa2aa949a88068f980740e55"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb00d4039993a6984752e150e4a3c16594ed8859ad533f9d767f536871250832"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:667cf58adf6789857e1bfe83d88b2c9a6791935f1a4b207f18e9c3efce12deea"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f79553fbd3e86ac39d36a8b9d06a20eed3916084e847915eda4573ac7fb0a9d"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bdadd5d4c84c36ea0c41e7f1d4dde4e9cd43bd3d1a24100f472251c0571eea8"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:449fd6af0f7addcd9f825b5099ee7abf13f8427de87da4fa87980e8f91b506ed"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4551c65d8da46ce76ff038e8469ef595bae509c48247a18044be185721e3b46f"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d8ccb23c91093c6b71f480050cfdf33a5b0f29c72b2592c66febbb678791b763"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0d7d6d0c37ada28b6ac9895e79053c6fde0173cdbd36bb19777f0a646c9e20e8"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:24aed28bcab26172deec551095f907dfc1b259440ef4a448a936eaa70dbe3282"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-win32.whl", hash = "sha256:692a55f30e1b706cfed3a7bb7789d85e064a6af18aedb976d81c6887f421ef41"},
|
||||
{file = "ogn_parser-0.3.13-cp39-cp39-win_amd64.whl", hash = "sha256:599a7c290727a0e78cb73d0103daa6f568bfb077ac94b924f1b9fa44fa18b064"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72f2c9d5c8c5d8bec83add4dd03ac3400afa6023baec4974aa38dfc3a32f8fd1"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:98f6353d684b7fdfab5e9d45417b633654b1de2719a819171b62739b7ce80baf"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1320c0a3c5e54440676b4f51bae79cfaa9907bbfdf5310ef018dc477be85dad"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9068d75e0a4d0c5a42fae78c273e03fb6c398162aef2001ec99df14e8c7f2409"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c060c78a35fcd4febd4fa0243ce2ae08e680a0124544ad093087aa17a415f8"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a5e8e0ddeca4bfdc9c559712bae414690e53ef2716b863a53db066073d0d478"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a615a0f081ab3cbe5e4579f9202b6e2ea9c830bbce065c5f81301639971894e7"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:b17026ea518870040688d61ca9f22a96503f6d3abc16726525558a13b0e65840"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:094899100b6f85503f4861fa5e8f39cf2a8e163e56aa8241984deb02b474a2d5"},
|
||||
{file = "ogn_parser-0.3.13-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:821fcd2a5dd0376091ecbe8510d9ee11bdc676b298af06b91e88dc6879082350"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616f8b41709e7010ed9d93d32fcb565ed8868e8fbbb9e33092d60731ddd29d9f"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f644e07fba5433761eb95de2439a9fc44b4fac91a754551b6908af03ede9607b"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:445953ec3c53e3d041d00a00a92bf5875e313b13f5fd2cb7831bffb381990a0d"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88ac6bcfb5efa58de04acd43bb26dc26e30e2c96aa06b9f6a13f1f8dd197767f"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ad5a2b02a2a53341481646a4ee0d68818b9310e32744f6e830e182aeaef6cef"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b1119864a63982d43d489ff924ca7f65d5ee2872d3cd344ba929bb401f9b70"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:28aaa7543553507aeaca570f7e262a7eb0995a3357c1fb76e781362e4e3b03c5"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:575cb45d951243634f946cf3551a7c9e7ec0b019a238d0d078c02b48a5e5478a"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:52aed456327e175dae3ac5dec29728d4f153e44be107ef9e65d13048e1b5b744"},
|
||||
{file = "ogn_parser-0.3.13-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c6c468138742e1f1f4ffc8f5e673e3224ebde02629ec6f7d253a6a5fcfd3831f"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4faec36470e8dc28eecdd417409043ab70a986bf2ff20e9d2db9ae065d4c0e6d"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3a81708ad82f591d192ef1a877dfa7e8245505f9029385dae43211794961c71"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:529b40aec0311839f7dc10d9d2b0fb00cea8605de66d6f05d9946f6f64ba349c"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34b448f355a95107bc957941e3406edd82aecf6bade1d1271baa4ae8c11f901c"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:44c69b4a798fbae245ed8ebc65436d24c10068551b4bb4d44c3627bae341d385"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c260c363ab204cec007d96896ffb82530fa900220bd9d0056cdacc8e866d4cb9"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:84adfe75e8f3a4852750d4a89f661bd2680ddc5054892b6fb46d89e90cc88f95"},
|
||||
{file = "ogn_parser-0.3.13-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6c3917f0f18744811e9e6439dc55473ae6768b0316297bc704516477094642cc"},
|
||||
{file = "ogn_parser-0.3.13.tar.gz", hash = "sha256:c654a04fe11108708c76d644d1ae2b31c653fefb7fac94223ce5151de6669c95"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -620,4 +620,4 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.9"
|
||||
content-hash = "47c1919292ff2eb7b8e5655ad8252ee7c6cfc1c977ab5aa845a52483bb7fe681"
|
||||
content-hash = "4d22acabee7fa2f4e77f11f6c238bc5178c3cbcc8df086d534f0084a13b54ae8"
|
||||
|
|
|
@ -20,7 +20,7 @@ readme = "README.md"
|
|||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"requests (>=2.32.3,<3.0.0)",
|
||||
"ogn-parser (>=0.3.12,<0.4.0)"
|
||||
"ogn-parser (>=0.3.13,<0.4.0)"
|
||||
]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import unittest.mock as mock
|
||||
import pytest
|
||||
|
||||
from ogn.parser import parse
|
||||
from ogn.client.client import create_aprs_login, AprsClient
|
||||
|
@ -126,9 +125,9 @@ def test_reset_kill_reconnect():
|
|||
assert mock_callback.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.skip("Too much invalid APRS data on the live feed")
|
||||
def test_50_live_messages():
|
||||
print("Enter")
|
||||
global remaining_messages
|
||||
remaining_messages = 50
|
||||
|
||||
def process_message(raw_message):
|
||||
|
|
|
@ -6,7 +6,7 @@ from datetime import datetime
|
|||
from time import sleep
|
||||
|
||||
from ogn.parser.parse import parse
|
||||
from ogn.parser.exceptions import AprsParseError, OgnParseError
|
||||
from ogn.parser.exceptions import AprsParseError
|
||||
|
||||
|
||||
def _parse_valid_beacon_data_file(filename, beacon_type):
|
||||
|
@ -24,14 +24,6 @@ def _parse_valid_beacon_data_file(filename, beacon_type):
|
|||
print(e)
|
||||
|
||||
|
||||
def test_aprs_aircraft_beacons():
|
||||
_parse_valid_beacon_data_file(filename='APRS_aircraft.txt', beacon_type='aprs_aircraft')
|
||||
|
||||
|
||||
def test_aprs_receiver_beacons():
|
||||
_parse_valid_beacon_data_file(filename='APRS_receiver.txt', beacon_type='aprs_receiver')
|
||||
|
||||
|
||||
def test_flyxc_beacons():
|
||||
_parse_valid_beacon_data_file(filename='FXCAPP_flyxc.txt', beacon_type='unknown')
|
||||
|
||||
|
@ -158,10 +150,10 @@ def test_spot_beacons():
|
|||
def test_generic_beacons():
|
||||
message = parse("EPZR>WTFDSTCALL,TCPIP*,qAC,GLIDERN1:>093456h this is a comment")
|
||||
assert message['beacon_type'] == 'unknown'
|
||||
assert message['comment'] == "this is a comment"
|
||||
assert message['user_comment'] == "this is a comment"
|
||||
|
||||
|
||||
def test_fail_parse_aprs_none():
|
||||
def test_fail_parse_none():
|
||||
with pytest.raises(TypeError):
|
||||
parse(None)
|
||||
|
||||
|
@ -208,11 +200,6 @@ def test_copy_constructor():
|
|||
assert message['address'] == 'DDA5BA'
|
||||
|
||||
|
||||
def test_bad_naviter_format():
|
||||
with pytest.raises(OgnParseError):
|
||||
parse("FLRA51D93>OGNAVI,qAS,NAVITER2:/204507h4444.98N/09323.34W'000/000/A=000925 !W67! id06A51D93 +000fpm +0.0rot")
|
||||
|
||||
|
||||
def test_no_receiver():
|
||||
result = parse("EDFW>OGNSDR:/102713h4949.02NI00953.88E&/A=000984")
|
||||
|
||||
|
@ -220,4 +207,4 @@ def test_no_receiver():
|
|||
assert result['beacon_type'] == 'receiver'
|
||||
assert result['name'] == 'EDFW'
|
||||
assert result['dstcall'] == 'OGNSDR'
|
||||
assert result['receiver_name'] is None
|
||||
assert result.get('receiver_name') is None
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import pytest
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from ogn.parser import parse
|
||||
from ogn.parser.utils import KNOTS_TO_MS, KPH_TO_MS, FEETS_TO_METER, INCH_TO_MM, fahrenheit_to_celsius
|
||||
from ogn.parser.parse import parse_aprs
|
||||
from ogn.parser.exceptions import AprsParseError
|
||||
|
||||
|
||||
def test_fail_validationassert():
|
||||
with pytest.raises(AprsParseError):
|
||||
parse_aprs("notAValidString")
|
||||
parse("notAValidString")
|
||||
|
||||
|
||||
def test_basic():
|
||||
message = parse_aprs("FLRDDA5BA>APRS,qAS,LFMX:/160829h4415.41N/00600.03E'342/049/A=005524 this is a comment")
|
||||
message = parse("FLRDDA5BA>APRS,qAS,LFMX:/160829h4415.41N/00600.03E'342/049/A=005524 this is a comment")
|
||||
|
||||
assert message['aprs_type'] == 'position'
|
||||
assert message['name'] == "FLRDDA5BA"
|
||||
|
@ -27,13 +27,13 @@ def test_basic():
|
|||
assert message['track'] == 342
|
||||
assert message['ground_speed'] == 49 * KNOTS_TO_MS / KPH_TO_MS
|
||||
assert message['altitude'] == pytest.approx(5524 * FEETS_TO_METER, 5)
|
||||
assert message['comment'] == "this is a comment"
|
||||
assert message['user_comment'] == "this is a comment"
|
||||
|
||||
|
||||
def test_v024():
|
||||
# higher precision datum format introduced
|
||||
raw_message = "FLRDDA5BA>APRS,qAS,LFMX:/160829h4415.41N/00600.03E'342/049/A=005524 !W26! id21400EA9 -2454fpm +0.9rot 19.5dB 0e -6.6kHz gps1x1 s6.02 h44 rDF0C56"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'position'
|
||||
assert message['latitude'] - 44.2568 - 1 / 30000 == pytest.approx(2 / 1000 / 60, 10)
|
||||
|
@ -43,28 +43,28 @@ def test_v024():
|
|||
def test_v025():
|
||||
# introduced the "aprs status" format where many informations (lat, lon, alt, speed, ...) are just optional
|
||||
raw_message = "EPZR>APRS,TCPIP*,qAC,GLIDERN1:>093456h this is a comment"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'status'
|
||||
assert message['name'] == "EPZR"
|
||||
assert message['receiver_name'] == "GLIDERN1"
|
||||
assert message['timestamp'].strftime('%H:%M:%S') == "09:34:56"
|
||||
assert message['comment'] == "this is a comment"
|
||||
assert message['user_comment'] == "this is a comment"
|
||||
|
||||
|
||||
def test_v026():
|
||||
# from 0.2.6 the ogn comment of a receiver beacon is just optional
|
||||
raw_message = "Ulrichamn>APRS,TCPIP*,qAC,GLIDERN1:/085616h5747.30NI01324.77E&/A=001322"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'position'
|
||||
assert message['comment'] == ''
|
||||
assert message.get('comment') is None
|
||||
|
||||
|
||||
def test_v026_relay():
|
||||
# beacons can be relayed
|
||||
raw_message = "FLRFFFFFF>OGNAVI,NAV07220E*,qAS,NAVITER:/092002h1000.00S/01000.00W'000/000/A=003281 !W00! id2820FFFFFF +300fpm +1.7rot"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'position'
|
||||
assert message['relay'] == "NAV07220E"
|
||||
|
@ -73,7 +73,7 @@ def test_v026_relay():
|
|||
def test_v027_ddhhmm():
|
||||
# beacons can have hhmmss or ddhhmm timestamp
|
||||
raw_message = "ICA4B0678>APRS,qAS,LSZF:/301046z4729.50N/00812.89E'227/091/A=002854 !W01! id054B0678 +040fpm +0.0rot 19.0dB 0e +1.5kHz gps1x1"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'position'
|
||||
assert message['timestamp'].strftime('%d %H:%M') == "30 10:46"
|
||||
|
@ -82,7 +82,7 @@ def test_v027_ddhhmm():
|
|||
def test_v028_fanet_position_weather():
|
||||
# with v0.2.8 fanet devices can report weather data
|
||||
raw_message = 'FNTFC9002>OGNFNT,qAS,LSXI2:/163051h4640.33N/00752.21E_187/004g007t075h78b63620 29.0dB -8.0kHz'
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'position_weather'
|
||||
assert message['wind_direction'] == 187
|
||||
|
@ -92,72 +92,47 @@ def test_v028_fanet_position_weather():
|
|||
assert message['humidity'] == 78 * 0.01
|
||||
assert message['barometric_pressure'] == 63620
|
||||
|
||||
assert message['comment'] == '29.0dB -8.0kHz'
|
||||
assert message['signal_quality'] == 29.0
|
||||
assert message['frequency_offset'] == -8.0
|
||||
|
||||
|
||||
def test_GXAirCom_fanet_position_weather_rainfall():
|
||||
raw_message = 'FNT08F298>OGNFNT,qAS,DREIFBERG:/082654h4804.90N/00845.74E_273/005g008t057r123p234h90b10264 0.0dB'
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'position_weather'
|
||||
assert message['rainfall_1h'] == 123 / 100 * INCH_TO_MM
|
||||
assert message['rainfall_24h'] == 234 / 100 * INCH_TO_MM
|
||||
|
||||
|
||||
def test_v028_fanet_position_weather_empty():
|
||||
raw_message = 'FNT010115>OGNFNT,qAS,DB7MJ:/065738h4727.72N/01012.83E_.../...g...t... 27.8dB -13.8kHz'
|
||||
message = parse_aprs(raw_message)
|
||||
|
||||
assert message['aprs_type'] == 'position_weather'
|
||||
assert message['wind_direction'] is None
|
||||
assert message['wind_speed'] is None
|
||||
assert message['wind_speed_peak'] is None
|
||||
assert message['temperature'] is None
|
||||
assert message['humidity'] is None
|
||||
assert message['barometric_pressure'] is None
|
||||
|
||||
|
||||
def test_negative_altitude():
|
||||
# some devices can report negative altitudes
|
||||
raw_message = "OGNF71F40>APRS,qAS,NAVITER:/080852h4414.37N/01532.06E'253/052/A=-00013 !W73! id1EF71F40 -060fpm +0.0rot"
|
||||
message = parse_aprs(raw_message)
|
||||
|
||||
assert message['altitude'] == pytest.approx(-13 * FEETS_TO_METER, 5)
|
||||
|
||||
|
||||
def test_no_altitude():
|
||||
# altitude is not a 'must have'
|
||||
raw_message = "FLRDDEEF1>OGCAPT,qAS,CAPTURS:/065511h4837.63N/00233.79E'000/000"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['altitude'] is None
|
||||
assert message.get('altitude') is None
|
||||
|
||||
|
||||
def test_invalid_coordinates():
|
||||
# sometimes the coordinates leave their valid range: -90<=latitude<=90 or -180<=longitude<=180
|
||||
with pytest.raises(AprsParseError):
|
||||
parse_aprs("RND000000>APRS,qAS,TROCALAN1:/210042h6505.31S/18136.75W^054/325/A=002591 !W31! idA4000000 +099fpm +1.8rot FL029.04 12.0dB 5e -6.3kHz gps11x17")
|
||||
parse("RND000000>APRS,qAS,TROCALAN1:/210042h6505.31S/18136.75W^054/325/A=002591 !W31! idA4000000 +099fpm +1.8rot FL029.04 12.0dB 5e -6.3kHz gps11x17")
|
||||
|
||||
with pytest.raises(AprsParseError):
|
||||
parse_aprs("RND000000>APRS,qAS,TROCALAN1:/210042h9505.31S/17136.75W^054/325/A=002591 !W31! idA4000000 +099fpm +1.8rot FL029.04 12.0dB 5e -6.3kHz gps11x17")
|
||||
parse("RND000000>APRS,qAS,TROCALAN1:/210042h9505.31S/17136.75W^054/325/A=002591 !W31! idA4000000 +099fpm +1.8rot FL029.04 12.0dB 5e -6.3kHz gps11x17")
|
||||
|
||||
|
||||
def test_invalid_timestamp():
|
||||
with pytest.raises(AprsParseError):
|
||||
parse_aprs("OGND4362A>APRS,qAS,Eternoz:/194490h4700.25N/00601.47E'003/063/A=000000 !W22! id07D4362A 0fpm +0.0rot FL000.00 2.0dB 3e -2.8kHz gps3x4 +12.2dBm")
|
||||
parse("OGND4362A>APRS,qAS,Eternoz:/194490h4700.25N/00601.47E'003/063/A=000000 !W22! id07D4362A 0fpm +0.0rot FL000.00 2.0dB 3e -2.8kHz gps3x4 +12.2dBm")
|
||||
|
||||
with pytest.raises(AprsParseError):
|
||||
parse_aprs("Ulrichamn>APRS,TCPIP*,qAC,GLIDERN1:/194490h5747.30NI01324.77E&/A=001322")
|
||||
|
||||
|
||||
def test_invalid_altitude():
|
||||
with pytest.raises(AprsParseError):
|
||||
parse_aprs("Ulrichamn>APRS,TCPIP*,qAC,GLIDERN1:/085616h5747.30NI01324.77E&/A=12-345")
|
||||
parse("Ulrichamn>APRS,TCPIP*,qAC,GLIDERN1:/194490h5747.30NI01324.77E&/A=001322")
|
||||
|
||||
|
||||
def test_bad_comment():
|
||||
raw_message = "# bad configured ogn receiver"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['comment'] == raw_message
|
||||
assert message['aprs_type'] == 'comment'
|
||||
|
@ -165,11 +140,11 @@ def test_bad_comment():
|
|||
|
||||
def test_server_comment():
|
||||
raw_message = "# aprsc 2.1.4-g408ed49 17 Mar 2018 09:30:36 GMT GLIDERN1 37.187.40.234:10152"
|
||||
message = parse_aprs(raw_message)
|
||||
message = parse(raw_message)
|
||||
|
||||
assert message['version'] == '2.1.4-g408ed49'
|
||||
assert message['timestamp'] == datetime(2018, 3, 17, 9, 30, 36)
|
||||
assert message['timestamp'] == datetime(2018, 3, 17, 9, 30, 36, tzinfo=timezone.utc)
|
||||
assert message['server'] == 'GLIDERN1'
|
||||
assert message['ip_address'] == '37.187.40.234'
|
||||
assert message['port'] == '10152'
|
||||
assert message['port'] == 10152
|
||||
assert message['aprs_type'] == 'server'
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.aprs_comment.fanet_parser import FanetParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = FanetParser().parse_position("id1E1103CE -02fpm")
|
||||
|
||||
assert message['address_type'] == 2
|
||||
assert message['aircraft_type'] == 7
|
||||
assert message['stealth'] is False
|
||||
assert message['address'] == "1103CE"
|
||||
assert message['climb_rate'] == pytest.approx(-2 * FPM_TO_MS, 0.1)
|
||||
|
||||
|
||||
def test_pseudo_status_comment():
|
||||
message = FanetParser().parse_position("")
|
||||
|
||||
assert message == {}
|
||||
|
||||
|
||||
def test_v028_status():
|
||||
message = FanetParser().parse_status('Name="Juerg Zweifel" 15.0dB -17.1kHz 1e')
|
||||
|
||||
assert message['fanet_name'] == "Juerg Zweifel"
|
||||
assert message['signal_quality'] == 15.0
|
||||
assert message['frequency_offset'] == -17.1
|
||||
assert message['error_count'] == 1
|
|
@ -1,31 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
from ogn.parser.aprs_comment.flarm_parser import FlarmParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = FlarmParser().parse_position("id21A8CBA8 -039fpm +0.1rot 3.5dB 2e -8.7kHz gps1x2 s6.09 h43 rDF0267")
|
||||
|
||||
assert message['address_type'] == 1
|
||||
assert message['aircraft_type'] == 8
|
||||
assert message['stealth'] is False
|
||||
assert message['no-tracking'] is False
|
||||
assert message['address'] == "A8CBA8"
|
||||
assert message['climb_rate'] == pytest.approx(-39 * FPM_TO_MS, 2)
|
||||
assert message['turn_rate'] == 0.1 * HPM_TO_DEGS
|
||||
assert message['signal_quality'] == 3.5
|
||||
assert message['error_count'] == 2
|
||||
assert message['frequency_offset'] == -8.7
|
||||
assert message['gps_quality'] == {'horizontal': 1, 'vertical': 2}
|
||||
assert message['software_version'] == 6.09
|
||||
assert message['hardware_version'] == 67
|
||||
assert message['real_address'] == "DF0267"
|
||||
|
||||
|
||||
def test_position_comment_relevant_keys_only():
|
||||
# return only keys where we got informations
|
||||
message = FlarmParser().parse_position("id21A8CBA8")
|
||||
|
||||
assert message is not None
|
||||
assert sorted(message.keys()) == sorted(['address_type', 'aircraft_type', 'stealth', 'address', 'no-tracking'])
|
|
@ -1,9 +0,0 @@
|
|||
from ogn.parser.aprs_comment.generic_parser import GenericParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = GenericParser().parse_position("id0123456789 weather is good, climbing with 123fpm")
|
||||
assert 'comment' in message
|
||||
|
||||
message = GenericParser().parse_status("id0123456789 weather is good, climbing with 123fpm")
|
||||
assert 'comment' in message
|
|
@ -1,15 +0,0 @@
|
|||
from ogn.parser.aprs_comment.inreach_parser import InreachParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = InreachParser().parse_position("id300434060496190 inReac True")
|
||||
assert message['address'] == "300434060496190"
|
||||
assert message['model'] == 'inReac'
|
||||
assert message['status'] is True
|
||||
assert message['pilot_name'] is None
|
||||
|
||||
message = InreachParser().parse_position("id300434060496190 inReac True Jim Bob")
|
||||
assert message['address'] == "300434060496190"
|
||||
assert message['model'] == 'inReac'
|
||||
assert message['status'] is True
|
||||
assert message['pilot_name'] == "Jim Bob"
|
|
@ -1,12 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.aprs_comment.lt24_parser import LT24Parser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = LT24Parser().parse_position("id25387 +123fpm GPS")
|
||||
|
||||
assert message['lt24_id'] == "25387"
|
||||
assert message['climb_rate'] == pytest.approx(123 * FPM_TO_MS, 2)
|
||||
assert message['source'] == 'GPS'
|
|
@ -1,19 +0,0 @@
|
|||
from ogn.parser.aprs_comment.microtrak_parser import MicrotrakParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = MicrotrakParser().parse_position("id21A8CBA8")
|
||||
|
||||
assert message['address_type'] == 1
|
||||
assert message['aircraft_type'] == 8
|
||||
assert message['stealth'] is False
|
||||
assert message['no-tracking'] is False
|
||||
assert message['address'] == "A8CBA8"
|
||||
|
||||
|
||||
def test_position_comment_relevant_keys_only():
|
||||
# return only keys where we got informations
|
||||
message = MicrotrakParser().parse_position("id21A8CBA8")
|
||||
|
||||
assert message is not None
|
||||
assert sorted(message.keys()) == sorted(['address_type', 'aircraft_type', 'stealth', 'address', 'no-tracking'])
|
|
@ -1,25 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
from ogn.parser.aprs_comment.naviter_parser import NaviterParser
|
||||
|
||||
|
||||
def test_OGNAVI_1():
|
||||
message = NaviterParser().parse_position("id0440042121 +123fpm +0.5rot")
|
||||
|
||||
# id0440042121 == 0b0000 0100 0100 0000 0000 0100 0010 0001 0010 0001
|
||||
# bit 0: stealth mode
|
||||
# bit 1: do not track mode
|
||||
# bits 2-5: aircraft type
|
||||
# bits 6-11: address type (namespace is extended from 2 to 6 bits to avoid collisions with other tracking providers)
|
||||
# bits 12-15: reserved for use at a later time
|
||||
# bits 16-39: device id (24-bit device identifier, same as in APRS header)
|
||||
assert message['stealth'] is False
|
||||
assert message['do_not_track'] is False
|
||||
assert message['aircraft_type'] == 1
|
||||
assert message['address_type'] == 4
|
||||
assert message['reserved'] == 0
|
||||
assert message['address'] == "042121"
|
||||
|
||||
assert message['climb_rate'] == pytest.approx(123 * FPM_TO_MS, 2)
|
||||
assert message['turn_rate'] == 0.5 * HPM_TO_DEGS
|
|
@ -1,81 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
from ogn.parser.aprs_comment.ogn_parser import OgnParser
|
||||
|
||||
|
||||
def test_invalid_token():
|
||||
assert OgnParser().parse_aircraft_beacon("notAValidToken") is None
|
||||
|
||||
|
||||
def test_basic():
|
||||
message = OgnParser().parse_aircraft_beacon("id0ADDA5BA -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5 hear1084 hearB597 hearB598")
|
||||
|
||||
assert message['address_type'] == 2
|
||||
assert message['aircraft_type'] == 2
|
||||
assert message['stealth'] is False
|
||||
assert message['no-tracking'] is False
|
||||
assert message['address'] == "DDA5BA"
|
||||
assert message['climb_rate'] == pytest.approx(-454 * FPM_TO_MS, 2)
|
||||
assert message['turn_rate'] == -1.1 * HPM_TO_DEGS
|
||||
assert message['signal_quality'] == 8.8
|
||||
assert message['error_count'] == 0
|
||||
assert message['frequency_offset'] == 51.2
|
||||
assert message['gps_quality'] == {'horizontal': 4, 'vertical': 5}
|
||||
assert len(message['proximity']) == 3
|
||||
assert message['proximity'][0] == '1084'
|
||||
assert message['proximity'][1] == 'B597'
|
||||
assert message['proximity'][2] == 'B598'
|
||||
|
||||
|
||||
def test_no_tracking():
|
||||
message = OgnParser().parse_aircraft_beacon("id0ADD1234 -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5 hear1084 hearB597 hearB598")
|
||||
assert message['no-tracking'] is False
|
||||
|
||||
message = OgnParser().parse_aircraft_beacon("id4ADD1234 -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5 hear1084 hearB597 hearB598")
|
||||
assert message['no-tracking'] is True
|
||||
|
||||
|
||||
def test_stealth():
|
||||
message = OgnParser().parse_aircraft_beacon("id0ADD1234 -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5 hear1084 hearB597 hearB598")
|
||||
assert message['stealth'] is False
|
||||
|
||||
message = OgnParser().parse_aircraft_beacon("id8ADD1234 -454fpm -1.1rot 8.8dB 0e +51.2kHz gps4x5 hear1084 hearB597 hearB598")
|
||||
assert message['stealth'] is True
|
||||
|
||||
|
||||
def test_v024():
|
||||
message = OgnParser().parse_aircraft_beacon("id21400EA9 -2454fpm +0.9rot 19.5dB 0e -6.6kHz gps1x1 s6.02 h0A rDF0C56")
|
||||
|
||||
assert message['software_version'] == 6.02
|
||||
assert message['hardware_version'] == 10
|
||||
assert message['real_address'] == "DF0C56"
|
||||
|
||||
|
||||
def test_v024_ogn_tracker():
|
||||
message = OgnParser().parse_aircraft_beacon("id07353800 +020fpm -14.0rot FL004.43 38.5dB 0e -2.9kHz")
|
||||
|
||||
assert message['flightlevel'] == 4.43
|
||||
|
||||
|
||||
def test_v025():
|
||||
message = OgnParser().parse_aircraft_beacon("id06DDE28D +535fpm +3.8rot 11.5dB 0e -1.0kHz gps2x3 s6.01 h0C +7.4dBm")
|
||||
|
||||
assert message['signal_power'] == 7.4
|
||||
|
||||
|
||||
def test_v026():
|
||||
# from 0.2.6 it is sufficent we have only the ID, climb and turn rate or just the ID
|
||||
message_triple = OgnParser().parse_aircraft_beacon("id093D0930 +000fpm +0.0rot")
|
||||
message_single = OgnParser().parse_aircraft_beacon("id093D0930")
|
||||
|
||||
assert message_triple is not None
|
||||
assert message_single is not None
|
||||
|
||||
|
||||
def test_relevant_keys_only():
|
||||
# return only keys where we got informations
|
||||
message = OgnParser().parse_aircraft_beacon("id093D0930")
|
||||
|
||||
assert message is not None
|
||||
assert sorted(message.keys()) == sorted(['address_type', 'aircraft_type', 'stealth', 'address', 'no-tracking'])
|
|
@ -1,56 +0,0 @@
|
|||
from ogn.parser.aprs_comment.ogn_parser import OgnParser
|
||||
|
||||
|
||||
def test_fail_validation():
|
||||
assert OgnParser().parse_receiver_beacon("notAValidToken") is None
|
||||
|
||||
|
||||
def test_v021():
|
||||
message = OgnParser().parse_receiver_beacon("v0.2.1 CPU:0.8 RAM:25.6/458.9MB NTP:0.1ms/+2.3ppm +51.9C RF:+26-1.4ppm/-0.25dB")
|
||||
|
||||
assert message['version'] == "0.2.1"
|
||||
assert message['cpu_load'] == 0.8
|
||||
assert message['free_ram'] == 25.6
|
||||
assert message['total_ram'] == 458.9
|
||||
assert message['ntp_error'] == 0.1
|
||||
assert message['rt_crystal_correction'] == 2.3
|
||||
assert message['cpu_temp'] == 51.9
|
||||
|
||||
assert message['rec_crystal_correction'] == 26
|
||||
assert message['rec_crystal_correction_fine'] == -1.4
|
||||
assert message['rec_input_noise'] == -0.25
|
||||
|
||||
|
||||
def test_v022():
|
||||
message = OgnParser().parse_receiver_beacon("v0.2.2.x86 CPU:0.5 RAM:669.9/887.7MB NTP:1.0ms/+6.2ppm +52.0C RF:+0.06dB")
|
||||
assert message['platform'] == 'x86'
|
||||
|
||||
|
||||
def test_v025():
|
||||
message = OgnParser().parse_receiver_beacon("v0.2.5.RPI-GPU CPU:0.8 RAM:287.3/458.7MB NTP:1.0ms/-6.4ppm 5.016V 0.534A +51.9C RF:+55+0.4ppm/-0.67dB/+10.8dB@10km[57282]")
|
||||
assert message['voltage'] == 5.016
|
||||
assert message['amperage'] == 0.534
|
||||
assert message['senders_signal'] == 10.8
|
||||
assert message['senders_messages'] == 57282
|
||||
|
||||
message = OgnParser().parse_receiver_beacon("v0.2.5.ARM CPU:0.4 RAM:638.0/970.5MB NTP:0.2ms/-1.1ppm +65.5C 14/16Acfts[1h] RF:+45+0.0ppm/+3.88dB/+24.0dB@10km[143717]/+26.7dB@10km[68/135]")
|
||||
assert message['senders_visible'] == 14
|
||||
assert message['senders_total'] == 16
|
||||
assert message['senders_signal'] == 24.0
|
||||
assert message['senders_messages'] == 143717
|
||||
assert message['good_senders_signal'] == 26.7
|
||||
assert message['good_senders'] == 68
|
||||
assert message['good_and_bad_senders'] == 135
|
||||
|
||||
|
||||
def test_v028():
|
||||
message = OgnParser().parse_receiver_beacon("v0.2.8.RPI-GPU CPU:0.3 RAM:744.5/968.2MB NTP:3.6ms/+2.0ppm +68.2C 3/3Acfts[1h] Lat:1.6s RF:-8+67.8ppm/+10.33dB/+1.3dB@10km[30998]/+10.4dB@10km[3/5]")
|
||||
assert message['latency'] == 1.6
|
||||
|
||||
|
||||
def test_relevant_keys_only():
|
||||
# return only keys where we got informations
|
||||
message = OgnParser().parse_receiver_beacon("v0.2.5.ARM CPU:0.4 RAM:638.0/970.5MB NTP:0.2ms/-1.1ppm")
|
||||
|
||||
assert message is not None
|
||||
assert sorted(message.keys()) == sorted(['version', 'platform', 'cpu_load', 'free_ram', 'total_ram', 'ntp_error', 'rt_crystal_correction'])
|
|
@ -1,36 +0,0 @@
|
|||
from ogn.parser.aprs_comment.receiver_parser import ReceiverParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = ReceiverParser().parse_position("Antenna: chinese, on a pylon, 20 meter above ground")
|
||||
|
||||
assert message['user_comment'] == "Antenna: chinese, on a pylon, 20 meter above ground"
|
||||
|
||||
|
||||
def test_position_comment_empty():
|
||||
message = ReceiverParser().parse_position("")
|
||||
|
||||
assert message is not None
|
||||
|
||||
|
||||
def test_status_comment():
|
||||
message = ReceiverParser().parse_status("v0.2.7.RPI-GPU CPU:0.7 RAM:770.2/968.2MB NTP:1.8ms/-3.3ppm +55.7C 7/8Acfts[1h] RF:+54-1.1ppm/-0.16dB/+7.1dB@10km[19481]/+16.8dB@10km[7/13]")
|
||||
|
||||
assert message['version'] == "0.2.7"
|
||||
assert message['platform'] == 'RPI-GPU'
|
||||
assert message['cpu_load'] == 0.7
|
||||
assert message['free_ram'] == 770.2
|
||||
assert message['total_ram'] == 968.2
|
||||
assert message['ntp_error'] == 1.8
|
||||
assert message['rt_crystal_correction'] == -3.3
|
||||
assert message['cpu_temp'] == 55.7
|
||||
assert message['senders_visible'] == 7
|
||||
assert message['senders_total'] == 8
|
||||
assert message['rec_crystal_correction'] == 54
|
||||
assert message['rec_crystal_correction_fine'] == -1.1
|
||||
assert message['rec_input_noise'] == -0.16
|
||||
assert message['senders_signal'] == 7.1
|
||||
assert message['senders_messages'] == 19481
|
||||
assert message['good_senders_signal'] == 16.8
|
||||
assert message['good_senders'] == 7
|
||||
assert message['good_and_bad_senders'] == 13
|
|
@ -1,15 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.aprs_comment.safesky_parser import SafeskyParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
# "SKY3E5906>OGNSKY,qAS,SafeSky:/072555h5103.47N/00524.81E'065/031/A=001250 !W05! id1C3E5906 +010fpm gps6x1"
|
||||
message = SafeskyParser().parse_position("id1C3E5906 +010fpm gps6x1")
|
||||
assert message['address'] == '3E5906'
|
||||
assert message['address_type'] == 0
|
||||
assert message['aircraft_type'] == 7
|
||||
assert message['stealth'] is False
|
||||
assert message['climb_rate'] == pytest.approx(10 * FPM_TO_MS, 2)
|
||||
assert message['gps_quality'] == {'horizontal': 6, 'vertical': 1}
|
|
@ -1,11 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS
|
||||
from ogn.parser.aprs_comment.skylines_parser import SkylinesParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = SkylinesParser().parse_position("id2816 -015fpm")
|
||||
|
||||
assert message['skylines_id'] == "2816"
|
||||
assert message['climb_rate'] == pytest.approx(-15 * FPM_TO_MS, 2)
|
|
@ -1,10 +0,0 @@
|
|||
from ogn.parser.aprs_comment.spider_parser import SpiderParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = SpiderParser().parse_position("id300234060668560 +30dB K23W 3D")
|
||||
|
||||
assert message['spider_id'] == "300234060668560"
|
||||
assert message['signal_power'] == 30
|
||||
assert message['spider_registration'] == "K23W"
|
||||
assert message['gps_quality'] == "3D"
|
|
@ -1,9 +0,0 @@
|
|||
from ogn.parser.aprs_comment.spot_parser import SpotParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = SpotParser().parse_position("id0-2860357 SPOT3 GOOD")
|
||||
|
||||
assert message['spot_id'] == "0-2860357"
|
||||
assert message['model'] == 'SPOT3'
|
||||
assert message['status'] == "GOOD"
|
|
@ -1,44 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from ogn.parser.utils import FPM_TO_MS, HPM_TO_DEGS
|
||||
from ogn.parser.aprs_comment.tracker_parser import TrackerParser
|
||||
|
||||
|
||||
def test_position_comment():
|
||||
message = TrackerParser().parse_position("id072FD00F -058fpm +1.1rot FL003.12 32.8dB 0e -0.8kHz gps3x5 +12.7dBm")
|
||||
|
||||
assert message['address_type'] == 3
|
||||
assert message['aircraft_type'] == 1
|
||||
assert message['stealth'] is False
|
||||
assert message['address'] == "2FD00F"
|
||||
assert message['climb_rate'] == pytest.approx(-58 * FPM_TO_MS, 2)
|
||||
assert message['turn_rate'] == 1.1 * HPM_TO_DEGS
|
||||
assert message['flightlevel'] == 3.12
|
||||
assert message['signal_quality'] == 32.8
|
||||
assert message['error_count'] == 0
|
||||
assert message['frequency_offset'] == -0.8
|
||||
assert message['gps_quality'] == {'horizontal': 3, 'vertical': 5}
|
||||
assert message['signal_power'] == 12.7
|
||||
|
||||
|
||||
def test_status_comment():
|
||||
message = TrackerParser().parse_status("h00 v00 9sat/1 164m 1002.6hPa +20.2degC 0% 3.34V 14/-110.5dBm 1/min")
|
||||
|
||||
assert message['hardware_version'] == 0
|
||||
assert message['software_version'] == 0
|
||||
assert message['gps_satellites'] == 9
|
||||
assert message['gps_quality'] == 1
|
||||
assert message['gps_altitude'] == 164
|
||||
assert message['pressure'] == 1002.6
|
||||
assert message['temperature'] == 20.2
|
||||
assert message['humidity'] == 0
|
||||
assert message['voltage'] == 3.34
|
||||
assert message['transmitter_power'] == 14
|
||||
assert message['noise_level'] == -110.5
|
||||
assert message['relays'] == 1
|
||||
|
||||
|
||||
def test_status_comment_comment():
|
||||
message = TrackerParser().parse_status("Pilot=Pawel Hard=DIY/STM32")
|
||||
|
||||
assert message['comment'] == "Pilot=Pawel Hard=DIY/STM32"
|
|
@ -1,20 +0,0 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_valid_beacons():
|
||||
# iterate over all txt files in the valid_messages directory
|
||||
valid_beacons = []
|
||||
for filename in os.listdir(Path(__file__).parent.parent.parent / "ogn-aprs-protocol" / "valid_messages"):
|
||||
if filename in ('OGNINRE_InReach.txt', 'OGCAPT_Capturs.txt'):
|
||||
continue
|
||||
|
||||
if filename.endswith('.txt'):
|
||||
with open(os.path.dirname(__file__) + '/../../ogn-aprs-protocol/valid_messages/' + filename) as f:
|
||||
for line in f:
|
||||
if line.strip() == '':
|
||||
continue
|
||||
|
||||
valid_beacons.append(line.strip())
|
||||
|
||||
return valid_beacons
|
|
@ -1,26 +0,0 @@
|
|||
from ogn.parser.parse import parse
|
||||
from datetime import datetime
|
||||
|
||||
from tests.rust_migration import get_valid_beacons
|
||||
|
||||
valid_beacons = get_valid_beacons()
|
||||
|
||||
|
||||
def legacy_parser():
|
||||
reference_timestamp = datetime(2015, 4, 10, 17, 0)
|
||||
for line in valid_beacons:
|
||||
parse(line, reference_timestamp=reference_timestamp)
|
||||
|
||||
|
||||
def rust_parser():
|
||||
reference_timestamp = datetime(2015, 4, 10, 17, 0)
|
||||
for line in valid_beacons:
|
||||
parse(line, reference_timestamp=reference_timestamp, use_rust_parser=True)
|
||||
|
||||
|
||||
def test_legacy_parser(benchmark):
|
||||
benchmark(legacy_parser)
|
||||
|
||||
|
||||
def test_rust_parser(benchmark):
|
||||
benchmark(rust_parser)
|
|
@ -1,85 +0,0 @@
|
|||
from ogn.parser.parse import parse
|
||||
from datetime import datetime
|
||||
import pytest
|
||||
|
||||
from tests.rust_migration import get_valid_beacons
|
||||
|
||||
valid_beacons = get_valid_beacons()
|
||||
|
||||
|
||||
@pytest.mark.skip("For development only")
|
||||
def test_parser_differences_keywise():
|
||||
differences = []
|
||||
error_combinations = {}
|
||||
for line in valid_beacons:
|
||||
py_parse_result = parse(line, reference_timestamp=datetime(2015, 4, 10, 17, 0), use_server_timestamp=False)
|
||||
rust_parse_result = parse(line, reference_timestamp=datetime(2015, 4, 10, 17, 0), use_server_timestamp=False, use_rust_parser=True)
|
||||
py_parse_result, rust_parse_result = sort_dicts(py_parse_result, rust_parse_result)
|
||||
|
||||
# Skip deprecated APRS messages
|
||||
if py_parse_result['aprs_type'] in ('status', 'position') and py_parse_result['dstcall'] == 'APRS':
|
||||
continue
|
||||
|
||||
missing_keys = [k for k in py_parse_result.keys() - rust_parse_result.keys() if py_parse_result[k] not in ('', None) and k not in ('comment')]
|
||||
extra_keys = rust_parse_result.keys() - py_parse_result.keys()
|
||||
if (missing_keys or extra_keys) and str((py_parse_result['dstcall'], missing_keys, extra_keys)) not in error_combinations:
|
||||
error_combinations[str((py_parse_result['dstcall'], missing_keys, extra_keys))] = True
|
||||
missing_entries = ('\n' + '\n'.join([f" - {k}: {py_parse_result[k]}" for k in missing_keys])) if missing_keys else ' []'
|
||||
extra_entries = ('\n' + '\n'.join([f" - {k}: {rust_parse_result[k]}" for k in extra_keys])) if extra_keys else ' []'
|
||||
delta = f"```\n{line}\ndropped:{missing_entries}\nadded:{extra_entries}\n```"
|
||||
differences.append(delta)
|
||||
|
||||
if differences:
|
||||
pytest.fail('\n\n'.join(differences))
|
||||
|
||||
|
||||
@pytest.mark.skip("For development only")
|
||||
def test_parser_differences_valuewise():
|
||||
differences = []
|
||||
for line in valid_beacons:
|
||||
py_parse_result = parse(line, reference_timestamp=datetime(2015, 4, 10, 17, 0), use_server_timestamp=False)
|
||||
rust_parse_result = parse(line, reference_timestamp=datetime(2015, 4, 10, 17, 0), use_server_timestamp=False, use_rust_parser=True)
|
||||
py_parse_result, rust_parse_result = sort_dicts(py_parse_result, rust_parse_result)
|
||||
|
||||
# Skip deprecated APRS messages
|
||||
if py_parse_result['aprs_type'] in ('status', 'position') and py_parse_result['dstcall'] == 'APRS':
|
||||
continue
|
||||
|
||||
for key in py_parse_result.keys() & rust_parse_result.keys():
|
||||
# Skip keys that differ too much (comment: intended; gps_quality and timestamp: FIXME)
|
||||
if key in ('comment', 'gps_quality'):
|
||||
continue
|
||||
|
||||
py_value, rust_value = py_parse_result[key], rust_parse_result[key]
|
||||
|
||||
# Skip keys that are not equal but are close enough (float values)
|
||||
if isinstance(py_value, float) and isinstance(rust_value, float) and abs(py_value - rust_value) < 1e-4:
|
||||
continue
|
||||
|
||||
if py_value != rust_value:
|
||||
entry = f"{line}\nPython: {key}={py_value}\nRust: {key}={rust_value}"
|
||||
differences.append(entry)
|
||||
|
||||
if differences:
|
||||
pytest.fail('\n\n'.join(differences))
|
||||
|
||||
|
||||
@pytest.mark.skip("For development only")
|
||||
def test_failing():
|
||||
failing_lines = [
|
||||
r"""MYC78FF44>OGNMYC:>140735h Pilot=RichardHunt""",
|
||||
]
|
||||
|
||||
for line in failing_lines:
|
||||
py_parse_result = parse(line, reference_timestamp=datetime(2015, 4, 10, 17, 0), use_server_timestamp=False)
|
||||
rust_parse_result = parse(line, reference_timestamp=datetime(2015, 4, 10, 17, 0), use_server_timestamp=False, use_rust_parser=True)
|
||||
py_parse_result, rust_parse_result = sort_dicts(py_parse_result, rust_parse_result)
|
||||
|
||||
assert py_parse_result == rust_parse_result, f"Results do not match for line: {line}\nPy: {py_parse_result}\nRu: {rust_parse_result}"
|
||||
|
||||
|
||||
def sort_dicts(dict1, dict2):
|
||||
# sort dictionaries for comparison
|
||||
dict1 = {k: dict1[k] for k in sorted(dict1.keys())}
|
||||
dict2 = {k: dict2[k] for k in sorted(dict2.keys())}
|
||||
return dict1, dict2
|
Ładowanie…
Reference in New Issue