--- a/eric7/DebugClients/Python/coverage/sqldata.py Sun Mar 20 17:26:35 2022 +0100 +++ b/eric7/DebugClients/Python/coverage/sqldata.py Sun Mar 20 17:49:44 2022 +0100 @@ -215,7 +215,7 @@ self._dbs = {} self._pid = os.getpid() # Synchronize the operations used during collection. - self._lock = threading.Lock() + self._lock = threading.RLock() # Are we in sync with the data file? self._have_used = False @@ -231,7 +231,11 @@ """A decorator for methods that should hold self._lock.""" @functools.wraps(method) def _wrapped(self, *args, **kwargs): + if self._debug.should("lock"): + self._debug.write(f"Locking {self._lock!r} for {method.__name__}") with self._lock: + if self._debug.should("lock"): + self._debug.write(f"Locked {self._lock!r} for {method.__name__}") # pylint: disable=not-callable return method(self, *args, **kwargs) return _wrapped @@ -256,26 +260,6 @@ self._have_used = False self._current_context_id = None - def _create_db(self): - """Create a db file that doesn't exist yet. - - Initializes the schema and certain metadata. - """ - if self._debug.should("dataio"): - self._debug.write(f"Creating data file {self._filename!r}") - self._dbs[threading.get_ident()] = db = SqliteDb(self._filename, self._debug) - with db: - db.executescript(SCHEMA) - db.execute("insert into coverage_schema (version) values (?)", (SCHEMA_VERSION,)) - db.executemany( - "insert into meta (key, value) values (?, ?)", - [ - ("sys_argv", str(getattr(sys, "argv", None))), - ("version", __version__), - ("when", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")), - ] - ) - def _open_db(self): """Open an existing db file, and read its metadata.""" if self._debug.should("dataio"): @@ -289,11 +273,14 @@ try: schema_version, = db.execute_one("select version from coverage_schema") except Exception as exc: - raise DataError( - "Data file {!r} doesn't seem to be a coverage data file: {}".format( - self._filename, exc - ) - ) from exc + if "no such table: coverage_schema" in str(exc): + self._init_db(db) + else: + raise DataError( + "Data file {!r} doesn't seem to be a coverage data file: {}".format( + self._filename, exc + ) + ) from exc else: if schema_version != SCHEMA_VERSION: raise DataError( @@ -309,13 +296,25 @@ for path, file_id in db.execute("select path, id from file"): self._file_map[path] = file_id + def _init_db(self, db): + """Write the initial contents of the database.""" + if self._debug.should("dataio"): + self._debug.write(f"Initing data file {self._filename!r}") + db.executescript(SCHEMA) + db.execute("insert into coverage_schema (version) values (?)", (SCHEMA_VERSION,)) + db.executemany( + "insert or ignore into meta (key, value) values (?, ?)", + [ + ("sys_argv", str(getattr(sys, "argv", None))), + ("version", __version__), + ("when", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")), + ] + ) + def _connect(self): """Get the SqliteDb object to use.""" if threading.get_ident() not in self._dbs: - if os.path.exists(self._filename): - self._open_db() - else: - self._create_db() + self._open_db() return self._dbs[threading.get_ident()] def __bool__(self): @@ -349,7 +348,8 @@ if self._debug.should("dataio"): self._debug.write(f"Dumping data from data file {self._filename!r}") with self._connect() as con: - return b"z" + zlib.compress(con.dump().encode("utf-8")) + script = con.dump() + return b"z" + zlib.compress(script.encode("utf-8")) @contract(data="bytes") def loads(self, data): @@ -501,6 +501,9 @@ self._set_context_id() for filename, arcs in arc_data.items(): file_id = self._file_id(filename, add=True) + from coverage import env + if env.PYVERSION == (3, 11, 0, "alpha", 4, 0): + arcs = [(a, b) for a, b in arcs if a is not None and b is not None] data = [(file_id, self._current_context_id, fromno, tono) for fromno, tono in arcs] con.executemany( "insert or ignore into arc " + @@ -513,15 +516,19 @@ assert lines or arcs assert not (lines and arcs) if lines and self._has_arcs: + if self._debug.should("dataop"): + self._debug.write("Error: Can't add line measurements to existing branch data") raise DataError("Can't add line measurements to existing branch data") if arcs and self._has_lines: + if self._debug.should("dataop"): + self._debug.write("Error: Can't add branch measurements to existing line data") raise DataError("Can't add branch measurements to existing line data") if not self._has_arcs and not self._has_lines: self._has_lines = lines self._has_arcs = arcs with self._connect() as con: con.execute( - "insert into meta (key, value) values (?, ?)", + "insert or ignore into meta (key, value) values (?, ?)", ("has_arcs", str(int(arcs))) )