openrvdas.logger.utils.formats
#
DEPRECATED! Please see logger/utils/base_module.py for the now-preferred way to validate component inputs.
#
Set of hierarchical utility classes used to check for input/output compatibility between Readers, Writers and Transforms.
The idea is that each class defined here (or elsewhere) represents a particular data exchange format, including everything from raw binary (Bytes) to JSON encodings of RVDAS Records (JSON_Record). Processes that accept inputs higher in the inheritance tree can also accept inputs that inherit from them. So something that accepts Text can also accept NMEA or XML, but not vice versa.
The only methods defined here are class methods belonging to the base class (Bytes):
A.can_accept(B) - true iff format A can accept format B, e.g. assertTrue(JSON.can_accept(JSON_Record))
A.common(B) - the lowest common format A and B share, e.g. XML.common(JSON_Record) == Text
Reader objects are intended to be instantiated such that their output_format() method returns a format class, and Writers such that their input_format() method also returns one. It is the responsibility of whatever program look encloses them to ensure compatibility by checking that
writer.input_format().can_accept(reader.output_format())
Transforms have both an input_format() and output_format(), with the unsolved complication that, for some transforms, the output format depends on the input format.
Currently-defined format hierarchy is:
Bytes
Text
NMEA
JSON - generic JSON string
JSON_Record - JSON string representing a DAS Record
XML
XML_OSU
Python - e.g. a dict or list
Python_Record - a Python DAS Record
There is also a special case 'Unknown' format that can't accept anything, and has no common elements with any other format.
1#!/usr/bin/env python3 2 3""" 4############################################################################### 5DEPRECATED! Please see logger/utils/base_module.py for the now-preferred way to 6validate component inputs. 7############################################################################### 8 9Set of hierarchical utility classes used to check for input/output 10compatibility between Readers, Writers and Transforms. 11 12The idea is that each class defined here (or elsewhere) represents a 13particular data exchange format, including everything from raw binary 14(Bytes) to JSON encodings of RVDAS Records (JSON_Record). Processes 15that accept inputs higher in the inheritance tree can also accept 16inputs that inherit from them. So something that accepts Text can also 17accept NMEA or XML, but not vice versa. 18 19The only methods defined here are class methods belonging to the base 20class (Bytes): 21 22 A.can_accept(B) - true iff format A can accept format B, e.g. 23 assertTrue(JSON.can_accept(JSON_Record)) 24 25 A.common(B) - the lowest common format A and B share, e.g. 26 XML.common(JSON_Record) == Text 27 28Reader objects are intended to be instantiated such that their 29output_format() method returns a format class, and Writers such that 30their input_format() method also returns one. It is the responsibility 31of whatever program look encloses them to ensure compatibility by 32checking that 33 34 writer.input_format().can_accept(reader.output_format()) 35 36Transforms have both an input_format() and output_format(), with the 37unsolved complication that, for some transforms, the output format 38depends on the input format. 39 40Currently-defined format hierarchy is: 41 42 Bytes 43 Text 44 NMEA 45 JSON - generic JSON string 46 JSON_Record - JSON string representing a DAS Record 47 XML 48 XML_OSU 49 Python - e.g. a dict or list 50 Python_Record - a Python DAS Record 51 52There is also a special case 'Unknown' format that can't accept 53anything, and has no common elements with any other format. 54 55""" 56import logging 57 58logging.warning('Coding error: Module "formats" is deprecated. Please use type hints, as ' 59 'described in logging/utils/base_module.py.') 60 61 62######################################## 63# Test whether the passed object is actually a valid format, as 64# defined in this file. 65def is_format(format): 66 # Is format even a class? 67 if not isinstance(format, type(Bytes)): 68 return False 69 70 # Is it a class that inherits from one of the format classes defined here? 71 if format == Unknown or Bytes.can_accept(format): 72 return True 73 74 return False 75 76 77######################################## 78# 'Unknown' is a special case format - it can't accept anything, and 79# has no other common formats 80class Unknown: 81 @classmethod 82 def can_accept(self, other_format): 83 return False 84 85 @classmethod 86 def common(self, other_format): 87 return None 88 89 90######################################## 91# 'Bytes' is the highest, most general format in the hierarchy. All 92# more-specific formats inherit from it. 93class Bytes: 94 @classmethod 95 def can_accept(self, other_format): 96 return self in other_format.mro() 97 98 # Most specific common format 99 @classmethod 100 def common(self, other_format): 101 # We have nothing in common with Unknown 102 if not other_format or other_format == Unknown: 103 return None 104 105 # Chase up module resolution order of superclasses for a match 106 other_hierarchy = other_format.mro() 107 for c in self.mro(): 108 if c in other_hierarchy: 109 return c 110 # Shouldn't actually get here, but... 111 return None 112 113 114class Text(Bytes): 115 pass 116 117 118class NMEA(Text): 119 pass 120 121 122class JSON(Text): 123 pass 124 125 126class JSON_Record(JSON): 127 pass 128 129 130class Python(Bytes): 131 pass 132 133 134class Python_Record(Python): 135 pass 136 137 138class XML(Text): 139 pass 140 141 142class XML_OSU(XML): 143 pass
81class Unknown: 82 @classmethod 83 def can_accept(self, other_format): 84 return False 85 86 @classmethod 87 def common(self, other_format): 88 return None
94class Bytes: 95 @classmethod 96 def can_accept(self, other_format): 97 return self in other_format.mro() 98 99 # Most specific common format 100 @classmethod 101 def common(self, other_format): 102 # We have nothing in common with Unknown 103 if not other_format or other_format == Unknown: 104 return None 105 106 # Chase up module resolution order of superclasses for a match 107 other_hierarchy = other_format.mro() 108 for c in self.mro(): 109 if c in other_hierarchy: 110 return c 111 # Shouldn't actually get here, but... 112 return None
100 @classmethod 101 def common(self, other_format): 102 # We have nothing in common with Unknown 103 if not other_format or other_format == Unknown: 104 return None 105 106 # Chase up module resolution order of superclasses for a match 107 other_hierarchy = other_format.mro() 108 for c in self.mro(): 109 if c in other_hierarchy: 110 return c 111 # Shouldn't actually get here, but... 112 return None