main commit
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-10-16 16:30:25 +09:00
parent 91c7e04474
commit 537e7b363f
1146 changed files with 45926 additions and 77196 deletions

View File

@@ -1,5 +1,5 @@
# dialects/postgresql/psycopg.py
# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
# postgresql/psycopg2.py
# Copyright (C) 2005-2023 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -29,29 +29,20 @@ selected depending on how the engine is created:
automatically select the sync version, e.g.::
from sqlalchemy import create_engine
sync_engine = create_engine(
"postgresql+psycopg://scott:tiger@localhost/test"
)
sync_engine = create_engine("postgresql+psycopg://scott:tiger@localhost/test")
* calling :func:`_asyncio.create_async_engine` with
``postgresql+psycopg://...`` will automatically select the async version,
e.g.::
from sqlalchemy.ext.asyncio import create_async_engine
asyncio_engine = create_async_engine(
"postgresql+psycopg://scott:tiger@localhost/test"
)
asyncio_engine = create_async_engine("postgresql+psycopg://scott:tiger@localhost/test")
The asyncio version of the dialect may also be specified explicitly using the
``psycopg_async`` suffix, as::
from sqlalchemy.ext.asyncio import create_async_engine
asyncio_engine = create_async_engine(
"postgresql+psycopg_async://scott:tiger@localhost/test"
)
asyncio_engine = create_async_engine("postgresql+psycopg_async://scott:tiger@localhost/test")
.. seealso::
@@ -59,42 +50,9 @@ The asyncio version of the dialect may also be specified explicitly using the
dialect shares most of its behavior with the ``psycopg2`` dialect.
Further documentation is available there.
Using a different Cursor class
------------------------------
One of the differences between ``psycopg`` and the older ``psycopg2``
is how bound parameters are handled: ``psycopg2`` would bind them
client side, while ``psycopg`` by default will bind them server side.
It's possible to configure ``psycopg`` to do client side binding by
specifying the ``cursor_factory`` to be ``ClientCursor`` when creating
the engine::
from psycopg import ClientCursor
client_side_engine = create_engine(
"postgresql+psycopg://...",
connect_args={"cursor_factory": ClientCursor},
)
Similarly when using an async engine the ``AsyncClientCursor`` can be
specified::
from psycopg import AsyncClientCursor
client_side_engine = create_async_engine(
"postgresql+psycopg://...",
connect_args={"cursor_factory": AsyncClientCursor},
)
.. seealso::
`Client-side-binding cursors <https://www.psycopg.org/psycopg3/docs/advanced/cursors.html#client-side-binding-cursors>`_
""" # noqa
from __future__ import annotations
from collections import deque
import logging
import re
from typing import cast
@@ -121,8 +79,6 @@ from ...util.concurrency import await_only
if TYPE_CHECKING:
from typing import Iterable
from psycopg import AsyncConnection
logger = logging.getLogger("sqlalchemy.dialects.postgresql")
@@ -135,6 +91,8 @@ class _PGREGCONFIG(REGCONFIG):
class _PGJSON(JSON):
render_bind_cast = True
def bind_processor(self, dialect):
return self._make_bind_processor(None, dialect._psycopg_Json)
@@ -143,6 +101,8 @@ class _PGJSON(JSON):
class _PGJSONB(JSONB):
render_bind_cast = True
def bind_processor(self, dialect):
return self._make_bind_processor(None, dialect._psycopg_Jsonb)
@@ -202,7 +162,7 @@ class _PGBoolean(sqltypes.Boolean):
render_bind_cast = True
class _PsycopgRange(ranges.AbstractSingleRangeImpl):
class _PsycopgRange(ranges.AbstractRangeImpl):
def bind_processor(self, dialect):
psycopg_Range = cast(PGDialect_psycopg, dialect)._psycopg_Range
@@ -258,10 +218,8 @@ class _PsycopgMultiRange(ranges.AbstractMultiRangeImpl):
def result_processor(self, dialect, coltype):
def to_range(value):
if value is None:
return None
else:
return ranges.MultiRange(
if value is not None:
value = [
ranges.Range(
elem._lower,
elem._upper,
@@ -269,7 +227,9 @@ class _PsycopgMultiRange(ranges.AbstractMultiRangeImpl):
empty=not elem._bounds,
)
for elem in value
)
]
return value
return to_range
@@ -326,7 +286,7 @@ class PGDialect_psycopg(_PGDialect_common_psycopg):
sqltypes.Integer: _PGInteger,
sqltypes.SmallInteger: _PGSmallInteger,
sqltypes.BigInteger: _PGBigInteger,
ranges.AbstractSingleRange: _PsycopgRange,
ranges.AbstractRange: _PsycopgRange,
ranges.AbstractMultiRange: _PsycopgMultiRange,
},
)
@@ -406,12 +366,10 @@ class PGDialect_psycopg(_PGDialect_common_psycopg):
# register the adapter for connections made subsequent to
# this one
assert self._psycopg_adapters_map
register_hstore(info, self._psycopg_adapters_map)
# register the adapter for this connection
assert connection.connection
register_hstore(info, connection.connection.driver_connection)
register_hstore(info, connection.connection)
@classmethod
def import_dbapi(cls):
@@ -572,7 +530,7 @@ class AsyncAdapt_psycopg_cursor:
def __init__(self, cursor, await_) -> None:
self._cursor = cursor
self.await_ = await_
self._rows = deque()
self._rows = []
def __getattr__(self, name):
return getattr(self._cursor, name)
@@ -599,19 +557,24 @@ class AsyncAdapt_psycopg_cursor:
# eq/ne
if res and res.status == self._psycopg_ExecStatus.TUPLES_OK:
rows = self.await_(self._cursor.fetchall())
self._rows = deque(rows)
if not isinstance(rows, list):
self._rows = list(rows)
else:
self._rows = rows
return result
def executemany(self, query, params_seq):
return self.await_(self._cursor.executemany(query, params_seq))
def __iter__(self):
# TODO: try to avoid pop(0) on a list
while self._rows:
yield self._rows.popleft()
yield self._rows.pop(0)
def fetchone(self):
if self._rows:
return self._rows.popleft()
# TODO: try to avoid pop(0) on a list
return self._rows.pop(0)
else:
return None
@@ -619,12 +582,13 @@ class AsyncAdapt_psycopg_cursor:
if size is None:
size = self._cursor.arraysize
rr = self._rows
return [rr.popleft() for _ in range(min(size, len(rr)))]
retval = self._rows[0:size]
self._rows = self._rows[size:]
return retval
def fetchall(self):
retval = list(self._rows)
self._rows.clear()
retval = self._rows
self._rows = []
return retval
@@ -655,7 +619,6 @@ class AsyncAdapt_psycopg_ss_cursor(AsyncAdapt_psycopg_cursor):
class AsyncAdapt_psycopg_connection(AdaptedConnection):
_connection: AsyncConnection
__slots__ = ()
await_ = staticmethod(await_only)