Better error handling.

pull/61/head
Christian T. Jacobs 2017-07-03 13:27:12 +01:00
rodzic 3e32142e8a
commit e34253adb2
5 zmienionych plików z 103 dodań i 96 usunięć

Wyświetl plik

@ -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.

Wyświetl plik

@ -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)):

Wyświetl plik

@ -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

Wyświetl plik

@ -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]

Wyświetl plik

@ -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):