kopia lustrzana https://github.com/ctjacobs/pyqso
Better error handling.
rodzic
3e32142e8a
commit
e34253adb2
|
@ -204,22 +204,13 @@ class ADIF:
|
|||
:arg str path: The path to the ADIF file to read.
|
||||
:returns: A list of dictionaries (one dictionary per QSO), with each dictionary containing field-value pairs, e.g. {FREQ:145.500, BAND:2M, MODE:FM}. If the file cannot be read, the method returns None.
|
||||
:rtype: list
|
||||
:raises IOError: if the ADIF file does not exist or cannot be read (e.g. due to lack of read permissions).
|
||||
:raises IOError: If the ADIF file does not exist or cannot be read (e.g. due to lack of read permissions).
|
||||
"""
|
||||
logging.debug("Reading in ADIF file with path: %s..." % path)
|
||||
|
||||
text = ""
|
||||
try:
|
||||
f = open(path, mode='r', errors="replace")
|
||||
with open(path, mode='r', errors="replace") as f:
|
||||
text = f.read()
|
||||
f.close() # Close the file, otherwise "bad things" might happen!
|
||||
except IOError as e:
|
||||
logging.error("I/O error %d: %s" % (e.errno, e.strerror))
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.error("An error occurred when reading the ADIF file.")
|
||||
logging.exception(e)
|
||||
return None
|
||||
|
||||
records = self.parse_adi(text)
|
||||
|
||||
|
@ -333,16 +324,13 @@ class ADIF:
|
|||
|
||||
:arg list records: The list of QSO records to write.
|
||||
:arg str path: The desired path of the ADIF file to write to.
|
||||
:returns: True if the write process was successful, otherwise False.
|
||||
:rtype: bool
|
||||
:raises IOError: if the ADIF file cannot be written (e.g. due to lack of write permissions).
|
||||
:returns: None
|
||||
:raises IOError: If the ADIF file cannot be written (e.g. due to lack of write permissions).
|
||||
"""
|
||||
|
||||
logging.debug("Writing records to an ADIF file...")
|
||||
|
||||
success = False
|
||||
try:
|
||||
f = open(path, mode='w', errors="replace") # Open file for writing
|
||||
with open(path, mode='w', errors="replace") as f: # Open file for writing
|
||||
|
||||
# First write a header containing program version, number of records, etc.
|
||||
dt = datetime.now()
|
||||
|
@ -368,15 +356,10 @@ class ADIF:
|
|||
|
||||
logging.debug("Finished writing records to the ADIF file.")
|
||||
f.close()
|
||||
logging.info("Wrote %d QSOs to %s in ADIF format." % (len(records), path))
|
||||
success = True
|
||||
except IOError as e:
|
||||
logging.error("I/O error %d: %s" % (e.errno, e.strerror))
|
||||
except Exception as e: # All other exceptions.
|
||||
logging.error("An error occurred when writing the ADIF file.")
|
||||
logging.exception(e)
|
||||
|
||||
return success
|
||||
logging.info("Wrote %d QSOs to %s in ADIF format." % (len(records), path))
|
||||
|
||||
return
|
||||
|
||||
def is_valid(self, field_name, data, data_type):
|
||||
""" Validate the data in a field with respect to the ADIF specification.
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
from gi.repository import Gtk
|
||||
import logging
|
||||
import sqlite
|
||||
|
||||
|
||||
class Awards:
|
||||
|
@ -78,16 +79,18 @@ class Awards:
|
|||
"""
|
||||
|
||||
logging.debug("Counting the band/mode combinations for the awards table...")
|
||||
|
||||
# Wipe everything and start again.
|
||||
self.awards.clear()
|
||||
|
||||
# For each mode, add a new list for holding the totals, and initialise the values to zero.
|
||||
count = []
|
||||
for i in range(0, len(self.bands)):
|
||||
count.append([0]*len(self.bands))
|
||||
|
||||
for log in logbook.logs:
|
||||
records = log.records
|
||||
if(records is not None):
|
||||
try:
|
||||
records = log.records
|
||||
for r in records:
|
||||
if(r["BAND"] is not None and r["MODE"] is not None):
|
||||
if(r["BAND"].lower() in self.bands and r["MODE"] != ""):
|
||||
|
@ -101,8 +104,10 @@ class Awards:
|
|||
# FIXME: This assumes that all the other modes in the ADIF list are digital modes. Is this the case?
|
||||
count[2][band] += 1
|
||||
count[3][band] += 1 # Keep the total of each column in the "Mixed" mode.
|
||||
else:
|
||||
|
||||
except sqlite.Error as e:
|
||||
logging.error("Could not update the awards table for '%s' because of a database error." % log.name)
|
||||
logging.exception(e)
|
||||
|
||||
# Insert the rows containing the totals.
|
||||
for i in range(0, len(self.modes)):
|
||||
|
|
|
@ -40,15 +40,12 @@ class Cabrillo:
|
|||
:arg str path: The desired path of the Cabrillo file to write to.
|
||||
:arg str contest: The name of the contest.
|
||||
:arg str mycall: The callsign used during the contest.
|
||||
:returns: True if the write process was successful, otherwise False.
|
||||
:rtype: bool
|
||||
:raises IOError: if the Cabrillo file cannot be written (e.g. due to lack of write permissions)."""
|
||||
:returns: None
|
||||
:raises IOError: If the Cabrillo file cannot be written (e.g. due to lack of write permissions)."""
|
||||
|
||||
logging.debug("Writing records to a Cabrillo file...")
|
||||
|
||||
success = False
|
||||
try:
|
||||
f = open(path, mode='w', errors="replace") # Open file for writing
|
||||
with open(path, mode='w', errors="replace") as f: # Open file for writing
|
||||
|
||||
# Header
|
||||
f.write("""START-OF-LOG: %s\n""" % (CABRILLO_VERSION))
|
||||
|
@ -62,7 +59,7 @@ class Cabrillo:
|
|||
# Frequency. Note that this must be in kHz. The frequency is stored in MHz in the database, so it's converted to kHz here.
|
||||
try:
|
||||
freq = str(float(r["FREQ"])*1e3)
|
||||
except ValueError as e:
|
||||
except ValueError:
|
||||
freq = ""
|
||||
|
||||
# Mode
|
||||
|
@ -103,15 +100,6 @@ class Cabrillo:
|
|||
# Footer
|
||||
f.write("END-OF-LOG:")
|
||||
|
||||
f.close()
|
||||
|
||||
logging.info("Wrote %d QSOs to %s in Cabrillo format." % (len(records), path))
|
||||
success = True
|
||||
|
||||
except IOError as e:
|
||||
logging.error("I/O error %d: %s" % (e.errno, e.strerror))
|
||||
except Exception as e: # All other exceptions.
|
||||
logging.error("An error occurred when writing the Cabrillo file.")
|
||||
logging.exception(e)
|
||||
|
||||
return success
|
||||
return
|
||||
|
|
37
pyqso/log.py
37
pyqso/log.py
|
@ -52,8 +52,10 @@ class Log(Gtk.ListStore):
|
|||
logging.debug("Populating '%s'..." % self.name)
|
||||
self.add_missing_db_columns()
|
||||
self.clear()
|
||||
records = self.records
|
||||
if(records is not None):
|
||||
|
||||
try:
|
||||
records = self.records
|
||||
|
||||
for r in records:
|
||||
liststore_entry = [r["id"]]
|
||||
for field_name in AVAILABLE_FIELD_NAMES_ORDERED:
|
||||
|
@ -63,8 +65,11 @@ class Log(Gtk.ListStore):
|
|||
liststore_entry.append(r[field_name])
|
||||
self.append(liststore_entry)
|
||||
logging.debug("Finished populating '%s'." % self.name)
|
||||
else:
|
||||
|
||||
except sqlite.Error as e:
|
||||
logging.error("Could not populate '%s' because of a database error." % self.name)
|
||||
logging.exception(e)
|
||||
|
||||
return
|
||||
|
||||
def add_missing_db_columns(self):
|
||||
|
@ -315,15 +320,12 @@ class Log(Gtk.ListStore):
|
|||
|
||||
:returns: A list of all the records in the log. Each record is represented by a dictionary.
|
||||
:rtype: dict
|
||||
:raises sqlite.Error: If the records could not be retrieved from the database.
|
||||
"""
|
||||
try:
|
||||
with self.connection:
|
||||
c = self.connection.cursor()
|
||||
c.execute("SELECT * FROM %s" % self.name)
|
||||
return c.fetchall()
|
||||
except sqlite.Error as e:
|
||||
logging.exception(e)
|
||||
return None
|
||||
with self.connection:
|
||||
c = self.connection.cursor()
|
||||
c.execute("SELECT * FROM %s" % self.name)
|
||||
return c.fetchall()
|
||||
|
||||
@property
|
||||
def record_count(self):
|
||||
|
@ -331,12 +333,9 @@ class Log(Gtk.ListStore):
|
|||
|
||||
:returns: The total number of records in the log.
|
||||
:rtype: int
|
||||
:raises sqlite.Error: If the record count could not be determined due to a database error.
|
||||
"""
|
||||
try:
|
||||
with self.connection:
|
||||
c = self.connection.cursor()
|
||||
c.execute("SELECT Count(*) FROM %s" % self.name)
|
||||
return c.fetchone()[0]
|
||||
except (sqlite.Error, IndexError) as e:
|
||||
logging.exception(e)
|
||||
return None
|
||||
with self.connection:
|
||||
c = self.connection.cursor()
|
||||
c.execute("SELECT Count(*) FROM %s" % self.name)
|
||||
return c.fetchone()[0]
|
||||
|
|
|
@ -204,9 +204,9 @@ class Logbook:
|
|||
self.connection = sqlite.connect(path)
|
||||
self.connection.row_factory = sqlite.Row
|
||||
except sqlite.Error as e:
|
||||
# PyQSO can't connect to the database.
|
||||
# Cannot connect to the database.
|
||||
logging.exception(e)
|
||||
error(parent=self.application.window, message="PyQSO cannot connect to the database. Check file permissions?")
|
||||
error(parent=self.application.window, message="Cannot connect to the database. Check file permissions?")
|
||||
return False
|
||||
|
||||
logging.debug("Database connection created successfully!")
|
||||
|
@ -555,16 +555,21 @@ class Logbook:
|
|||
path = None
|
||||
dialog.destroy()
|
||||
|
||||
# Read the records.
|
||||
adif = ADIF()
|
||||
if(path is None):
|
||||
logging.debug("No file path specified.")
|
||||
return
|
||||
else:
|
||||
|
||||
# Read the records.
|
||||
adif = ADIF()
|
||||
try:
|
||||
records = adif.read(path)
|
||||
if(records is None):
|
||||
error(parent=self.application.window, message="Could not import the log.")
|
||||
return
|
||||
except IOError as e:
|
||||
error(parent=self.application.window, message="Could not import the log. I/O error %d: %s" % (e.errno, e.strerror))
|
||||
return
|
||||
except Exception as e:
|
||||
error(parent=self.application.window, message="Could not import the log.")
|
||||
logging.exception(e)
|
||||
return
|
||||
|
||||
# Get the new log's name (or the name of the existing log the user wants to import into).
|
||||
ln = LogNameDialog(self.application, title="Import Log")
|
||||
|
@ -662,16 +667,26 @@ class Logbook:
|
|||
if(path is None):
|
||||
logging.debug("No file path specified.")
|
||||
else:
|
||||
adif = ADIF()
|
||||
records = log.records
|
||||
if(records is not None):
|
||||
success = adif.write(records, path)
|
||||
if(success):
|
||||
info(parent=self.application.window, message="Exported %d QSOs to %s in ADIF format." % (len(records), path))
|
||||
else:
|
||||
error(parent=self.application.window, message="Could not export the records.")
|
||||
else:
|
||||
|
||||
# Retrieve the log's records from the database.
|
||||
try:
|
||||
records = log.records
|
||||
except sqlite.Error as e:
|
||||
error(parent=self.application.window, message="Could not retrieve the records from the SQL database. No records have been exported.")
|
||||
logging.exception(e)
|
||||
return
|
||||
|
||||
# Write the records.
|
||||
adif = ADIF()
|
||||
try:
|
||||
adif.write(records, path)
|
||||
info(parent=self.application.window, message="Exported %d QSOs to %s in ADIF format." % (len(records), path))
|
||||
except IOError as e:
|
||||
error(parent=self.application.window, message="Could not export the records. I/O error %d: %s" % (e.errno, e.strerror))
|
||||
except Exception as e: # All other exceptions.
|
||||
error(parent=self.application.window, message="Could not export the records.")
|
||||
logging.exception(e)
|
||||
|
||||
return
|
||||
|
||||
def export_log_cabrillo(self, widget=None):
|
||||
|
@ -723,33 +738,50 @@ class Logbook:
|
|||
return
|
||||
ced.dialog.destroy()
|
||||
|
||||
cabrillo = Cabrillo()
|
||||
records = log.records
|
||||
if(records is not None):
|
||||
success = cabrillo.write(records, path, contest=contest, mycall=mycall)
|
||||
if(success):
|
||||
info(parent=self.application.window, message="Exported %d QSOs to %s in Cabrillo format." % (len(records), path))
|
||||
else:
|
||||
error(parent=self.application.window, message="Could not export the records.")
|
||||
else:
|
||||
# Retrieve the log's records from the database.
|
||||
try:
|
||||
records = log.records
|
||||
except sqlite.Error as e:
|
||||
error(parent=self.application.window, message="Could not retrieve the records from the SQL database. No records have been exported.")
|
||||
logging.exception(e)
|
||||
return
|
||||
|
||||
# Write the records.
|
||||
cabrillo = Cabrillo()
|
||||
try:
|
||||
cabrillo.write(records, path, contest=contest, mycall=mycall)
|
||||
info(parent=self.application.window, message="Exported %d QSOs to %s in Cabrillo format." % (len(records), path))
|
||||
except IOError as e:
|
||||
error(parent=self.application.window, message="Could not export the records. I/O error %d: %s" % (e.errno, e.strerror))
|
||||
except Exception as e: # All other exceptions.
|
||||
error(parent=self.application.window, message="Could not export the records.")
|
||||
logging.exception(e)
|
||||
|
||||
return
|
||||
|
||||
def print_log(self, widget=None):
|
||||
""" Print all the records in the log (that is currently selected).
|
||||
Note that only a few important fields are printed because of the restricted width of the page. """
|
||||
|
||||
page_index = self.notebook.get_current_page() # Get the index of the selected tab in the logbook.
|
||||
if(page_index == 0): # If we are on the Summary page...
|
||||
logging.debug("No log currently selected!")
|
||||
return
|
||||
log_index = self.get_log_index()
|
||||
log = self.logs[log_index]
|
||||
records = log.records
|
||||
if(records is not None):
|
||||
printer = Printer(self.application)
|
||||
printer.print_records(records, title="Log: %s" % log.name)
|
||||
else:
|
||||
|
||||
# Retrieve the records.
|
||||
try:
|
||||
records = log.records
|
||||
except sqlite.Error as e:
|
||||
error(parent=self.application.window, message="Could not retrieve the records from the SQL database. No records have been printed.")
|
||||
logging.exception(e)
|
||||
return
|
||||
|
||||
# Print the records.
|
||||
printer = Printer(self.application)
|
||||
printer.print_records(records, title="Log: %s" % log.name)
|
||||
|
||||
return
|
||||
|
||||
def add_record_callback(self, widget):
|
||||
|
@ -997,7 +1029,7 @@ class Logbook:
|
|||
else:
|
||||
return False
|
||||
except (sqlite.Error, IndexError) as e:
|
||||
logging.exception(e) # Database error. PyQSO could not check if the log name exists.
|
||||
logging.exception(e) # Database error. Could not check if the log name exists.
|
||||
return None
|
||||
|
||||
def get_log_index(self, name=None):
|
||||
|
|
Ładowanie…
Reference in New Issue