Commit graph

55 commits

Author SHA1 Message Date
Claude
cffe30fd2f
Fix ValueTracker skipping type evaluation for empty strings
`ValueTracker.evaluate()` used `if not value` to skip NULL values, but
this also skipped empty strings (`""`), `0`, and other falsy values.
A CSV column containing only empty strings was incorrectly inferred as
INTEGER (the initial default) instead of TEXT.

Replace the falsy check with an explicit `if value is None` so that only
NULL is skipped and all other values — including `""` — are evaluated
against the type tests.
2026-07-20 14:57:53 +00:00
Simon Willison
07b603e562
Preserve duplicate column names in query results
Queries returning duplicate column names - e.g. joins between tables
sharing column names - silently lost values because rows were built
with dict(zip(keys, row)), where the last duplicate wins.

Later occurrences are now renamed with a numeric suffix: id, id
becomes id, id_2 - skipping any suffix that would collide with a
real column in the same query.

The new utils.dedupe_keys() helper transforms the key list once per
query, so the per-row dict construction is unchanged and there is no
measurable performance impact.

Applied in Database.query() (including the PRAGMA and RETURNING
paths), Table.rows_where(), Table.search() and the CLI's JSON output.
CSV, TSV and table output keep the original duplicate headers.

Closes #624
2026-07-05 21:20:39 -07:00
Simon Willison
afbfd95273
Remove sqlean.py support (#772)
Closes #771, refs #769
2026-07-05 16:00:52 -07:00
Simon Willison
8f0c06e188
Test against Python 3.15-dev, bump ty and Black (#738)
* Add Python 3.15-dev to test matrix
* Run ty check only on 3.14
* Bump Black version
* Update tabulate and use that in 
* Bump to latest ty
2026-05-17 16:52:48 -07:00
Simon Willison
8d74ffc932
More type annotations (#697)
* Add comprehensive type annotations

- mypy.ini: expanded configuration with module-specific settings
- hookspecs.py: type annotations for hook functions
- plugins.py: typed get_plugins() return value
- recipes.py: full type annotations for parsedate, parsedatetime, jsonsplit
- utils.py: extensive type annotations including Row type alias,
  TypeTracker, ValueTracker, and all utility functions
- db.py: type annotations for Database methods (__exit__,
  ensure_autocommit_off, tracer, register_function, etc.) and
  Queryable class methods
- tests/test_docs.py: updated to match new signature display format

* Fix type errors caught by ty check

- Add type: ignore comments for external library type stub limitations
  (csv.reader, click.progressbar, IOBase.name, Callable.__name__)
- Change Iterable to Sequence for SQL where_args parameters
- Use db.table() instead of db[name] for proper Table return type
- Fix rebuild_fts return type from None to Table
- Update test_tracer to expect fewer queries (optimization side effect)

* Fix mypy type errors

- Add type: ignore comments for runtime-valid patterns mypy can't verify
- Fix new_column_types annotation to Dict[str, Set[type]]
- Add type: ignore for Default sentinel values passed to create_table

* mypy skip tests directory

* Fix CI: exclude typing imports from recipe docs, skip mypy on tests

- Add Callable and Optional to exclusion list in _generate_convert_help()
- Regenerate docs/cli-reference.rst with cog
- Add [mypy-tests.*] ignore_errors = True to skip test type errors

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 22:11:47 -08:00
Simon Willison
871038505b
Type fixes now enforced by ty
* Fix type warning for pipe.stdout possibly being None

Add conditional check before calling .read() on pipe.stdout since
Popen can return None for stdout.

* Use ctx.meta instead of dynamic attribute for database cleanup

Click's Context.meta dictionary is the proper way to store arbitrary
data on the context object, avoiding type checker warnings about
dynamic attribute assignment.

* Add assert for tables.callback before calling

Click's callback attribute is typed as Optional[Callable], so add
assert to satisfy type checker that it's not None.

* Fix type errors in cli.py and db.py

- Add type annotation for Database.conn to fix context manager errors
- Convert exception objects to str() when raising ClickException
- Handle None return from find_spatialite() with proper error message

* Fix remaining type errors in cli.py

- Add typing import and type annotations for dict kwargs
- Use db.table() instead of db[] for extract command
- Fix missing str() conversion for exception

* Fix type errors in db.py

- Add type annotation for Database.conn
- Add type: ignore for optional sqlite_dump import
- Update execute/query parameter types to Sequence|Dict for sqlite3 compatibility
- Use getattr for fn.__name__ access to handle callables without __name__
- Handle None return from find_spatialite() with OSError
- Fix pk_values assignment to use local variable

* Add type: ignore for optional pysqlite3 and sqlean imports

These are alternative sqlite3 implementations that may not be installed.

* Fix type errors in tests and plugins

- Add type: ignore for monkey-patching Database.__init__ in conftest
- Fix CLI test to pass string "2" instead of integer to Click invoke
- Add type: ignore for optional sqlean import
- Fix add_geometry_column test to use "XY" instead of integer 2
- Add type: ignore for click.Context as context manager
- Add type: ignore for enable_fts test that intentionally omits argument
- Add type: ignore for sys._called_from_test dynamic attribute
- Fix rows_from_file test type error for intentional wrong argument
- Handle None from pm.get_hookcallers in plugins.py

* Use db.table() instead of db[] for Table-specific operations

Changes db[table] to db.table(table) in CLI commands where we know
we're working with tables, not views. This resolves most of the
Table | View disambiguation type warnings since db.table() returns
Table directly rather than Table | View.

* Fix remaining type warnings in sqlite_utils package

- Add assert for sniff_buffer not being None
- Handle cursor.fetchone() potentially returning None
- Use db.table() for counts_table and index_foreign_keys
- Add type: ignore for cursor union type in raw mode

* Ran Black

* Run ty in CI

* ty check sqlite_utils

* Skip running ty on Windows

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 19:34:45 -08:00
Simon Willison
fd5b09f64b
Database as a context manager, fixed many pytest warnings
* Database can now work as a context manager
* Claude Code helped fix a ton of .close() warnings

https://gistpreview.github.io/?730f0c5dc38528a1dd0615f330bd5481

* New autouse fixture to help with test warnings

Refs https://github.com/simonw/sqlite-utils/issues/692#issuecomment-3644371889

* Fix all remaining resource warnings

https://gistpreview.github.io/?0bb8e869b82f6ff0db647de755182502

Closes #692
2025-12-11 16:56:12 -08:00
Simon Willison
5a7f522980
sqlite-utils convert can now use callable references, closes #686
This now works:

    echo '{"date": "13th January 2025"}' | sqlite-utils insert dates.db dates -
    sqlite-utils convert dates.db dates date r.parsedate
    sqlite-utils rows dates.db dates

Previously the command would have been:

    sqlite-utils convert dates.db dates date 'r.parsedate(value)'
2025-11-29 14:43:02 -08:00
Simon Willison
b7def00b8c More consistent indentation 2024-01-14 09:27:58 -08:00
Mike Coats
4b3c83cd9f Add spatialite arm64 linux path
Issue: #599
2023-11-03 17:31:49 -07:00
Simon Willison
f5c63088e1
Use sqlean if available in environment (#560)
Closes #559
Closes #235

Refs https://github.com/simonw/llm/issues/60

- Uses `sqlean` in place of `sqlite3` if `sqlean.py` is installed
- Uses `sqlite-dump` if available and `conn.iterdump()` does not exist
- New `with db.ensure_autocommit_off()` method for ensuring autocommit is off, used by `enable_wal()` and `disable_wal()`.
2023-06-25 16:25:51 -07:00
Simon Willison
dab23884ae Better error message if rows_from_file called with StringIO, closes #520
Refs #448
2023-05-08 15:08:02 -07:00
Chris Amico
8f9a729e8a
Add paths for homebrew on Apple silicon (#536) 2023-04-12 18:44:43 -07:00
Simon Willison
7ca497a8f5 repr improvements, refs #503 2022-10-25 13:14:41 -07:00
Simon Willison
34e75ed0dd sqlite_utils.utils.flatten() function, closes #500 2022-10-18 11:00:35 -07:00
Mischa Untaga
0b315d3fa8
progressbar for inserts/upserts of other file formats
* progressbar for inserts/upserts of other file formats, closes #485
* Pin to Python 3.10.6 for the moment as workaround for mypy error

Co-authored-by: Simon Willison <swillison@gmail.com>
2022-09-15 13:37:51 -07:00
Simon Willison
a46a5e3a9e Improved code compilation pattern, closes #472 2022-08-26 22:20:09 -07:00
Simon Willison
e10536c7f5 utils.chunks() is now a documented API, closes #451 2022-07-15 14:59:30 -07:00
Simon Willison
8a9fe6498f Applied Black, refs #445 2022-06-20 12:50:15 -07:00
Simon Willison
773f2b6b20 Documented TypeTracker, closes #445 2022-06-20 12:46:49 -07:00
Simon Willison
0cee77b176 Update test for renamed restkey, refs #440, #443 2022-06-14 14:14:20 -07:00
Simon Willison
ce670e2d44 Docs for rows_from_file
Closes #440, closes #443
2022-06-14 13:12:42 -07:00
Simon Willison
f142bb1212
flake8 fix, refs #440 2022-06-14 09:14:57 -07:00
Simon Willison
d9c715a2fc One more typing fix, refs #440 2022-06-14 09:07:57 -07:00
Simon Willison
19efee2746 mypy fixes, refs #440 2022-06-14 08:39:08 -07:00
Simon Willison
d379f430f8 rows_from_file(... ignore_extras: bool, restkey: str), refs #440 2022-06-14 08:14:02 -07:00
Simon Willison
26e6d2622c Use :param x: for docstring comments, refs #413 2022-03-11 09:39:17 -08:00
Simon Willison
931b1e1513 .insert(hash_id_columns=) parameter, closes #343 2022-03-01 16:00:51 -08:00
Simon Willison
482fcc0da7 Fix for flake8, refs #79 2022-02-03 22:13:17 -08:00
Simon Willison
0fe0f476a7 Fix for mypy error, closes #396
Should help tests pass for #395 and #79
2022-02-03 22:10:28 -08:00
Chris Amico
ee11274fcb
New spatialite helper methods, closes #79
- db.init_spatialite()
- table.add_geometry_column()
- table.create_spatial_index()

Co-authored-by: Simon Willison <swillison@gmail.com>
2022-02-03 21:55:09 -08:00
Simon Willison
22c8d10dd3 --convert function can now modify row in place, closes #371 2022-01-09 12:06:02 -08:00
Simon Willison
a8f9cc6f64 Add test for chunks(), refs #364 2022-01-08 13:16:52 -08:00
Simon Willison
2e4847e493 Implemented --convert for different things, renamed --all to --text 2022-01-05 22:24:53 -08:00
Simon Willison
500a35ad4d Also support def convert(value), closes #355
Plus added custom syntax error display
2021-12-10 16:49:28 -08:00
Simon Willison
60dea99ef7 --silent option for sqlite-utils insert-files, closes #301 2021-08-02 12:12:16 -07:00
Simon Willison
5ec6686153
sqlite-utils convert command and db[table].convert(...) method
Closes #251, closes #302.
2021-08-01 21:47:39 -07:00
Simon Willison
7b3fdf0fcd mypy annotations for rows_from_file(), run mypy in CI
Refs #289, #279
2021-06-22 11:04:32 -07:00
Simon Willison
dc94f4bb8c Don't detect types on JSON input to memory, closes #283 2021-06-19 07:52:44 -07:00
Simon Willison
ec5174ed40 Detect types for sqlite-utils memory CSV, opt out with --no-detect-types - closes #282 2021-06-18 21:37:56 -07:00
Simon Willison
fd9867d145 sqlite-utils insert --detect-types option, refs #282 2021-06-18 21:18:58 -07:00
Simon Willison
00e4bd5ff1 TSV and JSON support for sqlite-utils memory
Closes #281, closes #279, refs #272
2021-06-18 20:11:54 -07:00
Simon Willison
1e9eb875a6 Switch from codecs.getreader to io.TextIOWrapper, refs #230 2021-02-14 10:33:26 -08:00
Simon Willison
f99a236529
Progress bar for sqlite-utils insert command, closes #173 2020-10-27 11:16:02 -07:00
Simon Willison
bf4c6b7c82 find_spatialite() utility function, closes #135 2020-08-21 13:30:02 -07:00
Simon Willison
1a61a6d3d6 Ability to insert base64 binary data as JSON, closes #126 2020-07-26 20:59:34 -07:00
Simon Willison
b436bdb594 Fixed bug with null columns, closes #95 2020-03-23 13:31:06 -07:00
Simon Willison
1c745df923 Suggest column types ignores nulls, closes #94 2020-03-23 12:57:02 -07:00
Simon Willison
1125460497 Improved column type introspection, closes #92 2020-03-14 13:04:06 -07:00
Simon Willison
685e6a1bb3 Detect subclasses of dict/tuple/list, fixes #87 2020-02-15 18:20:39 -08:00