openrvdas.logger.transforms.slice_transform
Slice fields out of the specified text record.
1#!/usr/bin/env python3 2"""Slice fields out of the specified text record.""" 3 4import logging 5import sys 6 7from logger.transforms.transform import Transform # noqa: E402 8 9 10################################################################################ 11class SliceTransform(Transform): 12 def __init__(self, fields=None, sep=None, **kwargs): 13 """ 14 ``` 15 fields A comma-separated list of integers and/or ranges. A range 16 is an int:int pair, where either or both of the ints may 17 be omitted to mean the extreme values (0 or sys.maxsize). 18 19 sep Field separator; if omitted, uses default behavior of split() 20 which assumes all contiguous whitespace as a single separator. 21 ``` 22 Example: 23 ``` 24 transform = SliceTransform(':3,5:7,9,11:') 25 26 record = transform.transform('a b c d e f g h i j k l') 27 ``` 28 should yield ``'a b c f g j l'``. 29 30 Note that Python slice indexing applies, so '-3:-1' is a valid spec. 31 Note also that there's nothing requiring that fields are in order, 32 non-overlapping and/or non-repeating. The following definition is just 33 fine. 34 ``` 35 transform = SliceTransform('9,0,4,0,0:2') 36 ``` 37 """ 38 super().__init__(**kwargs) # processes 'quiet' and type hints 39 40 if not fields: 41 fields = ':' 42 43 self.fields = [] 44 self.sep = sep 45 try: 46 for field in fields.split(','): 47 logging.debug('SliceTransform parsing field "%s"', field) 48 # If field spec is a range, num:num, store as tuple of ints 49 if field.find(':') > -1: 50 (start, end) = field.split(':') 51 if start == '': # if missing start, e.g. ':5' 52 start = 0 53 if end == '': # if missing end, e.g. '1:' 54 end = sys.maxsize 55 self.fields.append((int(start), int(end))) 56 57 # If field is a simple number 58 else: 59 self.fields.append(int(field)) 60 except ValueError as e: 61 logging.error('Bad field format "%s" - %s', field, e) 62 raise e 63 64 ############################ 65 def transform(self, record: str) -> str: 66 """Strip and return only the requested fields.""" 67 68 # See if it's something we can process, and if not, try digesting 69 if not self.can_process_record(record): # inherited from BaseModule() 70 return self.digest_record(record) # inherited from BaseModule() 71 72 in_record = record.split(self.sep) 73 out_record = [] 74 for field in self.fields: 75 if type(field) is tuple: 76 slice = in_record[field[0]:field[1]] 77 else: 78 slice = [in_record[field]] 79 80 logging.debug('SliceTransform.write() selecting %s: %s', field, slice) 81 out_record.extend(slice) 82 separator = self.sep or ' ' 83 return separator.join(out_record)
class
SliceTransform(logger.transforms.transform.Transform):
12class SliceTransform(Transform): 13 def __init__(self, fields=None, sep=None, **kwargs): 14 """ 15 ``` 16 fields A comma-separated list of integers and/or ranges. A range 17 is an int:int pair, where either or both of the ints may 18 be omitted to mean the extreme values (0 or sys.maxsize). 19 20 sep Field separator; if omitted, uses default behavior of split() 21 which assumes all contiguous whitespace as a single separator. 22 ``` 23 Example: 24 ``` 25 transform = SliceTransform(':3,5:7,9,11:') 26 27 record = transform.transform('a b c d e f g h i j k l') 28 ``` 29 should yield ``'a b c f g j l'``. 30 31 Note that Python slice indexing applies, so '-3:-1' is a valid spec. 32 Note also that there's nothing requiring that fields are in order, 33 non-overlapping and/or non-repeating. The following definition is just 34 fine. 35 ``` 36 transform = SliceTransform('9,0,4,0,0:2') 37 ``` 38 """ 39 super().__init__(**kwargs) # processes 'quiet' and type hints 40 41 if not fields: 42 fields = ':' 43 44 self.fields = [] 45 self.sep = sep 46 try: 47 for field in fields.split(','): 48 logging.debug('SliceTransform parsing field "%s"', field) 49 # If field spec is a range, num:num, store as tuple of ints 50 if field.find(':') > -1: 51 (start, end) = field.split(':') 52 if start == '': # if missing start, e.g. ':5' 53 start = 0 54 if end == '': # if missing end, e.g. '1:' 55 end = sys.maxsize 56 self.fields.append((int(start), int(end))) 57 58 # If field is a simple number 59 else: 60 self.fields.append(int(field)) 61 except ValueError as e: 62 logging.error('Bad field format "%s" - %s', field, e) 63 raise e 64 65 ############################ 66 def transform(self, record: str) -> str: 67 """Strip and return only the requested fields.""" 68 69 # See if it's something we can process, and if not, try digesting 70 if not self.can_process_record(record): # inherited from BaseModule() 71 return self.digest_record(record) # inherited from BaseModule() 72 73 in_record = record.split(self.sep) 74 out_record = [] 75 for field in self.fields: 76 if type(field) is tuple: 77 slice = in_record[field[0]:field[1]] 78 else: 79 slice = [in_record[field]] 80 81 logging.debug('SliceTransform.write() selecting %s: %s', field, slice) 82 out_record.extend(slice) 83 separator = self.sep or ' ' 84 return separator.join(out_record)
Base class Transform about which we know nothing else.
Passes arguments quiet, encoding and encoding_errors up to BaseModule
SliceTransform(fields=None, sep=None, **kwargs)
13 def __init__(self, fields=None, sep=None, **kwargs): 14 """ 15 ``` 16 fields A comma-separated list of integers and/or ranges. A range 17 is an int:int pair, where either or both of the ints may 18 be omitted to mean the extreme values (0 or sys.maxsize). 19 20 sep Field separator; if omitted, uses default behavior of split() 21 which assumes all contiguous whitespace as a single separator. 22 ``` 23 Example: 24 ``` 25 transform = SliceTransform(':3,5:7,9,11:') 26 27 record = transform.transform('a b c d e f g h i j k l') 28 ``` 29 should yield ``'a b c f g j l'``. 30 31 Note that Python slice indexing applies, so '-3:-1' is a valid spec. 32 Note also that there's nothing requiring that fields are in order, 33 non-overlapping and/or non-repeating. The following definition is just 34 fine. 35 ``` 36 transform = SliceTransform('9,0,4,0,0:2') 37 ``` 38 """ 39 super().__init__(**kwargs) # processes 'quiet' and type hints 40 41 if not fields: 42 fields = ':' 43 44 self.fields = [] 45 self.sep = sep 46 try: 47 for field in fields.split(','): 48 logging.debug('SliceTransform parsing field "%s"', field) 49 # If field spec is a range, num:num, store as tuple of ints 50 if field.find(':') > -1: 51 (start, end) = field.split(':') 52 if start == '': # if missing start, e.g. ':5' 53 start = 0 54 if end == '': # if missing end, e.g. '1:' 55 end = sys.maxsize 56 self.fields.append((int(start), int(end))) 57 58 # If field is a simple number 59 else: 60 self.fields.append(int(field)) 61 except ValueError as e: 62 logging.error('Bad field format "%s" - %s', field, e) 63 raise e
fields A comma-separated list of integers and/or ranges. A range
is an int:int pair, where either or both of the ints may
be omitted to mean the extreme values (0 or sys.maxsize).
sep Field separator; if omitted, uses default behavior of split()
which assumes all contiguous whitespace as a single separator.
Example:
transform = SliceTransform(':3,5:7,9,11:')
record = transform.transform('a b c d e f g h i j k l')
should yield 'a b c f g j l'.
Note that Python slice indexing applies, so '-3:-1' is a valid spec. Note also that there's nothing requiring that fields are in order, non-overlapping and/or non-repeating. The following definition is just fine.
transform = SliceTransform('9,0,4,0,0:2')
def
transform(self, record: str) -> str:
66 def transform(self, record: str) -> str: 67 """Strip and return only the requested fields.""" 68 69 # See if it's something we can process, and if not, try digesting 70 if not self.can_process_record(record): # inherited from BaseModule() 71 return self.digest_record(record) # inherited from BaseModule() 72 73 in_record = record.split(self.sep) 74 out_record = [] 75 for field in self.fields: 76 if type(field) is tuple: 77 slice = in_record[field[0]:field[1]] 78 else: 79 slice = [in_record[field]] 80 81 logging.debug('SliceTransform.write() selecting %s: %s', field, slice) 82 out_record.extend(slice) 83 separator = self.sep or ' ' 84 return separator.join(out_record)
Strip and return only the requested fields.