diff options
-rw-r--r-- | TODO.txt | 8 | ||||
-rw-r--r-- | coverage/html.py | 57 | ||||
-rw-r--r-- | coverage/misc.py | 6 | ||||
-rw-r--r-- | coverage/results.py | 7 | ||||
-rw-r--r-- | tests/test_misc.py | 6 |
5 files changed, 63 insertions, 21 deletions
@@ -31,10 +31,10 @@ Key: - Change data file to json - Create data api - New ast-based branch coverage? -- gevent, etc. -- Remove the old command-line syntax - - A pain, b/c of the structure of the tests. - - BTW: make an easier way to write those tests. ++ gevent, etc. ++ Remove the old command-line syntax + + A pain, b/c of the structure of the tests. + + BTW: make an easier way to write those tests. diff --git a/coverage/html.py b/coverage/html.py index 0829f219..37d62280 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -1,9 +1,9 @@ """HTML reporting for Coverage.""" -import os, re, shutil, sys +import json, os, re, shutil, sys import coverage -from coverage.backward import pickle +from coverage.backward import iitems from coverage.misc import CoverageException, Hasher from coverage.report import Reporter from coverage.results import Numbers @@ -98,7 +98,7 @@ class HtmlReporter(Reporter): # Check that this run used the same settings as the last run. m = Hasher() m.update(self.config) - these_settings = m.digest() + these_settings = m.hexdigest() if self.status.settings_hash() != these_settings: self.status.reset() self.status.set_settings_hash(these_settings) @@ -146,7 +146,7 @@ class HtmlReporter(Reporter): m = Hasher() m.update(source) self.coverage.data.add_to_hash(cu.filename, m) - return m.digest() + return m.hexdigest() def html_file(self, cu, analysis): """Generate an HTML file for one source file.""" @@ -286,9 +286,36 @@ class HtmlReporter(Reporter): class HtmlStatus(object): """The status information we keep to support incremental reporting.""" - STATUS_FILE = "status.dat" + STATUS_FILE = "status.json" STATUS_FORMAT = 1 + # The data looks like: + # + # { + # 'format': 1, + # 'settings': '\x87\x9cc8\x80\xe5\x97\xb16\xfcv\xa2\x8d\x8a\xbb\xcf', + # 'version': '4.0a1', + # 'files': { + # 'cogapp___init__': { + # 'hash': '\x99*\x0e\\\x10\x11O\x06WG/gJ\x83\xdd\x99', + # 'index': { + # 'html_filename': 'cogapp___init__.html', + # 'name': 'cogapp/__init__', + # 'nums': <coverage.results.Numbers object at 0x10ab7ed0>, + # } + # }, + # ... + # 'cogapp_whiteutils': { + # 'hash': 'o\xfd\x0e+s2="\xb2\x1c\xd6\xa1\xee\x85\x85\xda', + # 'index': { + # 'html_filename': 'cogapp_whiteutils.html', + # 'name': 'cogapp/whiteutils', + # 'nums': <coverage.results.Numbers object at 0x10ab7d90>, + # } + # }, + # }, + # } + def __init__(self): self.reset() @@ -302,8 +329,8 @@ class HtmlStatus(object): usable = False try: status_file = os.path.join(directory, self.STATUS_FILE) - with open(status_file, "rb") as fstatus: - status = pickle.load(fstatus) + with open(status_file, "r") as fstatus: + status = json.load(fstatus) except (IOError, ValueError): usable = False else: @@ -314,7 +341,10 @@ class HtmlStatus(object): usable = False if usable: - self.files = status['files'] + self.files = {} + for filename, fileinfo in iitems(status['files']): + fileinfo['index']['nums'] = Numbers(*fileinfo['index']['nums']) + self.files[filename] = fileinfo self.settings = status['settings'] else: self.reset() @@ -322,14 +352,19 @@ class HtmlStatus(object): def write(self, directory): """Write the current status to `directory`.""" status_file = os.path.join(directory, self.STATUS_FILE) + files = {} + for filename, fileinfo in iitems(self.files): + fileinfo['index']['nums'] = fileinfo['index']['nums'].init_args() + files[filename] = fileinfo + status = { 'format': self.STATUS_FORMAT, 'version': coverage.__version__, 'settings': self.settings, - 'files': self.files, + 'files': files, } - with open(status_file, "wb") as fout: - pickle.dump(status, fout) + with open(status_file, "w") as fout: + json.dump(status, fout) def settings_hash(self): """Get the hash of the coverage.py settings.""" diff --git a/coverage/misc.py b/coverage/misc.py index a653bb62..f9a30bc5 100644 --- a/coverage/misc.py +++ b/coverage/misc.py @@ -130,9 +130,9 @@ class Hasher(object): self.update(k) self.update(a) - def digest(self): - """Retrieve the digest of the hash.""" - return self.md5.digest() + def hexdigest(self): + """Retrieve the hex digest of the hash.""" + return self.md5.hexdigest() class CoverageException(Exception): diff --git a/coverage/results.py b/coverage/results.py index 5eff0f3e..f1c63bbb 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -182,6 +182,13 @@ class Numbers(object): self.n_partial_branches = n_partial_branches self.n_missing_branches = n_missing_branches + def init_args(self): + """Return a list for __init__(*args) to recreate this object.""" + return [ + self.n_files, self.n_statements, self.n_excluded, self.n_missing, + self.n_branches, self.n_partial_branches, self.n_missing_branches, + ] + @classmethod def set_precision(cls, precision): """Set the number of decimal places used to report percentages.""" diff --git a/tests/test_misc.py b/tests/test_misc.py index 74ed1a78..37191f67 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -18,15 +18,15 @@ class HasherTest(CoverageTest): h2.update("Goodbye!") h3 = Hasher() h3.update("Hello, world!") - self.assertNotEqual(h1.digest(), h2.digest()) - self.assertEqual(h1.digest(), h3.digest()) + self.assertNotEqual(h1.hexdigest(), h2.hexdigest()) + self.assertEqual(h1.hexdigest(), h3.hexdigest()) def test_dict_hashing(self): h1 = Hasher() h1.update({'a': 17, 'b': 23}) h2 = Hasher() h2.update({'b': 23, 'a': 17}) - self.assertEqual(h1.digest(), h2.digest()) + self.assertEqual(h1.hexdigest(), h2.hexdigest()) class RemoveFileTest(CoverageTest): |