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')
fields
sep
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.