Ejemplo n.º 1
0
    def write(self, file):
        """writes a Cabrillo log text to the text-file-like object file.

        Arguments:
            file: Anything that has a write() - method accepting a string.
                  Cabrillo log file text is written here. `_` in attribute
                  names are automatically replaced by `-`.

        Raises:
            InvalidLogException when target Cabrillo version is not 3.0
            or ignore_ordered mode is active.
        """
        if self.version != '3.0':
            raise InvalidLogException("Only Cabrillo v3 supported.")

        if self.ignore_order:
            raise InvalidLogException("Refuse produce output in ignore_ordered mode as Cabrillo logs need to be ordered time-wise.")

        print('START-OF-LOG: {}'.format(self.version), file=file)

        # Output known attributes.
        for attribute, keyword in data.OUTPUT_KEYWORD_MAP.items():
            value = getattr(self, attribute, None)
            if value is not None:
                if attribute == 'certificate':
                    # Convert boolean to YES/NO.
                    print('{}: {}'.format(keyword, 'YES' if value else 'NO'), file=file)
                elif attribute in ['address', 'soapbox']:
                    # Process multi-line attributes.
                    for x in value:
                        print('{}: {}'.format(keyword, x), file=file)
                elif attribute == 'operators':
                    # Process attributes delimited by space.
                    print('{}: {}'.format(keyword, ' '.join(value)), file=file)
                elif attribute == 'offtime':
                    # Process offtime dates.
                    print('{}: {}'.format(keyword, ' '.join(
                        [x.strftime("%Y-%m-%d %H%M") for x in value])), file=file)
                elif value and attribute != 'version':
                    print('{}: {}'.format(keyword, value), file=file)

        # Output ignored attributes.
        for attribute, keyword in self.x_anything.items():
            print('{}: {}'.format(attribute.replace('_', '-'), keyword), file=file)

        # Output QSOs:
        for qso in self.qso:
            print(qso, file=file)

        print('END-OF-LOG:', file=file)
Ejemplo n.º 2
0
    def append_qso(self, qso, ignore_order):
        """Add one QSO to the end of this log."""
        if 0 < len(self.qso) and qso.date < self.qso[-1].date and not ignore_order:
            # The Cabrillo spec says QSOs need to be ordered by time.
            # The timestamps from Cabrillo's point of view
            # give time only to minute precision, and
            # QSO rates above 60 / hour are by no means uncommon.
            # So we refrain from ordering QSOs by timestamps ourselves.
            raise InvalidLogException("QSOs need to be ordered time-wise.")

        self.qso.append(qso)
Ejemplo n.º 3
0
    def __init__(self, check_categories=True, ignore_order=False, **d):
        """Construct a Cabrillo object.

        Use named arguments only.

        Attributes:
            check_categories: Check if categories, if given, exist in the
            Cabrillo specification.
            See class attributes for other parameters.

        Raises:
            InvalidLogException
        """
        d.setdefault('created_by', 'cabrillo (Python)')
        for key in data.OUTPUT_KEYWORD_MAP:
            setattr(self, key, d.get(key, None))

        self.x_anything = d.get('x_anything', collections.OrderedDict())

        version = d.get('version', '3.0')
        if version != '3.0':
            raise InvalidLogException("Only Cabrillo v3 supported, "
                                      "got {}".format(version))
        else:
            self.version = version

        self.qso = []
        for qso in d.get('qso', []):
            self.append_qso(qso, ignore_order)

        self.ignore_order = ignore_order

        if check_categories:
            for attribute, candidates in data.VALID_CATEGORIES_MAP.items():
                value = getattr(self, attribute, None)
                if value and value not in candidates:
                    raise InvalidLogException(
                        'Got {} for {} but expecting one of {}.'.format(
                            value, attribute, candidates))
Ejemplo n.º 4
0
    def write_text(self):
        """write_text generates a Cabrillo log text.

        Arguments:
            None.

        Returns:
            str: Cabrillo log file text. `_` in Attribute
              names are automatically replaced to `-` upon text output.

        Raises:
            InvalidLogException when target Cabrillo version is not 3.0.
        """
        if self.version != '3.0':
            raise InvalidLogException("Only Cabrillo v3 supported.")

        lines = list()
        lines.append('START-OF-LOG: {}'.format(self.version))

        # Output known attributes.
        for attribute, keyword in data.KEYWORD_MAP.items():
            value = getattr(self, attribute, None)
            if value is not None:
                if attribute == 'certificate':
                    # Convert boolean to YES/NO.
                    if value:
                        lines.append('{}: YES'.format(keyword))
                    else:
                        lines.append('{}: NO'.format(keyword))
                elif attribute in ['address', 'soapbox', 'qso', 'x_qso']:
                    # Process multi-line attributes.
                    output_lines = ['{}: {}'.format(keyword, str(x)) for x in
                                    value]
                    lines += output_lines
                elif attribute == 'operators':
                    # Process attributes delimited by space.
                    lines.append('{}: {}'.format(keyword, ' '.join(value)))
                elif attribute == 'offtime':
                    # Process offtime dates.
                    lines.append('{}: {}'.format(keyword, ' '.join(
                        [x.strftime("%Y-%m-%d %H%M") for x in value])))
                elif value and attribute != 'version':
                    lines.append('{}: {}'.format(keyword, value))

        # Output ignored attributes.
        for attribute, keyword in self.x_anything.items():
            lines.append('{}: {}'.format(attribute.replace('_', '-'), keyword))

        lines.append('END-OF-LOG:')

        return '\n'.join(lines)
Ejemplo n.º 5
0
    def __init__(self, check_categories=True, **d):
        """Construct a Cabrillo object.

        Use named arguments only.

        Attributes:
            check_categories: Check if categories, if given, exist in the
            Cabrillo specification.
            See class attributes for other parameters.

        Raises:
            InvalidLogException
        """
        d.setdefault('version', '3.0')
        d.setdefault('created_by', 'cabrillo (Python)')
        for key in data.KEYWORD_MAP:
            setattr(self, key, d.setdefault(key, None))

        self.x_anything = d.setdefault('x_anything', dict())

        if self.version != '3.0':
            raise InvalidLogException("Only Cabrillo v3 supported, "
                                      "got {}".format(self.version))

        if not self.qso:
            self.qso = list()

        if not self.x_qso:
            self.x_qso = list()

        if check_categories:
            for attribute, candidates in data.VALID_CATEGORIES_MAP.items():
                value = getattr(self, attribute, None)
                if value and value not in candidates:
                    raise InvalidLogException(
                        'Got {} for {} but expecting one of {}.'.format(
                            value,
                            attribute, candidates))
Ejemplo n.º 6
0
def parse_log_text(text, ignore_unknown_key=False, check_categories=True):
    """Parse a Cabrillo log in text form.

    Attributes in cabrillo.data.KEYWORD_MAP will be parsed accordingly. X-
    attributes will be sorted into the x_anything attribute of the Cabrillo
    object.

    Arguments:
        text: str of log
        check_categories: Check if categories, if given, exist in the
            Cabrillo specification.
        ignore_unknown_key: Boolean denoting whether if unknown and non X-
            attributes should be ignored if found in long. Otherwise,
            an InvalidLogException will be raised. Defaults to False (
            enforces valid keyword).

    Returns:
        cabrillo.Cabrillo

    Raises:
        InvalidQSOException, InvalidLogException
    """
    inverse_keywords = {v: k for k, v in KEYWORD_MAP.items()}
    results = dict()
    results['x_anything'] = dict()

    for line in text.split('\n'):
        try:
            key, value = [x.replace('\r', '').strip() for x in line.split(':')]
        except ValueError:
            raise InvalidLogException('Line not delimited by `:`, '
                                      'got {}.'.format(line))

        if key == 'END-OF-LOG':
            break
        elif key == 'CLAIMED-SCORE':
            try:
                results[inverse_keywords[key]] = int(value)
            except ValueError:
                raise InvalidLogException('Improperly formatted claimed '
                                          'score "{}". Per specification the'
                                          ' score, if given, must be an '
                                          'integer without any formatting, '
                                          'like "12345678".'.format(value))
        elif key == 'CERTIFICATE':
            results[inverse_keywords[key]] = value == 'YES'
        elif key in ['QSO', 'X-QSO']:
            results.setdefault(inverse_keywords[key],
                               list()).append(parse_qso(value))
        elif key == 'OPERATORS':
            results[inverse_keywords[key]] = value.replace(',', ' ').split()
        elif key in ['ADDRESS', 'SOAPBOX']:
            results.setdefault(inverse_keywords[key], list()).append(value)
        elif key in inverse_keywords.keys():
            results[inverse_keywords[key]] = value
        elif key.startswith('X-'):
            results['x_anything'][key] = value
        elif not ignore_unknown_key:
            raise InvalidLogException("Unknown key {} read.".format(key))

    return Cabrillo(check_categories=check_categories, **results)
Ejemplo n.º 7
0
def parse_log_text(text, ignore_unknown_key=False, check_categories=True, ignore_order=False):
    """Parse a Cabrillo log in text form.

    Attributes in cabrillo.data.KEYWORD_MAP will be parsed accordingly. X-
    attributes will be sorted into the x_anything attribute of the Cabrillo
    object.

    Arguments:
        text: str of log
        check_categories: Check if categories, if given, exist in the
            Cabrillo specification.
        ignore_unknown_key: Boolean denoting whether if unknown and non X-
            attributes should be ignored if found in long. Otherwise,
            an InvalidLogException will be raised. Defaults to False
            (which enforces valid keywords).

    Returns:
        cabrillo.Cabrillo

    Raises:
        InvalidQSOException, InvalidLogException
    """
    inverse_keywords = {v: k for k, v in KEYWORD_MAP.items()}
    results = dict()
    results['x_anything'] = collections.OrderedDict()

    key_colon_value = re.compile(r'^\s*([^:]+?)\s*:\s*(.*?)\s*$')
    for line in text.split('\n'):
        match = key_colon_value.fullmatch(line)
        if match:
            key, value = match.group(1), match.group(2)
        else:
            raise InvalidLogException('Line does not start with `:`-delimited key, '
                                      'got `{}`.'.format(line))

        if key == 'END-OF-LOG':
            break
        elif key == 'CLAIMED-SCORE':
            try:
                results[inverse_keywords[key]] = int(value)
            except ValueError:
                raise InvalidLogException('Improperly formatted claimed '
                                          'score "{}". Per specification the'
                                          ' score, if given, must be an '
                                          'integer without any formatting, '
                                          'like "12345678".'.format(value))
        elif key == 'CERTIFICATE':
            results[inverse_keywords[key]] = value == 'YES'
        elif key in ['QSO', 'X-QSO']:
            # Do not split QSO and X-QSO case here.
            # By not splitting, we keep timewise order for QSOs that have the same timestamp.
            results.setdefault("qso", []).append(parse_qso(value, key == "QSO"))
        elif key == 'OPERATORS':
            results.setdefault(inverse_keywords[key], list()).extend(value.replace(',', ' ').split())
        elif key in ['ADDRESS', 'SOAPBOX']:
            results.setdefault(inverse_keywords[key], list()).append(value)
        elif key in inverse_keywords.keys():
            results[inverse_keywords[key]] = value
        elif key.startswith('X-'):
            # We keep the order that we were given.
            results['x_anything'][key] = value
        elif not ignore_unknown_key:
            raise InvalidLogException("Unknown key {} read.".format(key))

    return Cabrillo(check_categories=check_categories, ignore_order=ignore_order, **results)