Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-databases for
openSUSE:Factory checked in at 2021-06-01 10:37:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-databases (Old)
and /work/SRC/openSUSE:Factory/.python-databases.new.1898 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-databases"
Tue Jun 1 10:37:03 2021 rev:4 rq:895539 version:0.4.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-databases/python-databases.changes
2021-04-15 16:58:19.318760186 +0200
+++
/work/SRC/openSUSE:Factory/.python-databases.new.1898/python-databases.changes
2021-06-01 10:38:02.764872737 +0200
@@ -1,0 +2,5 @@
+Wed May 26 12:10:35 UTC 2021 - Matej Cepl <[email protected]>
+
+- Add sqlalchemy-14.patch upgrading used API of SQLAlchemy to 1.4.
+
+-------------------------------------------------------------------
New:
----
sqlalchemy-14.patch
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-databases.spec ++++++
--- /var/tmp/diff_new_pack.wZZMw2/_old 2021-06-01 10:38:03.288873629 +0200
+++ /var/tmp/diff_new_pack.wZZMw2/_new 2021-06-01 10:38:03.292873636 +0200
@@ -25,6 +25,9 @@
License: BSD-3-Clause
URL: https://github.com/encode/databases
Source:
https://github.com/encode/databases/archive/%{version}.tar.gz#/databases-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM sqlalchemy-14.patch gh#encode/databases#299 [email protected]
+# Upgrade used API of SQLAlchemy to 1.4
+Patch0: sqlalchemy-14.patch
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
@@ -50,7 +53,8 @@
Async database support for Python.
%prep
-%setup -q -n databases-%{version}
+%autosetup -p1 -n databases-%{version}
+
# tests/test_integration.py depends on starlette
rm tests/test_integration.py
++++++ sqlalchemy-14.patch ++++++
>From 9d6e0c024833bd41421f0798a94ef2bbf27a31d5 Mon Sep 17 00:00:00 2001
From: PrettyWood <[email protected]>
Date: Mon, 15 Mar 2021 22:33:21 +0100
Subject: [PATCH 1/2] build(deps): switch to sqlalchemy 1.4
---
databases/backends/aiopg.py | 35 ++++++++++++++++++++------
databases/backends/mysql.py | 35 ++++++++++++++++++++------
databases/backends/postgres.py | 23 ++++++++++++++++-
databases/backends/sqlite.py | 35 ++++++++++++++++++++------
databases/core.py | 2 -
requirements.txt | 2 -
setup.py | 2 -
tests/test_database_url.py | 4 ++
tests/test_databases.py | 55 ++++++++++++++++++++++++++++++++++++++---
9 files changed, 160 insertions(+), 33 deletions(-)
--- a/databases/backends/aiopg.py
+++ b/databases/backends/aiopg.py
@@ -7,11 +7,11 @@ import uuid
import aiopg
from aiopg.sa.engine import APGCompiler_psycopg2
from sqlalchemy.dialects.postgresql.psycopg2 import PGDialect_psycopg2
+from sqlalchemy.engine.cursor import CursorResultMetaData
from sqlalchemy.engine.interfaces import Dialect, ExecutionContext
-from sqlalchemy.engine.result import ResultMetaData, RowProxy
+from sqlalchemy.engine.result import Row
from sqlalchemy.sql import ClauseElement
from sqlalchemy.sql.ddl import DDLElement
-from sqlalchemy.types import TypeEngine
from databases.core import DatabaseURL
from databases.interfaces import ConnectionBackend, DatabaseBackend,
TransactionBackend
@@ -119,9 +119,15 @@ class AiopgConnection(ConnectionBackend)
try:
await cursor.execute(query, args)
rows = await cursor.fetchall()
- metadata = ResultMetaData(context, cursor.description)
+ metadata = CursorResultMetaData(context, cursor.description)
return [
- RowProxy(metadata, row, metadata._processors, metadata._keymap)
+ Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
for row in rows
]
finally:
@@ -136,8 +142,14 @@ class AiopgConnection(ConnectionBackend)
row = await cursor.fetchone()
if row is None:
return None
- metadata = ResultMetaData(context, cursor.description)
- return RowProxy(metadata, row, metadata._processors,
metadata._keymap)
+ metadata = CursorResultMetaData(context, cursor.description)
+ return Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
finally:
cursor.close()
@@ -169,9 +181,15 @@ class AiopgConnection(ConnectionBackend)
cursor = await self._connection.cursor()
try:
await cursor.execute(query, args)
- metadata = ResultMetaData(context, cursor.description)
+ metadata = CursorResultMetaData(context, cursor.description)
async for row in cursor:
- yield RowProxy(metadata, row, metadata._processors,
metadata._keymap)
+ yield Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
finally:
cursor.close()
@@ -196,6 +214,7 @@ class AiopgConnection(ConnectionBackend)
compiled._result_columns,
compiled._ordered_columns,
compiled._textual_ordered_columns,
+ compiled._loose_column_name_matching,
)
else:
args = {}
--- a/databases/backends/mysql.py
+++ b/databases/backends/mysql.py
@@ -5,11 +5,11 @@ import uuid
import aiomysql
from sqlalchemy.dialects.mysql import pymysql
+from sqlalchemy.engine.cursor import CursorResultMetaData
from sqlalchemy.engine.interfaces import Dialect, ExecutionContext
-from sqlalchemy.engine.result import ResultMetaData, RowProxy
+from sqlalchemy.engine.result import Row
from sqlalchemy.sql import ClauseElement
from sqlalchemy.sql.ddl import DDLElement
-from sqlalchemy.types import TypeEngine
from databases.core import LOG_EXTRA, DatabaseURL
from databases.interfaces import ConnectionBackend, DatabaseBackend,
TransactionBackend
@@ -107,9 +107,15 @@ class MySQLConnection(ConnectionBackend)
try:
await cursor.execute(query, args)
rows = await cursor.fetchall()
- metadata = ResultMetaData(context, cursor.description)
+ metadata = CursorResultMetaData(context, cursor.description)
return [
- RowProxy(metadata, row, metadata._processors, metadata._keymap)
+ Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
for row in rows
]
finally:
@@ -124,8 +130,14 @@ class MySQLConnection(ConnectionBackend)
row = await cursor.fetchone()
if row is None:
return None
- metadata = ResultMetaData(context, cursor.description)
- return RowProxy(metadata, row, metadata._processors,
metadata._keymap)
+ metadata = CursorResultMetaData(context, cursor.description)
+ return Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
finally:
await cursor.close()
@@ -159,9 +171,15 @@ class MySQLConnection(ConnectionBackend)
cursor = await self._connection.cursor()
try:
await cursor.execute(query, args)
- metadata = ResultMetaData(context, cursor.description)
+ metadata = CursorResultMetaData(context, cursor.description)
async for row in cursor:
- yield RowProxy(metadata, row, metadata._processors,
metadata._keymap)
+ yield Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
finally:
await cursor.close()
@@ -186,6 +204,7 @@ class MySQLConnection(ConnectionBackend)
compiled._result_columns,
compiled._ordered_columns,
compiled._textual_ordered_columns,
+ compiled._loose_column_name_matching,
)
else:
args = {}
--- a/databases/backends/postgres.py
+++ b/databases/backends/postgres.py
@@ -104,8 +104,29 @@ class Record(Mapping):
self._dialect = dialect
self._column_map, self._column_map_int, self._column_map_full =
column_maps
+ @property
+ def _mapping(self) -> asyncpg.Record:
+ return self._row
+
+ def keys(self) -> typing.KeysView:
+ import warnings
+
+ warnings.warn(
+ "The `Row.keys()` method is deprecated to mimic SQLAlchemy
behaviour, "
+ "use `Row._mapping.keys()` instead.",
+ DeprecationWarning,
+ )
+ return self._mapping.keys()
+
def values(self) -> typing.ValuesView:
- return self._row.values()
+ import warnings
+
+ warnings.warn(
+ "The `Row.values()` method is deprecated to mimic SQLAlchemy
behaviour, "
+ "use `Row._mapping.values()` instead.",
+ DeprecationWarning,
+ )
+ return self._mapping.values()
def __getitem__(self, key: typing.Any) -> typing.Any:
if len(self._column_map) == 0: # raw query
--- a/databases/backends/sqlite.py
+++ b/databases/backends/sqlite.py
@@ -4,11 +4,11 @@ import uuid
import aiosqlite
from sqlalchemy.dialects.sqlite import pysqlite
+from sqlalchemy.engine.cursor import CursorResultMetaData
from sqlalchemy.engine.interfaces import Dialect, ExecutionContext
-from sqlalchemy.engine.result import ResultMetaData, RowProxy
+from sqlalchemy.engine.result import Row
from sqlalchemy.sql import ClauseElement
from sqlalchemy.sql.ddl import DDLElement
-from sqlalchemy.types import TypeEngine
from databases.core import LOG_EXTRA, DatabaseURL
from databases.interfaces import ConnectionBackend, DatabaseBackend,
TransactionBackend
@@ -92,9 +92,15 @@ class SQLiteConnection(ConnectionBackend
async with self._connection.execute(query, args) as cursor:
rows = await cursor.fetchall()
- metadata = ResultMetaData(context, cursor.description)
+ metadata = CursorResultMetaData(context, cursor.description)
return [
- RowProxy(metadata, row, metadata._processors, metadata._keymap)
+ Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
for row in rows
]
@@ -106,8 +112,14 @@ class SQLiteConnection(ConnectionBackend
row = await cursor.fetchone()
if row is None:
return None
- metadata = ResultMetaData(context, cursor.description)
- return RowProxy(metadata, row, metadata._processors,
metadata._keymap)
+ metadata = CursorResultMetaData(context, cursor.description)
+ return Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
async def execute(self, query: ClauseElement) -> typing.Any:
assert self._connection is not None, "Connection is not acquired"
@@ -129,9 +141,15 @@ class SQLiteConnection(ConnectionBackend
assert self._connection is not None, "Connection is not acquired"
query, args, context = self._compile(query)
async with self._connection.execute(query, args) as cursor:
- metadata = ResultMetaData(context, cursor.description)
+ metadata = CursorResultMetaData(context, cursor.description)
async for row in cursor:
- yield RowProxy(metadata, row, metadata._processors,
metadata._keymap)
+ yield Row(
+ metadata,
+ metadata._processors,
+ metadata._keymap,
+ Row._default_key_style,
+ row,
+ )
def transaction(self) -> TransactionBackend:
return SQLiteTransaction(self)
@@ -158,6 +176,7 @@ class SQLiteConnection(ConnectionBackend
compiled._result_columns,
compiled._ordered_columns,
compiled._textual_ordered_columns,
+ compiled._loose_column_name_matching,
)
query_message = compiled.string.replace(" \n", " ").replace("\n", " ")
--- a/databases/core.py
+++ b/databases/core.py
@@ -5,7 +5,7 @@ import logging
import sys
import typing
from types import TracebackType
-from urllib.parse import SplitResult, parse_qsl, urlsplit, unquote
+from urllib.parse import SplitResult, parse_qsl, unquote, urlsplit
from sqlalchemy import text
from sqlalchemy.sql import ClauseElement
--- a/requirements.txt
+++ b/requirements.txt
@@ -22,4 +22,4 @@ mypy
pytest
pytest-cov
starlette
-requests
+requests
\ No newline at end of file
--- a/setup.py
+++ b/setup.py
@@ -48,7 +48,7 @@ setup(
packages=get_packages("databases"),
package_data={"databases": ["py.typed"]},
data_files=[("", ["LICENSE.md"])],
- install_requires=['sqlalchemy<1.4', 'aiocontextvars;python_version<"3.7"'],
+ install_requires=['sqlalchemy>=1.4,<1.5',
'aiocontextvars;python_version<"3.7"'],
extras_require={
"postgresql": ["asyncpg"],
"mysql": ["aiomysql"],
--- a/tests/test_database_url.py
+++ b/tests/test_database_url.py
@@ -1,7 +1,9 @@
-from databases import DatabaseURL
from urllib.parse import quote
+
import pytest
+from databases import DatabaseURL
+
def test_database_url_repr():
u = DatabaseURL("postgresql://localhost/name")
--- a/tests/test_databases.py
+++ b/tests/test_databases.py
@@ -3,6 +3,7 @@ import datetime
import decimal
import functools
import os
+import re
import pytest
import sqlalchemy
@@ -336,8 +337,8 @@ async def test_result_values_allow_dupli
query = "SELECT 1 AS id, 2 AS id"
row = await database.fetch_one(query=query)
- assert list(row.keys()) == ["id", "id"]
- assert list(row.values()) == [1, 2]
+ assert list(row._mapping.keys()) == ["id", "id"]
+ assert list(row._mapping.values()) == [1, 2]
@pytest.mark.parametrize("database_url", DATABASE_URLS)
@@ -981,7 +982,7 @@ async def test_iterate_outside_transacti
@async_adapter
async def test_column_names(database_url, select_query):
"""
- Test that column names are exposed correctly through `.keys()` on each row.
+ Test that column names are exposed correctly through `._mapping.keys()` on
each row.
"""
async with Database(database_url) as database:
async with database.transaction(force_rollback=True):
@@ -993,6 +994,52 @@ async def test_column_names(database_url
results = await database.fetch_all(query=select_query)
assert len(results) == 1
- assert sorted(results[0].keys()) == ["completed", "id", "text"]
+ assert sorted(results[0]._mapping.keys()) == ["completed", "id",
"text"]
assert results[0]["text"] == "example1"
assert results[0]["completed"] == True
+
+
[email protected]("database_url", DATABASE_URLS)
+@async_adapter
+async def test_posgres_interface(database_url):
+ """
+ Since SQLAlchemy 1.4, `Row.values()` is removed and `Row.keys()` is
deprecated.
+ Custom postgres interface mimics more or less this behaviour by
deprecating those
+ two methods
+ """
+ database_url = DatabaseURL(database_url)
+
+ if database_url.scheme != "postgresql":
+ pytest.skip("Test is only for postgresql")
+
+ async with Database(database_url) as database:
+ async with database.transaction(force_rollback=True):
+ query = notes.insert()
+ values = {"text": "example1", "completed": True}
+ await database.execute(query, values)
+
+ query = notes.select()
+ result = await database.fetch_one(query=query)
+
+ with pytest.warns(
+ DeprecationWarning,
+ match=re.escape(
+ "The `Row.keys()` method is deprecated to mimic SQLAlchemy
behaviour, "
+ "use `Row._mapping.keys()` instead."
+ ),
+ ):
+ assert (
+ list(result.keys())
+ == [k for k in result]
+ == ["id", "text", "completed"]
+ )
+
+ with pytest.warns(
+ DeprecationWarning,
+ match=re.escape(
+ "The `Row.values()` method is deprecated to mimic
SQLAlchemy behaviour, "
+ "use `Row._mapping.values()` instead."
+ ),
+ ):
+ # avoid checking `id` at index 0 since it may change depending
on the launched tests
+ assert list(result.values())[1:] == ["example1", True]