From 181f5a78fdbdb7d6f90a478482512297f3a0f845 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 9 Sep 2018 09:38:27 -0400 Subject: Super-simple contexts added to the schema --- coverage/sqldata.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'coverage/sqldata.py') diff --git a/coverage/sqldata.py b/coverage/sqldata.py index 91508586..0c05ae1f 100644 --- a/coverage/sqldata.py +++ b/coverage/sqldata.py @@ -22,7 +22,11 @@ from coverage.files import PathAliases from coverage.misc import CoverageException, file_be_gone -SCHEMA_VERSION = 1 +# Schema versions: +# 1: Released in 5.0a2 +# 2: Added contexts + +SCHEMA_VERSION = 2 SCHEMA = """ create table coverage_schema ( @@ -40,17 +44,25 @@ create table file ( unique(path) ); +create table context ( + id integer primary key, + context text, + unique(context) +); + create table line ( file_id integer, + context_id integer, lineno integer, - unique(file_id, lineno) + unique(file_id, context_id, lineno) ); create table arc ( file_id integer, + context_id integer, fromno integer, tono integer, - unique(file_id, fromno, tono) + unique(file_id, context_id, fromno, tono) ); create table tracer ( @@ -78,6 +90,8 @@ class CoverageSqliteData(SimpleRepr): self._has_lines = False self._has_arcs = False + self._context_id = 0 + def _choose_filename(self): self.filename = self._basename suffix = filename_suffix(self._suffix) @@ -181,9 +195,9 @@ class CoverageSqliteData(SimpleRepr): with self._connect() as con: for filename, linenos in iitems(line_data): file_id = self._file_id(filename, add=True) - data = [(file_id, lineno) for lineno in linenos] + data = [(file_id, self._context_id, lineno) for lineno in linenos] con.executemany( - "insert or ignore into line (file_id, lineno) values (?, ?)", + "insert or ignore into line (file_id, context_id, lineno) values (?, ?, ?)", data, ) @@ -204,9 +218,9 @@ class CoverageSqliteData(SimpleRepr): with self._connect() as con: for filename, arcs in iitems(arc_data): file_id = self._file_id(filename, add=True) - data = [(file_id, fromno, tono) for fromno, tono in arcs] + data = [(file_id, self._context_id, fromno, tono) for fromno, tono in arcs] con.executemany( - "insert or ignore into arc (file_id, fromno, tono) values (?, ?, ?)", + "insert or ignore into arc (file_id, context_id, fromno, tono) values (?, ?, ?, ?)", data, ) -- cgit v1.2.1 From d5d3427c92b78324beaba4babb281ac96eb1ebc1 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 10 Sep 2018 15:19:21 -0400 Subject: SqlData can set_context --- coverage/sqldata.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'coverage/sqldata.py') diff --git a/coverage/sqldata.py b/coverage/sqldata.py index 0c05ae1f..641e8ae1 100644 --- a/coverage/sqldata.py +++ b/coverage/sqldata.py @@ -178,6 +178,20 @@ class CoverageSqliteData(SimpleRepr): self._file_map[filename] = cur.lastrowid return self._file_map.get(filename) + def set_context(self, context): + """Get the context id for `context`.""" + self._start_using() + if not context: + self._context_id = 0 + else: + with self._connect() as con: + row = con.execute("select id from context where context = ?", (context,)).fetchone() + if row is not None: + self._context_id = row[0] + else: + cur = con.execute("insert into context (context) values (?)", (context,)) + self._context_id = cur.lastrowid + def add_lines(self, line_data): """Add measured line data. -- cgit v1.2.1 From 8c05c99a4782e67c75e361f3fcb06ae32559e5f1 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 12 Sep 2018 08:39:37 -0400 Subject: Set the context in the data --- coverage/sqldata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/sqldata.py') diff --git a/coverage/sqldata.py b/coverage/sqldata.py index 641e8ae1..6dde9c2e 100644 --- a/coverage/sqldata.py +++ b/coverage/sqldata.py @@ -111,7 +111,7 @@ class CoverageSqliteData(SimpleRepr): self._db = Sqlite(self.filename, self._debug) with self._db: for stmt in SCHEMA.split(';'): - stmt = stmt.strip() + stmt = " ".join(stmt.strip().split()) if stmt: self._db.execute(stmt) self._db.execute("insert into coverage_schema (version) values (?)", (SCHEMA_VERSION,)) -- cgit v1.2.1 From 2f1b8cfcfe184a8fd6f3f2f789530bddb233dda8 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 14 Sep 2018 07:05:51 -0400 Subject: Change measured_files to a set --- coverage/sqldata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'coverage/sqldata.py') diff --git a/coverage/sqldata.py b/coverage/sqldata.py index 6dde9c2e..b9488557 100644 --- a/coverage/sqldata.py +++ b/coverage/sqldata.py @@ -304,7 +304,7 @@ class CoverageSqliteData(SimpleRepr): aliases = aliases or PathAliases() # See what we had already measured, for accurate conflict reporting. - this_measured = set(self.measured_files()) + this_measured = self.measured_files() # lines if other_data._has_lines: @@ -381,8 +381,8 @@ class CoverageSqliteData(SimpleRepr): return bool(self._has_arcs) def measured_files(self): - """A list of all files that had been measured.""" - return list(self._file_map) + """A set of all files that had been measured.""" + return set(self._file_map) def file_tracer(self, filename): """Get the plugin name of the file tracer for a file. -- cgit v1.2.1 From d2f77ab2ffc308e616af0207546ee1bef1cb8c75 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 15 Sep 2018 08:07:26 -0400 Subject: measured_contexts() and two simple tests of the global context --- coverage/sqldata.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'coverage/sqldata.py') diff --git a/coverage/sqldata.py b/coverage/sqldata.py index b9488557..45c1570c 100644 --- a/coverage/sqldata.py +++ b/coverage/sqldata.py @@ -179,18 +179,16 @@ class CoverageSqliteData(SimpleRepr): return self._file_map.get(filename) def set_context(self, context): - """Get the context id for `context`.""" + """Set the current context for future `add_lines` etc.""" self._start_using() - if not context: - self._context_id = 0 - else: - with self._connect() as con: - row = con.execute("select id from context where context = ?", (context,)).fetchone() - if row is not None: - self._context_id = row[0] - else: - cur = con.execute("insert into context (context) values (?)", (context,)) - self._context_id = cur.lastrowid + context = context or "" + with self._connect() as con: + row = con.execute("select id from context where context = ?", (context,)).fetchone() + if row is not None: + self._context_id = row[0] + else: + cur = con.execute("insert into context (context) values (?)", (context,)) + self._context_id = cur.lastrowid def add_lines(self, line_data): """Add measured line data. @@ -384,6 +382,13 @@ class CoverageSqliteData(SimpleRepr): """A set of all files that had been measured.""" return set(self._file_map) + def measured_contexts(self): + """A set of all contexts that have been measured.""" + self._start_using() + with self._connect() as con: + contexts = set(row[0] for row in con.execute("select distinct(context) from context")) + return contexts + def file_tracer(self, filename): """Get the plugin name of the file tracer for a file. -- cgit v1.2.1 From 5ff763737475f8fa1a587f6903de1329b41090ae Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 18 Sep 2018 07:49:54 -0400 Subject: Combining contexts works --- coverage/sqldata.py | 74 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 22 deletions(-) (limited to 'coverage/sqldata.py') diff --git a/coverage/sqldata.py b/coverage/sqldata.py index 45c1570c..224573be 100644 --- a/coverage/sqldata.py +++ b/coverage/sqldata.py @@ -12,6 +12,7 @@ # TODO: run_info import glob +import itertools import os import sqlite3 @@ -90,7 +91,7 @@ class CoverageSqliteData(SimpleRepr): self._has_lines = False self._has_arcs = False - self._context_id = 0 + self._current_context_id = None def _choose_filename(self): self.filename = self._basename @@ -104,6 +105,7 @@ class CoverageSqliteData(SimpleRepr): self._db = None self._file_map = {} self._have_used = False + self._current_context_id = None def _create_db(self): if self._debug and self._debug.should('dataio'): @@ -178,6 +180,17 @@ class CoverageSqliteData(SimpleRepr): self._file_map[filename] = cur.lastrowid return self._file_map.get(filename) + def _context_id(self, context): + """Get the id for a context.""" + assert context is not None + self._start_using() + with self._connect() as con: + row = con.execute("select id from context where context = ?", (context,)).fetchone() + if row is not None: + return row[0] + else: + return None + def set_context(self, context): """Set the current context for future `add_lines` etc.""" self._start_using() @@ -185,10 +198,10 @@ class CoverageSqliteData(SimpleRepr): with self._connect() as con: row = con.execute("select id from context where context = ?", (context,)).fetchone() if row is not None: - self._context_id = row[0] + self._current_context_id = row[0] else: cur = con.execute("insert into context (context) values (?)", (context,)) - self._context_id = cur.lastrowid + self._current_context_id = cur.lastrowid def add_lines(self, line_data): """Add measured line data. @@ -204,10 +217,12 @@ class CoverageSqliteData(SimpleRepr): )) self._start_using() self._choose_lines_or_arcs(lines=True) + if self._current_context_id is None: + self.set_context("") with self._connect() as con: for filename, linenos in iitems(line_data): file_id = self._file_id(filename, add=True) - data = [(file_id, self._context_id, lineno) for lineno in linenos] + data = [(file_id, self._current_context_id, lineno) for lineno in linenos] con.executemany( "insert or ignore into line (file_id, context_id, lineno) values (?, ?, ?)", data, @@ -227,10 +242,12 @@ class CoverageSqliteData(SimpleRepr): )) self._start_using() self._choose_lines_or_arcs(arcs=True) + if self._current_context_id is None: + self.set_context("") with self._connect() as con: for filename, arcs in iitems(arc_data): file_id = self._file_id(filename, add=True) - data = [(file_id, self._context_id, fromno, tono) for fromno, tono in arcs] + data = [(file_id, self._current_context_id, fromno, tono) for fromno, tono in arcs] con.executemany( "insert or ignore into arc (file_id, context_id, fromno, tono) values (?, ?, ?, ?)", data, @@ -306,19 +323,23 @@ class CoverageSqliteData(SimpleRepr): # lines if other_data._has_lines: - for filename in other_data.measured_files(): - lines = set(other_data.lines(filename)) - filename = aliases.map(filename) - lines.update(self.lines(filename) or ()) - self.add_lines({filename: lines}) + for context in other_data.measured_contexts(): + self.set_context(context) + for filename in other_data.measured_files(): + lines = set(other_data.lines(filename, context=context)) + filename = aliases.map(filename) + lines.update(self.lines(filename, context=context) or ()) + self.add_lines({filename: lines}) # arcs if other_data._has_arcs: - for filename in other_data.measured_files(): - arcs = set(other_data.arcs(filename)) - filename = aliases.map(filename) - arcs.update(self.arcs(filename) or ()) - self.add_arcs({filename: arcs}) + for context in other_data.measured_contexts(): + self.set_context(context) + for filename in other_data.measured_files(): + arcs = set(other_data.arcs(filename, context=context)) + filename = aliases.map(filename) + arcs.update(self.arcs(filename, context=context) or ()) + self.add_arcs({filename: arcs}) # file_tracers for filename in other_data.measured_files(): @@ -407,12 +428,11 @@ class CoverageSqliteData(SimpleRepr): return row[0] or "" return "" # File was measured, but no tracer associated. - def lines(self, filename): + def lines(self, filename, context=None): self._start_using() if self.has_arcs(): - arcs = self.arcs(filename) + arcs = self.arcs(filename, context=context) if arcs is not None: - import itertools all_lines = itertools.chain.from_iterable(arcs) return list(set(l for l in all_lines if l > 0)) @@ -421,18 +441,28 @@ class CoverageSqliteData(SimpleRepr): if file_id is None: return None else: - linenos = con.execute("select lineno from line where file_id = ?", (file_id,)) + query = "select lineno from line where file_id = ?" + data = [file_id] + if context is not None: + query += " and context_id = ?" + data += [self._context_id(context)] + linenos = con.execute(query, data) return [lineno for lineno, in linenos] - def arcs(self, filename): + def arcs(self, filename, context=None): self._start_using() with self._connect() as con: file_id = self._file_id(filename) if file_id is None: return None else: - arcs = con.execute("select fromno, tono from arc where file_id = ?", (file_id,)) - return [pair for pair in arcs] + query = "select fromno, tono from arc where file_id = ?" + data = [file_id] + if context is not None: + query += " and context_id = ?" + data += [self._context_id(context)] + arcs = con.execute(query, data) + return list(arcs) def run_infos(self): return [] # TODO -- cgit v1.2.1 From edc25b9a723272f869c598e929d72e5db341ba0d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 20 Sep 2018 19:45:17 -0400 Subject: More debugging. --- coverage/sqldata.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'coverage/sqldata.py') diff --git a/coverage/sqldata.py b/coverage/sqldata.py index 224573be..e644ec16 100644 --- a/coverage/sqldata.py +++ b/coverage/sqldata.py @@ -167,6 +167,12 @@ class CoverageSqliteData(SimpleRepr): __bool__ = __nonzero__ + def dump(self): # pragma: debugging + """Write a dump of the database.""" + if self._debug: + with self._connect() as con: + self._debug.write(con.dump()) + def _file_id(self, filename, add=False): """Get the file id for `filename`. @@ -519,3 +525,7 @@ class Sqlite(SimpleRepr): if self.debug: self.debug.write("Executing many {!r} with {} rows".format(sql, len(data))) return self.con.executemany(sql, data) + + def dump(self): # pragma: debugging + """Return a multi-line string, the dump of the database.""" + return "\n".join(self.con.iterdump()) -- cgit v1.2.1