Skip to content

Commit f5b6429

Browse files
authored
Linting (and a fix) (#3)
Use the proper isolation level on psycopg, where it is no longer an int.
1 parent 9f77ac4 commit f5b6429

File tree

9 files changed

+41
-36
lines changed

9 files changed

+41
-36
lines changed

synapse/storage/database.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
PsycopgEngine,
7272
Sqlite3Engine,
7373
)
74+
from synapse.storage.engines._base import IsolationLevel
7475
from synapse.storage.types import Connection, Cursor, SQLQueryParameters
7576
from synapse.types import StrCollection
7677
from synapse.util.async_helpers import delay_cancellation
@@ -408,7 +409,7 @@ def execute_values(
408409
values: Collection[Iterable[Any]],
409410
template: Optional[str] = None,
410411
fetch: bool = True,
411-
) -> List[Tuple]:
412+
) -> Iterable[Tuple]:
412413
"""Corresponds to psycopg2.extras.execute_values. Only available when
413414
using postgres.
414415
@@ -453,7 +454,7 @@ def execute_values(
453454
def f(
454455
the_sql: str, the_args: Sequence[Sequence[Any]]
455456
) -> Iterable[Tuple[Any, ...]]:
456-
with self.txn.copy(the_sql, the_args) as copy:
457+
with self.txn.copy(the_sql, the_args) as copy: # type: ignore[attr-defined]
457458
yield from copy.rows()
458459

459460
# Flatten the values.
@@ -468,7 +469,7 @@ def copy_write(
468469
def f(
469470
the_sql: str, the_args: Iterable[Any], the_values: Iterable[Iterable[Any]]
470471
) -> None:
471-
with self.txn.copy(the_sql, the_args) as copy:
472+
with self.txn.copy(the_sql, the_args) as copy: # type: ignore[attr-defined]
472473
for record in the_values:
473474
copy.write_row(record)
474475

@@ -504,12 +505,6 @@ def executescript(self, sql: str) -> None:
504505

505506
def _make_sql_one_line(self, sql: str) -> str:
506507
"Strip newlines out of SQL so that the loggers in the DB are on one line"
507-
if isinstance(self.database_engine, PsycopgEngine):
508-
import psycopg.sql
509-
510-
if isinstance(sql, psycopg.sql.Composed):
511-
return sql.as_string(None)
512-
513508
return " ".join(line.strip() for line in sql.splitlines() if line.strip())
514509

515510
def _do_execute(
@@ -933,7 +928,7 @@ async def runInteraction(
933928
func: Callable[..., R],
934929
*args: Any,
935930
db_autocommit: bool = False,
936-
isolation_level: Optional[int] = None,
931+
isolation_level: Optional[IsolationLevel] = None,
937932
**kwargs: Any,
938933
) -> R:
939934
"""Starts a transaction on the database and runs a given function
@@ -1015,7 +1010,7 @@ async def runWithConnection(
10151010
func: Callable[Concatenate[LoggingDatabaseConnection, P], R],
10161011
*args: Any,
10171012
db_autocommit: bool = False,
1018-
isolation_level: Optional[int] = None,
1013+
isolation_level: Optional[IsolationLevel] = None,
10191014
**kwargs: Any,
10201015
) -> R:
10211016
"""Wraps the .runWithConnection() method on the underlying db_pool.
@@ -2421,7 +2416,7 @@ def simple_delete_many_batch_txn(
24212416
txn: LoggingTransaction,
24222417
table: str,
24232418
keys: Collection[str],
2424-
values: Iterable[Iterable[Any]],
2419+
values: Sequence[Iterable[Any]],
24252420
) -> None:
24262421
"""Executes a DELETE query on the named table.
24272422

synapse/storage/databases/main/end_to_end_keys.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,7 @@ async def claim_e2e_fallback_keys(
12141214
def _claim_e2e_fallback_keys_bulk_txn(
12151215
self,
12161216
txn: LoggingTransaction,
1217-
query_list: Iterable[Tuple[str, str, str, bool]],
1217+
query_list: Collection[Tuple[str, str, str, bool]],
12181218
) -> Dict[str, Dict[str, Dict[str, JsonDict]]]:
12191219
"""Efficient implementation of claim_e2e_fallback_keys for Postgres.
12201220
@@ -1342,7 +1342,7 @@ def _claim_e2e_one_time_key_simple(
13421342
def _claim_e2e_one_time_keys_bulk(
13431343
self,
13441344
txn: LoggingTransaction,
1345-
query_list: Iterable[Tuple[str, str, str, int]],
1345+
query_list: Collection[Tuple[str, str, str, int]],
13461346
) -> List[Tuple[str, str, str, str, str]]:
13471347
"""Bulk claim OTKs, for DBs that support DELETE FROM... RETURNING.
13481348

synapse/storage/databases/main/event_push_actions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@
102102
DatabasePool,
103103
LoggingDatabaseConnection,
104104
LoggingTransaction,
105-
PostgresEngine,
106105
)
107106
from synapse.storage.databases.main.receipts import ReceiptsWorkerStore
108107
from synapse.storage.databases.main.stream import StreamWorkerStore
108+
from synapse.storage.engines import PostgresEngine
109109
from synapse.types import JsonDict, StrCollection
110110
from synapse.util import json_encoder
111111
from synapse.util.caches.descriptors import cached

synapse/storage/engines/_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def attempt_to_set_autocommit(self, conn: ConnectionType, autocommit: bool) -> N
132132

133133
@abc.abstractmethod
134134
def attempt_to_set_isolation_level(
135-
self, conn: ConnectionType, isolation_level: Optional[IsolationLevelType]
135+
self, conn: ConnectionType, isolation_level: Optional[IsolationLevel] = None
136136
) -> None:
137137
"""Attempt to set the connections isolation level.
138138

synapse/storage/engines/postgres.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,30 @@
2121

2222
import abc
2323
import logging
24-
from typing import TYPE_CHECKING, Any, Generic, Mapping, Optional, Tuple, cast
24+
from typing import TYPE_CHECKING, Any, Mapping, Optional, Tuple, cast
2525

2626
from synapse.storage.engines._base import (
2727
AUTO_INCREMENT_PRIMARY_KEYPLACEHOLDER,
2828
BaseDatabaseEngine,
2929
ConnectionType,
3030
CursorType,
3131
IncorrectDatabaseSetup,
32+
IsolationLevel,
3233
IsolationLevelType,
3334
)
3435
from synapse.storage.types import Cursor, DBAPI2Module
3536

3637
if TYPE_CHECKING:
3738
from synapse.storage.database import LoggingDatabaseConnection
3839

39-
4040
logger = logging.getLogger(__name__)
4141

4242

4343
class PostgresEngine(
44-
Generic[ConnectionType, CursorType, IsolationLevelType],
4544
BaseDatabaseEngine[ConnectionType, CursorType, IsolationLevelType],
4645
metaclass=abc.ABCMeta,
4746
):
48-
isolation_level_map: Mapping[int, IsolationLevelType]
47+
isolation_level_map: Mapping[IsolationLevel, IsolationLevelType]
4948
default_isolation_level: IsolationLevelType
5049

5150
def __init__(self, module: DBAPI2Module, database_config: Mapping[str, Any]):
@@ -173,7 +172,7 @@ def convert_param_style(self, sql: str) -> str:
173172

174173
def on_new_connection(self, db_conn: "LoggingDatabaseConnection") -> None:
175174
# mypy doesn't realize that ConnectionType matches the Connection protocol.
176-
self.attempt_to_set_isolation_level(db_conn.conn, self.default_isolation_level) # type: ignore[arg-type]
175+
self.attempt_to_set_isolation_level(db_conn.conn) # type: ignore[arg-type]
177176

178177
# Set the bytea output to escape, vs the default of hex
179178
cursor = db_conn.cursor()
@@ -187,7 +186,12 @@ def on_new_connection(self, db_conn: "LoggingDatabaseConnection") -> None:
187186

188187
# Abort really long-running statements and turn them into errors.
189188
if self.statement_timeout is not None:
190-
self.set_statement_timeout(cursor.txn, self.statement_timeout)
189+
# Because the PostgresEngine is considered an ABCMeta, a superclass and a
190+
# subclass, cursor's type is messy. We know it should be a CursorType,
191+
# but for now that doesn't pass cleanly through LoggingDatabaseConnection
192+
# and LoggingTransaction. Fortunately, it's merely running an execute()
193+
# and nothing more exotic.
194+
self.set_statement_timeout(cursor.txn, self.statement_timeout) # type: ignore[arg-type]
191195

192196
cursor.close()
193197
db_conn.commit()

synapse/storage/engines/psycopg.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ def set_statement_timeout(
5656
self, cursor: psycopg.Cursor, statement_timeout: int
5757
) -> None:
5858
"""Configure the current cursor's statement timeout."""
59-
cursor.execute(
60-
psycopg.sql.SQL("SET statement_timeout TO {}").format(statement_timeout)
59+
query_str = psycopg.sql.SQL("SET statement_timeout TO {}").format(
60+
statement_timeout
6161
)
62+
cursor.execute(query_str.as_string())
6263

6364
def convert_param_style(self, sql: str) -> str:
6465
# if isinstance(sql, psycopg.sql.Composed):
@@ -87,7 +88,7 @@ def attempt_to_set_autocommit(
8788
conn.autocommit = autocommit
8889

8990
def attempt_to_set_isolation_level(
90-
self, conn: psycopg.Connection, isolation_level: Optional[int]
91+
self, conn: psycopg.Connection, isolation_level: Optional[IsolationLevel] = None
9192
) -> None:
9293
if isolation_level is None:
9394
pg_isolation_level = self.default_isolation_level

synapse/storage/engines/psycopg2.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,12 @@ def attempt_to_set_autocommit(
7676
return conn.set_session(autocommit=autocommit)
7777

7878
def attempt_to_set_isolation_level(
79-
self, conn: psycopg2.extensions.connection, isolation_level: Optional[int]
79+
self,
80+
conn: psycopg2.extensions.connection,
81+
isolation_level: Optional[IsolationLevel] = None,
8082
) -> None:
8183
if isolation_level is None:
82-
isolation_level = self.default_isolation_level
84+
pg_isolation_level = self.default_isolation_level
8385
else:
84-
isolation_level = self.isolation_level_map[isolation_level]
85-
return conn.set_isolation_level(isolation_level)
86+
pg_isolation_level = self.isolation_level_map[isolation_level]
87+
return conn.set_isolation_level(pg_isolation_level)

synapse/storage/engines/sqlite.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
from typing import TYPE_CHECKING, Any, List, Mapping, Optional
2626

2727
from synapse.storage.engines import BaseDatabaseEngine
28-
from synapse.storage.engines._base import AUTO_INCREMENT_PRIMARY_KEYPLACEHOLDER
28+
from synapse.storage.engines._base import (
29+
AUTO_INCREMENT_PRIMARY_KEYPLACEHOLDER,
30+
IsolationLevel,
31+
)
2932
from synapse.storage.types import Cursor
3033

3134
if TYPE_CHECKING:
@@ -146,7 +149,7 @@ def attempt_to_set_autocommit(
146149
pass
147150

148151
def attempt_to_set_isolation_level(
149-
self, conn: sqlite3.Connection, isolation_level: Optional[int]
152+
self, conn: sqlite3.Connection, isolation_level: Optional[IsolationLevel] = None
150153
) -> None:
151154
# All transactions are SERIALIZABLE by default in sqlite
152155
pass

tests/storage/test_base.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def runWithConnection(func, *args, **kwargs): # type: ignore[no-untyped-def]
123123
self.datastore = SQLBaseStore(db, None, hs) # type: ignore[arg-type]
124124

125125
def tearDown(self) -> None:
126-
if USE_POSTGRES_FOR_TESTS != "psycopg":
126+
if USE_POSTGRES_FOR_TESTS and USE_POSTGRES_FOR_TESTS != "psycopg":
127127
self.execute_batch_patcher.stop()
128128
self.execute_values_patcher.stop()
129129

@@ -388,7 +388,7 @@ def test_update_many(self) -> Generator["defer.Deferred[object]", object, None]:
388388
)
389389

390390
# execute_batch is only used on psycopg2.
391-
if USE_POSTGRES_FOR_TESTS != "psycopg":
391+
if USE_POSTGRES_FOR_TESTS and USE_POSTGRES_FOR_TESTS != "psycopg":
392392
self.mock_execute_batch.assert_called_once_with(
393393
self.mock_txn,
394394
"UPDATE tablename SET col3 = ? WHERE col1 = ? AND col2 = ?",
@@ -429,7 +429,7 @@ def test_update_many_no_iterable(
429429
)
430430

431431
# execute_batch is only used on psycopg2.
432-
if USE_POSTGRES_FOR_TESTS != "psycopg":
432+
if USE_POSTGRES_FOR_TESTS and USE_POSTGRES_FOR_TESTS != "psycopg":
433433
self.mock_execute_batch.assert_not_called()
434434
else:
435435
self.mock_txn.executemany.assert_not_called()
@@ -601,7 +601,7 @@ def test_upsert_many(self) -> Generator["defer.Deferred[object]", object, None]:
601601
)
602602

603603
# execute_values is only used on psycopg2.
604-
if USE_POSTGRES_FOR_TESTS != "psycopg":
604+
if USE_POSTGRES_FOR_TESTS and USE_POSTGRES_FOR_TESTS != "psycopg":
605605
self.mock_execute_values.assert_called_once_with(
606606
self.mock_txn,
607607
"INSERT INTO tablename (keycol1, keycol2, valuecol3) VALUES ? ON CONFLICT (keycol1, keycol2) DO UPDATE SET valuecol3=EXCLUDED.valuecol3",
@@ -631,7 +631,7 @@ def test_upsert_many_no_values(
631631
)
632632

633633
# execute_values is only used on psycopg2.
634-
if USE_POSTGRES_FOR_TESTS != "psycopg":
634+
if USE_POSTGRES_FOR_TESTS and USE_POSTGRES_FOR_TESTS != "psycopg":
635635
self.mock_execute_values.assert_called_once_with(
636636
self.mock_txn,
637637
"INSERT INTO tablename (columnname) VALUES ? ON CONFLICT (columnname) DO NOTHING",

0 commit comments

Comments
 (0)