From 989e9753e3d23485aa1c0c96bd749f95aecfad94 Mon Sep 17 00:00:00 2001 From: tarsil Date: Wed, 22 Mar 2023 14:28:02 +0000 Subject: [PATCH] Add release-noted.md * Add docker-compose.yml for local development * Added Makefile for local automations --- CHANGELOG.md | 138 +------------------------------- Makefile | 36 +++++++++ databases/backends/asyncmy.py | 6 +- databases/backends/mysql.py | 4 +- databases/backends/postgres.py | 4 +- databases/backends/sqlite.py | 24 +++--- docker-compose.yml | 36 +++++++++ docs/release-notes.md | 140 +++++++++++++++++++++++++++++++++ mkdocs.yml | 21 ++--- scripts/clean | 6 ++ 10 files changed, 248 insertions(+), 167 deletions(-) create mode 100644 Makefile create mode 100644 docker-compose.yml create mode 100644 docs/release-notes.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fa26e30..1ac717ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,140 +1,4 @@ # Changelog -All notable changes to this project will be documented in this file. +[Visit](https://www.encode.io/databases/release-notes) to see the changelog. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - -## 0.8.0 (Mar 21, 2022) - -### Added - -- Support for SQLAlchemy 2.0+ -- Added internal support for psycopg dialect. - -### Changed - -- Removed support for python 3.7 in favour to 3.8. - - Python 3.7 support will end in June 2023 -- Removed support for `aiopg`. - - -## 0.7.0 (Dec 18th, 2022) - -### Fixed - -* Fixed breaking changes in SQLAlchemy cursor; supports `>=1.4.42,<1.5` (#513). -* Wrapped types in `typing.Optional` where applicable (#510). - -## 0.6.2 (Nov 7th, 2022) - -### Changed - -* Pinned SQLAlchemy `<=1.4.41` to avoid breaking changes (#520). - -## 0.6.1 (Aug 9th, 2022) - -### Fixed - -* Improve typing for `Transaction` (#493) -* Allow string indexing into Record (#501) - -## 0.6.0 (May 29th, 2022) - -* Dropped Python 3.6 support (#458) - -### Added - -* Add _mapping property to the result set interface (#447 ) -* Add contributing docs (#453 ) - -### Fixed - -* Fix query result named access (#448) -* Fix connections getting into a bad state when a task is cancelled (#457) -* Revert #328 parallel transactions (#472) -* Change extra installations to specific drivers (#436) - -## 0.5.4 (January 14th, 2022) - -### Added - -* Support for Unix domain in connections (#423) -* Added `asyncmy` MySQL driver (#382) - -### Fixed - -* Fix SQLite fetch queries with multiple parameters (#435) -* Changed `Record` type to `Sequence` (#408) - -## 0.5.3 (October 10th, 2021) - -### Added - -* Support `dialect+driver` for default database drivers like `postgresql+asyncpg` (#396) - -### Fixed - -* Documentation of low-level transaction (#390) - -## 0.5.2 (September 10th, 2021) - -### Fixed - -* Reset counter for failed connections (#385) -* Avoid dangling task-local connections after Database.disconnect() (#211) - -## 0.5.1 (September 2nd, 2021) - -### Added - -* Make database `connect` and `disconnect` calls idempotent (#379) - -### Fixed - -* Fix `in_` and `notin_` queries in SQLAlchemy 1.4 (#378) - -## 0.5.0 (August 26th, 2021) - -### Added -* Support SQLAlchemy 1.4 (#299) - -### Fixed - -* Fix concurrent transactions (#328) - -## 0.4.3 (March 26th, 2021) - -### Fixed - -* Pin SQLAlchemy to <1.4 (#314) - -## 0.4.2 (March 14th, 2021) - -### Fixed - -* Fix memory leak with asyncpg for SQLAlchemy generic functions (#273) - -## 0.4.1 (November 16th, 2020) - -### Fixed - -* Remove package dependency on the synchronous DB drivers (#256) - -## 0.4.0 (October 20th, 2020) - -### Added - -* Use backend native fetch_val() implementation when available (#132) -* Replace psycopg2-binary with psycopg2 (#204) -* Speed up PostgresConnection fetch() and iterate() (#193) -* Access asyncpg Record field by key on raw query (#207) -* Allow setting min_size and max_size in postgres DSN (#210) -* Add option pool_recycle in postgres DSN (#233) -* Allow extra transaction options (#242) - -### Fixed - -* Fix type hinting for sqlite backend (#227) -* Fix SQLAlchemy DDL statements (#226) -* Make fetch_val call fetch_one for type conversion (#246) -* Unquote username and password in DatabaseURL (#248) diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..f3f01d93 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +.DEFAULT_GOAL := help + +.PHONY: help +help: + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: clean +clean: clean_pyc ## Clean all PYC in the system + +.PHONY: clean_pyc +clean_pyc: ## Cleans all *.pyc in the system + find . -type f -name "*.pyc" -delete || true + +.PHONY: clean_pycache +clean_pycache: ## Removes the __pycaches__ + find . -type d -name "*__pycache__*" -delete + +.PHONY: serve-docs +serve-docs: ## Runs the local docs + mkdocs serve + +.PHONY: build-docs +build-docs: ## Runs the local docs + mkdocs build + +.PHONY: test +test: ## Runs the tests + pytest $(TESTONLY) --disable-pytest-warnings -s -vv && scripts/clean + +.PHONY: requirements +requirements: ## Install requirements for development + pip install -r requirements.txt + +ifndef VERBOSE +.SILENT: +endif diff --git a/databases/backends/asyncmy.py b/databases/backends/asyncmy.py index 14ebfed9..f224c7cc 100644 --- a/databases/backends/asyncmy.py +++ b/databases/backends/asyncmy.py @@ -157,7 +157,7 @@ async def fetch_one(self, query: ClauseElement) -> typing.Optional[RecordInterfa async def execute(self, query: ClauseElement) -> typing.Any: assert self._connection is not None, "Connection is not acquired" - query_str, args, results_map, context = self._compile(query) + query_str, args, _, _ = self._compile(query) async with self._connection.cursor() as cursor: try: await cursor.execute(query_str, args) @@ -172,9 +172,7 @@ async def execute_many(self, queries: typing.List[ClauseElement]) -> None: async with self._connection.cursor() as cursor: try: for single_query in queries: - single_query, args, results_map, context = self._compile( - single_query - ) + single_query, args, _, _ = self._compile(single_query) await cursor.execute(single_query, args) finally: await cursor.close() diff --git a/databases/backends/mysql.py b/databases/backends/mysql.py index 7526bfbf..d93b4a7f 100644 --- a/databases/backends/mysql.py +++ b/databases/backends/mysql.py @@ -154,7 +154,7 @@ async def fetch_one(self, query: ClauseElement) -> typing.Optional[RecordInterfa async def execute(self, query: ClauseElement) -> typing.Any: assert self._connection is not None, "Connection is not acquired" - query_str, args, results_map, context = self._compile(query) + query_str, args, _, _ = self._compile(query) cursor = await self._connection.cursor() try: await cursor.execute(query_str, args) @@ -169,7 +169,7 @@ async def execute_many(self, queries: typing.List[ClauseElement]) -> None: cursor = await self._connection.cursor() try: for single_query in queries: - single_query, args, results_map, context = self._compile(single_query) + single_query, args, _, _ = self._compile(single_query) await cursor.execute(single_query, args) finally: await cursor.close() diff --git a/databases/backends/postgres.py b/databases/backends/postgres.py index 549af68c..917d4e1f 100644 --- a/databases/backends/postgres.py +++ b/databases/backends/postgres.py @@ -136,7 +136,7 @@ async def fetch_val( async def execute(self, query: ClauseElement) -> typing.Any: assert self._connection is not None, "Connection is not acquired" - query_str, args, result_columns = self._compile(query) + query_str, args, _ = self._compile(query) return await self._connection.fetchval(query_str, *args) async def execute_many(self, queries: typing.List[ClauseElement]) -> None: @@ -145,7 +145,7 @@ async def execute_many(self, queries: typing.List[ClauseElement]) -> None: # loop through multiple executes here, which should all end up # using the same prepared statement. for single_query in queries: - single_query, args, result_columns = self._compile(single_query) + single_query, args, _ = self._compile(single_query) await self._connection.execute(single_query, *args) async def iterate( diff --git a/databases/backends/sqlite.py b/databases/backends/sqlite.py index e68bb005..f0732d6f 100644 --- a/databases/backends/sqlite.py +++ b/databases/backends/sqlite.py @@ -11,12 +11,7 @@ from databases.backends.common.records import Record, Row, create_column_maps from databases.core import LOG_EXTRA, DatabaseURL -from databases.interfaces import ( - ConnectionBackend, - DatabaseBackend, - Record, - TransactionBackend, -) +from databases.interfaces import ConnectionBackend, DatabaseBackend, TransactionBackend logger = logging.getLogger("databases") @@ -121,7 +116,7 @@ async def fetch_one(self, query: ClauseElement) -> typing.Optional[Record]: async def execute(self, query: ClauseElement) -> typing.Any: assert self._connection is not None, "Connection is not acquired" - query_str, args, context = self._compile(query) + query_str, args, result_columns, context = self._compile(query) async with self._connection.cursor() as cursor: await cursor.execute(query_str, args) if cursor.lastrowid == 0: @@ -163,13 +158,20 @@ def _compile(self, query: ClauseElement) -> typing.Tuple[str, list, tuple]: execution_context = self._dialect.execution_ctx_cls() execution_context.dialect = self._dialect + args = [] + result_map = None + if not isinstance(query, DDLElement): compiled_params = sorted(compiled.params.items()) - args = compiled.construct_params() - for key, val in args.items(): + params = compiled.construct_params() + for key in compiled.positiontup: + raw_val = params[key] if key in compiled._bind_processors: - args[key] = compiled._bind_processors[key](val) + val = compiled._bind_processors[key](raw_val) + else: + val = raw_val + args.append(val) execution_context.result_column_struct = ( compiled._result_columns, @@ -186,8 +188,6 @@ def _compile(self, query: ClauseElement) -> typing.Tuple[str, list, tuple]: result_map = compiled._result_columns else: - args = {} - result_map = None compiled_query = compiled.string query_message = compiled_query.replace(" \n", " ").replace("\n", " ") diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..07875051 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,36 @@ +version: "3.8" +services: + db: + restart: always + image: postgres:14 + environment: + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: "postgres" + POSTGRES_DB: "testsuite" + expose: + - "5432" + ports: + - "5432:5432" + + mysql: + restart: always + image: mysql:5.7 + environment: + MYSQL_USER: "mysql" + MYSQL_PASSWORD: "mysql" + MYSQL_DATABASE: "testsuite" + MYSQL_ROOT_PASSWORD: "password" + expose: + - "3306" + ports: + - "3306:3306" + command: --default-authentication-plugin=mysql_native_password + + redis: + restart: always + image: redis:latest + ports: + - "6379:6379" + expose: + - "6379" diff --git a/docs/release-notes.md b/docs/release-notes.md new file mode 100644 index 00000000..db75057a --- /dev/null +++ b/docs/release-notes.md @@ -0,0 +1,140 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## 0.8.0 (Mar 21, 2022) + +### Added + +- Support for SQLAlchemy 2.0+ +- Added internal support for the new psycopg dialect. + +### Changed + +- Removed support for python 3.7 in favour to 3.8. + - Python 3.7 support will end in June 2023 +- Removed support for `aiopg`. + + +## 0.7.0 (Dec 18th, 2022) + +### Fixed + +* Fixed breaking changes in SQLAlchemy cursor; supports `>=1.4.42,<1.5` (#513). +* Wrapped types in `typing.Optional` where applicable (#510). + +## 0.6.2 (Nov 7th, 2022) + +### Changed + +* Pinned SQLAlchemy `<=1.4.41` to avoid breaking changes (#520). + +## 0.6.1 (Aug 9th, 2022) + +### Fixed + +* Improve typing for `Transaction` (#493) +* Allow string indexing into Record (#501) + +## 0.6.0 (May 29th, 2022) + +* Dropped Python 3.6 support (#458) + +### Added + +* Add _mapping property to the result set interface (#447 ) +* Add contributing docs (#453 ) + +### Fixed + +* Fix query result named access (#448) +* Fix connections getting into a bad state when a task is cancelled (#457) +* Revert #328 parallel transactions (#472) +* Change extra installations to specific drivers (#436) + +## 0.5.4 (January 14th, 2022) + +### Added + +* Support for Unix domain in connections (#423) +* Added `asyncmy` MySQL driver (#382) + +### Fixed + +* Fix SQLite fetch queries with multiple parameters (#435) +* Changed `Record` type to `Sequence` (#408) + +## 0.5.3 (October 10th, 2021) + +### Added + +* Support `dialect+driver` for default database drivers like `postgresql+asyncpg` (#396) + +### Fixed + +* Documentation of low-level transaction (#390) + +## 0.5.2 (September 10th, 2021) + +### Fixed + +* Reset counter for failed connections (#385) +* Avoid dangling task-local connections after Database.disconnect() (#211) + +## 0.5.1 (September 2nd, 2021) + +### Added + +* Make database `connect` and `disconnect` calls idempotent (#379) + +### Fixed + +* Fix `in_` and `notin_` queries in SQLAlchemy 1.4 (#378) + +## 0.5.0 (August 26th, 2021) + +### Added +* Support SQLAlchemy 1.4 (#299) + +### Fixed + +* Fix concurrent transactions (#328) + +## 0.4.3 (March 26th, 2021) + +### Fixed + +* Pin SQLAlchemy to <1.4 (#314) + +## 0.4.2 (March 14th, 2021) + +### Fixed + +* Fix memory leak with asyncpg for SQLAlchemy generic functions (#273) + +## 0.4.1 (November 16th, 2020) + +### Fixed + +* Remove package dependency on the synchronous DB drivers (#256) + +## 0.4.0 (October 20th, 2020) + +### Added + +* Use backend native fetch_val() implementation when available (#132) +* Replace psycopg2-binary with psycopg2 (#204) +* Speed up PostgresConnection fetch() and iterate() (#193) +* Access asyncpg Record field by key on raw query (#207) +* Allow setting min_size and max_size in postgres DSN (#210) +* Add option pool_recycle in postgres DSN (#233) +* Allow extra transaction options (#242) + +### Fixed + +* Fix type hinting for sqlite backend (#227) +* Fix SQLAlchemy DDL statements (#226) +* Make fetch_val call fetch_one for type conversion (#246) +* Unquote username and password in DatabaseURL (#248) diff --git a/mkdocs.yml b/mkdocs.yml index 2dbabde8..4974412d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,21 +2,22 @@ site_name: Databases site_description: Async database support for Python. theme: - name: 'material' + name: "material" repo_name: encode/databases repo_url: https://github.com/encode/databases # edit_uri: "" nav: - - Introduction: 'index.md' - - Database Queries: 'database_queries.md' - - Connections & Transactions: 'connections_and_transactions.md' - - Tests & Migrations: 'tests_and_migrations.md' - - Contributing: 'contributing.md' + - Introduction: "index.md" + - Database Queries: "database_queries.md" + - Connections & Transactions: "connections_and_transactions.md" + - Tests & Migrations: "tests_and_migrations.md" + - Contributing: "contributing.md" + - Release Notes: "release-notes.md" markdown_extensions: - - mkautodoc - - admonition - - pymdownx.highlight - - pymdownx.superfences + - mkautodoc + - admonition + - pymdownx.highlight + - pymdownx.superfences diff --git a/scripts/clean b/scripts/clean index f01cc831..d7388629 100755 --- a/scripts/clean +++ b/scripts/clean @@ -9,6 +9,12 @@ fi if [ -d 'databases.egg-info' ] ; then rm -r databases.egg-info fi +if [ -d '.mypy_cache' ] ; then + rm -r .mypy_cache +fi +if [ -d '.pytest_cache' ] ; then + rm -r .pytest_cache +fi find databases -type f -name "*.py[co]" -delete find databases -type d -name __pycache__ -delete