summaryrefslogtreecommitdiff
path: root/coverage/misc.py
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/misc.py')
-rw-r--r--coverage/misc.py70
1 files changed, 69 insertions, 1 deletions
diff --git a/coverage/misc.py b/coverage/misc.py
index 4218536d..3ed854a7 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -1,5 +1,14 @@
"""Miscellaneous stuff for Coverage."""
+import errno
+import inspect
+import os
+import sys
+
+from coverage.backward import md5, sorted # pylint: disable=W0622
+from coverage.backward import string_class, to_bytes
+
+
def nice_pair(pair):
"""Make a nice string representation of a pair of numbers.
@@ -68,12 +77,71 @@ def bool_or_none(b):
return bool(b)
+def join_regex(regexes):
+ """Combine a list of regexes into one that matches any of them."""
+ if len(regexes) > 1:
+ return "(" + ")|(".join(regexes) + ")"
+ elif regexes:
+ return regexes[0]
+ else:
+ return ""
+
+
+def file_be_gone(path):
+ """Remove a file, and don't get annoyed if it doesn't exist."""
+ try:
+ os.remove(path)
+ except OSError:
+ _, e, _ = sys.exc_info()
+ if e.errno != errno.ENOENT:
+ raise
+
+
+class Hasher(object):
+ """Hashes Python data into md5."""
+ def __init__(self):
+ self.md5 = md5()
+
+ def update(self, v):
+ """Add `v` to the hash, recursively if needed."""
+ self.md5.update(to_bytes(str(type(v))))
+ if isinstance(v, string_class):
+ self.md5.update(to_bytes(v))
+ elif isinstance(v, (int, float)):
+ self.update(str(v))
+ elif isinstance(v, (tuple, list)):
+ for e in v:
+ self.update(e)
+ elif isinstance(v, dict):
+ keys = v.keys()
+ for k in sorted(keys):
+ self.update(k)
+ self.update(v[k])
+ else:
+ for k in dir(v):
+ if k.startswith('__'):
+ continue
+ a = getattr(v, k)
+ if inspect.isroutine(a):
+ continue
+ self.update(k)
+ self.update(a)
+
+ def digest(self):
+ """Retrieve the digest of the hash."""
+ return self.md5.digest()
+
+
class CoverageException(Exception):
"""An exception specific to Coverage."""
pass
class NoSource(CoverageException):
- """Used to indicate we couldn't find the source for a module."""
+ """We couldn't find the source for a module."""
+ pass
+
+class NotPython(CoverageException):
+ """A source file turned out not to be parsable Python."""
pass
class ExceptionDuringRun(CoverageException):