|
14 | 14 | import glob |
15 | 15 | import itertools |
16 | 16 | import os |
| 17 | +import re |
17 | 18 | import sqlite3 |
18 | 19 | import sys |
19 | 20 | import zlib |
20 | 21 |
|
21 | 22 | from coverage.backward import get_thread_id, iitems, to_bytes, to_string |
22 | 23 | from coverage.debug import NoDebugging, SimpleReprMixin, clipped_repr |
23 | 24 | from coverage.files import PathAliases |
24 | | -from coverage.misc import CoverageException, file_be_gone, filename_suffix, isolate_module |
25 | | -from coverage.misc import contract |
26 | | -from coverage.numbits import nums_to_numbits, numbits_to_nums, numbits_union |
| 25 | +from coverage.misc import CoverageException, contract, file_be_gone, filename_suffix, isolate_module |
| 26 | +from coverage.numbits import numbits_to_nums, numbits_union, nums_to_numbits |
27 | 27 | from coverage.version import __version__ |
28 | 28 |
|
29 | 29 | os = isolate_module(os) |
@@ -714,17 +714,33 @@ def file_tracer(self, filename): |
714 | 714 | return "" # File was measured, but no tracer associated. |
715 | 715 |
|
716 | 716 | def set_query_context(self, context): |
| 717 | + """Set the context for subsequent querying. |
| 718 | +
|
| 719 | + The next `lines`, `arcs`, or `contexts_by_lineno` calls will be limited |
| 720 | + to only one context. `context` is a string which must match a context |
| 721 | + exactly. If it does not, no exception is raised, but queries will |
| 722 | + return no data. |
| 723 | +
|
| 724 | + """ |
717 | 725 | self._start_using() |
718 | 726 | with self._connect() as con: |
719 | 727 | cur = con.execute("select id from context where context = ?", (context,)) |
720 | 728 | self._query_context_ids = [row[0] for row in cur.fetchall()] |
721 | 729 |
|
722 | 730 | def set_query_contexts(self, contexts): |
723 | | - """Set query contexts for future `lines`, `arcs` etc. calls.""" |
| 731 | + """Set the contexts for subsequent querying. |
| 732 | +
|
| 733 | + The next `lines`, `arcs`, or `contexts_by_lineno` calls will be limited |
| 734 | + to the specified contexts. `contexts` is a list of Python regular |
| 735 | + expressions. Contexts will be matched using :func:`re.search <python:re.search>`. |
| 736 | + Data will be included in query results if they are part of any of the |
| 737 | + contexts matched. |
| 738 | +
|
| 739 | + """ |
724 | 740 | self._start_using() |
725 | 741 | if contexts: |
726 | 742 | with self._connect() as con: |
727 | | - context_clause = ' or '.join(['context glob ?'] * len(contexts)) |
| 743 | + context_clause = ' or '.join(['context regexp ?'] * len(contexts)) |
728 | 744 | cur = con.execute("select id from context where " + context_clause, contexts) |
729 | 745 | self._query_context_ids = [row[0] for row in cur.fetchall()] |
730 | 746 | else: |
@@ -842,6 +858,7 @@ def connect(self): |
842 | 858 | if self.debug: |
843 | 859 | self.debug.write("Connecting to {!r}".format(self.filename)) |
844 | 860 | self.con = sqlite3.connect(filename, check_same_thread=False) |
| 861 | + self.con.create_function('REGEXP', 2, _regexp) |
845 | 862 |
|
846 | 863 | # This pragma makes writing faster. It disables rollbacks, but we never need them. |
847 | 864 | # PyPy needs the .close() calls here, or sqlite gets twisted up: |
@@ -893,3 +910,8 @@ def executescript(self, script): |
893 | 910 | def dump(self): |
894 | 911 | """Return a multi-line string, the dump of the database.""" |
895 | 912 | return "\n".join(self.con.iterdump()) |
| 913 | + |
| 914 | + |
| 915 | +def _regexp(text, pattern): |
| 916 | + """A regexp function for SQLite.""" |
| 917 | + return re.search(text, pattern) is not None |
0 commit comments