{"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.29", "id": 75560168, "node_id": "RE_kwDOCGYnMM4EgPTo", "tag_name": "3.29", "target_commitish": "main", "name": "3.29", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2022-08-28T03:48:36Z", "published_at": "2022-08-28T03:50:29Z", "body": "- The `sqlite-utils query`, `memory` and `bulk` commands now all accept a new `--functions` option. This can be passed a string of Python code, and any callable objects defined in that code will be made available to SQL queries as custom SQL functions. See [Defining custom SQL functions](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-query-functions) for details. ([#471](https://github.com/simonw/sqlite-utils/issues/471))\r\n- `db[table].create(...)` method now accepts a new `transform=True` parameter. If the table already exists it will be transform to match the schema configuration options passed to the function. This may result in columns being added or dropped, column types being changed, column order being updated or not null and default values for columns being set. ([#467](https://github.com/simonw/sqlite-utils/issues/467))\r\n- Related to the above, the `sqlite-utils create-table` command now accepts a `--transform` option.\r\n- New introspection property: `table.default_values` returns a dictionary mapping each column name with a default value to the configured default value. ([#475](https://github.com/simonw/sqlite-utils/issues/475))\r\n- The `--load-extension` option can now be provided a path to a compiled SQLite extension module accompanied by the name of an entrypoint, separated by a colon - for example `--load-extension ./lines0:sqlite3_lines0_noread_init`. This feature is modelled on code first [contributed to Datasette](https://github.com/simonw/datasette/pull/1789) by Alex Garcia. ([#470](https://github.com/simonw/sqlite-utils/issues/470))\r\n- Functions registered using the [db.register_function()](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-register-function) method can now have a custom name specified using the new `db.register_function(fn, name=...)` parameter. ([#458](https://github.com/simonw/sqlite-utils/issues/458))\r\n- [sqlite-utils rows](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-rows) has a new `--order` option for specifying the sort order for the returned rows. ([#469](https://github.com/simonw/sqlite-utils/issues/469))\r\n- All of the CLI options that accept Python code blocks can now all be used to define functions that can access modules imported in that same block of code without needing to use the `global` keyword. ([#472](https://github.com/simonw/sqlite-utils/issues/472))\r\n- Fixed bug where `table.extract()` would not behave correctly for columns containing null values. Thanks, Forest Gregg. ([#423](https://github.com/simonw/sqlite-utils/issues/423))\r\n- New tutorial: [Cleaning data with sqlite-utils and Datasette](https://datasette.io/tutorials/clean-data) shows how to use `sqlite-utils` to import and clean an example CSV file.\r\n- Datasette and `sqlite-utils` now have a Discord community. [Join the Discord here](https://discord.gg/Ass7bCAMDw).", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/75560168/reactions\", \"total_count\": 1, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 1, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.26.1", "id": 65833874, "node_id": "RE_kwDOCGYnMM4D7IuS", "tag_name": "3.26.1", "target_commitish": "main", "name": "3.26.1", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2022-05-02T18:17:19Z", "published_at": "2022-05-02T18:18:01Z", "body": "- Now depends on [click-default-group-wheel](https://github.com/simonw/click-default-group-wheel), a pure Python wheel package. This means you can install and use this package with [Pyodide](https://pyodide.org/), which can run Python entirely in your browser using WebAssembly. ([#429](https://github.com/simonw/sqlite-utils/pull/429))\r\n\r\n Try that out using the [Pyodide REPL](https://pyodide.org/en/stable/console.html):\r\n\r\n ```pycon\r\n >>> import micropip\r\n >>> await micropip.install(\"sqlite-utils\")\r\n >>> import sqlite_utils\r\n >>> db = sqlite_utils.Database(memory=True)\r\n >>> list(db.query(\"select 3 * 5\"))\r\n [{'3 * 5': 15}]\r\n ```", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/65833874/reactions\", \"total_count\": 1, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 1, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.24", "id": 59656694, "node_id": "RE_kwDOCGYnMM4Djkn2", "tag_name": "3.24", "target_commitish": "main", "name": "3.24", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2022-02-16T01:39:13Z", "published_at": "2022-02-16T01:41:50Z", "body": "- SpatiaLite helpers for the `sqlite-utils` command-line tool - thanks, Chris Amico. ([#398](https://github.com/simonw/sqlite-utils/issues/398))\r\n - [sqlite-utils create-database](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-create-database) `--init-spatialite` option for initializing SpatiaLite on a newly created database.\r\n - [sqlite-utils add-geometry-column](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-spatialite) command for adding geometry columns.\r\n - [sqlite-utils create-spatial-index](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-spatialite-indexes) command for adding spatial indexes.\r\n- `db[table].create(..., if_not_exists=True)` option for [creating a table](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-explicit-create) only if it does not already exist. ([#397](https://github.com/simonw/sqlite-utils/issues/397))\r\n- `Database(memory_name=\"my_shared_database\")` parameter for creating a [named in-memory database](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-connect) that can be shared between multiple connections. ([#405](https://github.com/simonw/sqlite-utils/issues/405))\r\n- Documentation now describes [how to add a primary key to a rowid table](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-transform-table-add-primary-key-to-rowid) using `sqlite-utils transform`. ([#403](https://github.com/simonw/sqlite-utils/issues/403))", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/59656694/reactions\", \"total_count\": 2, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 1, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.18", "id": 53350811, "node_id": "RE_kwDOCGYnMM4DLhGb", "tag_name": "3.18", "target_commitish": "main", "name": "3.18", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2021-11-15T03:15:23Z", "published_at": "2021-11-15T03:17:31Z", "body": "- The `table.lookup()` method now has an optional second argument which can be used to populate columns only the first time the record is created, see [Working with lookup tables](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-lookup-tables). ([#339](https://github.com/simonw/sqlite-utils/issues/339))\r\n- `sqlite-utils memory` now has a `--flatten` option for [flattening nested JSON objects](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-inserting-data-flatten) into separate columns, consistent with `sqlite-utils insert`. ([#332](https://github.com/simonw/sqlite-utils/issues/332))\r\n- `table.create_index(..., find_unique_name=True)` parameter, which finds an available name for the created index even if the default name has already been taken. This means that `index-foreign-keys` will work even if one of the indexes it tries to create clashes with an existing index name. ([#335](https://github.com/simonw/sqlite-utils/issues/335))\r\n- Added `py.typed` to the module, so [mypy](http://mypy-lang.org/) should now correctly pick up the type annotations. Thanks, Andreas Longo. ([#331](https://github.com/simonw/sqlite-utils/issues/331))\r\n- Now depends on `python-dateutil` instead of depending on `dateutils`. Thanks, Denys Pavlov. ([#324](https://github.com/simonw/sqlite-utils/issues/324))\r\n- `table.create()` (see [Explicitly creating a table](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-explicit-create)) now handles `dict`, `list` and `tuple` types, mapping them to `TEXT` columns in SQLite so that they can be stored encoded as JSON. ([#338](https://github.com/simonw/sqlite-utils/issues/338))\r\n- Inserted data with square braces in the column names (for example a CSV file containing a `item[price]`) column now have the braces converted to underscores: `item_price_`. Previously such columns would be rejected with an error. ([#329](https://github.com/simonw/sqlite-utils/issues/329))\r\n- Now also tested against Python 3.10. ([#330](https://github.com/simonw/sqlite-utils/pull/330))", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/53350811/reactions\", \"total_count\": 1, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 1, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.17", "id": 48389722, "node_id": "MDc6UmVsZWFzZTQ4Mzg5NzIy", "tag_name": "3.17", "target_commitish": "main", "name": "3.17", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2021-08-24T23:40:18Z", "published_at": "2021-08-24T23:42:22Z", "body": "- The [sqlite-utils memory](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-memory) command has a new `--analyze` option, which runs the equivalent of the [analyze-tables](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-analyze-tables) command directly against the in-memory database created from the incoming CSV or JSON data. ([#320](https://github.com/simonw/sqlite-utils/issues/320))\r\n- [sqlite-utils insert-files](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-insert-files) now has the ability to insert file contents in to `TEXT` columns in addition to the default `BLOB`. Pass the `--text` option or use `content_text` as a column specifier. ([#319](https://github.com/simonw/sqlite-utils/issues/319))", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/48389722/reactions\", \"total_count\": 1, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 1, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.15.1", "id": 47636109, "node_id": "MDc6UmVsZWFzZTQ3NjM2MTA5", "tag_name": "3.15.1", "target_commitish": "main", "name": "3.15.1", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2021-08-10T23:55:12Z", "published_at": "2021-08-10T23:55:38Z", "body": "- Python library now includes type annotations on almost all of the methods, plus detailed docstrings describing each one. ([#311](https://github.com/simonw/sqlite-utils/issues/311))\r\n- New [API Reference](https://sqlite-utils.datasette.io/en/stable/reference.html) documentation page, powered by those docstrings.\r\n- Fixed bug where `.add_foreign_keys()` failed to raise an error if called against a `View`. ([#313](https://github.com/simonw/sqlite-utils/issues/313))\r\n- Fixed bug where `.delete_where()` returned a `[]` instead of returning `self` if called against a non-existant table. ([#315](https://github.com/simonw/sqlite-utils/issues/315))", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/47636109/reactions\", \"total_count\": 1, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 1, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.10", "id": 44904928, "node_id": "MDc6UmVsZWFzZTQ0OTA0OTI4", "tag_name": "3.10", "target_commitish": "main", "name": "3.10", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2021-06-19T16:09:29Z", "published_at": "2021-06-19T16:13:11Z", "body": "This release introduces the `sqlite-utils memory` command, which can be used to load CSV or JSON data into a temporary in-memory database and run SQL queries (including joins across multiple files) directly against that data.\r\n\r\nAlso new: `sqlite-utils insert --detect-types`, `sqlite-utils dump`, `table.use_rowid` plus some smaller fixes.\r\n\r\n### sqlite-utils memory\r\n\r\nThis example of `sqlite-utils memory` retrieves information about the all of the repositories in the [Dogsheep](https://github.com/dogsheep) organization on GitHub using [this JSON API](https://api.github.com/users/dogsheep/repos), sorts them by their number of stars and outputs a table of the top five (using `-t`):\r\n\r\n```\r\n$ curl -s 'https://api.github.com/users/dogsheep/repos'\\\r\n | sqlite-utils memory - '\r\n select full_name, forks_count, stargazers_count\r\n from stdin order by stargazers_count desc limit 5\r\n ' -t\r\nfull_name forks_count stargazers_count\r\n--------------------------------- ------------- ------------------\r\ndogsheep/twitter-to-sqlite 12 225\r\ndogsheep/github-to-sqlite 14 139\r\ndogsheep/dogsheep-photos 5 116\r\ndogsheep/dogsheep.github.io 7 90\r\ndogsheep/healthkit-to-sqlite 4 85\r\n```\r\n\r\nThe tool works against files on disk as well. This example joins data from two CSV files:\r\n\r\n```\r\n$ cat creatures.csv\r\nspecies_id,name\r\n1,Cleo\r\n2,Bants\r\n2,Dori\r\n2,Azi\r\n$ cat species.csv\r\nid,species_name\r\n1,Dog\r\n2,Chicken\r\n$ sqlite-utils memory species.csv creatures.csv '\r\n select * from creatures join species on creatures.species_id = species.id\r\n'\r\n[{\"species_id\": 1, \"name\": \"Cleo\", \"id\": 1, \"species_name\": \"Dog\"},\r\n {\"species_id\": 2, \"name\": \"Bants\", \"id\": 2, \"species_name\": \"Chicken\"},\r\n {\"species_id\": 2, \"name\": \"Dori\", \"id\": 2, \"species_name\": \"Chicken\"},\r\n {\"species_id\": 2, \"name\": \"Azi\", \"id\": 2, \"species_name\": \"Chicken\"}]\r\n```\r\n\r\nHere the `species.csv` file becomes the `species` table, the `creatures.csv` file becomes the `creatures` table and the output is JSON, the default output format.\r\n\r\nYou can also use the `--attach` option to attach existing SQLite database files to the in-memory database, in order to join data from CSV or JSON directly against your existing tables.\r\n\r\nFull documentation of this new feature is available in [Querying data directly using an in-memory database](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-memory). ([#272](https://github.com/simonw/sqlite-utils/issues/272))\r\n\r\n### sqlite-utils insert --detect-types\r\n\r\nThe [sqlite-utils insert](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-inserting-data) command can be used to insert data from JSON, CSV or TSV files into a SQLite database file. The new `--detect-types` option (shortcut `-d`), when used in conjunction with a CSV or TSV import, will automatically detect if columns in the file are integers or floating point numbers as opposed to treating everything as a text column and create the new table with the corresponding schema. See [Inserting CSV or TSV data](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-insert-csv-tsv) for details. ([#282](https://github.com/simonw/sqlite-utils/issues/282))\r\n\r\n### Other changes\r\n\r\n- **Bug fix**: `table.transform()`, when run against a table without explicit primary keys, would incorrectly create a new version of the table with an explicit primary key column called `rowid`. ([#284](https://github.com/simonw/sqlite-utils/issues/284))\r\n- New `table.use_rowid` introspection property, see [.use_rowid](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-introspection-use-rowid). ([#285](https://github.com/simonw/sqlite-utils/issues/285))\r\n- The new `sqlite-utils dump file.db` command outputs a SQL dump that can be used to recreate a database. ([#274](https://github.com/simonw/sqlite-utils/issues/274))\r\n- `-h` now works as a shortcut for `--help`, thanks Loren McIntyre. ([#276](https://github.com/simonw/sqlite-utils/issues/276))\r\n- Now using [pytest-cov](https://pytest-cov.readthedocs.io/) and [Codecov](https://about.codecov.io/) to track test coverage - currently at 96%. ([#275](https://github.com/simonw/sqlite-utils/issues/275))\r\n- SQL errors that occur when using `sqlite-utils query` are now displayed as CLI errors.", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/44904928/reactions\", \"total_count\": 3, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 1, \"eyes\": 1}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.9", "id": 44511190, "node_id": "MDc6UmVsZWFzZTQ0NTExMTkw", "tag_name": "3.9", "target_commitish": "main", "name": "3.9", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2021-06-12T02:07:18Z", "published_at": "2021-06-12T02:08:03Z", "body": "- New `sqlite-utils schema` command showing the full SQL schema for a database, see [Showing the schema (CLI)](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-schema). ([#268](https://github.com/simonw/sqlite-utils/issues/268))\r\n- `db.schema` introspection property exposing the same feature to the Python library, see [Showing the schema (Python library)](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-schema).", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/44511190/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.35", "id": 117703394, "node_id": "RE_kwDOCGYnMM4HBALi", "tag_name": "3.35", "target_commitish": "main", "name": "3.35", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2023-08-18T02:05:15Z", "published_at": "2023-08-18T02:05:22Z", "body": "Adding foreign keys to a table no longer uses `PRAGMA writable_schema = 1` to directly manipulate the `sqlite_master` table. This was resulting in errors in some Python installations where the SQLite library was compiled in a way that prevented this from working, in particular on macOS. Foreign keys are now added using the [table transformation](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-transform) mechanism instead. ([#577](https://github.com/simonw/sqlite-utils/issues/577))\r\n\r\nThis new mechanism creates a full copy of the table, so it is likely to be significantly slower for large tables, but will no longer trigger table `sqlite_master may not be modified` errors on platforms that do not support `PRAGMA writable_schema = 1`.\r\n\r\nA new plugin, [sqlite-utils-fast-fks](https://github.com/simonw/sqlite-utils-fast-fks), is now available for developers who still want to use that faster but riskier implementation.\r\n\r\nOther changes:\r\n\r\n- The [table.transform() method](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-transform) has two new parameters: `foreign_keys=` allows you to replace the foreign key constraints defined on a table, and `add_foreign_keys=` lets you specify new foreign keys to add. These complement the existing `drop_foreign_keys=` parameter. ([#577](https://github.com/simonw/sqlite-utils/issues/577))\r\n- The [sqlite-utils transform](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-transform-table) command has a new `--add-foreign-key` option which can be called multiple times to add foreign keys to a table that is being transformed. ([#585](https://github.com/simonw/sqlite-utils/issues/585))\r\n- [sqlite-utils convert](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-convert) now has a `--pdb` option for opening a debugger on the first encountered error in your conversion script. ([#581](https://github.com/simonw/sqlite-utils/issues/581))\r\n- Fixed a bug where `sqlite-utils install -e '.[test]'` option did not work correctly.", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/117703394/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.34", "id": 113203288, "node_id": "RE_kwDOCGYnMM4Gv1hY", "tag_name": "3.34", "target_commitish": "main", "name": "3.34", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2023-07-22T23:25:14Z", "published_at": "2023-07-22T23:30:49Z", "body": "This release introduces a new [plugin system](https://sqlite-utils.datasette.io/en/stable/plugins.html#plugins). ([#567](https://github.com/simonw/sqlite-utils/issues/567))\r\n\r\n- Documentation describing [how to build a plugin](https://sqlite-utils.datasette.io/en/stable/plugins.html#plugins-building).\r\n- Plugin hook: [register_commands(cli)](https://sqlite-utils.datasette.io/en/stable/plugins.html#plugins-hooks-register-commands), for plugins to add extra commands to `sqlite-utils`. ([#569](https://github.com/simonw/sqlite-utils/issues/569))\r\n- Plugin hook: [prepare_connection(conn)](https://sqlite-utils.datasette.io/en/stable/plugins.html#plugins-hooks-prepare-connection). Plugins can use this to help prepare the SQLite connection to do things like registering custom SQL functions. Thanks, [Alex Garcia](https://github.com/asg017). ([#574](https://github.com/simonw/sqlite-utils/issues/574))\r\n- `sqlite_utils.Database(..., execute_plugins=False)` option for disabling plugin execution. ([#575](https://github.com/simonw/sqlite-utils/issues/575))\r\n- `sqlite-utils install -e path-to-directory` option for installing editable code. This option is useful during the development of a plugin. ([#570](https://github.com/simonw/sqlite-utils/issues/570))\r\n- `table.create(...)` method now accepts `replace=True` to drop and replace an existing table with the same name, or `ignore=True` to silently do nothing if a table already exists with the same name. ([#568](https://github.com/simonw/sqlite-utils/issues/568))\r\n- `sqlite-utils insert ... --stop-after 10` option for stopping the insert after a specified number of records. Works for the `upsert` command as well. ([#561](https://github.com/simonw/sqlite-utils/issues/561))\r\n- The `--csv` and `--tsv` modes for `insert` now accept a `--empty-null` option, which cases empty strings in the CSV file to be stored as `null` in the database. ([#563](https://github.com/simonw/sqlite-utils/issues/563))\r\n- New `db.rename_table(table_name, new_name)` method for renaming tables. ([#565](https://github.com/simonw/sqlite-utils/issues/565))\r\n- `sqlite-utils rename-table my.db table_name new_name` command for renaming tables. ([#565](https://github.com/simonw/sqlite-utils/issues/565))\r\n- The `table.transform(...)` method now takes an optional `keep_table=new_table_name` parameter, which will cause the original table to be renamed to `new_table_name` rather than being dropped at the end of the transformation. ([#571](https://github.com/simonw/sqlite-utils/issues/571))\r\n- Documentation now notes that calling `table.transform()` without any arguments will reformat the SQL schema stored by SQLite to be more aesthetically pleasing. ([#564](https://github.com/simonw/sqlite-utils/issues/564))", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/113203288/reactions\", \"total_count\": 2, \"+1\": 2, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.33", "id": 109839649, "node_id": "RE_kwDOCGYnMM4GjAUh", "tag_name": "3.33", "target_commitish": "main", "name": "3.33", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2023-06-26T01:31:22Z", "published_at": "2023-06-26T01:32:30Z", "body": "- `sqlite-utils` will now use [sqlean.py](https://github.com/nalgeon/sqlean.py) in place of `sqlite3` if it is installed in the same virtual environment. This is useful for Python environments with either an outdated version of SQLite or with restrictions on SQLite such as disabled extension loading or restrictions resulting in the `sqlite3.OperationalError: table sqlite_master may not be modified` error. ([#559](https://github.com/simonw/sqlite-utils/issues/559))\r\n- New `with db.ensure_autocommit_off()` context manager, which ensures that the database is in autocommit mode for the duration of a block of code. This is used by `db.enable_wal()` and `db.disable_wal()` to ensure they work correctly with `pysqlite3` and `sqlean.py`.\r\n- New `db.iterdump()` method, providing an iterator over SQL strings representing a dump of the database. This uses `sqlite-dump` if it is available, otherwise falling back on the `conn.iterdump()` method from `sqlite3`. Both `pysqlite3` and `sqlean.py` omit support for `iterdump()` - this method helps paper over that difference.", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/109839649/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.32.1", "id": 103740013, "node_id": "RE_kwDOCGYnMM4GLvJt", "tag_name": "3.32.1", "target_commitish": "main", "name": "3.32.1", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2023-05-21T21:11:54Z", "published_at": "2023-05-21T21:12:05Z", "body": "- Examples in the [CLI documentation](https://sqlite-utils.datasette.io/en/stable/cli.html) can now all be copied and pasted without needing to remove a leading `$`. ([#551](https://github.com/simonw/sqlite-utils/issues/551))\r\n- Documentation now covers [Setting up shell completion](https://sqlite-utils.datasette.io/en/stable//installation.html#installation-completion) for `bash` and `zsh`. ([#552](https://github.com/simonw/sqlite-utils/issues/552))", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/103740013/reactions\", \"total_count\": 3, \"+1\": 3, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.32", "id": 103736235, "node_id": "RE_kwDOCGYnMM4GLuOr", "tag_name": "3.32", "target_commitish": "main", "name": "3.32", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2023-05-21T18:53:44Z", "published_at": "2023-05-21T18:55:42Z", "body": "- New experimental `sqlite-utils tui` interface for interactively building command-line invocations, powered by [Trogon](https://github.com/Textualize/trogon). This requires an optional dependency, installed using `sqlite-utils install trogon`. There is a screenshot [in the documentation](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-tui). ([#545](https://github.com/simonw/sqlite-utils/issues/545))\r\n- `sqlite-utils analyze-tables` command ([documentation](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-analyze-tables)) now has a `--common-limit 20` option for changing the number of common/least-common values shown for each column. ([#544](https://github.com/simonw/sqlite-utils/issues/544))\r\n- `sqlite-utils analyze-tables --no-most` and `--no-least` options for disabling calculation of most-common and least-common values.\r\n- If a column contains only `null` values, `analyze-tables` will no longer attempt to calculate the most common and least common values for that column. ([#547](https://github.com/simonw/sqlite-utils/issues/547))\r\n- Calling `sqlite-utils analyze-tables` with non-existent columns in the `-c/--column` option now results in an error message. ([#548](https://github.com/simonw/sqlite-utils/issues/548))\r\n- The `table.analyze_column()` method ([documented here](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-analyze-column)) now accepts `most_common=False` and `least_common=False` options for disabling calculation of those values.", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/103736235/reactions\", \"total_count\": 3, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 3, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/sqlite-utils/releases/tag/3.31", "id": 102274005, "node_id": "RE_kwDOCGYnMM4GGJPV", "tag_name": "3.31", "target_commitish": "main", "name": "3.31", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2023-05-08T22:33:57Z", "published_at": "2023-05-08T22:37:24Z", "body": "- Dropped support for Python 3.6. Tests now ensure compatibility with Python 3.11. ([#517](https://github.com/simonw/sqlite-utils/issues/517))\r\n- Automatically locates the SpatiaLite extension on Apple Silicon. Thanks, Chris Amico. ([#536](https://github.com/simonw/sqlite-utils/pull/536))\r\n- New `--raw-lines` option for the `sqlite-utils query` and `sqlite-utils memory` commands, which outputs just the raw value of the first column of evy row. ([#539](https://github.com/simonw/sqlite-utils/issues/539))\r\n- Fixed a bug where `table.upsert_all()` failed if the `not_null=` option was passed. ([#538](https://github.com/simonw/sqlite-utils/issues/538))\r\n- Fixed a `ResourceWarning` when using `sqlite-utils insert`. ([#534](https://github.com/simonw/sqlite-utils/issues/534))\r\n- Now shows a more detailed error message when `sqlite-utils insert` is called with invalid JSON. ([#532](https://github.com/simonw/sqlite-utils/ises/532))\r\n- `table.convert(..., skip_false=False)` and `sqlite-utils convert --no-skip-false` options, for avoiding a misfeature where the [convert()](http://127.0.0.1:8000/python-api.html#python-api-convert) mechanism skips rows in the database with a falsey value for the specified column. Fixing this by default would be a backwards-incompatible change and is under consideration for a 4.0 release in the future. ([#527](https://github.com/simonw/sqlite-utils/issues/527))\r\n- Tables can now be created with self-referential foreign keys. Thanks, Scott Perry. ([#537](https://github.com/simonw/sqlite-utils/pull/537))\r\n- `sqlite-utils transform` no longer breaks if a table defines default values for columns. Thanks, Kenny Song. ([#509](https://github.com/simonw/sqlite-utils/issues/509))\r\n- Fixed a bug where repeated calls to `table.transform()` did not work correctly. Thanks, Martin Carpenter. ([#525](https://github.com/simonw/sqlite-utils/issues/525))\r\n- Improved error message if `rows_from_file()` is passed a non-binary-mode file-like object. ([#520](https://github.com/simonw/sqlite-utils/issues/520))", "repo": {"value": 140912432, "label": "sqlite-utils"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/sqlite-utils/releases/102274005/reactions\", \"total_count\": 3, \"+1\": 3, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/datasette/releases/tag/0.64.2", "id": 94985654, "node_id": "RE_kwDOBm6k_c4FqV22", "tag_name": "0.64.2", "target_commitish": "0.64.x", "name": "0.64.2", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2023-03-08T20:41:13Z", "published_at": "2023-03-08T20:46:27Z", "body": "- Fixed a bug with `datasette publish cloudrun` where deploys all used the same Docker image tag. This was mostly inconsequential as the service is deployed as soon as the image has been pushed to the registry, but could result in the incorrect image being deployed if two different deploys for two separate services ran at exactly the same time. [#2036](https://github.com/simonw/datasette/issues/2036)\r\n", "repo": {"value": 107914493, "label": "datasette"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/releases/94985654/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/datasette/releases/tag/1.0a0", "id": 84496148, "node_id": "RE_kwDOBm6k_c4FCU8U", "tag_name": "1.0a0", "target_commitish": "main", "name": "1.0a0", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 1, "created_at": "2022-11-29T19:57:54Z", "published_at": "2022-11-29T19:58:55Z", "body": "This first alpha release of Datasette 1.0 introduces a brand new collection of APIs for writing to the database ([#1850](https://github.com/simonw/datasette/issues/1850)), as well as a new API token mechanism baked into Datasette core. Previously, API tokens have only been supported by installing additional plugins.\r\n\r\nThis is very much a preview: expect many more backwards incompatible API changes prior to the full 1.0 release.\r\n\r\nFeedback enthusiastically welcomed, either through [issue comments](https://github.com/simonw/datasette/issues/1850) or via the [Datasette Discord](https://datasette.io/discord) community.\r\n\r\n### Signed API tokens\r\n\r\n- New `/-/create-token` page allowing authenticated users to create signed API tokens that can act on their behalf, see [API Tokens](https://docs.datasette.io/en/1.0-dev/authentication.html#createtokenview). ([#1852](https://github.com/simonw/datasette/issues/1852))\r\n- New `datasette create-token` command for creating tokens from the command line: [datasette create-token](https://docs.datasette.io/en/1.0-dev/authentication.html#authentication-cli-create-token).\r\n- New [allow_signed_tokens](https://docs.datasette.io/en/1.0-dev/settings.html#setting-allow-signed-tokens) setting which can be used to turn off signed token support. ([#1856](https://github.com/simonw/datasette/issues/1856))\r\n- New [max_signed_tokens_ttl](https://docs.datasette.io/en/1.0-dev/settings.html#setting-max-signed-tokens-ttl) setting for restricting the maximum allowed duration of a signed token. ([#1858](https://github.com/simonw/datasette/issues/1858))\r\n\r\n### Write API\r\n\r\n- New API explorer at `/-/api` for trying out the API. ([#1871](https://github.com/simonw/datasette/issues/1871))\r\n- `/db/-/create` API for [Creating a table](https://docs.datasette.io/en/1.0-dev/json_api.html#tablecreateview). ([#1882](https://github.com/simonw/datasette/issues/1882))\r\n- `/db/table/-/insert` API for [Inserting rows](https://docs.datasette.io/en/1.0-dev/json_api.html#tableinsertview). ([#1851](https://github.com/simonw/datasette/issues/1851))\r\n- `/db/table/-/drop` API for [Dropping tables](https://docs.datasette.io/en/1.0-dev/json_api.html#tabledropview). ([#1874](https://github.com/simonw/datasette/issues/1874))\r\n- `/db/table/pk/-/update` API for [Updating a row](https://docs.datasette.io/en/1.0-dev/json_api.html#rowupdateview). ([#1863](https://github.com/simonw/datasette/issues/1863))\r\n- `/db/table/pk/-/delete` API for [Deleting a row](https://docs.datasette.io/en/1.0-dev/json_api.html#rowdeleteview). ([#1864](https://github.com/simonw/datasette/issues/1864))", "repo": {"value": 107914493, "label": "datasette"}, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/releases/84496148/reactions\", \"total_count\": 2, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 2, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}"} {"html_url": "https://github.com/simonw/datasette/releases/tag/0.63.1", "id": 82765509, "node_id": "RE_kwDOBm6k_c4E7ubF", "tag_name": "0.63.1", "target_commitish": "main", "name": "0.63.1", "draft": 0, "author": {"value": 9599, "label": "simonw"}, "prerelease": 0, "created_at": "2022-11-11T07:01:20Z", "published_at": "2022-11-11T07:02:36Z", "body": "- Fixed a bug where Datasette's table filter form would not redirect correctly when run behind a proxy using the [base_url](https://docs.datasette.io/en/stable/settings.html#setting-base-url) setting. ([#1883](https://github.com/simonw/datasette/issues/1883))\r\n- SQL query is now shown wrapped in a `