Skip to content
This repository was archived by the owner on Aug 19, 2025. It is now read-only.

Commit 83c1455

Browse files
committed
Sticking with postgresql+aiopg and some clean up
1 parent 66ec568 commit 83c1455

6 files changed

Lines changed: 65 additions & 78 deletions

File tree

databases/backends/aiopg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import getpass
12
import logging
23
import typing
34
import uuid
45

56
import aiopg
6-
77
from sqlalchemy.dialects.postgresql import pypostgresql
88
from sqlalchemy.engine.interfaces import Dialect, ExecutionContext
99
from sqlalchemy.engine.result import ResultMetaData, RowProxy
@@ -38,7 +38,7 @@ def _get_dialect(self) -> Dialect:
3838

3939
return dialect
4040

41-
def _get_connection_kwargs(self) -> dict: # TODO move to `core.py`
41+
def _get_connection_kwargs(self) -> dict:
4242
url_options = self._database_url.options
4343

4444
kwargs = {}

databases/core.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,9 @@
1818

1919

2020
class Database:
21-
# TODO Nested schema?
22-
# {
23-
# "postgresql": {
24-
# "asyncpg": "...", # Default
25-
# "aiopg": "..."
26-
# }
27-
# }
2821
SUPPORTED_BACKENDS = {
29-
# TODO `postgresql+asyncpg`?
3022
"postgresql": "databases.backends.postgres:PostgresBackend",
31-
"postgresql+psycopg2": "databases.backends.aiopg:AiopgBackend",
23+
"postgresql+aiopg": "databases.backends.aiopg:AiopgBackend",
3224
"mysql": "databases.backends.mysql:MySQLBackend",
3325
"sqlite": "databases.backends.sqlite:SQLiteBackend",
3426
}

tests/conftest.py

Lines changed: 0 additions & 39 deletions
This file was deleted.

tests/test_connection_options.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Unit tests for the backend connection arguments.
33
"""
44

5+
from databases.backends.aiopg import AiopgBackend
56
from databases.backends.mysql import MySQLBackend
67
from databases.backends.postgres import PostgresBackend
78

@@ -52,3 +53,29 @@ def test_mysql_explicit_ssl():
5253
backend = MySQLBackend("mysql://localhost/database", ssl=True)
5354
kwargs = backend._get_connection_kwargs()
5455
assert kwargs == {"ssl": True}
56+
57+
58+
def test_aiopg_pool_size():
59+
backend = AiopgBackend("postgres+aiopg://localhost/database?min_size=1&max_size=20")
60+
kwargs = backend._get_connection_kwargs()
61+
assert kwargs == {"minsize": 1, "maxsize": 20}
62+
63+
64+
def test_aiopg_explicit_pool_size():
65+
backend = AiopgBackend(
66+
"postgres+aiopg://localhost/database", min_size=1, max_size=20
67+
)
68+
kwargs = backend._get_connection_kwargs()
69+
assert kwargs == {"minsize": 1, "maxsize": 20}
70+
71+
72+
def test_aiopg_ssl():
73+
backend = AiopgBackend("postgres+aiopg://localhost/database?ssl=true")
74+
kwargs = backend._get_connection_kwargs()
75+
assert kwargs == {"ssl": True}
76+
77+
78+
def test_aiopg_explicit_ssl():
79+
backend = AiopgBackend("postgres+aiopg://localhost/database", ssl=True)
80+
kwargs = backend._get_connection_kwargs()
81+
assert kwargs == {"ssl": True}

tests/test_databases.py

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,15 @@ def process_result_value(self, value, dialect):
7272
)
7373

7474

75-
# TODO Move to `conftest.py`
7675
@pytest.fixture(autouse=True, scope="module")
7776
def create_test_database():
7877
# Create test databases with tables creation
7978
for url in DATABASE_URLS:
8079
database_url = DatabaseURL(url)
8180
if database_url.dialect == "mysql":
8281
url = str(database_url.replace(driver="pymysql"))
82+
elif database_url.driver == "aiopg":
83+
url = str(database_url.replace(driver=None))
8384
engine = sqlalchemy.create_engine(url)
8485
metadata.create_all(engine)
8586

@@ -91,6 +92,8 @@ def create_test_database():
9192
database_url = DatabaseURL(url)
9293
if database_url.dialect == "mysql":
9394
url = str(database_url.replace(driver="pymysql"))
95+
elif database_url.driver == "aiopg":
96+
url = str(database_url.replace(driver=None))
9497
engine = sqlalchemy.create_engine(url)
9598
metadata.drop_all(engine)
9699

@@ -301,15 +304,19 @@ async def test_execute_return_val(database_url):
301304
query = notes.insert()
302305
values = {"text": "example1", "completed": True}
303306
pk = await database.execute(query, values)
304-
# Apparently for `aiopg` it's OID that will always 0 in this case
305-
# As it's only one action within this cursor life cycle
306-
# Something to triple check
307307
assert isinstance(pk, int)
308308

309-
query = notes.select().where(notes.c.id == pk)
310-
result = await database.fetch_one(query)
311-
assert result["text"] == "example1"
312-
assert result["completed"] == True
309+
# Apparently for `aiopg` it's OID that will always 0 in this case
310+
# As it's only one action within this cursor life cycle
311+
# It's recommended to use the `RETURNING` clause
312+
# For obtaining the record id
313+
if database.url.scheme == "postgresql+aiopg":
314+
assert pk == 0
315+
else:
316+
query = notes.select().where(notes.c.id == pk)
317+
result = await database.fetch_one(query)
318+
assert result["text"] == "example1"
319+
assert result["completed"] == True
313320

314321

315322
@pytest.mark.parametrize("database_url", DATABASE_URLS)
@@ -508,14 +515,11 @@ async def test_json_field(database_url):
508515
async with database.transaction(force_rollback=True):
509516
# execute()
510517
query = session.insert()
511-
values = {"data": {"text": "hello", "boolean": True, "int": 1}}
512-
if str(database_url).startswith("postgresql+psycopg2"):
513-
await database.execute(
514-
query.values(
515-
# or wrapped with `psycopg2.extras.Json`
516-
data=json.dumps({"text": "hello", "boolean": True, "int": 1})
517-
)
518-
)
518+
data = {"text": "hello", "boolean": True, "int": 1}
519+
values = {"data": data}
520+
521+
if database.url.scheme == "postgresql+aiopg":
522+
await database.execute(query, {"data": json.dumps(data)})
519523
else:
520524
await database.execute(query, values)
521525

@@ -679,29 +683,29 @@ async def test_queries_with_expose_backend_connection(database_url):
679683
raw_connection = connection.raw_connection
680684

681685
# Insert query
682-
if str(database_url).startswith("mysql") or str(database_url).startswith("postgresql+psycopg2"):
686+
if database.url.scheme in ["mysql", "postgresql+aiopg"]:
683687
insert_query = "INSERT INTO notes (text, completed) VALUES (%s, %s)"
684688
else:
685689
insert_query = "INSERT INTO notes (text, completed) VALUES ($1, $2)"
686690

687691
# execute()
688692
values = ("example1", True)
689693

690-
if str(database_url).startswith("mysql") or str(database_url).startswith("postgresql+psycopg2"):
694+
if database.url.scheme in ["mysql", "postgresql+aiopg"]:
691695
cursor = await raw_connection.cursor()
692696
await cursor.execute(insert_query, values)
693-
elif str(database_url).startswith("postgresql"):
697+
elif database.url.scheme == "postgresql":
694698
await raw_connection.execute(insert_query, *values)
695-
elif str(database_url).startswith("sqlite"):
699+
elif database.url.scheme == "sqlite":
696700
await raw_connection.execute(insert_query, values)
697701

698702
# execute_many()
699703
values = [("example2", False), ("example3", True)]
700704

701-
if str(database_url).startswith("mysql"):
705+
if database.url.scheme == "mysql":
702706
cursor = await raw_connection.cursor()
703707
await cursor.executemany(insert_query, values)
704-
elif str(database_url).startswith("postgresql+psycopg2"):
708+
elif database.url.scheme == "postgresql+aiopg":
705709
cursor = await raw_connection.cursor()
706710
# No async support for `executemany`
707711
for value in values:
@@ -713,13 +717,13 @@ async def test_queries_with_expose_backend_connection(database_url):
713717
select_query = "SELECT notes.id, notes.text, notes.completed FROM notes"
714718

715719
# fetch_all()
716-
if str(database_url).startswith("mysql") or str(database_url).startswith("postgresql+psycopg2"):
720+
if database.url.scheme in ["mysql", "postgresql+aiopg"]:
717721
cursor = await raw_connection.cursor()
718722
await cursor.execute(select_query)
719723
results = await cursor.fetchall()
720-
elif str(database_url).startswith("postgresql"):
724+
elif database.url.scheme == "postgresql":
721725
results = await raw_connection.fetch(select_query)
722-
elif str(database_url).startswith("sqlite"):
726+
elif database.url.scheme == "sqlite":
723727
results = await raw_connection.execute_fetchall(select_query)
724728

725729
assert len(results) == 3
@@ -730,9 +734,9 @@ async def test_queries_with_expose_backend_connection(database_url):
730734
assert results[1][2] == False
731735
assert results[2][1] == "example3"
732736
assert results[2][2] == True
733-
737+
734738
# fetch_one()
735-
if str(database_url).startswith("postgresql") and not str(database_url).startswith("postgresql+psycopg2"):
739+
if database.url.scheme == "postgresql":
736740
result = await raw_connection.fetchrow(select_query)
737741
else:
738742
cursor = await raw_connection.cursor()

tests/test_integration.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@
2323
)
2424

2525

26-
# TODO Move to `conftest.py` with tables creation
2726
@pytest.fixture(autouse=True, scope="module")
2827
def create_test_database():
2928
# Create test databases
3029
for url in DATABASE_URLS:
3130
database_url = DatabaseURL(url)
3231
if database_url.dialect == "mysql":
3332
url = str(database_url.replace(driver="pymysql"))
33+
elif database_url.driver == "aiopg":
34+
url = str(database_url.replace(driver=None))
3435
engine = sqlalchemy.create_engine(url)
3536
metadata.create_all(engine)
3637

@@ -42,6 +43,8 @@ def create_test_database():
4243
database_url = DatabaseURL(url)
4344
if database_url.dialect == "mysql":
4445
url = str(database_url.replace(driver="pymysql"))
46+
elif database_url.driver == "aiopg":
47+
url = str(database_url.replace(driver=None))
4548
engine = sqlalchemy.create_engine(url)
4649
metadata.drop_all(engine)
4750

0 commit comments

Comments
 (0)