sqlite-utils 3.35.2__tar.gz → 3.37__tar.gz
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-3.35.2/sqlite_utils.egg-info → sqlite_utils-3.37}/PKG-INFO +4 -4
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/changelog.rst +20 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/cli-reference.rst +23 -19
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/cli.rst +33 -3
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/plugins.rst +2 -2
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/python-api.rst +31 -2
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/setup.py +4 -4
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/cli.py +47 -15
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/db.py +72 -29
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/utils.py +1 -4
- {sqlite-utils-3.35.2 → sqlite_utils-3.37/sqlite_utils.egg-info}/PKG-INFO +4 -4
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils.egg-info/requires.txt +1 -1
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_cli.py +55 -10
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_cli_insert.py +10 -5
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_create.py +43 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_insert_files.py +10 -2
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_lookup.py +6 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_transform.py +9 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/LICENSE +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/MANIFEST.in +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/README.md +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/contributing.rst +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/index.rst +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/installation.rst +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/docs/reference.rst +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/setup.cfg +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/__init__.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/__main__.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/hookspecs.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/plugins.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/py.typed +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils/recipes.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils.egg-info/SOURCES.txt +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils.egg-info/dependency_links.txt +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils.egg-info/entry_points.txt +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils.egg-info/not-zip-safe +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/sqlite_utils.egg-info/top_level.txt +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/__init__.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/conftest.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_analyze.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_analyze_tables.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_attach.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_cli_bulk.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_cli_convert.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_cli_memory.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_column_affinity.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_constructor.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_conversions.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_convert.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_create_view.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_default_value.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_delete.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_docs.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_duplicate.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_enable_counts.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_extract.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_extracts.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_fts.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_get.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_gis.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_hypothesis.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_introspect.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_m2m.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_plugins.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_query.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_recipes.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_recreate.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_register_function.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_rows.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_rows_from_file.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_sniff.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_suggest_column_types.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_tracer.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_update.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_upsert.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_utils.py +0 -0
- {sqlite-utils-3.35.2 → sqlite_utils-3.37}/tests/test_wal.py +0 -0
|
@@ -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
|
|
@@ -33,7 +33,7 @@ Requires-Dist: python-dateutil
|
|
|
33
33
|
Requires-Dist: pluggy
|
|
34
34
|
Provides-Extra: test
|
|
35
35
|
Requires-Dist: pytest; extra == "test"
|
|
36
|
-
Requires-Dist: black; extra == "test"
|
|
36
|
+
Requires-Dist: black>=24.1.1; extra == "test"
|
|
37
37
|
Requires-Dist: hypothesis; extra == "test"
|
|
38
38
|
Requires-Dist: cogapp; extra == "test"
|
|
39
39
|
Provides-Extra: docs
|
|
@@ -4,6 +4,26 @@
|
|
|
4
4
|
Changelog
|
|
5
5
|
===========
|
|
6
6
|
|
|
7
|
+
.. _v3_37:
|
|
8
|
+
|
|
9
|
+
3.37 (2024-07-18)
|
|
10
|
+
-----------------
|
|
11
|
+
|
|
12
|
+
- The ``create-table`` and ``insert-files`` commands all now accept multiple ``--pk`` options for compound primary keys. (:issue:`620`)
|
|
13
|
+
- Now tested against Python 3.13 pre-release. (`#619 <https://github.com/simonw/sqlite-utils/pull/619>`__)
|
|
14
|
+
- Fixed a crash that can occur in environments with a broken ``numpy`` installation, producing a ``module 'numpy' has no attribute 'int8'``. (:issue:`632`)
|
|
15
|
+
|
|
16
|
+
.. _v3_36:
|
|
17
|
+
|
|
18
|
+
3.36 (2023-12-07)
|
|
19
|
+
-----------------
|
|
20
|
+
|
|
21
|
+
- Support for creating tables in `SQLite STRICT mode <https://www.sqlite.org/stricttables.html>`__. Thanks, `Taj Khattra <https://github.com/tkhattra>`__. (:issue:`344`)
|
|
22
|
+
- CLI commands ``create-table``, ``insert`` and ``upsert`` all now accept a ``--strict`` option.
|
|
23
|
+
- Python methods that can create a table - ``table.create()`` and ``insert/upsert/insert_all/upsert_all`` all now accept an optional ``strict=True`` parameter.
|
|
24
|
+
- The ``transform`` command and ``table.transform()`` method preserve strict mode when transforming a table.
|
|
25
|
+
- The ``sqlite-utils create-table`` command now accepts ``str``, ``int`` and ``bytes`` as aliases for ``text``, ``integer`` and ``blob`` respectively. (:issue:`606`)
|
|
26
|
+
|
|
7
27
|
.. _v3_35_2:
|
|
8
28
|
|
|
9
29
|
3.35.2 (2023-11-03)
|
|
@@ -85,6 +85,7 @@ This page lists the ``--help`` for every ``sqlite-utils`` CLI sub-command.
|
|
|
85
85
|
cog.out("::\n\n")
|
|
86
86
|
result = CliRunner().invoke(cli.cli, [command, "--help"])
|
|
87
87
|
output = result.output.replace("Usage: cli ", "Usage: sqlite-utils ")
|
|
88
|
+
output = output.replace('\b', '')
|
|
88
89
|
cog.out(textwrap.indent(output, ' '))
|
|
89
90
|
cog.out("\n\n")
|
|
90
91
|
.. ]]]
|
|
@@ -289,6 +290,7 @@ See :ref:`cli_inserting_data`, :ref:`cli_insert_csv_tsv`, :ref:`cli_insert_unstr
|
|
|
289
290
|
--analyze Run ANALYZE at the end of this operation
|
|
290
291
|
--load-extension TEXT Path to SQLite extension, with optional :entrypoint
|
|
291
292
|
--silent Do not show progress bar
|
|
293
|
+
--strict Apply STRICT mode to created table
|
|
292
294
|
--ignore Ignore records if pk already exists
|
|
293
295
|
--replace Replace records if pk already exists
|
|
294
296
|
--truncate Truncate table before inserting records, if table
|
|
@@ -345,6 +347,7 @@ See :ref:`cli_upsert`.
|
|
|
345
347
|
--analyze Run ANALYZE at the end of this operation
|
|
346
348
|
--load-extension TEXT Path to SQLite extension, with optional :entrypoint
|
|
347
349
|
--silent Do not show progress bar
|
|
350
|
+
--strict Apply STRICT mode to created table
|
|
348
351
|
-h, --help Show this message and exit.
|
|
349
352
|
|
|
350
353
|
|
|
@@ -601,9 +604,9 @@ See :ref:`cli_convert`.
|
|
|
601
604
|
|
|
602
605
|
Convert columns using Python code you supply. For example:
|
|
603
606
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
+
sqlite-utils convert my.db mytable mycolumn \
|
|
608
|
+
'"\n".join(textwrap.wrap(value, 10))' \
|
|
609
|
+
--import=textwrap
|
|
607
610
|
|
|
608
611
|
"value" is a variable with the column value to be converted.
|
|
609
612
|
|
|
@@ -613,30 +616,30 @@ See :ref:`cli_convert`.
|
|
|
613
616
|
|
|
614
617
|
r.jsonsplit(value, delimiter=',', type=<class 'str'>)
|
|
615
618
|
|
|
616
|
-
|
|
619
|
+
Convert a string like a,b,c into a JSON array ["a", "b", "c"]
|
|
617
620
|
|
|
618
621
|
r.parsedate(value, dayfirst=False, yearfirst=False, errors=None)
|
|
619
622
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
623
|
+
Parse a date and convert it to ISO date format: yyyy-mm-dd
|
|
624
|
+
|
|
625
|
+
- dayfirst=True: treat xx as the day in xx/yy/zz
|
|
626
|
+
- yearfirst=True: treat xx as the year in xx/yy/zz
|
|
627
|
+
- errors=r.IGNORE to ignore values that cannot be parsed
|
|
628
|
+
- errors=r.SET_NULL to set values that cannot be parsed to null
|
|
626
629
|
|
|
627
630
|
r.parsedatetime(value, dayfirst=False, yearfirst=False, errors=None)
|
|
628
631
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
632
|
+
Parse a datetime and convert it to ISO datetime format: yyyy-mm-ddTHH:MM:SS
|
|
633
|
+
|
|
634
|
+
- dayfirst=True: treat xx as the day in xx/yy/zz
|
|
635
|
+
- yearfirst=True: treat xx as the year in xx/yy/zz
|
|
636
|
+
- errors=r.IGNORE to ignore values that cannot be parsed
|
|
637
|
+
- errors=r.SET_NULL to set values that cannot be parsed to null
|
|
635
638
|
|
|
636
639
|
You can use these recipes like so:
|
|
637
640
|
|
|
638
|
-
|
|
639
|
-
|
|
641
|
+
sqlite-utils convert my.db mytable mycolumn \
|
|
642
|
+
'r.jsonsplit(value, delimiter=":")'
|
|
640
643
|
|
|
641
644
|
Options:
|
|
642
645
|
--import TEXT Python modules to import
|
|
@@ -920,6 +923,7 @@ See :ref:`cli_create_table`.
|
|
|
920
923
|
--replace If table already exists, replace it
|
|
921
924
|
--transform If table already exists, try to transform the schema
|
|
922
925
|
--load-extension TEXT Path to SQLite extension, with optional :entrypoint
|
|
926
|
+
--strict Apply STRICT mode to created table
|
|
923
927
|
-h, --help Show this message and exit.
|
|
924
928
|
|
|
925
929
|
|
|
@@ -1157,7 +1161,7 @@ See :ref:`cli_add_column`.
|
|
|
1157
1161
|
::
|
|
1158
1162
|
|
|
1159
1163
|
Usage: sqlite-utils add-column [OPTIONS] PATH TABLE COL_NAME
|
|
1160
|
-
[[integer|float|
|
|
1164
|
+
[[integer|int|float|text|str|blob|bytes]]
|
|
1161
1165
|
|
|
1162
1166
|
Add a column to the specified table
|
|
1163
1167
|
|
|
@@ -1088,11 +1088,13 @@ You can import all three records into an automatically created ``dogs`` table an
|
|
|
1088
1088
|
|
|
1089
1089
|
sqlite-utils insert dogs.db dogs dogs.json --pk=id
|
|
1090
1090
|
|
|
1091
|
+
Pass ``--pk`` multiple times to define a compound primary key.
|
|
1092
|
+
|
|
1091
1093
|
You can skip inserting any records that have a primary key that already exists using ``--ignore``:
|
|
1092
1094
|
|
|
1093
1095
|
.. code-block:: bash
|
|
1094
1096
|
|
|
1095
|
-
sqlite-utils insert dogs.db dogs dogs.json --ignore
|
|
1097
|
+
sqlite-utils insert dogs.db dogs dogs.json --pk=id --ignore
|
|
1096
1098
|
|
|
1097
1099
|
You can delete all the existing rows in the table before inserting the new records using ``--truncate``:
|
|
1098
1100
|
|
|
@@ -1909,6 +1911,8 @@ This will create a table called ``mytable`` with two columns - an integer ``id``
|
|
|
1909
1911
|
|
|
1910
1912
|
You can pass as many column-name column-type pairs as you like. Valid types are ``integer``, ``text``, ``float`` and ``blob``.
|
|
1911
1913
|
|
|
1914
|
+
Pass ``--pk`` more than once for a compound primary key that covers multiple columns.
|
|
1915
|
+
|
|
1912
1916
|
You can specify columns that should be NOT NULL using ``--not-null colname``. You can specify default values for columns using ``--default colname defaultvalue``.
|
|
1913
1917
|
|
|
1914
1918
|
.. code-block:: bash
|
|
@@ -1972,6 +1976,25 @@ You can specify foreign key relationships between the tables you are creating us
|
|
|
1972
1976
|
[author_id] INTEGER REFERENCES [authors]([id])
|
|
1973
1977
|
)
|
|
1974
1978
|
|
|
1979
|
+
You can create a table in `SQLite STRICT mode <https://www.sqlite.org/stricttables.html>`__ using ``--strict``:
|
|
1980
|
+
|
|
1981
|
+
.. code-block:: bash
|
|
1982
|
+
|
|
1983
|
+
sqlite-utils create-table mydb.db mytable id integer name text --strict
|
|
1984
|
+
|
|
1985
|
+
.. code-block:: bash
|
|
1986
|
+
|
|
1987
|
+
sqlite-utils tables mydb.db --schema -t
|
|
1988
|
+
|
|
1989
|
+
.. code-block:: output
|
|
1990
|
+
|
|
1991
|
+
table schema
|
|
1992
|
+
------- ------------------------
|
|
1993
|
+
mytable CREATE TABLE [mytable] (
|
|
1994
|
+
[id] INTEGER,
|
|
1995
|
+
[name] TEXT
|
|
1996
|
+
) STRICT
|
|
1997
|
+
|
|
1975
1998
|
If a table with the same name already exists, you will get an error. You can choose to silently ignore this error with ``--ignore``, or you can replace the existing table with a new, empty table using ``--replace``.
|
|
1976
1999
|
|
|
1977
2000
|
You can also pass ``--transform`` to transform the existing table to match the new schema. See :ref:`python_api_explicit_create` in the Python library documentation for details of how this option works.
|
|
@@ -2018,7 +2041,7 @@ Use ``--ignore`` to ignore the error if the table does not exist.
|
|
|
2018
2041
|
Transforming tables
|
|
2019
2042
|
===================
|
|
2020
2043
|
|
|
2021
|
-
The ``transform`` command allows you to apply complex transformations to a table that cannot be implemented using a regular SQLite ``ALTER TABLE`` command. See :ref:`python_api_transform` for details of how this works.
|
|
2044
|
+
The ``transform`` command allows you to apply complex transformations to a table that cannot be implemented using a regular SQLite ``ALTER TABLE`` command. See :ref:`python_api_transform` for details of how this works. The ``transform`` command preserves a table's ``STRICT`` mode.
|
|
2022
2045
|
|
|
2023
2046
|
.. code-block:: bash
|
|
2024
2047
|
|
|
@@ -2310,7 +2333,14 @@ You can add a column using the ``add-column`` command:
|
|
|
2310
2333
|
|
|
2311
2334
|
sqlite-utils add-column mydb.db mytable nameofcolumn text
|
|
2312
2335
|
|
|
2313
|
-
The last argument here is the type of the column to be created.
|
|
2336
|
+
The last argument here is the type of the column to be created. This can be one of:
|
|
2337
|
+
|
|
2338
|
+
- ``text`` or ``str``
|
|
2339
|
+
- ``integer`` or ``int``
|
|
2340
|
+
- ``float``
|
|
2341
|
+
- ``blob`` or ``bytes``
|
|
2342
|
+
|
|
2343
|
+
This argument is optional and defaults to ``text``.
|
|
2314
2344
|
|
|
2315
2345
|
You can add a column that is a foreign key reference to another table using the ``--fk`` option:
|
|
2316
2346
|
|
|
@@ -49,7 +49,7 @@ In that folder create two files. The first is a ``pyproject.toml`` file describi
|
|
|
49
49
|
[project.entry-points.sqlite_utils]
|
|
50
50
|
hello_world = "sqlite_utils_hello_world"
|
|
51
51
|
|
|
52
|
-
The
|
|
52
|
+
The ``[project.entry-points.sqlite_utils]`` section tells ``sqlite-utils`` which module to load when executing the plugin.
|
|
53
53
|
|
|
54
54
|
Then create ``sqlite_utils_hello_world.py`` with the following content:
|
|
55
55
|
|
|
@@ -75,7 +75,7 @@ Or pass the path to your plugin directory:
|
|
|
75
75
|
|
|
76
76
|
.. code-block:: bash
|
|
77
77
|
|
|
78
|
-
sqlite-utils install -e
|
|
78
|
+
sqlite-utils install -e /dev/sqlite-utils-hello-world
|
|
79
79
|
|
|
80
80
|
Now, running this should execute your new command:
|
|
81
81
|
|
|
@@ -117,6 +117,12 @@ By default, any :ref:`sqlite-utils plugins <plugins>` that implement the :ref:`p
|
|
|
117
117
|
|
|
118
118
|
db = Database(memory=True, execute_plugins=False)
|
|
119
119
|
|
|
120
|
+
You can pass ``strict=True`` to enable `SQLite STRICT mode <https://www.sqlite.org/stricttables.html>`__ for all tables created using this database object:
|
|
121
|
+
|
|
122
|
+
.. code-block:: python
|
|
123
|
+
|
|
124
|
+
db = Database("my_database.db", strict=True)
|
|
125
|
+
|
|
120
126
|
.. _python_api_attach:
|
|
121
127
|
|
|
122
128
|
Attaching additional databases
|
|
@@ -581,6 +587,15 @@ The ``transform=True`` option will update the table schema if any of the followi
|
|
|
581
587
|
|
|
582
588
|
Changes to ``foreign_keys=`` are not currently detected and applied by ``transform=True``.
|
|
583
589
|
|
|
590
|
+
You can pass ``strict=True`` to create a table in ``STRICT`` mode:
|
|
591
|
+
|
|
592
|
+
.. code-block:: python
|
|
593
|
+
|
|
594
|
+
db["cats"].create({
|
|
595
|
+
"id": int,
|
|
596
|
+
"name": str,
|
|
597
|
+
}, strict=True)
|
|
598
|
+
|
|
584
599
|
.. _python_api_compound_primary_keys:
|
|
585
600
|
|
|
586
601
|
Compound primary keys
|
|
@@ -661,7 +676,7 @@ You can set default values for these methods by accessing the table through the
|
|
|
661
676
|
# Now you can call .insert() like so:
|
|
662
677
|
table.insert({"id": 1, "name": "Tracy", "score": 5})
|
|
663
678
|
|
|
664
|
-
The configuration options that can be specified in this way are ``pk``, ``foreign_keys``, ``column_order``, ``not_null``, ``defaults``, ``batch_size``, ``hash_id``, ``hash_id_columns``, ``alter``, ``ignore``, ``replace``, ``extracts``, ``conversions``, ``columns``. These are all documented below.
|
|
679
|
+
The configuration options that can be specified in this way are ``pk``, ``foreign_keys``, ``column_order``, ``not_null``, ``defaults``, ``batch_size``, ``hash_id``, ``hash_id_columns``, ``alter``, ``ignore``, ``replace``, ``extracts``, ``conversions``, ``columns``, ``strict``. These are all documented below.
|
|
665
680
|
|
|
666
681
|
.. _python_api_defaults_not_null:
|
|
667
682
|
|
|
@@ -875,7 +890,8 @@ You can delete all records in a table that match a specific WHERE statement usin
|
|
|
875
890
|
|
|
876
891
|
>>> db = sqlite_utils.Database("dogs.db")
|
|
877
892
|
>>> # Delete every dog with age less than 3
|
|
878
|
-
>>> db
|
|
893
|
+
>>> with db.conn:
|
|
894
|
+
>>> db["dogs"].delete_where("age < ?", [3])
|
|
879
895
|
|
|
880
896
|
Calling ``table.delete_where()`` with no other arguments will delete every row in the table.
|
|
881
897
|
|
|
@@ -1011,6 +1027,7 @@ The first time this is called the record will be created for ``name="Palm"``. An
|
|
|
1011
1027
|
- ``extracts``
|
|
1012
1028
|
- ``conversions``
|
|
1013
1029
|
- ``columns``
|
|
1030
|
+
- ``strict``
|
|
1014
1031
|
|
|
1015
1032
|
.. _python_api_extracts:
|
|
1016
1033
|
|
|
@@ -2161,6 +2178,18 @@ The ``.has_counts_triggers`` property shows if a table has been configured with
|
|
|
2161
2178
|
>>> db["authors"].has_counts_triggers
|
|
2162
2179
|
True
|
|
2163
2180
|
|
|
2181
|
+
.. _python_api_introspection_supports_strict:
|
|
2182
|
+
|
|
2183
|
+
db.supports_strict
|
|
2184
|
+
------------------
|
|
2185
|
+
|
|
2186
|
+
This property on the database object returns ``True`` if the available SQLite version supports `STRICT mode <https://www.sqlite.org/stricttables.html>`__, which was added in SQLite 3.37.0 (on 2021-11-27).
|
|
2187
|
+
|
|
2188
|
+
::
|
|
2189
|
+
|
|
2190
|
+
>>> db.supports_strict
|
|
2191
|
+
True
|
|
2192
|
+
|
|
2164
2193
|
.. _python_api_fts:
|
|
2165
2194
|
|
|
2166
2195
|
Full-text search
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
import io
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
-
VERSION = "3.
|
|
5
|
+
VERSION = "3.37"
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def get_long_description():
|
|
@@ -32,7 +32,7 @@ setup(
|
|
|
32
32
|
"pluggy",
|
|
33
33
|
],
|
|
34
34
|
extras_require={
|
|
35
|
-
"test": ["pytest", "black", "hypothesis", "cogapp"],
|
|
35
|
+
"test": ["pytest", "black>=24.1.1", "hypothesis", "cogapp"],
|
|
36
36
|
"docs": [
|
|
37
37
|
"furo",
|
|
38
38
|
"sphinx-autobuild",
|
|
@@ -64,7 +64,7 @@ setup(
|
|
|
64
64
|
"Issues": "https://github.com/simonw/sqlite-utils/issues",
|
|
65
65
|
"CI": "https://github.com/simonw/sqlite-utils/actions",
|
|
66
66
|
},
|
|
67
|
-
python_requires=">=3.
|
|
67
|
+
python_requires=">=3.8",
|
|
68
68
|
classifiers=[
|
|
69
69
|
"Development Status :: 5 - Production/Stable",
|
|
70
70
|
"Intended Audience :: Developers",
|
|
@@ -72,12 +72,12 @@ setup(
|
|
|
72
72
|
"Intended Audience :: End Users/Desktop",
|
|
73
73
|
"Topic :: Database",
|
|
74
74
|
"License :: OSI Approved :: Apache Software License",
|
|
75
|
-
"Programming Language :: Python :: 3.7",
|
|
76
75
|
"Programming Language :: Python :: 3.8",
|
|
77
76
|
"Programming Language :: Python :: 3.9",
|
|
78
77
|
"Programming Language :: Python :: 3.10",
|
|
79
78
|
"Programming Language :: Python :: 3.11",
|
|
80
79
|
"Programming Language :: Python :: 3.12",
|
|
80
|
+
"Programming Language :: Python :: 3.13",
|
|
81
81
|
],
|
|
82
82
|
# Needed to bundle py.typed so mypy can see it:
|
|
83
83
|
zip_safe=False,
|
|
@@ -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
|