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
""" Test program for import modules """
#
# Gramps - a GTK+/GNOME based genealogy program
#
@ -23,13 +24,12 @@ import unittest
import os
import sys
import re
import time
import logging
from gramps.gen.merge.diff import diff_dbs, import_as_dict
from gramps.gen.simple import SimpleAccess
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
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):
"""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"""
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
if diffs:
for diff in diffs:
obj_type, item1, item2 = diff
msg = self.report_diff(obj_type, item1.to_struct(),
item2.to_struct())
msg = self._report_diff(obj_type, item1.to_struct(),
item2.to_struct())
if msg != "":
if hasattr(item1, "gramps_id"):
self.msg += "%s: %s handle=%s\n" % \
@ -68,63 +68,20 @@ class CompleteCheck(unittest.TestCase):
deltas = True
if missing:
deltas = True
sa = SimpleAccess(self.database1)
sac = SimpleAccess(self.database1)
for pair in missing:
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:
deltas = True
sa = SimpleAccess(self.database2)
sac = SimpleAccess(self.database2)
for pair in added:
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
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):
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):
def _report_diff(self, path, struct1, struct2):
"""
Compare two struct objects and report differences.
"""
@ -138,7 +95,7 @@ class CompleteCheck(unittest.TestCase):
for pos in range(max(len1, len2)):
value1 = struct1[pos] if pos < len1 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):
keys = struct1.keys() if isinstance(struct1, dict)\
else struct2.keys()
@ -146,40 +103,92 @@ class CompleteCheck(unittest.TestCase):
value1 = struct1[key] if struct1 is not None else None
value2 = struct2[key] if struct2 is not None else None
if key == "dict": # a raw dict, not a struct
msg += self.report_details(path, value1, value2)
msg += _report_details(path, value1, value2)
else:
msg += self.report_diff(path + "." + key, value1, value2)
msg += self._report_diff(path + "." + key, value1, value2)
else:
msg += self.report_details(path, struct1, struct2)
msg += _report_details(path, struct1, struct2)
return msg
# The following make_test_function creates a test function (a method,
# to be precise) that compares the import file with the expected
# result '.gramps' file.
def make_tst_function(tstfile, fname):
def _report_details(path, diff1, diff2):
""" Checks if a detail is significant, needs adjusting for xml filter
effects, and returns a string describing the specific difference."""
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):
self._user = user.User(quiet=True)
f1 = os.path.join(TEST_DIR, tstfile)
f2 = os.path.join(TEST_DIR, (fname + ".gramps"))
fres = os.path.join(TEMP_DIR, (fname + ".difs"))
""" This compares the import file with the expected result '.gramps'
file. """
self.user = User(quiet=True)
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:
os.remove(fres)
except OSError:
pass
logging.info("\n**** %s ****" % tstfile)
logging.info("\n**** %s ****", tstfile)
set_det_id(True)
self.database1 = import_as_dict(f1, self._user)
self.database1 = import_as_dict(fn1, self.user)
set_det_id(True)
self.database2 = import_as_dict(f2, self._user)
self.database2 = import_as_dict(fn2, self.user)
self.assertIsNotNone(self.database1,
"Unable to import file: %s" % f1)
"Unable to import file: %s" % fn1)
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:
return
diffs, added, missing = diff_dbs(self.database1,
self.database2, self._user)
self.database2, self.user)
self.msg = "Mismatch on file: %s\n" % tstfile
deltas = self.prepare_result(diffs, added, missing)
# 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.close()
# 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:
hdif = open(fdif)
msg = hdif.read()
hdif.close()
except:
except (FileNotFoundError, IOError):
msg = ""
# if exception file matches exactly, we are done.
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;
# "python test_import.py -i sample.ged"
# This only works for files in normal test directory, so don't add a path
tstfile = ""
#pylint: disable=invalid-name
_tstfile = ""
if __name__ == "__main__":
for i, option in enumerate(sys.argv):
if option == '-i':
tstfile = sys.argv[i+1]
_tstfile = sys.argv[i+1]
del sys.argv[i]
del sys.argv[i]
# The following code dynamically creates the methods for each test file.
# The methods are inserted at load time into the 'CompleteCheck' class
# via the modules' globals, taking advantage that they are a dict.
if tstfile: # single file mode
(fname, ext) = os.path.splitext(os.path.basename(tstfile))
test_func = make_tst_function(tstfile, fname)
clname = 'Import_{0}'.format(tstfile)
if _tstfile: # single file mode
(fname, ext) = os.path.splitext(os.path.basename(_tstfile))
test_func = make_tst_function(_tstfile, fname)
clname = 'Import_{0}'.format(_tstfile)
globals()[clname] = type(clname,
(CompleteCheck,),
{"testit": test_func})
else:
for tstfile in os.listdir(TEST_DIR):
(fname, ext) = os.path.splitext(os.path.basename(tstfile))
for _tstfile in os.listdir(TEST_DIR):
(fname, ext) = os.path.splitext(os.path.basename(_tstfile))
if ext == ".gramps" or ext == ".difs" or ext == ".bak":
continue
test_func = make_tst_function(tstfile, fname)
clname = 'Import_{0}'.format(tstfile)
test_func = make_tst_function(_tstfile, fname)
clname = 'Import_{0}'.format(_tstfile)
globals()[clname] = type(clname,
(CompleteCheck,),
{"testit": test_func})