improving the pylint score

This commit is contained in:
prculley 2016-05-30 08:49:05 -05:00
parent edd9dda7ce
commit 4d60d19fd9
2 changed files with 96 additions and 86 deletions

View File

@ -1,4 +1,5 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
""" Test program for import modules """
# #
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
@ -23,13 +24,12 @@ import unittest
import os import os
import sys import sys
import re import re
import time
import logging import logging
from gramps.gen.merge.diff import diff_dbs, import_as_dict from gramps.gen.merge.diff import diff_dbs, import_as_dict
from gramps.gen.simple import SimpleAccess from gramps.gen.simple import SimpleAccess
from gramps.gen.utils.id import set_det_id from gramps.gen.utils.id import set_det_id
from gramps.cli import user from gramps.cli.user import User
from gramps.gen.const import TEMP_DIR, DATA_DIR from gramps.gen.const import TEMP_DIR, DATA_DIR
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -42,21 +42,21 @@ TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
def todate(t):
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t))
class CompleteCheck(unittest.TestCase): class CompleteCheck(unittest.TestCase):
"""The test class cases will be dynamically created at import time from """The test class cases will be dynamically created at import time from
files to be tested. The following defs are used by the test cases""" files to be tested. The following defs are used by the test cases"""
def prepare_result(self, diffs, added, missing): def prepare_result(self, diffs, added, missing):
""" Looks through the diffs, added, and missing items and begins
reporting process. Returns True if there were significant errors. """
# pylint: disable=E1101
# pylint does not like dynamically created methods
deltas = False deltas = False
if diffs: if diffs:
for diff in diffs: for diff in diffs:
obj_type, item1, item2 = diff obj_type, item1, item2 = diff
msg = self.report_diff(obj_type, item1.to_struct(), msg = self._report_diff(obj_type, item1.to_struct(),
item2.to_struct()) item2.to_struct())
if msg != "": if msg != "":
if hasattr(item1, "gramps_id"): if hasattr(item1, "gramps_id"):
self.msg += "%s: %s handle=%s\n" % \ self.msg += "%s: %s handle=%s\n" % \
@ -68,63 +68,20 @@ class CompleteCheck(unittest.TestCase):
deltas = True deltas = True
if missing: if missing:
deltas = True deltas = True
sa = SimpleAccess(self.database1) sac = SimpleAccess(self.database1)
for pair in missing: for pair in missing:
obj_type, item = pair obj_type, item = pair
self.msg += "Missing %s: %s\n" % (obj_type, sa.describe(item)) self.msg += "Missing %s: %s\n" % (obj_type, sac.describe(item))
if added: if added:
deltas = True deltas = True
sa = SimpleAccess(self.database2) sac = SimpleAccess(self.database2)
for pair in added: for pair in added:
obj_type, item = pair obj_type, item = pair
self.msg += "Added %s: %s\n" % (obj_type, sa.describe(item)) self.msg += "Added %s: %s\n" % (obj_type, sac.describe(item))
return deltas return deltas
def format_struct_path(self, path):
retval = ""
parts = path.split(".")
for part in parts:
if retval:
retval += ", "
if "[" in part and "]" in part:
part, index = re.match("(.*)\[(\d*)\]", part).groups()
retval += "%s #%s" % (part.replace("_", " "), int(index) + 1)
else:
retval += part
return retval
def report_details(self, path, diff1, diff2): def _report_diff(self, path, struct1, struct2):
if isinstance(diff1, bool):
desc1 = repr(diff1)
else:
desc1 = str(diff1) if diff1 else ""
if isinstance(diff2, bool):
desc2 = repr(diff2)
else:
desc2 = str(diff2) if diff2 else ""
d1t = type(diff1)
d2t = type(diff2)
# the xml exporter edits the data base by stripping spaces, so
# we have to ignore these differeces
if d1t == str: diff1 = diff1.strip()
if d2t == str: diff2 = diff2.strip()
d1l = len(diff1) if d1t == str else ""
d2l = len(diff2) if d2t == str else ""
# 'change' date is not significant for comparison
if path.endswith(".change"):
return ""
# the xml exporter edits the data base by converting media path
# to unix '/' conventions, so we have to ignore these differences
if path == "Media.path":
diff1 = diff1.replace('\\', '/')
if diff1 != diff2:
msg = " Diff on: %s\n %s%s: %s\n %s%s: %s\n" % \
(self.format_struct_path(path), d1t, d1l, desc1,
d2t, d2l, desc2)
return msg
return ""
def report_diff(self, path, struct1, struct2):
""" """
Compare two struct objects and report differences. Compare two struct objects and report differences.
""" """
@ -138,7 +95,7 @@ class CompleteCheck(unittest.TestCase):
for pos in range(max(len1, len2)): for pos in range(max(len1, len2)):
value1 = struct1[pos] if pos < len1 else None value1 = struct1[pos] if pos < len1 else None
value2 = struct2[pos] if pos < len2 else None value2 = struct2[pos] if pos < len2 else None
msg += self.report_diff(path + ("[%d]" % pos), value1, value2) msg += self._report_diff(path + ("[%d]" % pos), value1, value2)
elif isinstance(struct1, dict) or isinstance(struct2, dict): elif isinstance(struct1, dict) or isinstance(struct2, dict):
keys = struct1.keys() if isinstance(struct1, dict)\ keys = struct1.keys() if isinstance(struct1, dict)\
else struct2.keys() else struct2.keys()
@ -146,40 +103,92 @@ class CompleteCheck(unittest.TestCase):
value1 = struct1[key] if struct1 is not None else None value1 = struct1[key] if struct1 is not None else None
value2 = struct2[key] if struct2 is not None else None value2 = struct2[key] if struct2 is not None else None
if key == "dict": # a raw dict, not a struct if key == "dict": # a raw dict, not a struct
msg += self.report_details(path, value1, value2) msg += _report_details(path, value1, value2)
else: else:
msg += self.report_diff(path + "." + key, value1, value2) msg += self._report_diff(path + "." + key, value1, value2)
else: else:
msg += self.report_details(path, struct1, struct2) msg += _report_details(path, struct1, struct2)
return msg return msg
# The following make_test_function creates a test function (a method, def _report_details(path, diff1, diff2):
# to be precise) that compares the import file with the expected """ Checks if a detail is significant, needs adjusting for xml filter
# result '.gramps' file. effects, and returns a string describing the specific difference."""
def make_tst_function(tstfile, fname): if isinstance(diff1, bool):
desc1 = repr(diff1)
else:
desc1 = str(diff1) if diff1 else ""
if isinstance(diff2, bool):
desc2 = repr(diff2)
else:
desc2 = str(diff2) if diff2 else ""
d1t = type(diff1)
d2t = type(diff2)
# the xml exporter edits the data base by stripping spaces, so
# we have to ignore these differences
if d1t == str:
diff1 = diff1.strip()
if d2t == str:
diff2 = diff2.strip()
d1l = len(diff1) if d1t == str else ""
d2l = len(diff2) if d2t == str else ""
# 'change' date is not significant for comparison
if path.endswith(".change"):
return ""
# the xml exporter edits the data base by converting media path
# to unix '/' conventions, so we have to ignore these differences
if path == "Media.path":
diff1 = diff1.replace('\\', '/')
if diff1 != diff2:
msg = " Diff on: %s\n %s%s: %s\n %s%s: %s\n" % \
(_format_struct_path(path), d1t, d1l, desc1,
d2t, d2l, desc2)
return msg
return ""
def _format_struct_path(path):
""" prepares a 'path' string for the report out of the structure. """
retval = ""
parts = path.split(".")
for part in parts:
if retval:
retval += ", "
if "[" in part and "]" in part:
part, index = re.match(r"(.*)\[(\d*)\]", part).groups()
retval += "%s #%s" % (part.replace("_", " "), int(index) + 1)
else:
retval += part
return retval
def make_tst_function(tstfile, file_name):
""" This is here to support the dynamic function creation. This creates
the test function (a method, to be precise). """
def tst(self): def tst(self):
self._user = user.User(quiet=True) """ This compares the import file with the expected result '.gramps'
f1 = os.path.join(TEST_DIR, tstfile) file. """
f2 = os.path.join(TEST_DIR, (fname + ".gramps")) self.user = User(quiet=True)
fres = os.path.join(TEMP_DIR, (fname + ".difs")) fn1 = os.path.join(TEST_DIR, tstfile)
fn2 = os.path.join(TEST_DIR, (file_name + ".gramps"))
fres = os.path.join(TEMP_DIR, (file_name + ".difs"))
try: try:
os.remove(fres) os.remove(fres)
except OSError: except OSError:
pass pass
logging.info("\n**** %s ****" % tstfile) logging.info("\n**** %s ****", tstfile)
set_det_id(True) set_det_id(True)
self.database1 = import_as_dict(f1, self._user) self.database1 = import_as_dict(fn1, self.user)
set_det_id(True) set_det_id(True)
self.database2 = import_as_dict(f2, self._user) self.database2 = import_as_dict(fn2, self.user)
self.assertIsNotNone(self.database1, self.assertIsNotNone(self.database1,
"Unable to import file: %s" % f1) "Unable to import file: %s" % fn1)
self.assertIsNotNone(self.database2, self.assertIsNotNone(self.database2,
"Unable to import expected result file: %s" % f2) "Unable to import expected result file: %s" % fn2)
if self.database2 is None or self.database1 is None: if self.database2 is None or self.database1 is None:
return return
diffs, added, missing = diff_dbs(self.database1, diffs, added, missing = diff_dbs(self.database1,
self.database2, self._user) self.database2, self.user)
self.msg = "Mismatch on file: %s\n" % tstfile self.msg = "Mismatch on file: %s\n" % tstfile
deltas = self.prepare_result(diffs, added, missing) deltas = self.prepare_result(diffs, added, missing)
# We save a copy of any issues in the users Gramps TEMP_DIR in a file # We save a copy of any issues in the users Gramps TEMP_DIR in a file
@ -190,12 +199,12 @@ def make_tst_function(tstfile, fname):
hres.write(self.msg) hres.write(self.msg)
hres.close() hres.close()
# let's see if we have any allowed exception file # let's see if we have any allowed exception file
fdif = os.path.join(TEST_DIR, (fname + ".difs")) fdif = os.path.join(TEST_DIR, (file_name + ".difs"))
try: try:
hdif = open(fdif) hdif = open(fdif)
msg = hdif.read() msg = hdif.read()
hdif.close() hdif.close()
except: except (FileNotFoundError, IOError):
msg = "" msg = ""
# if exception file matches exactly, we are done. # if exception file matches exactly, we are done.
if self.msg != msg: if self.msg != msg:
@ -205,30 +214,31 @@ def make_tst_function(tstfile, fname):
# let's see if we have a single file to run, example; # let's see if we have a single file to run, example;
# "python test_import.py -i sample.ged" # "python test_import.py -i sample.ged"
# This only works for files in normal test directory, so don't add a path # This only works for files in normal test directory, so don't add a path
tstfile = "" #pylint: disable=invalid-name
_tstfile = ""
if __name__ == "__main__": if __name__ == "__main__":
for i, option in enumerate(sys.argv): for i, option in enumerate(sys.argv):
if option == '-i': if option == '-i':
tstfile = sys.argv[i+1] _tstfile = sys.argv[i+1]
del sys.argv[i] del sys.argv[i]
del sys.argv[i] del sys.argv[i]
# The following code dynamically creates the methods for each test file. # The following code dynamically creates the methods for each test file.
# The methods are inserted at load time into the 'CompleteCheck' class # The methods are inserted at load time into the 'CompleteCheck' class
# via the modules' globals, taking advantage that they are a dict. # via the modules' globals, taking advantage that they are a dict.
if tstfile: # single file mode if _tstfile: # single file mode
(fname, ext) = os.path.splitext(os.path.basename(tstfile)) (fname, ext) = os.path.splitext(os.path.basename(_tstfile))
test_func = make_tst_function(tstfile, fname) test_func = make_tst_function(_tstfile, fname)
clname = 'Import_{0}'.format(tstfile) clname = 'Import_{0}'.format(_tstfile)
globals()[clname] = type(clname, globals()[clname] = type(clname,
(CompleteCheck,), (CompleteCheck,),
{"testit": test_func}) {"testit": test_func})
else: else:
for tstfile in os.listdir(TEST_DIR): for _tstfile in os.listdir(TEST_DIR):
(fname, ext) = os.path.splitext(os.path.basename(tstfile)) (fname, ext) = os.path.splitext(os.path.basename(_tstfile))
if ext == ".gramps" or ext == ".difs" or ext == ".bak": if ext == ".gramps" or ext == ".difs" or ext == ".bak":
continue continue
test_func = make_tst_function(tstfile, fname) test_func = make_tst_function(_tstfile, fname)
clname = 'Import_{0}'.format(tstfile) clname = 'Import_{0}'.format(_tstfile)
globals()[clname] = type(clname, globals()[clname] = type(clname,
(CompleteCheck,), (CompleteCheck,),
{"testit": test_func}) {"testit": test_func})