summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2019-10-02 13:49:47 -0400
committerNed Batchelder <ned@nedbatchelder.com>2019-10-02 16:15:03 -0400
commit484e3639deabeccd4bbb3c2183e0e6c0f9407057 (patch)
tree1ad95727dc4303b2358fb6a3e3b8184a80b8d7b0
parent079b6d8f145f50918461a4568d9a961e1eb38024 (diff)
downloadpython-coveragepy-git-484e3639deabeccd4bbb3c2183e0e6c0f9407057.tar.gz
Context patterns are regexes, not globs
-rw-r--r--CHANGES.rst7
-rw-r--r--coverage/cmdline.py4
-rw-r--r--coverage/sqldata.py32
-rw-r--r--tests/test_html.py2
4 files changed, 36 insertions, 9 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index adcccb1a..5e8ac672 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -20,7 +20,12 @@ development at the same time, such as 4.5.x and 5.0.
Unreleased
----------
-Nothing yet.
+- The :class:`.CoverageData` API has changed how queries are limited to
+ specific contexts. Now you use :meth:`.CoverageData.set_query_context` to
+ set a single exact-match string, or :meth:`.CoverageData.set_query_contexts`
+ to set a list of regular expressions to match contexts. This changes the
+ command-line ``--contexts`` option to use regular expressions instead of
+ filename-style wildcards.
.. _changes_50a7:
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 2bec4ea8..66d4dc3c 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -107,10 +107,10 @@ class Opts(object):
)
contexts = optparse.make_option(
'', '--contexts', action='store',
- metavar="PAT1,PAT2,...",
+ metavar="REGEX1,REGEX2,...",
help=(
"Only display data from lines covered in the given contexts. "
- "Accepts shell-style wildcards, which must be quoted."
+ "Accepts Python regexes, which must be quoted."
),
)
output_xml = optparse.make_option(
diff --git a/coverage/sqldata.py b/coverage/sqldata.py
index 95af6072..044ddbf1 100644
--- a/coverage/sqldata.py
+++ b/coverage/sqldata.py
@@ -14,6 +14,7 @@ import datetime
import glob
import itertools
import os
+import re
import sqlite3
import sys
import zlib
@@ -21,9 +22,8 @@ import zlib
from coverage.backward import get_thread_id, iitems, to_bytes, to_string
from coverage.debug import NoDebugging, SimpleReprMixin, clipped_repr
from coverage.files import PathAliases
-from coverage.misc import CoverageException, file_be_gone, filename_suffix, isolate_module
-from coverage.misc import contract
-from coverage.numbits import nums_to_numbits, numbits_to_nums, numbits_union
+from coverage.misc import CoverageException, contract, file_be_gone, filename_suffix, isolate_module
+from coverage.numbits import numbits_to_nums, numbits_union, nums_to_numbits
from coverage.version import __version__
os = isolate_module(os)
@@ -714,17 +714,33 @@ class CoverageData(SimpleReprMixin):
return "" # File was measured, but no tracer associated.
def set_query_context(self, context):
+ """Set the context for subsequent querying.
+
+ The next `lines`, `arcs`, or `contexts_by_lineno` calls will be limited
+ to only one context. `context` is a string which must match a context
+ exactly. If it does not, no exception is raised, but queries will
+ return no data.
+
+ """
self._start_using()
with self._connect() as con:
cur = con.execute("select id from context where context = ?", (context,))
self._query_context_ids = [row[0] for row in cur.fetchall()]
def set_query_contexts(self, contexts):
- """Set query contexts for future `lines`, `arcs` etc. calls."""
+ """Set the contexts for subsequent querying.
+
+ The next `lines`, `arcs`, or `contexts_by_lineno` calls will be limited
+ to the specified contexts. `contexts` is a list of Python regular
+ expressions. Contexts will be matched using :func:`re.search <python:re.search>`.
+ Data will be included in query results if they are part of any of the
+ contexts matched.
+
+ """
self._start_using()
if contexts:
with self._connect() as con:
- context_clause = ' or '.join(['context glob ?'] * len(contexts))
+ context_clause = ' or '.join(['context regexp ?'] * len(contexts))
cur = con.execute("select id from context where " + context_clause, contexts)
self._query_context_ids = [row[0] for row in cur.fetchall()]
else:
@@ -842,6 +858,7 @@ class SqliteDb(SimpleReprMixin):
if self.debug:
self.debug.write("Connecting to {!r}".format(self.filename))
self.con = sqlite3.connect(filename, check_same_thread=False)
+ self.con.create_function('REGEXP', 2, _regexp)
# This pragma makes writing faster. It disables rollbacks, but we never need them.
# PyPy needs the .close() calls here, or sqlite gets twisted up:
@@ -893,3 +910,8 @@ class SqliteDb(SimpleReprMixin):
def dump(self):
"""Return a multi-line string, the dump of the database."""
return "\n".join(self.con.iterdump())
+
+
+def _regexp(text, pattern):
+ """A regexp function for SQLite."""
+ return re.search(text, pattern) is not None
diff --git a/tests/test_html.py b/tests/test_html.py
index d30279a5..36bfad08 100644
--- a/tests/test_html.py
+++ b/tests/test_html.py
@@ -1099,7 +1099,7 @@ class HtmlWithContextsTest(HtmlTestHelpers, CoverageTest):
cov = coverage.Coverage(source=["."])
cov.set_option("run:dynamic_context", "test_function")
cov.set_option("html:show_contexts", True)
- cov.set_option("report:contexts", ["*test_one*"])
+ cov.set_option("report:contexts", ["test_one"])
mod = self.start_import_stop(cov, "two_tests")
d = html_data_from_cov(cov, mod)