Source code for qspylib.logbook

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
"""Classes to provide the backbone of qspylib's logbook functionality
"""
import adif_io


[docs] class QSO: """A hambaseio QSO obj. Contains simple info on a QSO. Attributes: their_call (str): callsign the QSO is with band (str): band of QSO mode (str): mode of QSO qso_date (str): date of QSO time_on (str): time start of QSO qsl_rcvd (str): if QSO has been confirmed """ def __init__( self, their_call: str, band: str, mode: str, qso_date: str, time_on: str, qsl_rcvd: str = "N", ): """Initializes a QSO object. Args: their_call (str): callsign the QSO is with band (str): band of QSO mode (str): mode of QSO qso_date (str): date of QSO time_on (str): time start of QSO qsl_rcvd (str, optional): if QSO has been confirmed. Defaults to 'N'. """ self.their_call = their_call self.band = band self.mode = mode self.qso_date = qso_date self.time_on = time_on self.qsl_rcvd = qsl_rcvd def __str__(self): return f"CALL: {self.their_call} BAND: {self.band} MODE: {self.mode} \ DATE: {self.qso_date} TIME: {self.time_on} QSL: {self.qsl_rcvd}\n" # to-do: make this return as an actual adif formatted string def __eq__(self, other): if isinstance(other, QSO): if ( self.their_call == other.their_call and self.band == other.band and self.mode == other.mode and self.qso_date == other.qso_date and self.time_on == other.time_on ): return True return False
[docs] def qso_to_adif_io_qso(self) -> adif_io.QSO: """Converts a QSO object into an adif.io QSO object. Returns: adif_io.QSO: an adif.io QSO object """ return adif_io.QSO( { "CALL": self.their_call, "BAND": self.band, "MODE": self.mode, "QSO_DATE": self.qso_date, "TIME_ON": self.time_on, "QSL_RCVD": self.qsl_rcvd, } )
[docs] def qso_to_adif_string(self) -> str: """Converts a QSO object into an adif formatted string. Returns: str: an adif formatted string """ return f"<CALL:{len(self.their_call)}>{self.their_call}\ <BAND:{len(self.band)}>{self.band}\ <MODE:{len(self.mode)}>{self.mode}\ <QSO_DATE:{len(self.qso_date)}>{self.qso_date}\ <TIME_ON:{len(self.time_on)}>{self.time_on}\ <QSL_RCVD:{len(self.qsl_rcvd)}>{self.qsl_rcvd}"
[docs] class Logbook: """A Logbook has both an adi field, holding all fields parsed from an .adi\ log per QSO, and a simplified log field, holding a simplified set of\ fields per QSO. A QSO is one of qspylib.logbook.QSO. Interacting with the log field can provide one field to check for if a QSO\ is confirmed on one or more of: LoTW, eQSL, QRZ, or ClubLog. A Logbook is built by consuming an .adi formatted input string. Attributes: callsign (str): callsign of the logbook owner adi (list[adif_io.QSO]): a dict, where each "entry" is itself a dict\ of fields parsed from an .adi log. header (adif_io.Headers): header of the .adi log. log (list): simplified set of fields per QSO. """ def __init__(self, callsign: str, unparsed_log: str): """Initializes a Logbook. Args: callsign (str): callsign of the logbook owner unparsed_log (str): .adi formatted string input of a logbook """ self.callsign = callsign self.adi, self.header = adif_io.read_from_string(unparsed_log) self.log = [] for contact in self.adi: # whether this qsl has been confirmed; lotw & clublog use qsl_rcvd, # eqsl uses eqsl_qsl_rcvd, qrz most simply gives a qsl date self.log.append(qso_from_adi(contact)) def __str__(self): log_str = "" for qso in self.log: log_str += str(qso) return log_str def __eq__(self, other): if isinstance(other, Logbook): if ( self.callsign == other.callsign and self.adi == other.adi and self.header == other.header and self.log == other.log ): return True return False # public methods
[docs] def write_qso(self, contact: adif_io.QSO): """Append a QSO to both the .log and .adi portions of the Logbook object. Args: contact (adif_io.QSO): QSO object to be added, structured as from\ an adif.io QSO object """ logified_qso = qso_from_adi(contact) self.log.append(logified_qso) self.adi.append(contact)
[docs] def discard_qso(self, contact: adif_io.QSO): """Removes the corresponding QSO from the .log portion of a Logbook,\ if one exists. Args: contact (adif_io.QSO): QSO to be deleted, if it exists, structured\ as from an adif.io QSO object """ logified_qso = qso_from_adi(contact) self.log.remove(logified_qso) self.adi.remove(contact)
# region Module Functions
[docs] def qso_from_adi(contact: adif_io.QSO): """Transforms an adif_io.QSO object into a qspylib.logbook.QSO object. Args: contact (adif_io.QSO): contact to transform into a .log friendly QSO Returns: qspylib.logbook.QSO: a qspylib QSO object """ qsl_rcvd = contact.get("QSL_RCVD") qrz_qsl_dte = contact.get("app_qrzlog_qsldate") eqsl_qsl_rcvd = contact.get("eqsl_qsl_rcvd") qso_confirmed = ( "Y" if qsl_rcvd == "Y" or qrz_qsl_dte or eqsl_qsl_rcvd == "Y" else "N" ) return QSO( contact["CALL"], contact["BAND"], contact["MODE"], contact["QSO_DATE"], contact["TIME_ON"], qso_confirmed, )
# endregion