simonw / datasette
Showing 2 of 9 files from the diff.

@@ -0,0 +1,28 @@
Loading
1 +
try:
2 +
    import pysqlite3 as sqlite3
3 +
except ImportError:
4 +
    import sqlite3
5 +
6 +
if hasattr(sqlite3, "enable_callback_tracebacks"):
7 +
    sqlite3.enable_callback_tracebacks(True)
8 +
9 +
_cached_sqlite_version = None
10 +
11 +
12 +
def sqlite_version():
13 +
    global _cached_sqlite_version
14 +
    if _cached_sqlite_version is None:
15 +
        _cached_sqlite_version = _sqlite_version()
16 +
    return _cached_sqlite_version
17 +
18 +
19 +
def _sqlite_version():
20 +
    return tuple(
21 +
        map(
22 +
            int,
23 +
            sqlite3.connect(":memory:")
24 +
            .execute("select sqlite_version()")
25 +
            .fetchone()[0]
26 +
            .split("."),
27 +
        )
28 +
    )

@@ -19,15 +19,9 @@
Loading
19 19
import numbers
20 20
import yaml
21 21
from .shutil_backport import copytree
22 +
from .sqlite import sqlite3, sqlite_version
22 23
from ..plugins import pm
23 24
24 -
try:
25 -
    import pysqlite3 as sqlite3
26 -
except ImportError:
27 -
    import sqlite3
28 -
29 -
if hasattr(sqlite3, "enable_callback_tracebacks"):
30 -
    sqlite3.enable_callback_tracebacks(True)
31 25
32 26
# From https://www.sqlite.org/lang_keywords.html
33 27
reserved_words = set(
@@ -64,7 +58,7 @@
Loading
64 58
65 59
# Can replace this with Column from sqlite_utils when I add that dependency
66 60
Column = namedtuple(
67 -
    "Column", ("cid", "name", "type", "notnull", "default_value", "is_pk")
61 +
    "Column", ("cid", "name", "type", "notnull", "default_value", "is_pk", "hidden")
68 62
)
69 63
70 64
@@ -458,13 +452,10 @@
Loading
458 452
459 453
def detect_primary_keys(conn, table):
460 454
    " Figure out primary keys for a table. "
461 -
    table_info_rows = [
462 -
        row
463 -
        for row in conn.execute(f'PRAGMA table_info("{table}")').fetchall()
464 -
        if row[-1]
465 -
    ]
466 -
    table_info_rows.sort(key=lambda row: row[-1])
467 -
    return [str(r[1]) for r in table_info_rows]
455 +
    columns = table_column_details(conn, table)
456 +
    pks = [column for column in columns if column.is_pk]
457 +
    pks.sort(key=lambda column: column.is_pk)
458 +
    return [column.name for column in pks]
468 459
469 460
470 461
def get_outbound_foreign_keys(conn, table):
@@ -570,10 +561,22 @@
Loading
570 561
571 562
572 563
def table_column_details(conn, table):
573 -
    return [
574 -
        Column(*r)
575 -
        for r in conn.execute(f"PRAGMA table_info({escape_sqlite(table)});").fetchall()
576 -
    ]
564 +
    if sqlite_version() >= (3, 26, 0):
565 +
        # table_xinfo was added in 3.26.0
566 +
        return [
567 +
            Column(*r)
568 +
            for r in conn.execute(
569 +
                f"PRAGMA table_xinfo({escape_sqlite(table)});"
570 +
            ).fetchall()
571 +
        ]
572 +
    else:
573 +
        # Treat hidden as 0 for all columns
574 +
        return [
575 +
            Column(*(list(r) + [0]))
576 +
            for r in conn.execute(
577 +
                f"PRAGMA table_info({escape_sqlite(table)});"
578 +
            ).fetchall()
579 +
        ]
577 580
578 581
579 582
filter_column_re = re.compile(r"^_filter_column_\d+$")
Files Coverage
datasette 91.48%
Project Totals (31 files) 91.48%
1
coverage:
2
  status:
3
    project:
4
      default:
5
        informational: true
6
    patch:
7
      default:
8
        informational: true
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading