• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

spesmilo / electrum / 4861270052044800

30 Apr 2025 12:15PM UTC coverage: 60.206% (-0.03%) from 60.236%
4861270052044800

Pull #9773

CirrusCI

f321x
validate and deduplicate relay config input in qt gui

Adds validation and deduplication of the relay urls entered in the QT
settings dialog. This is supposed to prevent malformed or duplicated
relay entries.
Also resets the relays to the default value if no (valid) url
is entered. This prevents the user from getting stuck without relays
(otherwise the user would have to research for relay urls manually if
they don't know any).
Pull Request #9773: qt: validate and deduplicate relay config input in qt gui

2 of 8 new or added lines in 1 file covered. (25.0%)

190 existing lines in 5 files now uncovered.

21615 of 35902 relevant lines covered (60.21%)

3.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.59
/electrum/sql_db.py
1
import os
5✔
2
import queue
5✔
3
import threading
5✔
4
import asyncio
5✔
5
import sqlite3
5✔
6

7
from .logging import Logger
5✔
8
from .util import test_read_write_permissions
5✔
9

10

11
def sql(func):
5✔
12
    """wrapper for sql methods
13

14
    returns an awaitable asyncio.Future
15
    """
16
    def wrapper(self: 'SqlDB', *args, **kwargs):
5✔
17
        assert threading.current_thread() != self.sql_thread
5✔
18
        f = self.asyncio_loop.create_future()
5✔
19
        self.db_requests.put((f, func, args, kwargs))
5✔
20
        return f
5✔
21
    return wrapper
5✔
22

23

24
class SqlDB(Logger):
5✔
25

26
    def __init__(self, asyncio_loop: asyncio.BaseEventLoop, path, commit_interval=None):
5✔
27
        Logger.__init__(self)
5✔
28
        self.asyncio_loop = asyncio_loop
5✔
29
        self.stopping = False
5✔
30
        self.stopped_event = asyncio.Event()
5✔
31
        self.path = path
5✔
32
        test_read_write_permissions(path)
5✔
33
        self.commit_interval = commit_interval
5✔
34
        self.db_requests = queue.Queue()
5✔
35
        self.sql_thread = threading.Thread(target=self.run_sql)
5✔
36
        self.sql_thread.start()
5✔
37

38
    def stop(self):
5✔
39
        self.stopping = True
5✔
40

41
    def filesize(self):
5✔
42
        return os.stat(self.path).st_size
×
43

44
    def run_sql(self):
5✔
45
        self.logger.info("SQL thread started")
5✔
46
        self.conn = sqlite3.connect(self.path)
5✔
47
        self.logger.info("Creating database")
5✔
48
        self.create_database()
5✔
49
        i = 0
5✔
50
        while not self.stopping and self.asyncio_loop.is_running():
5✔
51
            try:
5✔
52
                future, func, args, kwargs = self.db_requests.get(timeout=0.1)
5✔
53
            except queue.Empty:
5✔
54
                continue
5✔
UNCOV
55
            try:
×
UNCOV
56
                result = func(self, *args, **kwargs)
×
57
            except BaseException as e:
×
58
                self.asyncio_loop.call_soon_threadsafe(future.set_exception, e)
×
59
                continue
×
UNCOV
60
            if not future.cancelled():
×
UNCOV
61
                self.asyncio_loop.call_soon_threadsafe(future.set_result, result)
×
62
            # note: in sweepstore session.commit() is called inside
63
            # the sql-decorated methods, so committing to disk is awaited
UNCOV
64
            if self.commit_interval:
×
UNCOV
65
                i = (i + 1) % self.commit_interval
×
UNCOV
66
                if i == 0:
×
67
                    self.conn.commit()
×
68
        # write
69
        self.conn.commit()
5✔
70
        self.conn.close()
5✔
71

72
        self.logger.info("SQL thread terminated")
5✔
73
        self.asyncio_loop.call_soon_threadsafe(self.stopped_event.set)
5✔
74

75
    def create_database(self):
5✔
76
        raise NotImplementedError()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc