summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2018-08-04 10:03:47 -0400
committerNed Batchelder <ned@nedbatchelder.com>2018-08-04 10:03:47 -0400
commitf1561b04f58fdd04b86d2ed0dc858a1222752b02 (patch)
treeac0a2aa1d1a1b19582bea26d1858e3fb6f522d0f
parent2f0d57856550ef7ad248e4e6127700bdabb91e7d (diff)
downloadpython-coveragepy-git-f1561b04f58fdd04b86d2ed0dc858a1222752b02.tar.gz
Improved debugging
-rw-r--r--coverage/debug.py17
-rw-r--r--coverage/misc.py10
-rw-r--r--coverage/results.py3
-rw-r--r--coverage/sqldata.py19
-rw-r--r--doc/cmd.rst2
5 files changed, 35 insertions, 16 deletions
diff --git a/coverage/debug.py b/coverage/debug.py
index d63a9070..fd27c731 100644
--- a/coverage/debug.py
+++ b/coverage/debug.py
@@ -31,6 +31,8 @@ _TEST_NAME_FILE = "" # "/tmp/covtest.txt"
class DebugControl(object):
"""Control and output for debugging."""
+ show_repr_attr = False # For SimpleRepr
+
def __init__(self, options, output):
"""Configure the options and output file for debugging."""
self.options = list(options) + FORCED_DEBUG
@@ -71,6 +73,10 @@ class DebugControl(object):
`msg` is the line to write. A newline will be appended.
"""
+ if self.should('self'):
+ caller_self = inspect.stack()[1][0].f_locals.get('self')
+ if caller_self is not None:
+ msg = "[self: {!r}] {}".format(caller_self, msg)
self.output.write(msg+"\n")
if self.should('callers'):
dump_stack_frames(out=self.output, skip=1)
@@ -167,6 +173,17 @@ def add_pid_and_tid(text):
return text
+class SimpleRepr(object):
+ """A mixin implementing a simple __repr__."""
+ def __repr__(self):
+ show_attrs = ((k, v) for k, v in self.__dict__.items() if getattr(v, "show_repr_attr", True))
+ return "<{klass} @0x{id:x} {attrs}>".format(
+ klass=self.__class__.__name__,
+ id=id(self),
+ attrs=" ".join("{}={!r}".format(k, v) for k, v in show_attrs),
+ )
+
+
def filter_text(text, filters):
"""Run `text` through a series of filters.
diff --git a/coverage/misc.py b/coverage/misc.py
index fff2a187..78ec027f 100644
--- a/coverage/misc.py
+++ b/coverage/misc.py
@@ -249,16 +249,6 @@ def _needs_to_implement(that, func_name):
)
-class SimpleRepr(object):
- """A mixin implementing a simple __repr__."""
- def __repr__(self):
- return "<{klass} @{id:x} {attrs}>".format(
- klass=self.__class__.__name__,
- id=id(self) & 0xFFFFFF,
- attrs=" ".join("{}={!r}".format(k, v) for k, v in self.__dict__.items()),
- )
-
-
class BaseCoverageException(Exception):
"""The base of all Coverage exceptions."""
pass
diff --git a/coverage/results.py b/coverage/results.py
index 7e3bd268..fb919c9b 100644
--- a/coverage/results.py
+++ b/coverage/results.py
@@ -6,7 +6,8 @@
import collections
from coverage.backward import iitems
-from coverage.misc import contract, format_lines, SimpleRepr
+from coverage.debug import SimpleRepr
+from coverage.misc import contract, format_lines
class Analysis(object):
diff --git a/coverage/sqldata.py b/coverage/sqldata.py
index cddece31..296e353e 100644
--- a/coverage/sqldata.py
+++ b/coverage/sqldata.py
@@ -7,6 +7,7 @@ import os
import sqlite3
from coverage.backward import iitems
+from coverage.debug import SimpleRepr
from coverage.misc import CoverageException, file_be_gone
@@ -47,7 +48,7 @@ create table arc (
# (-1065448850,)
APP_ID = -1065448850
-class CoverageSqliteData(object):
+class CoverageSqliteData(SimpleRepr):
def __init__(self, basename=None, warn=None, debug=None):
self.filename = os.path.abspath(basename or ".coverage")
self._warn = warn
@@ -125,6 +126,10 @@ class CoverageSqliteData(object):
{ filename: { lineno: None, ... }, ...}
"""
+ if self._debug and self._debug.should('dataop'):
+ self._debug.write("Adding lines: %d files, %d lines total" % (
+ len(line_data), sum(len(lines) for lines in line_data.values())
+ ))
self._start_writing()
self._choose_lines_or_arcs(lines=True)
with self._connect() as con:
@@ -144,6 +149,10 @@ class CoverageSqliteData(object):
{ filename: { (l1,l2): None, ... }, ...}
"""
+ if self._debug and self._debug.should('dataop'):
+ self._debug.write("Adding arcs: %d files, %d arcs total" % (
+ len(arc_data), sum(len(arcs) for arcs in arc_data.values())
+ ))
self._start_writing()
self._choose_lines_or_arcs(arcs=True)
with self._connect() as con:
@@ -242,7 +251,7 @@ class CoverageSqliteData(object):
return [pair for pair in con.execute("select fromno, tono from arc where file_id = ?", (file_id,))]
-class Sqlite(object):
+class Sqlite(SimpleRepr):
def __init__(self, filename, debug):
self.debug = debug if (debug and debug.should('sql')) else None
if self.debug:
@@ -250,9 +259,9 @@ class Sqlite(object):
self.con = sqlite3.connect(filename)
# This pragma makes writing faster. It disables rollbacks, but we never need them.
- self.con.execute("pragma journal_mode=off")
+ self.execute("pragma journal_mode=off")
# This pragma makes writing faster.
- self.con.execute("pragma synchronous=off")
+ self.execute("pragma synchronous=off")
def close(self):
self.con.close()
@@ -272,5 +281,5 @@ class Sqlite(object):
def executemany(self, sql, data):
if self.debug:
- self.debug.write("Executing many {!r}".format(sql))
+ self.debug.write("Executing many {!r} with {} rows".format(sql, len(data)))
return self.con.executemany(sql, data)
diff --git a/doc/cmd.rst b/doc/cmd.rst
index d198178f..908b2ee9 100644
--- a/doc/cmd.rst
+++ b/doc/cmd.rst
@@ -486,6 +486,8 @@ to log:
* ``process``: show process creation information, and changes in the current
directory.
+* ``self``: annotate each debug message with the object printing the message.
+
* ``sys``: before starting, dump all the system and environment information,
as with :ref:`coverage debug sys <cmd_debug>`.