openrvdas.logger.transforms.select_fields_transform

Compute subsamples of input data.

  1#!/usr/bin/env python3
  2"""Compute subsamples of input data.
  3"""
  4
  5import copy
  6import logging
  7from typing import Union
  8
  9from logger.utils.das_record import DASRecord  # noqa: E402
 10from logger.transforms.transform import Transform  # noqa: E402
 11
 12
 13################################################################################
 14class SelectFieldsTransform(Transform):
 15    """Cull key:value pairs from a record's field dict. Can accept a
 16    top-level dict, a field dict or a DASRecord, and will return a
 17    record in the same format as it received.
 18    """
 19
 20    def __init__(self, keep=None, delete=None, **kwargs):
 21        """
 22        ```
 23        keep - an optional list of field names to keep
 24
 25        delete - an optional list of field names to delete
 26
 27        One, but not both of these should be present. If both are present,
 28        the delete values will be ignored.
 29
 30        Can accept a top-level dict, a field dict or a DASRecord, and will
 31        return a record in the same format as it received.
 32        ```
 33        """
 34        super().__init__(**kwargs)  # processes 'quiet' and type hints
 35
 36        self.keep = keep or []
 37        self.delete = delete or []
 38
 39        if not keep and not delete:
 40            logging.warning('SelectFieldsTransform has empty "keep" and "delete" arguments; '
 41                            'no modifications will be made to passed records.')
 42        if keep and delete:
 43            logging.warning('SelectFieldsTransform has both "keep" and "delete" arguments; '
 44                            '"delete" arguments will be ignored.')
 45
 46    ############################
 47    def transform(self, record: Union[dict, DASRecord]):
 48        """
 49        Return a copy of the passed record with the relevant fields kept/deleted.
 50        """
 51        # See if it's something we can process, and if not, try digesting
 52        if not self.can_process_record(record):  # inherited from BaseModule()
 53            return self.digest_record(record)  # inherited from BaseModule()
 54
 55        # We need to make a deep copy of the record, because we're going
 56        # to modify it as we go, and the same record may be getting passed
 57        # to multiple transforms at the same time (e.g., if the transform
 58        # is part of a ComposedWriter, and we have multiple
 59        # ComposedWriters).
 60        new_record = copy.deepcopy(record)
 61
 62        # Below, we're counting on Python copying the relevant dict by
 63        # reference so that if we modify the 'fields' dict, it is also
 64        # modified in the record we were passed.
 65
 66        # As warned in the constructor, if we have both keep and delete,
 67        # we're going to pass records through unchanged.
 68        if self.keep and self.delete:
 69            return new_record
 70
 71        # If it's a dict, hope it's a single record.
 72        elif type(new_record) is DASRecord:
 73            fields = new_record.fields
 74
 75        elif type(new_record) is dict:
 76            # If we have a 'fields' dict inside the dict, use that
 77            if 'fields' in new_record and type(new_record['fields']) is dict:
 78                fields = new_record['fields']
 79
 80            # Otherwise treat the entire dict as a field dict
 81            else:
 82                fields = new_record
 83
 84        else:
 85            logging.warning('SelectFieldsTransform Got non-list/dict/DASRecord '
 86                            'record to interpolate: %s', new_record)
 87            return None
 88
 89        if self.delete:
 90            for key in self.delete:
 91                if key in fields:
 92                    del fields[key]
 93        else:
 94            field_list = list(fields.keys())
 95            for key in field_list:
 96                if key not in self.keep:
 97                    del fields[key]
 98
 99        # If no fields left, scrap the record
100        if not fields:
101            return None
102
103        return new_record
class SelectFieldsTransform(logger.transforms.transform.Transform):
 15class SelectFieldsTransform(Transform):
 16    """Cull key:value pairs from a record's field dict. Can accept a
 17    top-level dict, a field dict or a DASRecord, and will return a
 18    record in the same format as it received.
 19    """
 20
 21    def __init__(self, keep=None, delete=None, **kwargs):
 22        """
 23        ```
 24        keep - an optional list of field names to keep
 25
 26        delete - an optional list of field names to delete
 27
 28        One, but not both of these should be present. If both are present,
 29        the delete values will be ignored.
 30
 31        Can accept a top-level dict, a field dict or a DASRecord, and will
 32        return a record in the same format as it received.
 33        ```
 34        """
 35        super().__init__(**kwargs)  # processes 'quiet' and type hints
 36
 37        self.keep = keep or []
 38        self.delete = delete or []
 39
 40        if not keep and not delete:
 41            logging.warning('SelectFieldsTransform has empty "keep" and "delete" arguments; '
 42                            'no modifications will be made to passed records.')
 43        if keep and delete:
 44            logging.warning('SelectFieldsTransform has both "keep" and "delete" arguments; '
 45                            '"delete" arguments will be ignored.')
 46
 47    ############################
 48    def transform(self, record: Union[dict, DASRecord]):
 49        """
 50        Return a copy of the passed record with the relevant fields kept/deleted.
 51        """
 52        # See if it's something we can process, and if not, try digesting
 53        if not self.can_process_record(record):  # inherited from BaseModule()
 54            return self.digest_record(record)  # inherited from BaseModule()
 55
 56        # We need to make a deep copy of the record, because we're going
 57        # to modify it as we go, and the same record may be getting passed
 58        # to multiple transforms at the same time (e.g., if the transform
 59        # is part of a ComposedWriter, and we have multiple
 60        # ComposedWriters).
 61        new_record = copy.deepcopy(record)
 62
 63        # Below, we're counting on Python copying the relevant dict by
 64        # reference so that if we modify the 'fields' dict, it is also
 65        # modified in the record we were passed.
 66
 67        # As warned in the constructor, if we have both keep and delete,
 68        # we're going to pass records through unchanged.
 69        if self.keep and self.delete:
 70            return new_record
 71
 72        # If it's a dict, hope it's a single record.
 73        elif type(new_record) is DASRecord:
 74            fields = new_record.fields
 75
 76        elif type(new_record) is dict:
 77            # If we have a 'fields' dict inside the dict, use that
 78            if 'fields' in new_record and type(new_record['fields']) is dict:
 79                fields = new_record['fields']
 80
 81            # Otherwise treat the entire dict as a field dict
 82            else:
 83                fields = new_record
 84
 85        else:
 86            logging.warning('SelectFieldsTransform Got non-list/dict/DASRecord '
 87                            'record to interpolate: %s', new_record)
 88            return None
 89
 90        if self.delete:
 91            for key in self.delete:
 92                if key in fields:
 93                    del fields[key]
 94        else:
 95            field_list = list(fields.keys())
 96            for key in field_list:
 97                if key not in self.keep:
 98                    del fields[key]
 99
100        # If no fields left, scrap the record
101        if not fields:
102            return None
103
104        return new_record

Cull key:value pairs from a record's field dict. Can accept a top-level dict, a field dict or a DASRecord, and will return a record in the same format as it received.

SelectFieldsTransform(keep=None, delete=None, **kwargs)
21    def __init__(self, keep=None, delete=None, **kwargs):
22        """
23        ```
24        keep - an optional list of field names to keep
25
26        delete - an optional list of field names to delete
27
28        One, but not both of these should be present. If both are present,
29        the delete values will be ignored.
30
31        Can accept a top-level dict, a field dict or a DASRecord, and will
32        return a record in the same format as it received.
33        ```
34        """
35        super().__init__(**kwargs)  # processes 'quiet' and type hints
36
37        self.keep = keep or []
38        self.delete = delete or []
39
40        if not keep and not delete:
41            logging.warning('SelectFieldsTransform has empty "keep" and "delete" arguments; '
42                            'no modifications will be made to passed records.')
43        if keep and delete:
44            logging.warning('SelectFieldsTransform has both "keep" and "delete" arguments; '
45                            '"delete" arguments will be ignored.')
keep - an optional list of field names to keep

delete - an optional list of field names to delete

One, but not both of these should be present. If both are present,
the delete values will be ignored.

Can accept a top-level dict, a field dict or a DASRecord, and will
return a record in the same format as it received.
keep
delete
def transform(self, record: Union[dict, logger.utils.das_record.DASRecord]):
 48    def transform(self, record: Union[dict, DASRecord]):
 49        """
 50        Return a copy of the passed record with the relevant fields kept/deleted.
 51        """
 52        # See if it's something we can process, and if not, try digesting
 53        if not self.can_process_record(record):  # inherited from BaseModule()
 54            return self.digest_record(record)  # inherited from BaseModule()
 55
 56        # We need to make a deep copy of the record, because we're going
 57        # to modify it as we go, and the same record may be getting passed
 58        # to multiple transforms at the same time (e.g., if the transform
 59        # is part of a ComposedWriter, and we have multiple
 60        # ComposedWriters).
 61        new_record = copy.deepcopy(record)
 62
 63        # Below, we're counting on Python copying the relevant dict by
 64        # reference so that if we modify the 'fields' dict, it is also
 65        # modified in the record we were passed.
 66
 67        # As warned in the constructor, if we have both keep and delete,
 68        # we're going to pass records through unchanged.
 69        if self.keep and self.delete:
 70            return new_record
 71
 72        # If it's a dict, hope it's a single record.
 73        elif type(new_record) is DASRecord:
 74            fields = new_record.fields
 75
 76        elif type(new_record) is dict:
 77            # If we have a 'fields' dict inside the dict, use that
 78            if 'fields' in new_record and type(new_record['fields']) is dict:
 79                fields = new_record['fields']
 80
 81            # Otherwise treat the entire dict as a field dict
 82            else:
 83                fields = new_record
 84
 85        else:
 86            logging.warning('SelectFieldsTransform Got non-list/dict/DASRecord '
 87                            'record to interpolate: %s', new_record)
 88            return None
 89
 90        if self.delete:
 91            for key in self.delete:
 92                if key in fields:
 93                    del fields[key]
 94        else:
 95            field_list = list(fields.keys())
 96            for key in field_list:
 97                if key not in self.keep:
 98                    del fields[key]
 99
100        # If no fields left, scrap the record
101        if not fields:
102            return None
103
104        return new_record

Return a copy of the passed record with the relevant fields kept/deleted.