def parser(args, **kwargs): token_sep = re.compile('(?:([{}])\s*|\s+)'.format(''.join(decorations.keys()))) parsers = [ split_parser(token_sep, compact=False) ] fields = list(starmap(parser_from_header, enumerate(args.header))) # starmap(fn, iterable) ~ [ fn(*args) for args in iterable ] parsers.append(field_parser(fields)) parsers.append(lambda m: filter(lambda n: n.unit, m)) # get rid of mesaurements without unit set, in this case, the time field parsers.reverse() return compose(*parsers)
return unit_dict return inner def map_parser(fn): #parser = lambda d: map(fn, d) def inner(data): logger.log(logging.DEBUG, 'map_parser({})({})'.format(fn,data)) result = map(fn, data) logger.log(logging.DEBUG, 'result: {}'.format(result)) return result return inner # 0R5,Th=25.4242C,Vh=12.4242N,Vs=15.4242V parse_match = re.compile(r'^0R[1-3],(.*)$') # Th=25.4242C,Vh=12.4242N,Vs=15.4242V parsers = [split_parser(',')] # [ 'Th=25.4242C', 'Vh=12.4242N', 'Vs=15.4242V' ] value_sep = re.compile(r'(?:=|([a-zA-Z/]+))') # split on a single , or = and strings of one or more letters. group the latter. # [ '', 'Th', '', None, '25.4242', 'C', parsers.append(map_parser(split_parser(value_sep))) # [ [ 'Th', '25.4242', 'C' ], [ 'Vh', '12.4242', 'N' ], [ 'Vs', '15.4242', 'V' ] ] fields = [ (ig_float(1), metric_getter(0), unit_getter(0,2)) ] parsers.append(map_parser(field_parser(fields, container=False))) # [ [measurement], [measurement], [measurement] ] parsers.append(flatten) parsers.reverse() def parser(args, **kwargs): return { parse_match: compose(*parsers) } class WeatherStation(Instrument):
from lewas.models import Measurement from weather_station import weather_helper ### Discussion: requiring that we pass metrics and units arrays to ### the parser was not a good design: parsing really doesn't ### require that information, it's just the construction of the ### Measurement object that does. I changed the definition of ### parser to just return a list of coerced values if __name__ == '__main__': import sys string1 = "0R5,Th=25.9C,Vh=12.0N,Vs=15.2V\r\n" dataregex = re.compile(r'0R[0-5],(.*)') weather_parser = split_parser(regexp=dataregex, delim=",", helper=weather_helper) measurements = weather_parser(string1) for measurement in measurements: print(measurement) ### Let's say we have a sensor that just has a simple output ### format of comma separated numbers. print("\nAnother sensor") string2 = "sensor2: 23.1,34.3,56,34" ### We do need to provide the parser an array of units to use and ### metrics, presumably we get this from the sensor's
# UnitParser(int, ('time','hour'), None), # UnitParser(int, ('time', 'month'), None), # UnitParser(int, ('time', 'day'), None), # UnitParser(int, ('time', 'hour'), None), # UnitParser(int, ('time', 'minute'), None), # UnitParser(int, ('time', 'second'), None), # or will each one be passed a grouped item? # parsing change start_parsers = [] start_line = r'^[2-9][0-9]{3}\s+[0-9]{2}\s+[0-9]{2}\s+[0-9]{2}\s+[0-9]{2}\s+[0-9]{2}\s+(([0-9\.\-]+\s+){24}[0-9\.\-]+)' start_re = re.compile(start_line) #start_parsers.append(split_parser(start_re)) # this will match start line returning everything past the time # then we split on whitespace start_parsers.append(split_parser()) # default is to split on whitespace # we now have a list of numbers fields = [ (ig_float(0, stderr=3), ('water', 'downstream velocity'), 'cm/s'), (ig_float(1, stderr=4), ('water', 'lateral velocity'), 'cm/s'), (ig_float(2, stderr=5), ('water', 'depth'), 'm'), (ig_float(6), ('beam', 'signal strength 1'), 'counts'), (ig_float(7), ('beam', 'signal strength 2'), 'counts'), (ig_float(8), ('beam', 'signal strength 3'), 'counts'), # (float, 'pings', 'good', None), # (stderr_float, 'package', 'heading', None), # (stderr_float, 'package', 'pitch', None), # (stderr_float, 'package', 'roll', None), (ig_float(16), ('water', 'temperature'), 'C'), # (stderr_float, 'water', 'pressure', None),
def map_parser(fn): #parser = lambda d: map(fn, d) def inner(data): logger.log(logging.DEBUG, 'map_parser({})({})'.format(fn, data)) result = map(fn, data) logger.log(logging.DEBUG, 'result: {}'.format(result)) return result return inner # 0R5,Th=25.4242C,Vh=12.4242N,Vs=15.4242V parse_match = re.compile(r'^0R[1-3],(.*)$') # Th=25.4242C,Vh=12.4242N,Vs=15.4242V parsers = [split_parser(',')] # [ 'Th=25.4242C', 'Vh=12.4242N', 'Vs=15.4242V' ] value_sep = re.compile( r'(?:=|([a-zA-Z/]+))' ) # split on a single , or = and strings of one or more letters. group the latter. # [ '', 'Th', '', None, '25.4242', 'C', parsers.append(map_parser(split_parser(value_sep))) # [ [ 'Th', '25.4242', 'C' ], [ 'Vh', '12.4242', 'N' ], [ 'Vs', '15.4242', 'V' ] ] fields = [(ig_float(1), metric_getter(0), unit_getter(0, 2))] parsers.append(map_parser(field_parser(fields, container=False))) # [ [measurement], [measurement], [measurement] ] parsers.append(flatten) parsers.reverse() def parser(args, **kwargs):
# UnitParser(int, ('time','hour'), None), # UnitParser(int, ('time', 'month'), None), # UnitParser(int, ('time', 'day'), None), # UnitParser(int, ('time', 'hour'), None), # UnitParser(int, ('time', 'minute'), None), # UnitParser(int, ('time', 'second'), None), # or will each one be passed a grouped item? # parsing change start_parsers = [] start_line = r"^[2-9][0-9]{3}\s+[0-9]{2}\s+[0-9]{2}\s+[0-9]{2}\s+[0-9]{2}\s+[0-9]{2}\s+(([0-9\.\-]+\s+){24}[0-9\.\-]+)" start_re = re.compile(start_line) # start_parsers.append(split_parser(start_re)) # this will match start line returning everything past the time # then we split on whitespace start_parsers.append(split_parser()) # default is to split on whitespace # we now have a list of numbers fields = [ (ig_float(0, stderr=3), ("water", "downstream velocity"), "cm/s"), (ig_float(1, stderr=4), ("water", "lateral velocity"), "cm/s"), (ig_float(2, stderr=5), ("water", "depth"), "m"), (ig_float(6), ("beam", "signal strength 1"), "counts"), (ig_float(7), ("beam", "signal strength 2"), "counts"), (ig_float(8), ("beam", "signal strength 3"), "counts"), # (float, 'pings', 'good', None), # (stderr_float, 'package', 'heading', None), # (stderr_float, 'package', 'pitch', None), # (stderr_float, 'package', 'roll', None), (ig_float(16), ("water", "temperature"), "C"), # (stderr_float, 'water', 'pressure', None),