sqlite-utils 3.35.2__py3-none-any.whl → 3.37__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlite_utils/cli.py +47 -15
- sqlite_utils/db.py +72 -29
- sqlite_utils/utils.py +1 -4
- {sqlite_utils-3.35.2.dist-info → sqlite_utils-3.37.dist-info}/METADATA +4 -4
- sqlite_utils-3.37.dist-info/RECORD +15 -0
- {sqlite_utils-3.35.2.dist-info → sqlite_utils-3.37.dist-info}/WHEEL +1 -1
- sqlite_utils-3.35.2.dist-info/RECORD +0 -15
- {sqlite_utils-3.35.2.dist-info → sqlite_utils-3.37.dist-info}/LICENSE +0 -0
- {sqlite_utils-3.35.2.dist-info → sqlite_utils-3.37.dist-info}/entry_points.txt +0 -0
- {sqlite_utils-3.35.2.dist-info → sqlite_utils-3.37.dist-info}/top_level.txt +0 -0
sqlite_utils/cli.py
CHANGED
|
@@ -60,6 +60,14 @@ It's often worth trying: --encoding=latin-1
|
|
|
60
60
|
maximize_csv_field_size_limit()
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
class CaseInsensitiveChoice(click.Choice):
|
|
64
|
+
def __init__(self, choices):
|
|
65
|
+
super().__init__([choice.lower() for choice in choices])
|
|
66
|
+
|
|
67
|
+
def convert(self, value, param, ctx):
|
|
68
|
+
return super().convert(value.lower(), param, ctx)
|
|
69
|
+
|
|
70
|
+
|
|
63
71
|
def output_options(fn):
|
|
64
72
|
for decorator in reversed(
|
|
65
73
|
(
|
|
@@ -412,7 +420,8 @@ def dump(path, load_extension):
|
|
|
412
420
|
@click.argument(
|
|
413
421
|
"col_type",
|
|
414
422
|
type=click.Choice(
|
|
415
|
-
["integer", "
|
|
423
|
+
["integer", "int", "float", "text", "str", "blob", "bytes"],
|
|
424
|
+
case_sensitive=False,
|
|
416
425
|
),
|
|
417
426
|
required=False,
|
|
418
427
|
)
|
|
@@ -900,6 +909,12 @@ def insert_upsert_options(*, require_pk=False):
|
|
|
900
909
|
),
|
|
901
910
|
load_extension_option,
|
|
902
911
|
click.option("--silent", is_flag=True, help="Do not show progress bar"),
|
|
912
|
+
click.option(
|
|
913
|
+
"--strict",
|
|
914
|
+
is_flag=True,
|
|
915
|
+
default=False,
|
|
916
|
+
help="Apply STRICT mode to created table",
|
|
917
|
+
),
|
|
903
918
|
)
|
|
904
919
|
):
|
|
905
920
|
fn = decorator(fn)
|
|
@@ -942,6 +957,7 @@ def insert_upsert_implementation(
|
|
|
942
957
|
silent=False,
|
|
943
958
|
bulk_sql=None,
|
|
944
959
|
functions=None,
|
|
960
|
+
strict=False,
|
|
945
961
|
):
|
|
946
962
|
db = sqlite_utils.Database(path)
|
|
947
963
|
_load_extensions(db, load_extension)
|
|
@@ -1057,6 +1073,7 @@ def insert_upsert_implementation(
|
|
|
1057
1073
|
"replace": replace,
|
|
1058
1074
|
"truncate": truncate,
|
|
1059
1075
|
"analyze": analyze,
|
|
1076
|
+
"strict": strict,
|
|
1060
1077
|
}
|
|
1061
1078
|
if not_null:
|
|
1062
1079
|
extra_kwargs["not_null"] = set(not_null)
|
|
@@ -1177,6 +1194,7 @@ def insert(
|
|
|
1177
1194
|
truncate,
|
|
1178
1195
|
not_null,
|
|
1179
1196
|
default,
|
|
1197
|
+
strict,
|
|
1180
1198
|
):
|
|
1181
1199
|
"""
|
|
1182
1200
|
Insert records from FILE into a table, creating the table if it
|
|
@@ -1255,6 +1273,7 @@ def insert(
|
|
|
1255
1273
|
silent=silent,
|
|
1256
1274
|
not_null=not_null,
|
|
1257
1275
|
default=default,
|
|
1276
|
+
strict=strict,
|
|
1258
1277
|
)
|
|
1259
1278
|
except UnicodeDecodeError as ex:
|
|
1260
1279
|
raise click.ClickException(UNICODE_ERROR.format(ex))
|
|
@@ -1290,6 +1309,7 @@ def upsert(
|
|
|
1290
1309
|
analyze,
|
|
1291
1310
|
load_extension,
|
|
1292
1311
|
silent,
|
|
1312
|
+
strict,
|
|
1293
1313
|
):
|
|
1294
1314
|
"""
|
|
1295
1315
|
Upsert records based on their primary key. Works like 'insert' but if
|
|
@@ -1334,6 +1354,7 @@ def upsert(
|
|
|
1334
1354
|
analyze=analyze,
|
|
1335
1355
|
load_extension=load_extension,
|
|
1336
1356
|
silent=silent,
|
|
1357
|
+
strict=strict,
|
|
1337
1358
|
)
|
|
1338
1359
|
except UnicodeDecodeError as ex:
|
|
1339
1360
|
raise click.ClickException(UNICODE_ERROR.format(ex))
|
|
@@ -1468,7 +1489,7 @@ def create_database(path, enable_wal, init_spatialite, load_extension):
|
|
|
1468
1489
|
)
|
|
1469
1490
|
@click.argument("table")
|
|
1470
1491
|
@click.argument("columns", nargs=-1, required=True)
|
|
1471
|
-
@click.option("--pk", help="Column to use as primary key")
|
|
1492
|
+
@click.option("pks", "--pk", help="Column to use as primary key", multiple=True)
|
|
1472
1493
|
@click.option(
|
|
1473
1494
|
"--not-null",
|
|
1474
1495
|
multiple=True,
|
|
@@ -1502,11 +1523,16 @@ def create_database(path, enable_wal, init_spatialite, load_extension):
|
|
|
1502
1523
|
help="If table already exists, try to transform the schema",
|
|
1503
1524
|
)
|
|
1504
1525
|
@load_extension_option
|
|
1526
|
+
@click.option(
|
|
1527
|
+
"--strict",
|
|
1528
|
+
is_flag=True,
|
|
1529
|
+
help="Apply STRICT mode to created table",
|
|
1530
|
+
)
|
|
1505
1531
|
def create_table(
|
|
1506
1532
|
path,
|
|
1507
1533
|
table,
|
|
1508
1534
|
columns,
|
|
1509
|
-
|
|
1535
|
+
pks,
|
|
1510
1536
|
not_null,
|
|
1511
1537
|
default,
|
|
1512
1538
|
fk,
|
|
@@ -1514,6 +1540,7 @@ def create_table(
|
|
|
1514
1540
|
replace,
|
|
1515
1541
|
transform,
|
|
1516
1542
|
load_extension,
|
|
1543
|
+
strict,
|
|
1517
1544
|
):
|
|
1518
1545
|
"""
|
|
1519
1546
|
Add a table with the specified columns. Columns should be specified using
|
|
@@ -1554,13 +1581,14 @@ def create_table(
|
|
|
1554
1581
|
)
|
|
1555
1582
|
db[table].create(
|
|
1556
1583
|
coltypes,
|
|
1557
|
-
pk=
|
|
1584
|
+
pk=pks[0] if len(pks) == 1 else pks,
|
|
1558
1585
|
not_null=not_null,
|
|
1559
1586
|
defaults=dict(default),
|
|
1560
1587
|
foreign_keys=fk,
|
|
1561
1588
|
ignore=ignore,
|
|
1562
1589
|
replace=replace,
|
|
1563
1590
|
transform=transform,
|
|
1591
|
+
strict=strict,
|
|
1564
1592
|
)
|
|
1565
1593
|
|
|
1566
1594
|
|
|
@@ -2566,7 +2594,7 @@ def extract(
|
|
|
2566
2594
|
multiple=True,
|
|
2567
2595
|
help="Column definitions for the table",
|
|
2568
2596
|
)
|
|
2569
|
-
@click.option("--pk",
|
|
2597
|
+
@click.option("pks", "--pk", help="Column to use as primary key", multiple=True)
|
|
2570
2598
|
@click.option("--alter", is_flag=True, help="Alter table to add missing columns")
|
|
2571
2599
|
@click.option("--replace", is_flag=True, help="Replace files with matching primary key")
|
|
2572
2600
|
@click.option("--upsert", is_flag=True, help="Upsert files with matching primary key")
|
|
@@ -2583,7 +2611,7 @@ def insert_files(
|
|
|
2583
2611
|
table,
|
|
2584
2612
|
file_or_dir,
|
|
2585
2613
|
column,
|
|
2586
|
-
|
|
2614
|
+
pks,
|
|
2587
2615
|
alter,
|
|
2588
2616
|
replace,
|
|
2589
2617
|
upsert,
|
|
@@ -2613,8 +2641,8 @@ def insert_files(
|
|
|
2613
2641
|
column = ["path:path", "content_text:content_text", "size:size"]
|
|
2614
2642
|
else:
|
|
2615
2643
|
column = ["path:path", "content:content", "size:size"]
|
|
2616
|
-
if not
|
|
2617
|
-
|
|
2644
|
+
if not pks:
|
|
2645
|
+
pks = ["path"]
|
|
2618
2646
|
|
|
2619
2647
|
def yield_paths_and_relative_paths():
|
|
2620
2648
|
for f_or_d in file_or_dir:
|
|
@@ -2684,7 +2712,11 @@ def insert_files(
|
|
|
2684
2712
|
try:
|
|
2685
2713
|
with db.conn:
|
|
2686
2714
|
db[table].insert_all(
|
|
2687
|
-
to_insert(),
|
|
2715
|
+
to_insert(),
|
|
2716
|
+
pk=pks[0] if len(pks) == 1 else pks,
|
|
2717
|
+
alter=alter,
|
|
2718
|
+
replace=replace,
|
|
2719
|
+
upsert=upsert,
|
|
2688
2720
|
)
|
|
2689
2721
|
except UnicodeDecodeErrorForPath as e:
|
|
2690
2722
|
raise click.ClickException(
|
|
@@ -2843,9 +2875,9 @@ def _generate_convert_help():
|
|
|
2843
2875
|
Convert columns using Python code you supply. For example:
|
|
2844
2876
|
|
|
2845
2877
|
\b
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2878
|
+
sqlite-utils convert my.db mytable mycolumn \\
|
|
2879
|
+
'"\\n".join(textwrap.wrap(value, 10))' \\
|
|
2880
|
+
--import=textwrap
|
|
2849
2881
|
|
|
2850
2882
|
"value" is a variable with the column value to be converted.
|
|
2851
2883
|
|
|
@@ -2864,7 +2896,7 @@ def _generate_convert_help():
|
|
|
2864
2896
|
for name in recipe_names:
|
|
2865
2897
|
fn = getattr(recipes, name)
|
|
2866
2898
|
help += "\n\nr.{}{}\n\n\b{}".format(
|
|
2867
|
-
name, str(inspect.signature(fn)), fn.__doc__.rstrip()
|
|
2899
|
+
name, str(inspect.signature(fn)), textwrap.dedent(fn.__doc__.rstrip())
|
|
2868
2900
|
)
|
|
2869
2901
|
help += "\n\n"
|
|
2870
2902
|
help += textwrap.dedent(
|
|
@@ -2872,8 +2904,8 @@ def _generate_convert_help():
|
|
|
2872
2904
|
You can use these recipes like so:
|
|
2873
2905
|
|
|
2874
2906
|
\b
|
|
2875
|
-
|
|
2876
|
-
|
|
2907
|
+
sqlite-utils convert my.db mytable mycolumn \\
|
|
2908
|
+
'r.jsonsplit(value, delimiter=":")'
|
|
2877
2909
|
"""
|
|
2878
2910
|
).strip()
|
|
2879
2911
|
return help
|
sqlite_utils/db.py
CHANGED
|
@@ -197,27 +197,34 @@ COLUMN_TYPE_MAPPING = {
|
|
|
197
197
|
"FLOAT": "FLOAT",
|
|
198
198
|
"BLOB": "BLOB",
|
|
199
199
|
"text": "TEXT",
|
|
200
|
+
"str": "TEXT",
|
|
200
201
|
"integer": "INTEGER",
|
|
202
|
+
"int": "INTEGER",
|
|
201
203
|
"float": "FLOAT",
|
|
202
204
|
"blob": "BLOB",
|
|
205
|
+
"bytes": "BLOB",
|
|
203
206
|
}
|
|
204
207
|
# If numpy is available, add more types
|
|
205
208
|
if np:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
try:
|
|
210
|
+
COLUMN_TYPE_MAPPING.update(
|
|
211
|
+
{
|
|
212
|
+
np.int8: "INTEGER",
|
|
213
|
+
np.int16: "INTEGER",
|
|
214
|
+
np.int32: "INTEGER",
|
|
215
|
+
np.int64: "INTEGER",
|
|
216
|
+
np.uint8: "INTEGER",
|
|
217
|
+
np.uint16: "INTEGER",
|
|
218
|
+
np.uint32: "INTEGER",
|
|
219
|
+
np.uint64: "INTEGER",
|
|
220
|
+
np.float16: "FLOAT",
|
|
221
|
+
np.float32: "FLOAT",
|
|
222
|
+
np.float64: "FLOAT",
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
except AttributeError:
|
|
226
|
+
# https://github.com/simonw/sqlite-utils/issues/632
|
|
227
|
+
pass
|
|
221
228
|
|
|
222
229
|
# If pandas is available, add more types
|
|
223
230
|
if pd:
|
|
@@ -300,6 +307,7 @@ class Database:
|
|
|
300
307
|
``sql, parameters`` every time a SQL query is executed
|
|
301
308
|
:param use_counts_table: set to ``True`` to use a cached counts table, if available. See
|
|
302
309
|
:ref:`python_api_cached_table_counts`
|
|
310
|
+
:param strict: Apply STRICT mode to all created tables (unless overridden)
|
|
303
311
|
"""
|
|
304
312
|
|
|
305
313
|
_counts_table_name = "_counts"
|
|
@@ -315,6 +323,7 @@ class Database:
|
|
|
315
323
|
tracer: Optional[Callable] = None,
|
|
316
324
|
use_counts_table: bool = False,
|
|
317
325
|
execute_plugins: bool = True,
|
|
326
|
+
strict: bool = False,
|
|
318
327
|
):
|
|
319
328
|
assert (filename_or_conn is not None and (not memory and not memory_name)) or (
|
|
320
329
|
filename_or_conn is None and (memory or memory_name)
|
|
@@ -348,6 +357,7 @@ class Database:
|
|
|
348
357
|
self.use_counts_table = use_counts_table
|
|
349
358
|
if execute_plugins:
|
|
350
359
|
pm.hook.prepare_connection(conn=self.conn)
|
|
360
|
+
self.strict = strict
|
|
351
361
|
|
|
352
362
|
def close(self):
|
|
353
363
|
"Close the SQLite connection, and the underlying database file"
|
|
@@ -451,8 +461,7 @@ class Database:
|
|
|
451
461
|
fn_name, arity, fn, **dict(kwargs, deterministic=True)
|
|
452
462
|
)
|
|
453
463
|
registered = True
|
|
454
|
-
except
|
|
455
|
-
# TypeError is Python 3.7 "function takes at most 3 arguments"
|
|
464
|
+
except sqlite3.NotSupportedError:
|
|
456
465
|
pass
|
|
457
466
|
if not registered:
|
|
458
467
|
self.conn.create_function(fn_name, arity, fn, **kwargs)
|
|
@@ -534,8 +543,11 @@ class Database:
|
|
|
534
543
|
|
|
535
544
|
:param table_name: Name of the table
|
|
536
545
|
"""
|
|
537
|
-
|
|
538
|
-
|
|
546
|
+
if table_name in self.view_names():
|
|
547
|
+
return View(self, table_name, **kwargs)
|
|
548
|
+
else:
|
|
549
|
+
kwargs.setdefault("strict", self.strict)
|
|
550
|
+
return Table(self, table_name, **kwargs)
|
|
539
551
|
|
|
540
552
|
def quote(self, value: str) -> str:
|
|
541
553
|
"""
|
|
@@ -821,6 +833,7 @@ class Database:
|
|
|
821
833
|
hash_id_columns: Optional[Iterable[str]] = None,
|
|
822
834
|
extracts: Optional[Union[Dict[str, str], List[str]]] = None,
|
|
823
835
|
if_not_exists: bool = False,
|
|
836
|
+
strict: bool = False,
|
|
824
837
|
) -> str:
|
|
825
838
|
"""
|
|
826
839
|
Returns the SQL ``CREATE TABLE`` statement for creating the specified table.
|
|
@@ -836,6 +849,7 @@ class Database:
|
|
|
836
849
|
:param hash_id_columns: List of columns to be used when calculating the hash ID for a row
|
|
837
850
|
:param extracts: List or dictionary of columns to be extracted during inserts, see :ref:`python_api_extracts`
|
|
838
851
|
:param if_not_exists: Use ``CREATE TABLE IF NOT EXISTS``
|
|
852
|
+
:param strict: Apply STRICT mode to table
|
|
839
853
|
"""
|
|
840
854
|
if hash_id_columns and (hash_id is None):
|
|
841
855
|
hash_id = "id"
|
|
@@ -919,9 +933,9 @@ class Database:
|
|
|
919
933
|
" [{column_name}] {column_type}{column_extras}".format(
|
|
920
934
|
column_name=column_name,
|
|
921
935
|
column_type=COLUMN_TYPE_MAPPING[column_type],
|
|
922
|
-
column_extras=(
|
|
923
|
-
|
|
924
|
-
|
|
936
|
+
column_extras=(
|
|
937
|
+
(" " + " ".join(column_extras)) if column_extras else ""
|
|
938
|
+
),
|
|
925
939
|
)
|
|
926
940
|
)
|
|
927
941
|
extra_pk = ""
|
|
@@ -932,12 +946,13 @@ class Database:
|
|
|
932
946
|
columns_sql = ",\n".join(column_defs)
|
|
933
947
|
sql = """CREATE TABLE {if_not_exists}[{table}] (
|
|
934
948
|
{columns_sql}{extra_pk}
|
|
935
|
-
);
|
|
949
|
+
){strict};
|
|
936
950
|
""".format(
|
|
937
951
|
if_not_exists="IF NOT EXISTS " if if_not_exists else "",
|
|
938
952
|
table=name,
|
|
939
953
|
columns_sql=columns_sql,
|
|
940
954
|
extra_pk=extra_pk,
|
|
955
|
+
strict=" STRICT" if strict and self.supports_strict else "",
|
|
941
956
|
)
|
|
942
957
|
return sql
|
|
943
958
|
|
|
@@ -957,6 +972,7 @@ class Database:
|
|
|
957
972
|
replace: bool = False,
|
|
958
973
|
ignore: bool = False,
|
|
959
974
|
transform: bool = False,
|
|
975
|
+
strict: bool = False,
|
|
960
976
|
) -> "Table":
|
|
961
977
|
"""
|
|
962
978
|
Create a table with the specified name and the specified ``{column_name: type}`` columns.
|
|
@@ -977,6 +993,7 @@ class Database:
|
|
|
977
993
|
:param replace: Drop and replace table if it already exists
|
|
978
994
|
:param ignore: Silently do nothing if table already exists
|
|
979
995
|
:param transform: If table already exists transform it to fit the specified schema
|
|
996
|
+
:param strict: Apply STRICT mode to table
|
|
980
997
|
"""
|
|
981
998
|
# Transform table to match the new definition if table already exists:
|
|
982
999
|
if self[name].exists():
|
|
@@ -1048,6 +1065,7 @@ class Database:
|
|
|
1048
1065
|
hash_id_columns=hash_id_columns,
|
|
1049
1066
|
extracts=extracts,
|
|
1050
1067
|
if_not_exists=if_not_exists,
|
|
1068
|
+
strict=strict,
|
|
1051
1069
|
)
|
|
1052
1070
|
self.execute(sql)
|
|
1053
1071
|
created_table = self.table(
|
|
@@ -1416,6 +1434,7 @@ class Table(Queryable):
|
|
|
1416
1434
|
:param extracts: Dictionary or list of column names to extract into a separate table on inserts
|
|
1417
1435
|
:param conversions: Dictionary of column names and conversion functions
|
|
1418
1436
|
:param columns: Dictionary of column names to column types
|
|
1437
|
+
:param strict: If True, apply STRICT mode to table
|
|
1419
1438
|
"""
|
|
1420
1439
|
|
|
1421
1440
|
#: The ``rowid`` of the last inserted, updated or selected row.
|
|
@@ -1441,6 +1460,7 @@ class Table(Queryable):
|
|
|
1441
1460
|
extracts: Optional[Union[Dict[str, str], List[str]]] = None,
|
|
1442
1461
|
conversions: Optional[dict] = None,
|
|
1443
1462
|
columns: Optional[Dict[str, Any]] = None,
|
|
1463
|
+
strict: bool = False,
|
|
1444
1464
|
):
|
|
1445
1465
|
super().__init__(db, name)
|
|
1446
1466
|
self._defaults = dict(
|
|
@@ -1458,14 +1478,17 @@ class Table(Queryable):
|
|
|
1458
1478
|
extracts=extracts,
|
|
1459
1479
|
conversions=conversions or {},
|
|
1460
1480
|
columns=columns,
|
|
1481
|
+
strict=strict,
|
|
1461
1482
|
)
|
|
1462
1483
|
|
|
1463
1484
|
def __repr__(self) -> str:
|
|
1464
1485
|
return "<Table {}{}>".format(
|
|
1465
1486
|
self.name,
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1487
|
+
(
|
|
1488
|
+
" (does not exist yet)"
|
|
1489
|
+
if not self.exists()
|
|
1490
|
+
else " ({})".format(", ".join(c.name for c in self.columns))
|
|
1491
|
+
),
|
|
1469
1492
|
)
|
|
1470
1493
|
|
|
1471
1494
|
@property
|
|
@@ -1639,6 +1662,7 @@ class Table(Queryable):
|
|
|
1639
1662
|
replace: bool = False,
|
|
1640
1663
|
ignore: bool = False,
|
|
1641
1664
|
transform: bool = False,
|
|
1665
|
+
strict: bool = False,
|
|
1642
1666
|
) -> "Table":
|
|
1643
1667
|
"""
|
|
1644
1668
|
Create a table with the specified columns.
|
|
@@ -1658,6 +1682,7 @@ class Table(Queryable):
|
|
|
1658
1682
|
:param replace: Drop and replace table if it already exists
|
|
1659
1683
|
:param ignore: Silently do nothing if table already exists
|
|
1660
1684
|
:param transform: If table already exists transform it to fit the specified schema
|
|
1685
|
+
:param strict: Apply STRICT mode to table
|
|
1661
1686
|
"""
|
|
1662
1687
|
columns = {name: value for (name, value) in columns.items()}
|
|
1663
1688
|
with self.db.conn:
|
|
@@ -1676,6 +1701,7 @@ class Table(Queryable):
|
|
|
1676
1701
|
replace=replace,
|
|
1677
1702
|
ignore=ignore,
|
|
1678
1703
|
transform=transform,
|
|
1704
|
+
strict=strict,
|
|
1679
1705
|
)
|
|
1680
1706
|
return self
|
|
1681
1707
|
|
|
@@ -1909,6 +1935,7 @@ class Table(Queryable):
|
|
|
1909
1935
|
defaults=create_table_defaults,
|
|
1910
1936
|
foreign_keys=create_table_foreign_keys,
|
|
1911
1937
|
column_order=column_order,
|
|
1938
|
+
strict=self.strict,
|
|
1912
1939
|
).strip()
|
|
1913
1940
|
)
|
|
1914
1941
|
|
|
@@ -2918,9 +2945,11 @@ class Table(Queryable):
|
|
|
2918
2945
|
value = jsonify_if_needed(
|
|
2919
2946
|
record.get(
|
|
2920
2947
|
key,
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2948
|
+
(
|
|
2949
|
+
None
|
|
2950
|
+
if key != hash_id
|
|
2951
|
+
else hash_record(record, hash_id_columns)
|
|
2952
|
+
),
|
|
2924
2953
|
)
|
|
2925
2954
|
)
|
|
2926
2955
|
if key in extracts:
|
|
@@ -3111,6 +3140,7 @@ class Table(Queryable):
|
|
|
3111
3140
|
extracts: Optional[Union[Dict[str, str], List[str], Default]] = DEFAULT,
|
|
3112
3141
|
conversions: Optional[Union[Dict[str, str], Default]] = DEFAULT,
|
|
3113
3142
|
columns: Optional[Union[Dict[str, Any], Default]] = DEFAULT,
|
|
3143
|
+
strict: Optional[Union[bool, Default]] = DEFAULT,
|
|
3114
3144
|
) -> "Table":
|
|
3115
3145
|
"""
|
|
3116
3146
|
Insert a single record into the table. The table will be created with a schema that matches
|
|
@@ -3143,6 +3173,7 @@ class Table(Queryable):
|
|
|
3143
3173
|
is being inserted, for example ``{"name": "upper(?)"}``. See :ref:`python_api_conversions`.
|
|
3144
3174
|
:param columns: Dictionary over-riding the detected types used for the columns, for example
|
|
3145
3175
|
``{"age": int, "weight": float}``.
|
|
3176
|
+
:param strict: Boolean, apply STRICT mode if creating the table.
|
|
3146
3177
|
"""
|
|
3147
3178
|
return self.insert_all(
|
|
3148
3179
|
[record],
|
|
@@ -3159,6 +3190,7 @@ class Table(Queryable):
|
|
|
3159
3190
|
extracts=extracts,
|
|
3160
3191
|
conversions=conversions,
|
|
3161
3192
|
columns=columns,
|
|
3193
|
+
strict=strict,
|
|
3162
3194
|
)
|
|
3163
3195
|
|
|
3164
3196
|
def insert_all(
|
|
@@ -3181,6 +3213,7 @@ class Table(Queryable):
|
|
|
3181
3213
|
columns=DEFAULT,
|
|
3182
3214
|
upsert=False,
|
|
3183
3215
|
analyze=False,
|
|
3216
|
+
strict=DEFAULT,
|
|
3184
3217
|
) -> "Table":
|
|
3185
3218
|
"""
|
|
3186
3219
|
Like ``.insert()`` but takes a list of records and ensures that the table
|
|
@@ -3202,6 +3235,7 @@ class Table(Queryable):
|
|
|
3202
3235
|
extracts = self.value_or_default("extracts", extracts)
|
|
3203
3236
|
conversions = self.value_or_default("conversions", conversions) or {}
|
|
3204
3237
|
columns = self.value_or_default("columns", columns)
|
|
3238
|
+
strict = self.value_or_default("strict", strict)
|
|
3205
3239
|
|
|
3206
3240
|
if hash_id_columns and hash_id is None:
|
|
3207
3241
|
hash_id = "id"
|
|
@@ -3257,6 +3291,7 @@ class Table(Queryable):
|
|
|
3257
3291
|
hash_id=hash_id,
|
|
3258
3292
|
hash_id_columns=hash_id_columns,
|
|
3259
3293
|
extracts=extracts,
|
|
3294
|
+
strict=strict,
|
|
3260
3295
|
)
|
|
3261
3296
|
all_columns_set = set()
|
|
3262
3297
|
for record in chunk:
|
|
@@ -3307,6 +3342,7 @@ class Table(Queryable):
|
|
|
3307
3342
|
extracts=DEFAULT,
|
|
3308
3343
|
conversions=DEFAULT,
|
|
3309
3344
|
columns=DEFAULT,
|
|
3345
|
+
strict=DEFAULT,
|
|
3310
3346
|
) -> "Table":
|
|
3311
3347
|
"""
|
|
3312
3348
|
Like ``.insert()`` but performs an ``UPSERT``, where records are inserted if they do
|
|
@@ -3327,6 +3363,7 @@ class Table(Queryable):
|
|
|
3327
3363
|
extracts=extracts,
|
|
3328
3364
|
conversions=conversions,
|
|
3329
3365
|
columns=columns,
|
|
3366
|
+
strict=strict,
|
|
3330
3367
|
)
|
|
3331
3368
|
|
|
3332
3369
|
def upsert_all(
|
|
@@ -3345,6 +3382,7 @@ class Table(Queryable):
|
|
|
3345
3382
|
conversions=DEFAULT,
|
|
3346
3383
|
columns=DEFAULT,
|
|
3347
3384
|
analyze=False,
|
|
3385
|
+
strict=DEFAULT,
|
|
3348
3386
|
) -> "Table":
|
|
3349
3387
|
"""
|
|
3350
3388
|
Like ``.upsert()`` but can be applied to a list of records.
|
|
@@ -3365,6 +3403,7 @@ class Table(Queryable):
|
|
|
3365
3403
|
columns=columns,
|
|
3366
3404
|
upsert=True,
|
|
3367
3405
|
analyze=analyze,
|
|
3406
|
+
strict=strict,
|
|
3368
3407
|
)
|
|
3369
3408
|
|
|
3370
3409
|
def add_missing_columns(self, records: Iterable[Dict[str, Any]]) -> "Table":
|
|
@@ -3387,6 +3426,7 @@ class Table(Queryable):
|
|
|
3387
3426
|
extracts: Optional[Union[Dict[str, str], List[str]]] = None,
|
|
3388
3427
|
conversions: Optional[Dict[str, str]] = None,
|
|
3389
3428
|
columns: Optional[Dict[str, Any]] = None,
|
|
3429
|
+
strict: Optional[bool] = False,
|
|
3390
3430
|
):
|
|
3391
3431
|
"""
|
|
3392
3432
|
Create or populate a lookup table with the specified values.
|
|
@@ -3409,6 +3449,7 @@ class Table(Queryable):
|
|
|
3409
3449
|
|
|
3410
3450
|
:param lookup_values: Dictionary specifying column names and values to use for the lookup
|
|
3411
3451
|
:param extra_values: Additional column values to be used only if creating a new record
|
|
3452
|
+
:param strict: Boolean, apply STRICT mode if creating the table.
|
|
3412
3453
|
"""
|
|
3413
3454
|
assert isinstance(lookup_values, dict)
|
|
3414
3455
|
if extra_values is not None:
|
|
@@ -3440,6 +3481,7 @@ class Table(Queryable):
|
|
|
3440
3481
|
extracts=extracts,
|
|
3441
3482
|
conversions=conversions,
|
|
3442
3483
|
columns=columns,
|
|
3484
|
+
strict=strict,
|
|
3443
3485
|
).last_pk
|
|
3444
3486
|
else:
|
|
3445
3487
|
pk = self.insert(
|
|
@@ -3452,6 +3494,7 @@ class Table(Queryable):
|
|
|
3452
3494
|
extracts=extracts,
|
|
3453
3495
|
conversions=conversions,
|
|
3454
3496
|
columns=columns,
|
|
3497
|
+
strict=strict,
|
|
3455
3498
|
).last_pk
|
|
3456
3499
|
self.create_index(lookup_values.keys(), unique=True)
|
|
3457
3500
|
return pk
|
sqlite_utils/utils.py
CHANGED
|
@@ -304,10 +304,7 @@ def rows_from_file(
|
|
|
304
304
|
rows = rows_from_file(
|
|
305
305
|
fp, format=Format.CSV, dialect=csv.excel_tab, encoding=encoding
|
|
306
306
|
)[0]
|
|
307
|
-
return (
|
|
308
|
-
_extra_key_strategy(rows, ignore_extras, extras_key),
|
|
309
|
-
Format.TSV,
|
|
310
|
-
)
|
|
307
|
+
return _extra_key_strategy(rows, ignore_extras, extras_key), Format.TSV
|
|
311
308
|
elif format is None:
|
|
312
309
|
# Detect the format, then call this recursively
|
|
313
310
|
buffered = io.BufferedReader(cast(io.RawIOBase, fp), buffer_size=4096)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sqlite-utils
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.37
|
|
4
4
|
Summary: CLI tool and Python library for manipulating SQLite databases
|
|
5
5
|
Home-page: https://github.com/simonw/sqlite-utils
|
|
6
6
|
Author: Simon Willison
|
|
@@ -16,13 +16,13 @@ Classifier: Intended Audience :: Science/Research
|
|
|
16
16
|
Classifier: Intended Audience :: End Users/Desktop
|
|
17
17
|
Classifier: Topic :: Database
|
|
18
18
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.8
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.9
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
-
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
License-File: LICENSE
|
|
28
28
|
Requires-Dist: sqlite-fts4
|
|
@@ -49,7 +49,7 @@ Requires-Dist: types-pluggy ; extra == 'mypy'
|
|
|
49
49
|
Requires-Dist: data-science-types ; extra == 'mypy'
|
|
50
50
|
Provides-Extra: test
|
|
51
51
|
Requires-Dist: pytest ; extra == 'test'
|
|
52
|
-
Requires-Dist: black ; extra == 'test'
|
|
52
|
+
Requires-Dist: black >=24.1.1 ; extra == 'test'
|
|
53
53
|
Requires-Dist: hypothesis ; extra == 'test'
|
|
54
54
|
Requires-Dist: cogapp ; extra == 'test'
|
|
55
55
|
Provides-Extra: tui
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
sqlite_utils/__init__.py,sha256=eyDK-5KOo-ARS3i0JcuxGiJmk5T-58Z1p_bhACbBrGc,201
|
|
2
|
+
sqlite_utils/__main__.py,sha256=8hDtWlaFZK24KhfNq_ZKgtXqYHsDQDetukOCMlsbW0Q,59
|
|
3
|
+
sqlite_utils/cli.py,sha256=sBAF9cxvJ108OBWspzQoz1dvN_fLBhlJSaAbmWbYlHc,89771
|
|
4
|
+
sqlite_utils/db.py,sha256=na--6HxI5db7_LaZwwY2nAusVJaZ2AlC-DYTNHwY1A8,146365
|
|
5
|
+
sqlite_utils/hookspecs.py,sha256=NFA0BFZ8WUhnI_NRz4oFVDcomQYlguuAgUCBKAN792o,395
|
|
6
|
+
sqlite_utils/plugins.py,sha256=V5nXD4r0o1wSbIHHOAiUBBV66ZOfKVnywKfZzCUqdsA,771
|
|
7
|
+
sqlite_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
sqlite_utils/recipes.py,sha256=_npzti0nPV6XxvMj69Ca4QF-pXwZZQp_f_VY3i7pQDs,1687
|
|
9
|
+
sqlite_utils/utils.py,sha256=PRqoITtqmaUI7xzyB2exaTPg6oXbTMhGDzld7srNOG4,17099
|
|
10
|
+
sqlite_utils-3.37.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
11
|
+
sqlite_utils-3.37.dist-info/METADATA,sha256=DdfINwbgTnsxBvYUgSaz0pePxd9PqJCcyfn107VNkJA,7561
|
|
12
|
+
sqlite_utils-3.37.dist-info/WHEEL,sha256=-oYQCr74JF3a37z2nRlQays_SX2MqOANoqVjBBAP2yE,91
|
|
13
|
+
sqlite_utils-3.37.dist-info/entry_points.txt,sha256=33jbVHROlRBNhoXoSI-QI2rN6JDkJIkKIX7P5sNIWdY,54
|
|
14
|
+
sqlite_utils-3.37.dist-info/top_level.txt,sha256=_dw_n5BWKUEtCYB2DTlmPMQfdRZSuFsmRQe2ZhNYwnQ,13
|
|
15
|
+
sqlite_utils-3.37.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
sqlite_utils/__init__.py,sha256=eyDK-5KOo-ARS3i0JcuxGiJmk5T-58Z1p_bhACbBrGc,201
|
|
2
|
-
sqlite_utils/__main__.py,sha256=8hDtWlaFZK24KhfNq_ZKgtXqYHsDQDetukOCMlsbW0Q,59
|
|
3
|
-
sqlite_utils/cli.py,sha256=kHYDOWFbAbas5rkdr67BanbqHBVIlsymKkd0BRSsags,88859
|
|
4
|
-
sqlite_utils/db.py,sha256=a89cAwKNxrx0eAmhurorKDRWGyQ_u4II9-HwRSG0cuE,144794
|
|
5
|
-
sqlite_utils/hookspecs.py,sha256=NFA0BFZ8WUhnI_NRz4oFVDcomQYlguuAgUCBKAN792o,395
|
|
6
|
-
sqlite_utils/plugins.py,sha256=V5nXD4r0o1wSbIHHOAiUBBV66ZOfKVnywKfZzCUqdsA,771
|
|
7
|
-
sqlite_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
sqlite_utils/recipes.py,sha256=_npzti0nPV6XxvMj69Ca4QF-pXwZZQp_f_VY3i7pQDs,1687
|
|
9
|
-
sqlite_utils/utils.py,sha256=jvlsGQ5F_Z7-bAiP7gw4hmov_58PrVMvY_5UZ3nXfAg,17136
|
|
10
|
-
sqlite_utils-3.35.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
11
|
-
sqlite_utils-3.35.2.dist-info/METADATA,sha256=sWiT3qYyM8iNmyXtU993w5y-Y7LNu5l3sk1k4ZKHSos,7553
|
|
12
|
-
sqlite_utils-3.35.2.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
13
|
-
sqlite_utils-3.35.2.dist-info/entry_points.txt,sha256=33jbVHROlRBNhoXoSI-QI2rN6JDkJIkKIX7P5sNIWdY,54
|
|
14
|
-
sqlite_utils-3.35.2.dist-info/top_level.txt,sha256=_dw_n5BWKUEtCYB2DTlmPMQfdRZSuFsmRQe2ZhNYwnQ,13
|
|
15
|
-
sqlite_utils-3.35.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|