{"id":19188324,"url":"https://github.com/zx80/anodb","last_synced_at":"2026-01-04T21:12:59.365Z","repository":{"id":43362880,"uuid":"282900237","full_name":"zx80/anodb","owner":"zx80","description":"Convenient Wrapper around aiosql and a Database Connection.","archived":false,"fork":false,"pushed_at":"2024-11-10T15:58:34.000Z","size":256,"stargazers_count":22,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-11T18:43:23.307Z","etag":null,"topics":["aiosql","database","python","sql"],"latest_commit_sha":null,"homepage":"https://zx80.github.io/anodb/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zx80.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-27T13:04:50.000Z","updated_at":"2024-11-10T15:58:38.000Z","dependencies_parsed_at":"2023-11-18T19:24:05.963Z","dependency_job_id":"a270d411-b891-4519-867a-c11b7334c1a4","html_url":"https://github.com/zx80/anodb","commit_stats":{"total_commits":186,"total_committers":2,"mean_commits":93.0,"dds":0.005376344086021501,"last_synced_commit":"6f0f3f3fac50b28d4298131573e43163d13f8b33"},"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zx80%2Fanodb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zx80%2Fanodb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zx80%2Fanodb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zx80%2Fanodb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zx80","download_url":"https://codeload.github.com/zx80/anodb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230085286,"owners_count":18170423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiosql","database","python","sql"],"created_at":"2024-11-09T11:24:23.148Z","updated_at":"2026-01-04T21:12:59.252Z","avatar_url":"https://github.com/zx80.png","language":"Python","readme":"# AnoDB\n\nConvenient Wrapper around [aiosql](https://github.com/nackjicholson/aiosql)\nand a [Database Connection](https://www.python.org/dev/peps/pep-0249).\n\n![Status](https://github.com/zx80/anodb/actions/workflows/anodb-package.yml/badge.svg?branch=main\u0026style=flat)\n![Tests](https://img.shields.io/badge/tests-16%20✓-success)\n![Coverage](https://img.shields.io/badge/coverage-100%25-success)\n![Python](https://img.shields.io/badge/python-3-informational)\n![Databases](https://img.shields.io/badge/databases-6-informational)\n![Drivers](https://img.shields.io/badge/drivers-15-informational)\n![Version](https://img.shields.io/pypi/v/anodb)\n![Badges](https://img.shields.io/badge/badges-9-informational)\n![License](https://img.shields.io/pypi/l/anodb?style=flat)\n\n## Description\n\nThis class creates a persistent database connection and imports\nSQL queries from a file as simple Python functions.\n\nIf the connection is broken, a new connection is attempted with increasing\nthrottling delays.\n\nCompared to `aiosql`, the point is not to need to pass a connection\nas an argument on each call: The `DB` class embeds both connection\n*and* query methods.\n\nFor concurrent programming (threads, greenlets…), a relevant setup\nshould also consider thread-locals and pooling issues at some higher level.\n\n## Example\n\nInstall the module with `pip install anodb` or whatever method you like.\nOnce available:\n\n```python\nimport anodb\n\n# parameters: driver, connection string, SQL file\ndb = anodb.DB(\"sqlite3\", \"test.db\", \"test.sql\")\n\ndb.create_stuff()                       # table created\ndb.add_stuff(key=1, val=\"hello\")        # 1 row added\ndb.change_stuff(key=1, val=\"world\")     # 1 row changed\nprint(\"data\", db.get_stuff(key=1))      # (1, \"world\")\nprint(\"norm\", db.compute_norm(c=3+4j))  # 5.0\n\nfor key, val in db.get_all_stuff():\n    print(f\"{key}: {val}\")\n\ndb.commit()\ndb.close()\n```\n\nWith file `test.sql` to define parametric queries such as:\n\n```sql\n-- name: create_stuff#\nCREATE TABLE Stuff(key INTEGER PRIMARY KEY, val TEXT NOT NULL);\n\n-- name: add_stuff(key, val)!\nINSERT INTO Stuff(key, val) VALUES (:key, :val);\n\n-- name: change_stuff(key, val)!\nUPDATE Stuff SET val = :val WHERE key = :key;\n\n-- name: get_stuff(key)^\nSELECT * FROM Stuff WHERE key = :key;\n\n-- name: compute-norm(c)$\nSELECT SQRT(:c.real * :c.real + :c.imag * :c.imag);\n\n-- name: get_all_stuff()\nSELECT * FROM Stuff ORDER BY 1;\n```\n\n## Documentation\n\nThe `anodb` module provides the `DB` class which embeds both a\n[PEP 249](https://peps.python.org/pep-0249/) database connection\n(providing methods `commit`, `rollback`, `cursor`, `close` and\nits `connect` counterpart to re-connect) *and* SQL queries wrapped\ninto dynamically generated functions by\n[aiosql](https://pypi.org/project/aiosql/).\nSuch functions may be loaded from a string (`add_queries_from_str`) or a\npath (`add_queries_from_path`).\n\nThe `DB` constructor main parameters are:\n\n- `db` the name of the database driver: `sqlite3`, `psycopg`, `pymysql`, see\n  [aiosql documentation](https://nackjicholson.github.io/aiosql/database-driver-adapters.html)\n  for a list of supported drivers.\n- `conn` an optional connection string used to initiate a connection with the driver.\n  For instance, `psycopg` accepts a\n  [libpq connection string](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING)\n  such as: `\"host=db1.my.org port=5432 dbname=acme user=calvin …\"`.\n- `queries` a path name or list of path names from which to read query definitions.\n- `conn_args` and `conn_kwargs` a list and dictionary of further connection parameters.\n- `auto_reconnect` whether to attempt a reconnection if the connection is lost.\n  Default is _True_. Reconnection attempts are throttled exponentially\n  following powers of two delays from _0.001_ and capped at _30.0_ seconds.\n- `auto_rollback` whether to rollback internaly on query errors, before re-raising them.\n  Default is _True_.\n- `kwargs_only` whether to only accept named parameters to python functions.\n  This helps avoiding silly bugs!\n  Default is _True_.\n- `debug` whether to generate debugging messages through `logging`.\n  Default is _False_.\n- `cacher` factory to wrap functions for caching `SELECT` queries designated\n  as such because `CACHED` appears in their doctring.\n  The cacher is passed the query name and underlying function, and must\n  return the wrapped function.\n  See `test_cache` in the non regression tests for a simple example with\n  [`CacheToolsUtils`](https://pypi.org/project/CacheToolsUtils/).\n- other named parameters are passed as additional connection parameters.\n  For instance you might consider using `autocommit=True` with `psycopg`.\n\n```python\nimport anodb\n\ndb = anodb.DB(\"sqlite3\", \"acme.db\", \"acme-queries.sql\")\ndb = anodb.DB(\"duckdb\", \"acme.db\", \"acme-queries.sql\")\ndb = anodb.DB(\"psycopg\", \"host=localhost dbname=acme\", \"acme-queries.sql\", autocommit=True)\ndb = anodb.DB(\"psycopg\", None, \"acme-queries.sql\", host=\"localhost\", user=\"calvin\", password=\"...\", dbname=\"acme\")\ndb = anodb.DB(\"psycopg2\", \"host=localhost dbname=acme\", \"acme-queries.sql\")\ndb = anodb.DB(\"pygresql\", None, \"acme-queries.sql\", host=\"localhost:5432\", user=\"calvin\", password=\"...\", database=\"acme\")\ndb = anodb.DB(\"pg8000\", None, \"acme-queries.sql\", host=\"localhost\", port=5432, user=\"calvin\", password=\"...\", database=\"acme\")\ndb = anodb.DB(\"MySQLdb\", None, \"acme-queries.sql\", host=\"localhost\", port=3306, user=\"calvin\", password=\"...\", database=\"acme\")\ndb = anodb.DB(\"pymysql\", None, \"acme-queries.sql\", host=\"localhost\", port=3306, user=\"calvin\", password=\"...\", database=\"acme\")\ndb = anodb.DB(\"mysql-connector\", None, \"acme-queries.sql\", host=\"localhost\", port=3306, user=\"calvin\", password=\"...\", database=\"acme\")\ndb = anodb.DB(\"mariadb\", None, \"acme-queries.sql\", host=\"localhost\", port=3306, user=\"calvin\", password=\"...\", database=\"acme\")\ndb = anodb.DB(\"pymssql\", None, \"acme-queries.sql\", server=\"localhost\", port=1433, user=\"sa\", password=\"...\", database=\"acme\", as_dict=True, autocommit=False)\n```\n\nSee DB docstring for knowing about all parameters.\n\n## License\n\nThis code is [Public Domain](https://creativecommons.org/publicdomain/zero/1.0/).\n\nAll software has bug, this is software, hence… Beware that you may lose your\nhairs or your friends because of it. If you like it, feel free to send a\npostcard to the author.\n\n## Versions\n\n[Sources](https://github.com/zx80/anodb),\n[documentation](https://zx80.github.io/anodb/) and\n[issues](https://github.com/zx80/anodb/issues)\nare available on [GitHub](https://github.com/).\n\nSee [all versions](VERSIONS.md) and\nget [packages](https://pypi.org/project/anodb/) from [PyPI](https://pypi.org/).\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzx80%2Fanodb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzx80%2Fanodb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzx80%2Fanodb/lists"}