]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
refactor: drop use of typing.Optional
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 29 May 2024 23:58:04 +0000 (01:58 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 4 Jun 2024 14:52:16 +0000 (16:52 +0200)
81 files changed:
docs/advanced/typing.rst
psycopg/psycopg/_adapters_map.py
psycopg/psycopg/_cmodule.py
psycopg/psycopg/_column.py
psycopg/psycopg/_connection_base.py
psycopg/psycopg/_copy_base.py
psycopg/psycopg/_cursor_base.py
psycopg/psycopg/_dns.py
psycopg/psycopg/_encodings.py
psycopg/psycopg/_pipeline.py
psycopg/psycopg/_preparing.py
psycopg/psycopg/_py_transformer.py
psycopg/psycopg/_queries.py
psycopg/psycopg/_struct.py
psycopg/psycopg/_tpc.py
psycopg/psycopg/_tz.py
psycopg/psycopg/abc.py
psycopg/psycopg/adapt.py
psycopg/psycopg/client_cursor.py
psycopg/psycopg/connection.py
psycopg/psycopg/connection_async.py
psycopg/psycopg/crdb/connection.py
psycopg/psycopg/cursor.py
psycopg/psycopg/cursor_async.py
psycopg/psycopg/dbapi20.py
psycopg/psycopg/errors.py
psycopg/psycopg/generators.py
psycopg/psycopg/pq/_pq_ctypes.py
psycopg/psycopg/pq/_pq_ctypes.pyi
psycopg/psycopg/pq/abc.py
psycopg/psycopg/pq/misc.py
psycopg/psycopg/pq/pq_ctypes.py
psycopg/psycopg/raw_cursor.py
psycopg/psycopg/rows.py
psycopg/psycopg/server_cursor.py
psycopg/psycopg/sql.py
psycopg/psycopg/transaction.py
psycopg/psycopg/types/array.py
psycopg/psycopg/types/bool.py
psycopg/psycopg/types/composite.py
psycopg/psycopg/types/datetime.py
psycopg/psycopg/types/enum.py
psycopg/psycopg/types/hstore.py
psycopg/psycopg/types/json.py
psycopg/psycopg/types/multirange.py
psycopg/psycopg/types/net.py
psycopg/psycopg/types/none.py
psycopg/psycopg/types/numeric.py
psycopg/psycopg/types/range.py
psycopg/psycopg/types/shapely.py
psycopg/psycopg/types/string.py
psycopg/psycopg/types/uuid.py
psycopg/psycopg/waiting.py
psycopg_c/psycopg_c/_psycopg.pyi
psycopg_c/psycopg_c/_psycopg/adapt.pyx
psycopg_c/psycopg_c/_psycopg/generators.pyx
psycopg_c/psycopg_c/_psycopg/transform.pyx
psycopg_c/psycopg_c/pq/pgconn.pyx
psycopg_c/psycopg_c/pq/pgresult.pyx
psycopg_c/psycopg_c/types/bool.pyx
psycopg_c/psycopg_c/types/datetime.pyx
psycopg_c/psycopg_c/types/numeric.pyx
psycopg_c/psycopg_c/types/string.pyx
psycopg_pool/psycopg_pool/_task.py
psycopg_pool/psycopg_pool/base.py
psycopg_pool/psycopg_pool/null_pool.py
psycopg_pool/psycopg_pool/null_pool_async.py
psycopg_pool/psycopg_pool/pool.py
psycopg_pool/psycopg_pool/pool_async.py
psycopg_pool/psycopg_pool/sched.py
psycopg_pool/psycopg_pool/sched_async.py
tests/adapters_example.py
tests/fix_crdb.py
tests/fix_db.py
tests/fix_faker.py
tests/scripts/pipeline-demo.py
tests/test_adapt.py
tests/test_typing.py
tests/types/test_numeric.py
tests/typing_example.py
tests/utils.py

index f1f901268c4acac5361adc8042ffac5b93bb5a3c..98efb4067c00406398ed7aa7f232ba7cdfe60940 100644 (file)
@@ -36,7 +36,7 @@ annotations such as `!Connection[Any]` and `!Cursor[Any]`.
 
    cur = conn.cursor()      # type is psycopg.Cursor[tuple[Any, ...]]
 
-   rec = cur.fetchone()     # type is Optional[tuple[Any, ...]]
+   rec = cur.fetchone()     # type is tuple[Any, ...] | None
 
    recs = cur.fetchall()    # type is List[tuple[Any, ...]]
 
@@ -63,7 +63,7 @@ cursors and annotate the returned objects accordingly. See
    # dcur type is psycopg.Cursor[dict[str, Any]] in both cases
 
    drec = dcur.fetchone()
-   # drec type is Optional[dict[str, Any]]
+   # drec type is dict[str, Any] | None
 
 
 .. _pool-generic:
@@ -97,7 +97,7 @@ otherwise the typing system and the runtime will not agree.
             # reveal_type(conn): Connection[dict[str, Any]]
 
             row = conn.execute("SELECT now()").fetchone()
-            # reveal_type(row): Optional[dict[str, Any]]
+            # reveal_type(row): dict[str, Any] | None
 
             print(row)  # {"now": datetime.datetime(...)}
 
@@ -118,7 +118,7 @@ type is not parametric) then it's not necessary to specify `!kwargs`:
             # reveal_type(conn): MyConnection
 
             row = conn.execute("SELECT now()").fetchone()
-            # reveal_type(row): Optional[dict[str, Any]]
+            # reveal_type(row): dict[str, Any] | None
 
             print(row)  # {"now": datetime.datetime(...)}
 
index 904ec71d18b83370df3ee4ea7395f7809bd0fbc2..d76c8247fa0076d22bfc1bbd8f47880f0afd4de1 100644 (file)
@@ -4,7 +4,9 @@ Mapping from types/oids to Dumpers/Loaders
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Any, Dict, List, Optional, Type, Union
+from __future__ import annotations
+
+from typing import Any, Dict, List, Type, Union
 from typing import cast, TYPE_CHECKING
 
 from . import pq
@@ -69,8 +71,8 @@ class AdaptersMap:
 
     def __init__(
         self,
-        template: Optional["AdaptersMap"] = None,
-        types: Optional[TypesRegistry] = None,
+        template: "AdaptersMap" | None = None,
+        types: TypesRegistry | None = None,
     ):
         if template:
             self._dumpers = template._dumpers.copy()
@@ -105,7 +107,7 @@ class AdaptersMap:
         return self
 
     @property
-    def connection(self) -> Optional["BaseConnection[Any]"]:
+    def connection(self) -> "BaseConnection[Any]" | None:
         return None
 
     def register_dumper(
@@ -256,7 +258,7 @@ class AdaptersMap:
                 )
             raise e.ProgrammingError(msg)
 
-    def get_loader(self, oid: int, format: pq.Format) -> Optional[Type["Loader"]]:
+    def get_loader(self, oid: int, format: pq.Format) -> Type["Loader"] | None:
         """
         Return the loader class for the given oid and format.
 
index 288ef1ba0f551c590cd3ae06ac7dec4eab1e7ad6..33162bc10b2dc69c13b3ad2d1db074cd8caf2f0b 100644 (file)
@@ -4,11 +4,11 @@ Simplify access to the _psycopg module
 
 # Copyright (C) 2021 The Psycopg Team
 
-from typing import Optional
+from __future__ import annotations
 
 from . import pq
 
-__version__: Optional[str] = None
+__version__: str | None = None
 
 # Note: "c" must the first attempt so that mypy associates the variable the
 # right module interface. It will not result Optional, but hey.
index 7c879a60f12f4a477d0d9f7631a3910d50303e9c..2e441b678811d64cdbea1ba066a9e15cbf3559d6 100644 (file)
@@ -4,7 +4,9 @@ The Column object in Cursor.description
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Any, Optional, Sequence, TYPE_CHECKING
+from __future__ import annotations
+
+from typing import Any, Sequence, TYPE_CHECKING
 from operator import attrgetter
 
 if TYPE_CHECKING:
@@ -76,27 +78,27 @@ class Column(Sequence[Any]):
         return self._ftype
 
     @property
-    def display_size(self) -> Optional[int]:
+    def display_size(self) -> int | None:
         """The field size, for string types such as :sql:`varchar(n)`."""
         return self._type.get_display_size(self._fmod) if self._type else None
 
     @property
-    def internal_size(self) -> Optional[int]:
+    def internal_size(self) -> int | None:
         """The internal field size for fixed-size types, None otherwise."""
         fsize = self._fsize
         return fsize if fsize >= 0 else None
 
     @property
-    def precision(self) -> Optional[int]:
+    def precision(self) -> int | None:
         """The number of digits for fixed precision types."""
         return self._type.get_precision(self._fmod) if self._type else None
 
     @property
-    def scale(self) -> Optional[int]:
+    def scale(self) -> int | None:
         """The number of digits after the decimal point if available."""
         return self._type.get_scale(self._fmod) if self._type else None
 
     @property
-    def null_ok(self) -> Optional[bool]:
+    def null_ok(self) -> bool | None:
         """Always `!None`"""
         return None
index dde4e1f7c9542104f729dab42198da461cf6fdd1..2b862e8038ac4e8acb0bfd0d9791cd23cc3fe0af 100644 (file)
@@ -4,10 +4,12 @@ psycopg connection objects
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import sys
 import logging
 from typing import Callable, Generic
-from typing import List, NamedTuple, Optional, Tuple, Union
+from typing import List, NamedTuple, Tuple, Union
 from typing import TYPE_CHECKING
 from weakref import ref, ReferenceType
 from warnings import warn
@@ -104,7 +106,7 @@ class BaseConnection(Generic[Row]):
         self._autocommit = False
 
         # None, but set to a copy of the global adapters map as soon as requested.
-        self._adapters: Optional[AdaptersMap] = None
+        self._adapters: AdaptersMap | None = None
 
         self._notice_handlers: List[NoticeHandler] = []
         self._notify_handlers: List[NotifyHandler] = []
@@ -114,7 +116,7 @@ class BaseConnection(Generic[Row]):
 
         self._closed = False  # closed by an explicit close()
         self._prepared: PrepareManager = PrepareManager()
-        self._tpc: Optional[Tuple[Xid, bool]] = None  # xid, prepared
+        self._tpc: Tuple[Xid, bool] | None = None  # xid, prepared
 
         wself = ref(self)
         pgconn.notice_handler = partial(BaseConnection._notice_handler, wself)
@@ -122,16 +124,16 @@ class BaseConnection(Generic[Row]):
 
         # Attribute is only set if the connection is from a pool so we can tell
         # apart a connection in the pool too (when _pool = None)
-        self._pool: Optional["BasePool"]
+        self._pool: "BasePool" | None
 
-        self._pipeline: Optional[BasePipeline] = None
+        self._pipeline: BasePipeline | None = None
 
         # Time after which the connection should be closed
         self._expire_at: float
 
-        self._isolation_level: Optional[IsolationLevel] = None
-        self._read_only: Optional[bool] = None
-        self._deferrable: Optional[bool] = None
+        self._isolation_level: IsolationLevel | None = None
+        self._read_only: bool | None = None
+        self._deferrable: bool | None = None
         self._begin_statement = b""
 
     def __del__(self) -> None:
@@ -190,58 +192,58 @@ class BaseConnection(Generic[Row]):
         self._autocommit = bool(value)
 
     @property
-    def isolation_level(self) -> Optional[IsolationLevel]:
+    def isolation_level(self) -> IsolationLevel | None:
         """
         The isolation level of the new transactions started on the connection.
         """
         return self._isolation_level
 
     @isolation_level.setter
-    def isolation_level(self, value: Optional[IsolationLevel]) -> None:
+    def isolation_level(self, value: IsolationLevel | None) -> None:
         self._set_isolation_level(value)
 
-    def _set_isolation_level(self, value: Optional[IsolationLevel]) -> None:
+    def _set_isolation_level(self, value: IsolationLevel | None) -> None:
         raise NotImplementedError
 
-    def _set_isolation_level_gen(self, value: Optional[IsolationLevel]) -> PQGen[None]:
+    def _set_isolation_level_gen(self, value: IsolationLevel | None) -> PQGen[None]:
         yield from self._check_intrans_gen("isolation_level")
         self._isolation_level = IsolationLevel(value) if value is not None else None
         self._begin_statement = b""
 
     @property
-    def read_only(self) -> Optional[bool]:
+    def read_only(self) -> bool | None:
         """
         The read-only state of the new transactions started on the connection.
         """
         return self._read_only
 
     @read_only.setter
-    def read_only(self, value: Optional[bool]) -> None:
+    def read_only(self, value: bool | None) -> None:
         self._set_read_only(value)
 
-    def _set_read_only(self, value: Optional[bool]) -> None:
+    def _set_read_only(self, value: bool | None) -> None:
         raise NotImplementedError
 
-    def _set_read_only_gen(self, value: Optional[bool]) -> PQGen[None]:
+    def _set_read_only_gen(self, value: bool | None) -> PQGen[None]:
         yield from self._check_intrans_gen("read_only")
         self._read_only = bool(value) if value is not None else None
         self._begin_statement = b""
 
     @property
-    def deferrable(self) -> Optional[bool]:
+    def deferrable(self) -> bool | None:
         """
         The deferrable state of the new transactions started on the connection.
         """
         return self._deferrable
 
     @deferrable.setter
-    def deferrable(self, value: Optional[bool]) -> None:
+    def deferrable(self, value: bool | None) -> None:
         self._set_deferrable(value)
 
-    def _set_deferrable(self, value: Optional[bool]) -> None:
+    def _set_deferrable(self, value: bool | None) -> None:
         raise NotImplementedError
 
-    def _set_deferrable_gen(self, value: Optional[bool]) -> PQGen[None]:
+    def _set_deferrable_gen(self, value: bool | None) -> PQGen[None]:
         yield from self._check_intrans_gen("deferrable")
         self._deferrable = bool(value) if value is not None else None
         self._begin_statement = b""
@@ -382,7 +384,7 @@ class BaseConnection(Generic[Row]):
             cb(n)
 
     @property
-    def prepare_threshold(self) -> Optional[int]:
+    def prepare_threshold(self) -> int | None:
         """
         Number of times a query is executed before it is prepared.
 
@@ -396,11 +398,11 @@ class BaseConnection(Generic[Row]):
         return self._prepared.prepare_threshold
 
     @prepare_threshold.setter
-    def prepare_threshold(self, value: Optional[int]) -> None:
+    def prepare_threshold(self, value: int | None) -> None:
         self._prepared.prepare_threshold = value
 
     @property
-    def prepared_max(self) -> Optional[int]:
+    def prepared_max(self) -> int | None:
         """
         Maximum number of prepared statements on the connection.
 
@@ -411,7 +413,7 @@ class BaseConnection(Generic[Row]):
         return rv if rv != sys.maxsize else None
 
     @prepared_max.setter
-    def prepared_max(self, value: Optional[int]) -> None:
+    def prepared_max(self, value: int | None) -> None:
         if value is None:
             value = sys.maxsize
         self._prepared.prepared_max = value
@@ -437,7 +439,7 @@ class BaseConnection(Generic[Row]):
 
     def _exec_command(
         self, command: Query, result_format: pq.Format = TEXT
-    ) -> PQGen[Optional["PGresult"]]:
+    ) -> PQGen["PGresult" | None]:
         """
         Generator to send a command and receive the result to the backend.
 
@@ -481,7 +483,7 @@ class BaseConnection(Generic[Row]):
                 )
         return result
 
-    def _deallocate(self, name: Optional[bytes]) -> PQGen[None]:
+    def _deallocate(self, name: bytes | None) -> PQGen[None]:
         """
         Deallocate one, or all, prepared statement in the session.
 
index 47a028bf069ad0137e3bef91c79bd6b98a4d1cb0..3d239ad50c7c0d1b99ccf6ada4860310aef34b08 100644 (file)
@@ -11,7 +11,7 @@ import sys
 import struct
 from abc import ABC, abstractmethod
 from typing import Any, Dict, Generic, List, Match
-from typing import Optional, Sequence, Tuple, Union, TYPE_CHECKING
+from typing import Sequence, Tuple, Union, TYPE_CHECKING
 
 from . import pq
 from . import adapt
@@ -80,7 +80,7 @@ class BaseCopy(Generic[ConnectionType]):
         self,
         cursor: "BaseCursor[ConnectionType, Any]",
         *,
-        binary: Optional[bool] = None,
+        binary: bool | None = None,
     ):
         self.cursor = cursor
         self.connection = cursor.connection
@@ -165,7 +165,7 @@ class BaseCopy(Generic[ConnectionType]):
         self.cursor._rowcount = nrows if nrows is not None else -1
         return memoryview(b"")
 
-    def _read_row_gen(self) -> PQGen[Optional[Tuple[Any, ...]]]:
+    def _read_row_gen(self) -> PQGen[Tuple[Any, ...] | None]:
         data = yield from self._read_gen()
         if not data:
             return None
@@ -200,7 +200,7 @@ class Formatter(ABC):
         self._row_mode = False  # true if the user is using write_row()
 
     @abstractmethod
-    def parse_row(self, data: Buffer) -> Optional[Tuple[Any, ...]]: ...
+    def parse_row(self, data: Buffer) -> Tuple[Any, ...] | None: ...
 
     @abstractmethod
     def write(self, buffer: Union[Buffer, str]) -> Buffer: ...
@@ -219,7 +219,7 @@ class TextFormatter(Formatter):
         super().__init__(transformer)
         self._encoding = encoding
 
-    def parse_row(self, data: Buffer) -> Optional[Tuple[Any, ...]]:
+    def parse_row(self, data: Buffer) -> Tuple[Any, ...] | None:
         if data:
             return parse_row_text(data, self.transformer)
         else:
@@ -263,7 +263,7 @@ class BinaryFormatter(Formatter):
         super().__init__(transformer)
         self._signature_sent = False
 
-    def parse_row(self, data: Buffer) -> Optional[Tuple[Any, ...]]:
+    def parse_row(self, data: Buffer) -> Tuple[Any, ...] | None:
         if not self._signature_sent:
             if data[: len(_binary_signature)] != _binary_signature:
                 raise e.DataError(
@@ -328,7 +328,7 @@ class BinaryFormatter(Formatter):
 
 
 def _format_row_text(
-    row: Sequence[Any], tx: Transformer, out: Optional[bytearray] = None
+    row: Sequence[Any], tx: Transformer, out: bytearray | None = None
 ) -> bytearray:
     """Convert a row of objects to the data to send for copy."""
     if out is None:
@@ -348,7 +348,7 @@ def _format_row_text(
 
 
 def _format_row_binary(
-    row: Sequence[Any], tx: Transformer, out: Optional[bytearray] = None
+    row: Sequence[Any], tx: Transformer, out: bytearray | None = None
 ) -> bytearray:
     """Convert a row of objects to the data to send for binary copy."""
     if out is None:
@@ -376,7 +376,7 @@ def _parse_row_text(data: Buffer, tx: Transformer) -> Tuple[Any, ...]:
 
 
 def _parse_row_binary(data: Buffer, tx: Transformer) -> Tuple[Any, ...]:
-    row: List[Optional[Buffer]] = []
+    row: List[Buffer | None] = []
     nfields = _unpack_int2(data, 0)[0]
     pos = 2
     for i in range(nfields):
index 24a2cb1a286a77c05218b74a672a79c06e786662..587b821908c61b5c9337989da9436d78cd8508f8 100644 (file)
@@ -4,9 +4,11 @@ Psycopg BaseCursor object
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 from functools import partial
 from typing import Any, Generic, Iterable, List
-from typing import Optional, NoReturn, Sequence, Tuple, Type
+from typing import NoReturn, Sequence, Tuple, Type
 from typing import TYPE_CHECKING
 
 from . import pq
@@ -63,18 +65,18 @@ class BaseCursor(Generic[ConnectionType, Row]):
         self._adapters = adapt.AdaptersMap(connection.adapters)
         self.arraysize = 1
         self._closed = False
-        self._last_query: Optional[Query] = None
+        self._last_query: Query | None = None
         self._reset()
 
     def _reset(self, reset_query: bool = True) -> None:
         self._results: List["PGresult"] = []
-        self.pgresult: Optional["PGresult"] = None
+        self.pgresult: "PGresult" | None = None
         self._pos = 0
         self._iresult = 0
         self._rowcount = -1
-        self._query: Optional[PostgresQuery]
+        self._query: PostgresQuery | None
         # None if executemany() not executing, True/False according to returning state
-        self._execmany_returning: Optional[bool] = None
+        self._execmany_returning: bool | None = None
         if reset_query:
             self._query = None
 
@@ -104,7 +106,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
         return self._closed
 
     @property
-    def description(self) -> Optional[List[Column]]:
+    def description(self) -> List[Column] | None:
         """
         A list of `Column` objects describing the current resultset.
 
@@ -128,7 +130,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
         return self._rowcount
 
     @property
-    def rownumber(self) -> Optional[int]:
+    def rownumber(self) -> int | None:
         """Index of the next row to fetch in the current result.
 
         `!None` if there is no result to fetch.
@@ -140,11 +142,11 @@ class BaseCursor(Generic[ConnectionType, Row]):
         # no-op
         pass
 
-    def setoutputsize(self, size: Any, column: Optional[int] = None) -> None:
+    def setoutputsize(self, size: Any, column: int | None = None) -> None:
         # no-op
         pass
 
-    def nextset(self) -> Optional[bool]:
+    def nextset(self) -> bool | None:
         """
         Move to the result set of the next query executed through `executemany()`
         or to the next result set if `execute()` returned more than one.
@@ -159,7 +161,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
             return None
 
     @property
-    def statusmessage(self) -> Optional[str]:
+    def statusmessage(self) -> str | None:
         """
         The command status tag from the last SQL command executed.
 
@@ -182,10 +184,10 @@ class BaseCursor(Generic[ConnectionType, Row]):
     def _execute_gen(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        prepare: Optional[bool] = None,
-        binary: Optional[bool] = None,
+        prepare: bool | None = None,
+        binary: bool | None = None,
     ) -> PQGen[None]:
         """Generator implementing `Cursor.execute()`."""
         yield from self._start_query(query)
@@ -263,8 +265,8 @@ class BaseCursor(Generic[ConnectionType, Row]):
         self,
         pgq: PostgresQuery,
         *,
-        prepare: Optional[bool] = None,
-        binary: Optional[bool] = None,
+        prepare: bool | None = None,
+        binary: bool | None = None,
     ) -> PQGen[None]:
         # Check if the query is prepared or needs preparing
         prep, name = self._get_prepared(pgq, prepare)
@@ -304,16 +306,16 @@ class BaseCursor(Generic[ConnectionType, Row]):
         self._set_results(results)
 
     def _get_prepared(
-        self, pgq: PostgresQuery, prepare: Optional[bool] = None
+        self, pgq: PostgresQuery, prepare: bool | None = None
     ) -> Tuple[Prepare, bytes]:
         return self._conn._prepared.get(pgq, prepare)
 
     def _stream_send_gen(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        binary: Optional[bool] = None,
+        binary: bool | None = None,
     ) -> PQGen[None]:
         """Generator to send the query for `Cursor.stream()`."""
         yield from self._start_query(query)
@@ -323,7 +325,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
         self._last_query = query
         yield from send(self._pgconn)
 
-    def _stream_fetchone_gen(self, first: bool) -> PQGen[Optional["PGresult"]]:
+    def _stream_fetchone_gen(self, first: bool) -> PQGen["PGresult" | None]:
         res = yield from fetch(self._pgconn)
         if res is None:
             return None
@@ -350,7 +352,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
             # Errors, unexpected values
             return self._raise_for_result(res)
 
-    def _start_query(self, query: Optional[Query] = None) -> PQGen[None]:
+    def _start_query(self, query: Query | None = None) -> PQGen[None]:
         """Generator to start the processing of a query.
 
         It is implemented as generator because it may send additional queries,
@@ -366,7 +368,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
         yield from self._conn._start_query()
 
     def _start_copy_gen(
-        self, statement: Query, params: Optional[Params] = None
+        self, statement: Query, params: Params | None = None
     ) -> PQGen[None]:
         """Generator implementing sending a command for `Cursor.copy()."""
 
@@ -398,7 +400,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
         query: PostgresQuery,
         *,
         force_extended: bool = False,
-        binary: Optional[bool] = None,
+        binary: bool | None = None,
     ) -> None:
         """
         Implement part of execute() before waiting common to sync and async.
@@ -439,7 +441,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
             self._pgconn.send_query(query.query)
 
     def _convert_query(
-        self, query: Query, params: Optional[Params] = None
+        self, query: Query, params: Params | None = None
     ) -> PostgresQuery:
         pgq = self._query_cls(self._tx)
         pgq.convert(query, params)
@@ -478,9 +480,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
                 "unexpected result status from query:" f" {pq.ExecStatus(status).name}"
             )
 
-    def _select_current_result(
-        self, i: int, format: Optional[pq.Format] = None
-    ) -> None:
+    def _select_current_result(self, i: int, format: pq.Format | None = None) -> None:
         """
         Select one of the results in the cursor as the active one.
         """
@@ -540,7 +540,7 @@ class BaseCursor(Generic[ConnectionType, Row]):
             self._pgconn.send_prepare(name, query.query, param_types=query.types)
 
     def _send_query_prepared(
-        self, name: bytes, pgq: PostgresQuery, *, binary: Optional[bool] = None
+        self, name: bytes, pgq: PostgresQuery, *, binary: bool | None = None
     ) -> None:
         if binary is None:
             fmt = self.format
index a9619b56d09396a4418a0b9404f7714ae977e5dc..0701de482b46b2e5b96c9d7418a48fd0e46b52ef 100644 (file)
@@ -5,11 +5,13 @@ DNS query support
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 import os
 import re
 import warnings
 from random import randint
-from typing import Any, DefaultDict, Dict, List, NamedTuple, Optional, Sequence
+from typing import Any, DefaultDict, Dict, List, NamedTuple, Sequence
 from typing import TYPE_CHECKING
 from collections import defaultdict
 
@@ -88,7 +90,7 @@ class HostPort(NamedTuple):
     host: str
     port: str
     totry: bool = False
-    target: Optional[str] = None
+    target: str | None = None
 
 
 class Rfc2782Resolver:
index 4949e26c683da38f294219130bbe4b0e8739a7b5..cc2981a21ab217e7d4601f43462e39561dca808b 100644 (file)
@@ -4,10 +4,12 @@ Mappings between PostgreSQL and Python encodings.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import re
 import string
 import codecs
-from typing import Any, Dict, Optional, TYPE_CHECKING
+from typing import Any, Dict, TYPE_CHECKING
 
 from .pq._enums import ConnStatus
 from .errors import NotSupportedError
@@ -78,7 +80,7 @@ py_codecs.update(
 pg_codecs = {v: k.encode() for k, v in _py_codecs.items()}
 
 
-def conn_encoding(conn: "Optional[BaseConnection[Any]]") -> str:
+def conn_encoding(conn: "BaseConnection[Any] | None") -> str:
     """
     Return the Python encoding name of a psycopg connection.
 
index 0c4671e2bf5fbd5d14d6c894ca4c4086afd17fc4..268872234f52f68d42960e7643cb826a396d52b5 100644 (file)
@@ -4,9 +4,11 @@ commands pipeline management
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 import logging
 from types import TracebackType
-from typing import Any, List, Optional, Union, Tuple, Type, TYPE_CHECKING
+from typing import Any, List, Union, Tuple, Type, TYPE_CHECKING
 
 from . import pq
 from . import errors as e
@@ -27,7 +29,7 @@ if TYPE_CHECKING:
 
 
 PendingResult: TypeAlias = Union[
-    None, Tuple["BaseCursor[Any, Any]", Optional[Tuple[Key, Prepare, bytes]]]
+    None, Tuple["BaseCursor[Any, Any]", Tuple[Key, Prepare, bytes] | None]
 ]
 
 FATAL_ERROR = pq.ExecStatus.FATAL_ERROR
@@ -78,7 +80,7 @@ class BasePipeline:
             yield from self._sync_gen()
         self.level += 1
 
-    def _exit(self, exc: Optional[BaseException]) -> None:
+    def _exit(self, exc: BaseException | None) -> None:
         self.level -= 1
         if self.level == 0 and self.pgconn.status != BAD:
             try:
@@ -212,9 +214,9 @@ class Pipeline(BasePipeline):
 
     def __exit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         try:
             with self._conn.lock:
@@ -252,9 +254,9 @@ class AsyncPipeline(BasePipeline):
 
     async def __aexit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         try:
             async with self._conn.lock:
index 92385c0295d3bc2d97b8350be7f7854ad6b405d9..9c017e73e9157ba0677ad50e9b9a53435daf066c 100644 (file)
@@ -4,8 +4,10 @@ Support for prepared statements
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 from enum import IntEnum, auto
-from typing import Optional, Sequence, Tuple, TYPE_CHECKING
+from typing import Sequence, Tuple, TYPE_CHECKING
 from collections import OrderedDict
 
 from . import pq
@@ -32,7 +34,7 @@ class Prepare(IntEnum):
 
 class PrepareManager:
     # Number of times a query is executed before it is prepared.
-    prepare_threshold: Optional[int] = 5
+    prepare_threshold: int | None = 5
 
     # Maximum number of prepared statements on the connection.
     prepared_max: int = 100
@@ -47,14 +49,14 @@ class PrepareManager:
         # Counter to generate prepared statements names
         self._prepared_idx = 0
 
-        self._to_flush = Deque[Optional[bytes]]()
+        self._to_flush = Deque[bytes | None]()
 
     @staticmethod
     def key(query: PostgresQuery) -> Key:
         return (query.query, query.types)
 
     def get(
-        self, query: PostgresQuery, prepare: Optional[bool] = None
+        self, query: PostgresQuery, prepare: bool | None = None
     ) -> Tuple[Prepare, bytes]:
         """
         Check if a query is prepared, tell back whether to prepare it.
@@ -122,7 +124,7 @@ class PrepareManager:
 
     def maybe_add_to_cache(
         self, query: PostgresQuery, prep: Prepare, name: bytes
-    ) -> Optional[Key]:
+    ) -> Key | None:
         """Handle 'query' for possible addition to the cache.
 
         If a new entry has been added, return its key. Return None otherwise
index dd7f54759e29fabbeef4f7be25f9d3435bceba6c..6c3b8550e6fdfd61484fbfbfc443a490a1dfb302 100644 (file)
@@ -9,7 +9,9 @@ dependencies problems).
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Any, Dict, List, Optional, Sequence, Tuple
+from __future__ import annotations
+
+from typing import Any, Dict, List, Sequence, Tuple
 from typing import DefaultDict, TYPE_CHECKING
 from collections import defaultdict
 
@@ -54,14 +56,14 @@ class Transformer(AdaptContext):
         _oid_dumpers _oid_types _row_dumpers _row_loaders
         """.split()
 
-    types: Optional[Tuple[int, ...]]
-    formats: Optional[List[pq.Format]]
+    types: Tuple[int, ...] | None
+    formats: List[pq.Format] | None
 
     _adapters: "AdaptersMap"
-    _pgresult: Optional["PGresult"]
+    _pgresult: "PGresult" | None
     _none_oid: int
 
-    def __init__(self, context: Optional[AdaptContext] = None):
+    def __init__(self, context: AdaptContext | None = None):
         self._pgresult = self.types = self.formats = None
 
         # WARNING: don't store context, or you'll create a loop with the Cursor
@@ -80,13 +82,13 @@ class Transformer(AdaptContext):
 
         # mapping fmt, oid -> Dumper instance
         # Not often used, so create it only if needed.
-        self._oid_dumpers: Optional[Tuple[OidDumperCache, OidDumperCache]]
+        self._oid_dumpers: Tuple[OidDumperCache, OidDumperCache] | None
         self._oid_dumpers = None
 
         # mapping fmt, oid -> Loader instance
         self._loaders: Tuple[LoaderCache, LoaderCache] = ({}, {})
 
-        self._row_dumpers: Optional[List[abc.Dumper]] = None
+        self._row_dumpers: List[abc.Dumper] | None = None
 
         # sequence of load functions from value to python
         # the length of the result columns
@@ -98,7 +100,7 @@ class Transformer(AdaptContext):
         self._encoding = ""
 
     @classmethod
-    def from_context(cls, context: Optional[AdaptContext]) -> "Transformer":
+    def from_context(cls, context: AdaptContext | None) -> "Transformer":
         """
         Return a Transformer from an AdaptContext.
 
@@ -110,7 +112,7 @@ class Transformer(AdaptContext):
             return cls(context)
 
     @property
-    def connection(self) -> Optional["BaseConnection[Any]"]:
+    def connection(self) -> "BaseConnection[Any]" | None:
         return self._conn
 
     @property
@@ -124,15 +126,15 @@ class Transformer(AdaptContext):
         return self._adapters
 
     @property
-    def pgresult(self) -> Optional["PGresult"]:
+    def pgresult(self) -> "PGresult" | None:
         return self._pgresult
 
     def set_pgresult(
         self,
-        result: Optional["PGresult"],
+        result: "PGresult" | None,
         *,
         set_loaders: bool = True,
-        format: Optional[pq.Format] = None,
+        format: pq.Format | None = None,
     ) -> None:
         self._pgresult = result
 
@@ -168,9 +170,9 @@ class Transformer(AdaptContext):
 
     def dump_sequence(
         self, params: Sequence[Any], formats: Sequence[PyFormat]
-    ) -> Sequence[Optional[Buffer]]:
+    ) -> Sequence[Buffer | None]:
         nparams = len(params)
-        out: List[Optional[Buffer]] = [None] * nparams
+        out: List[Buffer | None] = [None] * nparams
 
         # If we have dumpers, it means set_dumper_types had been called, in
         # which case self.types and self.formats are set to sequences of the
@@ -316,7 +318,7 @@ class Transformer(AdaptContext):
 
         return records
 
-    def load_row(self, row: int, make_row: RowMaker[Row]) -> Optional[Row]:
+    def load_row(self, row: int, make_row: RowMaker[Row]) -> Row | None:
         res = self._pgresult
         if not res:
             return None
@@ -332,7 +334,7 @@ class Transformer(AdaptContext):
 
         return make_row(record)
 
-    def load_sequence(self, record: Sequence[Optional[Buffer]]) -> Tuple[Any, ...]:
+    def load_sequence(self, record: Sequence[Buffer | None]) -> Tuple[Any, ...]:
         if len(self._row_loaders) != len(record):
             raise e.ProgrammingError(
                 f"cannot load sequence of {len(record)} items:"
index 947b51a9ed56a59e9e1393c2e3e0886bb181ab98..b868d51d03548daaac8f18d5b3b2a72cb30aada0 100644 (file)
@@ -4,8 +4,10 @@ Utility module to manipulate queries
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import re
-from typing import Any, Callable, Dict, List, Mapping, Match, NamedTuple, Optional
+from typing import Any, Callable, Dict, List, Mapping, Match, NamedTuple
 from typing import Sequence, Tuple, Union, TYPE_CHECKING
 from functools import lru_cache
 
@@ -43,20 +45,20 @@ class PostgresQuery:
     def __init__(self, transformer: "Transformer"):
         self._tx = transformer
 
-        self.params: Optional[Sequence[Optional[Buffer]]] = None
+        self.params: Sequence[Buffer | None] | None = None
         # these are tuples so they can be used as keys e.g. in prepared stmts
         self.types: Tuple[int, ...] = ()
 
         # The format requested by the user and the ones to really pass Postgres
-        self._want_formats: Optional[List[PyFormat]] = None
-        self.formats: Optional[Sequence[pq.Format]] = None
+        self._want_formats: List[PyFormat] | None = None
+        self.formats: Sequence[pq.Format] | None = None
 
         self._encoding = conn_encoding(transformer.connection)
         self._parts: List[QueryPart]
         self.query = b""
-        self._order: Optional[List[str]] = None
+        self._order: List[str] | None = None
 
-    def convert(self, query: Query, vars: Optional[Params]) -> None:
+    def convert(self, query: Query, vars: Params | None) -> None:
         """
         Set up the query and parameters to convert.
 
@@ -93,7 +95,7 @@ class PostgresQuery:
 
         self.dump(vars)
 
-    def dump(self, vars: Optional[Params]) -> None:
+    def dump(self, vars: Params | None) -> None:
         """
         Process a new set of variables on the query processed by `convert()`.
 
@@ -131,7 +133,7 @@ class PostgresQuery:
 
     @staticmethod
     def validate_and_reorder_params(
-        parts: List[QueryPart], vars: Params, order: Optional[List[str]]
+        parts: List[QueryPart], vars: Params, order: List[str] | None
     ) -> Sequence[Any]:
         """
         Verify the compatibility between a query and a set of params.
@@ -167,13 +169,13 @@ class PostgresQuery:
 
 # The type of the _query2pg() and _query2pg_nocache() methods
 _Query2Pg: TypeAlias = Callable[
-    [bytes, str], Tuple[bytes, List[PyFormat], Optional[List[str]], List[QueryPart]]
+    [bytes, str], Tuple[bytes, List[PyFormat], List[str] | None, List[QueryPart]]
 ]
 
 
 def _query2pg_nocache(
     query: bytes, encoding: str
-) -> Tuple[bytes, List[PyFormat], Optional[List[str]], List[QueryPart]]:
+) -> Tuple[bytes, List[PyFormat], List[str] | None, List[QueryPart]]:
     """
     Convert Python query and params into something Postgres understands.
 
@@ -185,7 +187,7 @@ def _query2pg_nocache(
       ``parts`` (splits of queries and placeholders).
     """
     parts = _split_query(query, encoding)
-    order: Optional[List[str]] = None
+    order: List[str] | None = None
     chunks: List[bytes] = []
     formats = []
 
@@ -236,7 +238,7 @@ class PostgresClientQuery(PostgresQuery):
 
     __slots__ = ("template",)
 
-    def convert(self, query: Query, vars: Optional[Params]) -> None:
+    def convert(self, query: Query, vars: Params | None) -> None:
         """
         Set up the query and parameters to convert.
 
@@ -266,7 +268,7 @@ class PostgresClientQuery(PostgresQuery):
 
         self.dump(vars)
 
-    def dump(self, vars: Optional[Params]) -> None:
+    def dump(self, vars: Params | None) -> None:
         """
         Process a new set of variables on the query processed by `convert()`.
 
@@ -283,18 +285,18 @@ class PostgresClientQuery(PostgresQuery):
 
 
 _Query2PgClient: TypeAlias = Callable[
-    [bytes, str], Tuple[bytes, Optional[List[str]], List[QueryPart]]
+    [bytes, str], Tuple[bytes, List[str] | None, List[QueryPart]]
 ]
 
 
 def _query2pg_client_nocache(
     query: bytes, encoding: str
-) -> Tuple[bytes, Optional[List[str]], List[QueryPart]]:
+) -> Tuple[bytes, List[str] | None, List[QueryPart]]:
     """
     Convert Python query and params into a template to perform client-side binding
     """
     parts = _split_query(query, encoding, collapse_double_percent=False)
-    order: Optional[List[str]] = None
+    order: List[str] | None = None
     chunks: List[bytes] = []
 
     if isinstance(parts[0].item, int):
@@ -345,7 +347,7 @@ _re_placeholder = re.compile(
 def _split_query(
     query: bytes, encoding: str = "ascii", collapse_double_percent: bool = True
 ) -> List[QueryPart]:
-    parts: List[Tuple[bytes, Optional[Match[bytes]]]] = []
+    parts: List[Tuple[bytes, Match[bytes] | None]] = []
     cur = 0
 
     # pairs [(fragment, match], with the last match None
index 7232a20bd90b309ccbd17de66344ecce0410e18d..6d8da5a128d369f7a0677388eebe254423f92d36 100644 (file)
@@ -4,8 +4,10 @@ Utility functions to deal with binary structs.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import struct
-from typing import Callable, cast, Optional, Protocol, Tuple
+from typing import Callable, cast, Protocol, Tuple
 
 from . import errors as e
 from .abc import Buffer
@@ -18,7 +20,7 @@ UnpackFloat: TypeAlias = Callable[[Buffer], Tuple[float]]
 
 
 class UnpackLen(Protocol):
-    def __call__(self, data: Buffer, start: Optional[int]) -> Tuple[int]: ...
+    def __call__(self, data: Buffer, start: int | None) -> Tuple[int]: ...
 
 
 pack_int2 = cast(PackInt, struct.Struct("!h").pack)
index 35281881ce71f3608cc8d647d2b21edd39d1f61d..839db682902827161d17fb6220a1ba95430ac7ed 100644 (file)
@@ -4,10 +4,12 @@ psycopg two-phase commit support
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 import re
 import datetime as dt
 from base64 import b64encode, b64decode
-from typing import Optional, Union
+from typing import Union
 from dataclasses import dataclass, replace
 
 _re_xid = re.compile(r"^(\d+)_([^_]*)_([^_]*)$")
@@ -22,12 +24,12 @@ class Xid:
 
     """
 
-    format_id: Optional[int]
+    format_id: int | None
     gtrid: str
-    bqual: Optional[str]
-    prepared: Optional[dt.datetime] = None
-    owner: Optional[str] = None
-    database: Optional[str] = None
+    bqual: str | None
+    prepared: dt.datetime | None = None
+    owner: str | None = None
+    database: str | None = None
 
     @classmethod
     def from_string(cls, s: str) -> "Xid":
@@ -61,9 +63,7 @@ class Xid:
         return cls.from_parts(format_id, gtrid, bqual)
 
     @classmethod
-    def from_parts(
-        cls, format_id: Optional[int], gtrid: str, bqual: Optional[str]
-    ) -> "Xid":
+    def from_parts(cls, format_id: int | None, gtrid: str, bqual: str | None) -> "Xid":
         if format_id is not None:
             if bqual is None:
                 raise TypeError("if format_id is specified, bqual must be too")
index 813ed62617fd929a499e5fdc980855363caaa663..b7ae957398e0e425587b55d1e82932c5a76aebc3 100644 (file)
@@ -4,8 +4,10 @@ Timezone utility functions.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import logging
-from typing import Dict, Optional, Union
+from typing import Dict, Union
 from datetime import timezone, tzinfo
 
 from .pq.abc import PGconn
@@ -19,7 +21,7 @@ _timezones: Dict[Union[None, bytes], tzinfo] = {
 }
 
 
-def get_tzinfo(pgconn: Optional[PGconn]) -> tzinfo:
+def get_tzinfo(pgconn: PGconn | None) -> tzinfo:
     """Return the Python timezone info of the connection's timezone."""
     tzname = pgconn.parameter_status(b"TimeZone") if pgconn else None
     try:
index 11e10b161d0d76a57013a522b8af16d81f3377b6..74bc3f1be690ea14cb8e785e1bc91067917595db 100644 (file)
@@ -4,8 +4,10 @@ Protocol objects representing different implementations of the same classes.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 from typing import Any, Dict, Callable, Generator, Mapping
-from typing import List, Optional, Protocol, Sequence, Tuple, Union
+from typing import List, Protocol, Sequence, Tuple, Union
 from typing import TYPE_CHECKING
 
 from . import pq
@@ -56,13 +58,13 @@ class WaitFunc(Protocol):
     """
 
     def __call__(
-        self, gen: PQGen[RV], fileno: int, interval: Optional[float] = None
+        self, gen: PQGen[RV], fileno: int, interval: float | None = None
     ) -> RV: ...
 
 
 # Adaptation types
 
-DumpFunc: TypeAlias = Callable[[Any], Optional[Buffer]]
+DumpFunc: TypeAlias = Callable[[Any], Buffer | None]
 LoadFunc: TypeAlias = Callable[[Buffer], Any]
 
 
@@ -84,7 +86,7 @@ class AdaptContext(Protocol):
         ...
 
     @property
-    def connection(self) -> Optional["BaseConnection[Any]"]:
+    def connection(self) -> "BaseConnection[Any]" | None:
         """The connection used by this object, if available.
 
         :rtype: `~psycopg.Connection` or `~psycopg.AsyncConnection` or `!None`
@@ -108,9 +110,9 @@ class Dumper(Protocol):
     oid: int
     """The oid to pass to the server, if known; 0 otherwise (class attribute)."""
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None): ...
+    def __init__(self, cls: type, context: AdaptContext | None = None): ...
 
-    def dump(self, obj: Any) -> Optional[Buffer]:
+    def dump(self, obj: Any) -> Buffer | None:
         """Convert the object `!obj` to PostgreSQL representation.
 
         :param obj: the object to convert.
@@ -188,7 +190,7 @@ class Loader(Protocol):
     This is a class attribute.
     """
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None): ...
+    def __init__(self, oid: int, context: AdaptContext | None = None): ...
 
     def load(self, data: Buffer) -> Any:
         """
@@ -200,16 +202,16 @@ class Loader(Protocol):
 
 
 class Transformer(Protocol):
-    types: Optional[Tuple[int, ...]]
-    formats: Optional[List[pq.Format]]
+    types: Tuple[int, ...] | None
+    formats: List[pq.Format] | None
 
-    def __init__(self, context: Optional[AdaptContext] = None): ...
+    def __init__(self, context: AdaptContext | None = None): ...
 
     @classmethod
-    def from_context(cls, context: Optional[AdaptContext]) -> "Transformer": ...
+    def from_context(cls, context: AdaptContext | None) -> "Transformer": ...
 
     @property
-    def connection(self) -> Optional["BaseConnection[Any]"]: ...
+    def connection(self) -> "BaseConnection[Any]" | None: ...
 
     @property
     def encoding(self) -> str: ...
@@ -218,14 +220,14 @@ class Transformer(Protocol):
     def adapters(self) -> "AdaptersMap": ...
 
     @property
-    def pgresult(self) -> Optional["PGresult"]: ...
+    def pgresult(self) -> "PGresult" | None: ...
 
     def set_pgresult(
         self,
-        result: Optional["PGresult"],
+        result: "PGresult" | None,
         *,
         set_loaders: bool = True,
-        format: Optional[pq.Format] = None
+        format: pq.Format | None = None,
     ) -> None: ...
 
     def set_dumper_types(self, types: Sequence[int], format: pq.Format) -> None: ...
@@ -234,7 +236,7 @@ class Transformer(Protocol):
 
     def dump_sequence(
         self, params: Sequence[Any], formats: Sequence[PyFormat]
-    ) -> Sequence[Optional[Buffer]]: ...
+    ) -> Sequence[Buffer | None]: ...
 
     def as_literal(self, obj: Any) -> bytes: ...
 
@@ -244,8 +246,8 @@ class Transformer(Protocol):
         self, row0: int, row1: int, make_row: "RowMaker[Row]"
     ) -> List["Row"]: ...
 
-    def load_row(self, row: int, make_row: "RowMaker[Row]") -> Optional["Row"]: ...
+    def load_row(self, row: int, make_row: "RowMaker[Row]") -> "Row" | None: ...
 
-    def load_sequence(self, record: Sequence[Optional[Buffer]]) -> Tuple[Any, ...]: ...
+    def load_sequence(self, record: Sequence[Buffer | None]) -> Tuple[Any, ...]: ...
 
     def get_loader(self, oid: int, format: pq.Format) -> Loader: ...
index 07b7b9a5b7e0465f106874f15c5cb75246e7a72e..fa590332cf3dd8bff4cedfba3240f9af9b771d4f 100644 (file)
@@ -4,8 +4,10 @@ Entry point into the adaptation system.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 from abc import ABC, abstractmethod
-from typing import Any, Optional, TYPE_CHECKING
+from typing import Any, TYPE_CHECKING
 
 from . import pq, abc
 
@@ -33,11 +35,10 @@ class Dumper(abc.Dumper, ABC):
     format: pq.Format = pq.Format.TEXT
     """The format of the data dumped."""
 
-    def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, cls: type, context: abc.AdaptContext | None = None):
         self.cls = cls
-        self.connection: Optional["BaseConnection[Any]"] = (
-            context.connection if context else None
-        )
+        self.connection: "BaseConnection[Any]" | None
+        self.connection = context.connection if context else None
 
     def __repr__(self) -> str:
         return (
@@ -46,7 +47,7 @@ class Dumper(abc.Dumper, ABC):
         )
 
     @abstractmethod
-    def dump(self, obj: Any) -> Optional[Buffer]: ...
+    def dump(self, obj: Any) -> Buffer | None: ...
 
     def quote(self, obj: Any) -> Buffer:
         """
@@ -125,11 +126,10 @@ class Loader(abc.Loader, ABC):
     format: pq.Format = pq.Format.TEXT
     """The format of the data loaded."""
 
-    def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, oid: int, context: abc.AdaptContext | None = None):
         self.oid = oid
-        self.connection: Optional["BaseConnection[Any]"] = (
-            context.connection if context else None
-        )
+        self.connection: "BaseConnection[Any]" | None
+        self.connection = context.connection if context else None
 
     @abstractmethod
     def load(self, data: Buffer) -> Any:
@@ -140,7 +140,7 @@ class Loader(abc.Loader, ABC):
 class RecursiveDumper(Dumper):
     """Dumper with a transformer to help dumping recursive types."""
 
-    def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, cls: type, context: abc.AdaptContext | None = None):
         super().__init__(cls, context)
         self._tx = Transformer.from_context(context)
 
@@ -148,6 +148,6 @@ class RecursiveDumper(Dumper):
 class RecursiveLoader(Loader):
     """Loader with a transformer to help loading recursive types."""
 
-    def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, oid: int, context: abc.AdaptContext | None = None):
         super().__init__(oid, context)
         self._tx = Transformer.from_context(context)
index 24d7b45cb241df2dab76051b48fadf3c2759a108..48630758b59a80fe46654e226b18deb9a43bd85b 100644 (file)
@@ -4,7 +4,9 @@ psycopg client-side binding cursors
 
 # Copyright (C) 2022 The Psycopg Team
 
-from typing import Optional, Tuple, TYPE_CHECKING
+from __future__ import annotations
+
+from typing import Tuple, TYPE_CHECKING
 from functools import partial
 
 from ._queries import PostgresQuery, PostgresClientQuery
@@ -31,7 +33,7 @@ BINARY = pq.Format.BINARY
 class ClientCursorMixin(BaseCursor[ConnectionType, Row]):
     _query_cls = PostgresClientQuery
 
-    def mogrify(self, query: Query, params: Optional[Params] = None) -> str:
+    def mogrify(self, query: Query, params: Params | None = None) -> str:
         """
         Return the query and parameters merged.
 
@@ -48,7 +50,7 @@ class ClientCursorMixin(BaseCursor[ConnectionType, Row]):
         query: PostgresQuery,
         *,
         force_extended: bool = False,
-        binary: Optional[bool] = None,
+        binary: bool | None = None,
     ) -> None:
         if binary is None:
             fmt = self.format
@@ -76,7 +78,7 @@ class ClientCursorMixin(BaseCursor[ConnectionType, Row]):
             self._pgconn.send_query(query.query)
 
     def _get_prepared(
-        self, pgq: PostgresQuery, prepare: Optional[bool] = None
+        self, pgq: PostgresQuery, prepare: bool | None = None
     ) -> Tuple[Prepare, bytes]:
         return (Prepare.NO, b"")
 
index c2be01560e2d456d01d8c214ddb8da1343003e2a..7adad16c401cefe79a871b4f347525aaf2ab8233 100644 (file)
@@ -12,7 +12,7 @@ from __future__ import annotations
 import logging
 from time import monotonic
 from types import TracebackType
-from typing import Any, Generator, Iterator, List, Optional
+from typing import Any, Generator, Iterator, List
 from typing import Type, Union, cast, overload, TYPE_CHECKING
 from contextlib import contextmanager
 
@@ -65,7 +65,7 @@ class Connection(BaseConnection[Row]):
     cursor_factory: Type[Cursor[Row]]
     server_cursor_factory: Type[ServerCursor[Row]]
     row_factory: RowFactory[Row]
-    _pipeline: Optional[Pipeline]
+    _pipeline: Pipeline | None
 
     def __init__(
         self,
@@ -84,10 +84,10 @@ class Connection(BaseConnection[Row]):
         conninfo: str = "",
         *,
         autocommit: bool = False,
-        prepare_threshold: Optional[int] = 5,
-        context: Optional[AdaptContext] = None,
-        row_factory: Optional[RowFactory[Row]] = None,
-        cursor_factory: Optional[Type[Cursor[Row]]] = None,
+        prepare_threshold: int | None = 5,
+        context: AdaptContext | None = None,
+        row_factory: RowFactory[Row] | None = None,
+        cursor_factory: Type[Cursor[Row]] | None = None,
         **kwargs: ConnParam,
     ) -> Self:
         """
@@ -135,9 +135,9 @@ class Connection(BaseConnection[Row]):
 
     def __exit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         if self.closed:
             return
@@ -185,7 +185,7 @@ class Connection(BaseConnection[Row]):
         name: str,
         *,
         binary: bool = False,
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ) -> ServerCursor[Row]: ...
 
@@ -196,7 +196,7 @@ class Connection(BaseConnection[Row]):
         *,
         binary: bool = False,
         row_factory: RowFactory[CursorRow],
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ) -> ServerCursor[CursorRow]: ...
 
@@ -205,8 +205,8 @@ class Connection(BaseConnection[Row]):
         name: str = "",
         *,
         binary: bool = False,
-        row_factory: Optional[RowFactory[Any]] = None,
-        scrollable: Optional[bool] = None,
+        row_factory: RowFactory[Any] | None = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ) -> Union[Cursor[Any], ServerCursor[Any]]:
         """
@@ -237,9 +237,9 @@ class Connection(BaseConnection[Row]):
     def execute(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        prepare: Optional[bool] = None,
+        prepare: bool | None = None,
         binary: bool = False,
     ) -> Cursor[Row]:
         """Execute a query and return a cursor to read its results."""
@@ -296,7 +296,7 @@ class Connection(BaseConnection[Row]):
 
     @contextmanager
     def transaction(
-        self, savepoint_name: Optional[str] = None, force_rollback: bool = False
+        self, savepoint_name: str | None = None, force_rollback: bool = False
     ) -> Iterator[Transaction]:
         """
         Start a context block with a new transaction or nested transaction.
@@ -316,7 +316,7 @@ class Connection(BaseConnection[Row]):
                 yield tx
 
     def notifies(
-        self, *, timeout: Optional[float] = None, stop_after: Optional[int] = None
+        self, *, timeout: float | None = None, stop_after: int | None = None
     ) -> Generator[Notify, None, None]:
         """
         Yield `Notify` objects as soon as they are received from the database.
@@ -386,7 +386,7 @@ class Connection(BaseConnection[Row]):
                     assert pipeline is self._pipeline
                     self._pipeline = None
 
-    def wait(self, gen: PQGen[RV], interval: Optional[float] = _WAIT_INTERVAL) -> RV:
+    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
         """
         Consume a generator operating on the connection.
 
@@ -414,26 +414,26 @@ class Connection(BaseConnection[Row]):
         with self.lock:
             self.wait(self._set_autocommit_gen(value))
 
-    def _set_isolation_level(self, value: Optional[IsolationLevel]) -> None:
+    def _set_isolation_level(self, value: IsolationLevel | None) -> None:
         self.set_isolation_level(value)
 
-    def set_isolation_level(self, value: Optional[IsolationLevel]) -> None:
+    def set_isolation_level(self, value: IsolationLevel | None) -> None:
         """Method version of the `~Connection.isolation_level` setter."""
         with self.lock:
             self.wait(self._set_isolation_level_gen(value))
 
-    def _set_read_only(self, value: Optional[bool]) -> None:
+    def _set_read_only(self, value: bool | None) -> None:
         self.set_read_only(value)
 
-    def set_read_only(self, value: Optional[bool]) -> None:
+    def set_read_only(self, value: bool | None) -> None:
         """Method version of the `~Connection.read_only` setter."""
         with self.lock:
             self.wait(self._set_read_only_gen(value))
 
-    def _set_deferrable(self, value: Optional[bool]) -> None:
+    def _set_deferrable(self, value: bool | None) -> None:
         self.set_deferrable(value)
 
-    def set_deferrable(self, value: Optional[bool]) -> None:
+    def set_deferrable(self, value: bool | None) -> None:
         """Method version of the `~Connection.deferrable` setter."""
         with self.lock:
             self.wait(self._set_deferrable_gen(value))
index b0c8b753e2076f124a7230604ee72ac1b3ea382e..cf3f7230dd3c653177bdf5ed389edc772dd6dc06 100644 (file)
@@ -9,7 +9,7 @@ from __future__ import annotations
 import logging
 from time import monotonic
 from types import TracebackType
-from typing import Any, AsyncGenerator, AsyncIterator, List, Optional
+from typing import Any, AsyncGenerator, AsyncIterator, List
 from typing import Type, Union, cast, overload, TYPE_CHECKING
 from contextlib import asynccontextmanager
 
@@ -71,7 +71,7 @@ class AsyncConnection(BaseConnection[Row]):
     cursor_factory: Type[AsyncCursor[Row]]
     server_cursor_factory: Type[AsyncServerCursor[Row]]
     row_factory: AsyncRowFactory[Row]
-    _pipeline: Optional[AsyncPipeline]
+    _pipeline: AsyncPipeline | None
 
     def __init__(
         self,
@@ -90,10 +90,10 @@ class AsyncConnection(BaseConnection[Row]):
         conninfo: str = "",
         *,
         autocommit: bool = False,
-        prepare_threshold: Optional[int] = 5,
-        context: Optional[AdaptContext] = None,
-        row_factory: Optional[AsyncRowFactory[Row]] = None,
-        cursor_factory: Optional[Type[AsyncCursor[Row]]] = None,
+        prepare_threshold: int | None = 5,
+        context: AdaptContext | None = None,
+        row_factory: AsyncRowFactory[Row] | None = None,
+        cursor_factory: Type[AsyncCursor[Row]] | None = None,
         **kwargs: ConnParam,
     ) -> Self:
         """
@@ -151,9 +151,9 @@ class AsyncConnection(BaseConnection[Row]):
 
     async def __aexit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         if self.closed:
             return
@@ -201,7 +201,7 @@ class AsyncConnection(BaseConnection[Row]):
         name: str,
         *,
         binary: bool = False,
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ) -> AsyncServerCursor[Row]: ...
 
@@ -212,7 +212,7 @@ class AsyncConnection(BaseConnection[Row]):
         *,
         binary: bool = False,
         row_factory: AsyncRowFactory[CursorRow],
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ) -> AsyncServerCursor[CursorRow]: ...
 
@@ -221,8 +221,8 @@ class AsyncConnection(BaseConnection[Row]):
         name: str = "",
         *,
         binary: bool = False,
-        row_factory: Optional[AsyncRowFactory[Any]] = None,
-        scrollable: Optional[bool] = None,
+        row_factory: AsyncRowFactory[Any] | None = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ) -> Union[AsyncCursor[Any], AsyncServerCursor[Any]]:
         """
@@ -253,9 +253,9 @@ class AsyncConnection(BaseConnection[Row]):
     async def execute(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        prepare: Optional[bool] = None,
+        prepare: bool | None = None,
         binary: bool = False,
     ) -> AsyncCursor[Row]:
         """Execute a query and return a cursor to read its results."""
@@ -316,7 +316,7 @@ class AsyncConnection(BaseConnection[Row]):
 
     @asynccontextmanager
     async def transaction(
-        self, savepoint_name: Optional[str] = None, force_rollback: bool = False
+        self, savepoint_name: str | None = None, force_rollback: bool = False
     ) -> AsyncIterator[AsyncTransaction]:
         """
         Start a context block with a new transaction or nested transaction.
@@ -336,7 +336,7 @@ class AsyncConnection(BaseConnection[Row]):
                 yield tx
 
     async def notifies(
-        self, *, timeout: Optional[float] = None, stop_after: Optional[int] = None
+        self, *, timeout: float | None = None, stop_after: int | None = None
     ) -> AsyncGenerator[Notify, None]:
         """
         Yield `Notify` objects as soon as they are received from the database.
@@ -406,9 +406,7 @@ class AsyncConnection(BaseConnection[Row]):
                     assert pipeline is self._pipeline
                     self._pipeline = None
 
-    async def wait(
-        self, gen: PQGen[RV], interval: Optional[float] = _WAIT_INTERVAL
-    ) -> RV:
+    async def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
         """
         Consume a generator operating on the connection.
 
@@ -439,35 +437,35 @@ class AsyncConnection(BaseConnection[Row]):
         async with self.lock:
             await self.wait(self._set_autocommit_gen(value))
 
-    def _set_isolation_level(self, value: Optional[IsolationLevel]) -> None:
+    def _set_isolation_level(self, value: IsolationLevel | None) -> None:
         if True:  # ASYNC
             self._no_set_async("isolation_level")
         else:
             self.set_isolation_level(value)
 
-    async def set_isolation_level(self, value: Optional[IsolationLevel]) -> None:
+    async def set_isolation_level(self, value: IsolationLevel | None) -> None:
         """Method version of the `~Connection.isolation_level` setter."""
         async with self.lock:
             await self.wait(self._set_isolation_level_gen(value))
 
-    def _set_read_only(self, value: Optional[bool]) -> None:
+    def _set_read_only(self, value: bool | None) -> None:
         if True:  # ASYNC
             self._no_set_async("read_only")
         else:
             self.set_read_only(value)
 
-    async def set_read_only(self, value: Optional[bool]) -> None:
+    async def set_read_only(self, value: bool | None) -> None:
         """Method version of the `~Connection.read_only` setter."""
         async with self.lock:
             await self.wait(self._set_read_only_gen(value))
 
-    def _set_deferrable(self, value: Optional[bool]) -> None:
+    def _set_deferrable(self, value: bool | None) -> None:
         if True:  # ASYNC
             self._no_set_async("deferrable")
         else:
             self.set_deferrable(value)
 
-    async def set_deferrable(self, value: Optional[bool]) -> None:
+    async def set_deferrable(self, value: bool | None) -> None:
         """Method version of the `~Connection.deferrable` setter."""
         async with self.lock:
             await self.wait(self._set_deferrable_gen(value))
index d4690045ba8d37faf32b581536ad5c94725c556c..950b6d66e40b1de5f0f64994654a9a08c2387d92 100644 (file)
@@ -4,8 +4,10 @@ CockroachDB-specific connections.
 
 # Copyright (C) 2022 The Psycopg Team
 
+from __future__ import annotations
+
 import re
-from typing import Any, Optional, Union, TYPE_CHECKING
+from typing import Any, Union, TYPE_CHECKING
 
 from .. import errors as e
 from ..rows import Row
@@ -20,7 +22,7 @@ if TYPE_CHECKING:
 
 
 class _CrdbConnectionMixin:
-    _adapters: Optional[AdaptersMap]
+    _adapters: AdaptersMap | None
     pgconn: "PGconn"
 
     @classmethod
@@ -97,7 +99,7 @@ class CrdbConnectionInfo(ConnectionInfo):
         return ver
 
     @classmethod
-    def parse_crdb_version(self, sver: str) -> Optional[int]:
+    def parse_crdb_version(self, sver: str) -> int | None:
         m = re.search(r"\bv(\d+)\.(\d+)\.(\d+)", sver)
         if not m:
             return None
index 42d5d8e453b2055f2283c6dd056befeb59035d41..9ef66b852bd91d6e449e181290f90206ed8f4c66 100644 (file)
@@ -10,7 +10,7 @@ Psycopg Cursor object.
 from __future__ import annotations
 
 from types import TracebackType
-from typing import Any, Iterator, Iterable, List, Optional, Type
+from typing import Any, Iterator, Iterable, List, Type
 from typing import TYPE_CHECKING, overload
 from contextlib import contextmanager
 
@@ -42,10 +42,7 @@ class Cursor(BaseCursor["Connection[Any]", Row]):
     ): ...
 
     def __init__(
-        self,
-        connection: Connection[Any],
-        *,
-        row_factory: Optional[RowFactory[Row]] = None,
+        self, connection: Connection[Any], *, row_factory: RowFactory[Row] | None = None
     ):
         super().__init__(connection)
         self._row_factory = row_factory or connection.row_factory
@@ -55,9 +52,9 @@ class Cursor(BaseCursor["Connection[Any]", Row]):
 
     def __exit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         self.close()
 
@@ -84,10 +81,10 @@ class Cursor(BaseCursor["Connection[Any]", Row]):
     def execute(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        prepare: Optional[bool] = None,
-        binary: Optional[bool] = None,
+        prepare: bool | None = None,
+        binary: bool | None = None,
     ) -> Self:
         """
         Execute a query or command to the database.
@@ -132,11 +129,7 @@ class Cursor(BaseCursor["Connection[Any]", Row]):
             raise ex.with_traceback(None)
 
     def stream(
-        self,
-        query: Query,
-        params: Optional[Params] = None,
-        *,
-        binary: Optional[bool] = None,
+        self, query: Query, params: Params | None = None, *, binary: bool | None = None
     ) -> Iterator[Row]:
         """
         Iterate row-by-row on a result from the database.
@@ -173,13 +166,13 @@ class Cursor(BaseCursor["Connection[Any]", Row]):
                     except Exception:
                         pass
 
-    def fetchone(self) -> Optional[Row]:
+    def fetchone(self) -> Row | None:
         """
         Return the next record from the current recordset.
 
         Return `!None` the recordset is finished.
 
-        :rtype: Optional[Row], with Row defined by `row_factory`
+        :rtype: Row | None, with Row defined by `row_factory`
         """
         self._fetch_pipeline()
         self._check_result_for_fetch()
@@ -225,7 +218,7 @@ class Cursor(BaseCursor["Connection[Any]", Row]):
         self._fetch_pipeline()
         self._check_result_for_fetch()
 
-        def load(pos: int) -> Optional[Row]:
+        def load(pos: int) -> Row | None:
             return self._tx.load_row(pos, self._make_row)
 
         while True:
@@ -253,9 +246,9 @@ class Cursor(BaseCursor["Connection[Any]", Row]):
     def copy(
         self,
         statement: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        writer: Optional[Writer] = None,
+        writer: Writer | None = None,
     ) -> Iterator[Copy]:
         """
         Initiate a :sql:`COPY` operation and return an object to manage it.
index 37a0d255f92cb81336c284b4773f42029e0a6774..12c066b6c347bc6591ec65d3275275e8b2a54fba 100644 (file)
@@ -7,7 +7,7 @@ Psycopg AsyncCursor object.
 from __future__ import annotations
 
 from types import TracebackType
-from typing import Any, AsyncIterator, Iterable, List, Optional, Type
+from typing import Any, AsyncIterator, Iterable, List, Type
 from typing import TYPE_CHECKING, overload
 from contextlib import asynccontextmanager
 
@@ -42,7 +42,7 @@ class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]):
         self,
         connection: AsyncConnection[Any],
         *,
-        row_factory: Optional[AsyncRowFactory[Row]] = None,
+        row_factory: AsyncRowFactory[Row] | None = None,
     ):
         super().__init__(connection)
         self._row_factory = row_factory or connection.row_factory
@@ -52,9 +52,9 @@ class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]):
 
     async def __aexit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         await self.close()
 
@@ -81,10 +81,10 @@ class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]):
     async def execute(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        prepare: Optional[bool] = None,
-        binary: Optional[bool] = None,
+        prepare: bool | None = None,
+        binary: bool | None = None,
     ) -> Self:
         """
         Execute a query or command to the database.
@@ -133,11 +133,7 @@ class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]):
             raise ex.with_traceback(None)
 
     async def stream(
-        self,
-        query: Query,
-        params: Optional[Params] = None,
-        *,
-        binary: Optional[bool] = None,
+        self, query: Query, params: Params | None = None, *, binary: bool | None = None
     ) -> AsyncIterator[Row]:
         """
         Iterate row-by-row on a result from the database.
@@ -180,13 +176,13 @@ class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]):
                     except Exception:
                         pass
 
-    async def fetchone(self) -> Optional[Row]:
+    async def fetchone(self) -> Row | None:
         """
         Return the next record from the current recordset.
 
         Return `!None` the recordset is finished.
 
-        :rtype: Optional[Row], with Row defined by `row_factory`
+        :rtype: Row | None, with Row defined by `row_factory`
         """
         await self._fetch_pipeline()
         self._check_result_for_fetch()
@@ -234,7 +230,7 @@ class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]):
         await self._fetch_pipeline()
         self._check_result_for_fetch()
 
-        def load(pos: int) -> Optional[Row]:
+        def load(pos: int) -> Row | None:
             return self._tx.load_row(pos, self._make_row)
 
         while True:
@@ -262,9 +258,9 @@ class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]):
     async def copy(
         self,
         statement: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        writer: Optional[AsyncWriter] = None,
+        writer: AsyncWriter | None = None,
     ) -> AsyncIterator[AsyncCopy]:
         """
         Initiate a :sql:`COPY` operation and return an object to manage it.
index 919b0506c79c976d6a4154c47fac6a8c3cb2fd07..2536f3bcd563b6fdba608fb8573a217092761687 100644 (file)
@@ -4,10 +4,12 @@ Compatibility objects with DBAPI 2.0
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import time
 import datetime as dt
 from math import floor
-from typing import Any, Optional, Sequence, Union
+from typing import Any, Sequence, Union
 
 from . import _oids
 from .abc import AdaptContext, Buffer
@@ -76,7 +78,7 @@ class Binary:
 
 
 class BinaryBinaryDumper(BytesBinaryDumper):
-    def dump(self, obj: Union[Buffer, Binary]) -> Optional[Buffer]:
+    def dump(self, obj: Union[Buffer, Binary]) -> Buffer | None:
         if isinstance(obj, Binary):
             return super().dump(obj.obj)
         else:
@@ -84,7 +86,7 @@ class BinaryBinaryDumper(BytesBinaryDumper):
 
 
 class BinaryTextDumper(BytesDumper):
-    def dump(self, obj: Union[Buffer, Binary]) -> Optional[Buffer]:
+    def dump(self, obj: Union[Buffer, Binary]) -> Buffer | None:
         if isinstance(obj, Binary):
             return super().dump(obj.obj)
         else:
index 0f5218ba59b9d8b987ec54101c6a654e168d3b1e..082976be9d0b3810281123857b1b29386928dd1b 100644 (file)
@@ -18,8 +18,10 @@ DBAPI-defined Exceptions are defined in the following hierarchy::
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 from dataclasses import dataclass, field, fields
-from typing import Any, Callable, Dict, List, NoReturn, Optional, Sequence, Tuple, Type
+from typing import Any, Callable, Dict, List, NoReturn, Sequence, Tuple, Type
 from typing import Union, TYPE_CHECKING
 from asyncio import CancelledError
 
@@ -30,7 +32,7 @@ from ._compat import TypeAlias, TypeGuard
 if TYPE_CHECKING:
     from .pq.misc import PGnotify, ConninfoOption
 
-ErrorInfo: TypeAlias = Union[None, PGresult, Dict[int, Optional[bytes]]]
+ErrorInfo: TypeAlias = Union[None, PGresult, Dict[int, bytes | None]]
 
 _sqlcodes: Dict[str, "Type[Error]"] = {}
 
@@ -67,8 +69,8 @@ class FinishedPGconn:
 
     nonblocking: int = 0
 
-    notice_handler: Optional[Callable[["PGresult"], None]] = None
-    notify_handler: Optional[Callable[["PGnotify"], None]] = None
+    notice_handler: Callable[["PGresult"], None] | None = None
+    notify_handler: Callable[["PGnotify"], None] | None = None
 
     @staticmethod
     def _raise() -> NoReturn:
@@ -256,14 +258,14 @@ class Error(Exception):
 
     __module__ = "psycopg"
 
-    sqlstate: Optional[str] = None
+    sqlstate: str | None = None
 
     def __init__(
         self,
         *args: Sequence[Any],
         info: ErrorInfo = None,
         encoding: str = "utf-8",
-        pgconn: Optional[PGconn] = None,
+        pgconn: PGconn | None = None,
     ):
         super().__init__(*args)
         self._info = info
@@ -275,18 +277,18 @@ class Error(Exception):
             self.sqlstate = self.diag.sqlstate
 
     @property
-    def pgconn(self) -> Optional[PGconn]:
+    def pgconn(self) -> PGconn | None:
         """The connection object, if the error was raised from a connection attempt.
 
-        :rtype: Optional[psycopg.pq.PGconn]
+        :rtype: psycopg.pq.PGconn | None
         """
         return self._pgconn if self._pgconn else None
 
     @property
-    def pgresult(self) -> Optional[PGresult]:
+    def pgresult(self) -> PGresult | None:
         """The result object, if the exception was raised after a failed query.
 
-        :rtype: Optional[psycopg.pq.PGresult]
+        :rtype: psycopg.pq.PGresult | None
         """
         return self._info if _is_pgresult(self._info) else None
 
@@ -322,7 +324,7 @@ class DatabaseError(Error):
 
     __module__ = "psycopg"
 
-    def __init_subclass__(cls, code: Optional[str] = None, name: Optional[str] = None):
+    def __init_subclass__(cls, code: str | None = None, name: str | None = None):
         if code:
             _sqlcodes[code] = cls
             cls.sqlstate = code
@@ -429,78 +431,78 @@ class Diagnostic:
         self._encoding = encoding
 
     @property
-    def severity(self) -> Optional[str]:
+    def severity(self) -> str | None:
         return self._error_message(DiagnosticField.SEVERITY)
 
     @property
-    def severity_nonlocalized(self) -> Optional[str]:
+    def severity_nonlocalized(self) -> str | None:
         return self._error_message(DiagnosticField.SEVERITY_NONLOCALIZED)
 
     @property
-    def sqlstate(self) -> Optional[str]:
+    def sqlstate(self) -> str | None:
         return self._error_message(DiagnosticField.SQLSTATE)
 
     @property
-    def message_primary(self) -> Optional[str]:
+    def message_primary(self) -> str | None:
         return self._error_message(DiagnosticField.MESSAGE_PRIMARY)
 
     @property
-    def message_detail(self) -> Optional[str]:
+    def message_detail(self) -> str | None:
         return self._error_message(DiagnosticField.MESSAGE_DETAIL)
 
     @property
-    def message_hint(self) -> Optional[str]:
+    def message_hint(self) -> str | None:
         return self._error_message(DiagnosticField.MESSAGE_HINT)
 
     @property
-    def statement_position(self) -> Optional[str]:
+    def statement_position(self) -> str | None:
         return self._error_message(DiagnosticField.STATEMENT_POSITION)
 
     @property
-    def internal_position(self) -> Optional[str]:
+    def internal_position(self) -> str | None:
         return self._error_message(DiagnosticField.INTERNAL_POSITION)
 
     @property
-    def internal_query(self) -> Optional[str]:
+    def internal_query(self) -> str | None:
         return self._error_message(DiagnosticField.INTERNAL_QUERY)
 
     @property
-    def context(self) -> Optional[str]:
+    def context(self) -> str | None:
         return self._error_message(DiagnosticField.CONTEXT)
 
     @property
-    def schema_name(self) -> Optional[str]:
+    def schema_name(self) -> str | None:
         return self._error_message(DiagnosticField.SCHEMA_NAME)
 
     @property
-    def table_name(self) -> Optional[str]:
+    def table_name(self) -> str | None:
         return self._error_message(DiagnosticField.TABLE_NAME)
 
     @property
-    def column_name(self) -> Optional[str]:
+    def column_name(self) -> str | None:
         return self._error_message(DiagnosticField.COLUMN_NAME)
 
     @property
-    def datatype_name(self) -> Optional[str]:
+    def datatype_name(self) -> str | None:
         return self._error_message(DiagnosticField.DATATYPE_NAME)
 
     @property
-    def constraint_name(self) -> Optional[str]:
+    def constraint_name(self) -> str | None:
         return self._error_message(DiagnosticField.CONSTRAINT_NAME)
 
     @property
-    def source_file(self) -> Optional[str]:
+    def source_file(self) -> str | None:
         return self._error_message(DiagnosticField.SOURCE_FILE)
 
     @property
-    def source_line(self) -> Optional[str]:
+    def source_line(self) -> str | None:
         return self._error_message(DiagnosticField.SOURCE_LINE)
 
     @property
-    def source_function(self) -> Optional[str]:
+    def source_function(self) -> str | None:
         return self._error_message(DiagnosticField.SOURCE_FUNCTION)
 
-    def _error_message(self, field: DiagnosticField) -> Optional[str]:
+    def _error_message(self, field: DiagnosticField) -> str | None:
         if self._info:
             if isinstance(self._info, dict):
                 val = self._info.get(field)
index 96cc3dea35dff8df581f91682b1545783a17e3fb..823c655358e2ac756616954eca5a71a1a5727d2d 100644 (file)
@@ -20,9 +20,11 @@ generator should probably yield the same value again in order to wait more.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import logging
 from time import monotonic
-from typing import List, Optional, Union
+from typing import List, Union
 
 from . import pq
 from . import errors as e
@@ -195,7 +197,7 @@ def _fetch_many(pgconn: PGconn) -> PQGen[List[PGresult]]:
     return results
 
 
-def _fetch(pgconn: PGconn) -> PQGen[Optional[PGresult]]:
+def _fetch(pgconn: PGconn) -> PQGen[PGresult | None]:
     """
     Generator retrieving a single result from the database without blocking.
 
@@ -361,7 +363,7 @@ def copy_to(pgconn: PGconn, buffer: Buffer, flush: bool = True) -> PQGen[None]:
                 break
 
 
-def copy_end(pgconn: PGconn, error: Optional[bytes]) -> PQGen[PGresult]:
+def copy_end(pgconn: PGconn, error: bytes | None) -> PQGen[PGresult]:
     # Retry enqueuing end copy message until successful
     while pgconn.put_copy_end(error) == 0:
         while True:
index a76a898713b514f9f84c901a5dd2431f1ed0b53d..101ec838462afcd9255ffc3a236fe5d9512586be 100644 (file)
@@ -4,6 +4,8 @@ libpq access using ctypes
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import sys
 import ctypes
 import ctypes.util
@@ -769,7 +771,7 @@ def generate_stub() -> None:
             if narg is not None:
                 return "bytes"
             else:
-                return "Optional[bytes]"
+                return "bytes | None"
 
         elif t.__name__ in (
             "LP_PGconn_struct",
@@ -778,7 +780,7 @@ def generate_stub() -> None:
             "LP_PGcancel_struct",
         ):
             if narg is not None:
-                return f"Optional[{t.__name__[3:]}]"
+                return f"{t.__name__[3:]} | None"
             else:
                 return str(t.__name__[3:])
 
index 3828e94699602cc5cbe874ee4f7d19223e295cda..94e0af908dbdf50896cd3c80003b6408a4700302 100644 (file)
@@ -4,7 +4,7 @@ types stub for ctypes functions
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Any, Callable, Optional, Sequence
+from typing import Any, Callable, Sequence
 from ctypes import Array, pointer, _Pointer
 from ctypes import c_char, c_char_p, c_int, c_ubyte, c_uint, c_ulong
 
@@ -42,31 +42,31 @@ class PGresAttDesc_struct:
     typlen: int
     atttypmod: int
 
-def PQhostaddr(arg1: Optional[PGconn_struct]) -> bytes: ...
-def PQerrorMessage(arg1: Optional[PGconn_struct]) -> bytes: ...
-def PQresultErrorMessage(arg1: Optional[PGresult_struct]) -> bytes: ...
+def PQhostaddr(arg1: PGconn_struct | None) -> bytes: ...
+def PQerrorMessage(arg1: PGconn_struct | None) -> bytes: ...
+def PQresultErrorMessage(arg1: PGresult_struct | None) -> bytes: ...
 def PQexecPrepared(
-    arg1: Optional[PGconn_struct],
+    arg1: PGconn_struct | None,
     arg2: bytes,
     arg3: int,
-    arg4: Optional[Array[c_char_p]],
-    arg5: Optional[Array[c_int]],
-    arg6: Optional[Array[c_int]],
+    arg4: Array[c_char_p] | None,
+    arg5: Array[c_int] | None,
+    arg6: Array[c_int] | None,
     arg7: int,
 ) -> PGresult_struct: ...
 def PQprepare(
-    arg1: Optional[PGconn_struct],
+    arg1: PGconn_struct | None,
     arg2: bytes,
     arg3: bytes,
     arg4: int,
-    arg5: Optional[Array[c_uint]],
+    arg5: Array[c_uint] | None,
 ) -> PGresult_struct: ...
 def PQgetvalue(
-    arg1: Optional[PGresult_struct], arg2: int, arg3: int
+    arg1: PGresult_struct | None, arg2: int, arg3: int
 ) -> _Pointer[c_char]: ...
-def PQcmdTuples(arg1: Optional[PGresult_struct]) -> bytes: ...
+def PQcmdTuples(arg1: PGresult_struct | None) -> bytes: ...
 def PQescapeStringConn(
-    arg1: Optional[PGconn_struct],
+    arg1: PGconn_struct | None,
     arg2: c_char_p,
     arg3: bytes,
     arg4: int,
@@ -74,31 +74,31 @@ def PQescapeStringConn(
 ) -> int: ...
 def PQescapeString(arg1: c_char_p, arg2: bytes, arg3: int) -> int: ...
 def PQsendPrepare(
-    arg1: Optional[PGconn_struct],
+    arg1: PGconn_struct | None,
     arg2: bytes,
     arg3: bytes,
     arg4: int,
-    arg5: Optional[Array[c_uint]],
+    arg5: Array[c_uint] | None,
 ) -> int: ...
 def PQsendQueryPrepared(
-    arg1: Optional[PGconn_struct],
+    arg1: PGconn_struct | None,
     arg2: bytes,
     arg3: int,
-    arg4: Optional[Array[c_char_p]],
-    arg5: Optional[Array[c_int]],
-    arg6: Optional[Array[c_int]],
+    arg4: Array[c_char_p] | None,
+    arg5: Array[c_int] | None,
+    arg6: Array[c_int] | None,
     arg7: int,
 ) -> int: ...
-def PQcancelCreate(arg1: Optional[PGconn_struct]) -> PGcancelConn_struct: ...
-def PQcancelBlocking(arg1: Optional[PGcancelConn_struct]) -> int: ...
-def PQcancelStart(arg1: Optional[PGcancelConn_struct]) -> int: ...
-def PQcancelPoll(arg1: Optional[PGcancelConn_struct]) -> int: ...
-def PQcancelStatus(arg1: Optional[PGcancelConn_struct]) -> int: ...
-def PQcancelSocket(arg1: Optional[PGcancelConn_struct]) -> int: ...
-def PQcancelErrorMessage(arg1: Optional[PGcancelConn_struct]) -> bytes: ...
-def PQcancelReset(arg1: Optional[PGcancelConn_struct]) -> None: ...
-def PQcancelFinish(arg1: Optional[PGcancelConn_struct]) -> None: ...
-def PQcancel(arg1: Optional[PGcancel_struct], arg2: c_char_p, arg3: int) -> int: ...
+def PQcancelCreate(arg1: PGconn_struct | None) -> PGcancelConn_struct: ...
+def PQcancelBlocking(arg1: PGcancelConn_struct | None) -> int: ...
+def PQcancelStart(arg1: PGcancelConn_struct | None) -> int: ...
+def PQcancelPoll(arg1: PGcancelConn_struct | None) -> int: ...
+def PQcancelStatus(arg1: PGcancelConn_struct | None) -> int: ...
+def PQcancelSocket(arg1: PGcancelConn_struct | None) -> int: ...
+def PQcancelErrorMessage(arg1: PGcancelConn_struct | None) -> bytes: ...
+def PQcancelReset(arg1: PGcancelConn_struct | None) -> None: ...
+def PQcancelFinish(arg1: PGcancelConn_struct | None) -> None: ...
+def PQcancel(arg1: PGcancel_struct | None, arg2: c_char_p, arg3: int) -> int: ...
 def PQsetNoticeReceiver(
     arg1: PGconn_struct, arg2: Callable[[Any], PGresult_struct], arg3: Any
 ) -> Callable[[Any], PGresult_struct]: ...
@@ -107,117 +107,121 @@ def PQsetNoticeReceiver(
 # Type argument "psycopg.pq._pq_ctypes.PGnotify_struct" of "pointer" must be
 # a subtype of "ctypes._CData"
 def PQnotifies(
-    arg1: Optional[PGconn_struct],
-) -> Optional[_Pointer[PGnotify_struct]]: ...  # type: ignore
-def PQputCopyEnd(arg1: Optional[PGconn_struct], arg2: Optional[bytes]) -> int: ...
+    arg1: PGconn_struct | None,
+) -> _Pointer[PGnotify_struct] | None: ...  # type: ignore
+def PQputCopyEnd(arg1: PGconn_struct | None, arg2: bytes | None) -> int: ...
 
 # Arg 2 is a _Pointer, reported as _CArgObject by mypy
-def PQgetCopyData(arg1: Optional[PGconn_struct], arg2: Any, arg3: int) -> int: ...
+def PQgetCopyData(arg1: PGconn_struct | None, arg2: Any, arg3: int) -> int: ...
 def PQsetResultAttrs(
-    arg1: Optional[PGresult_struct],
+    arg1: PGresult_struct | None,
     arg2: int,
     arg3: Array[PGresAttDesc_struct],  # type: ignore
 ) -> int: ...
 def PQtrace(
-    arg1: Optional[PGconn_struct],
+    arg1: PGconn_struct | None,
     arg2: _Pointer[FILE],  # type: ignore[type-var]
 ) -> None: ...
-def PQsetTraceFlags(arg1: Optional[PGconn_struct], arg2: int) -> None: ...
+def PQsetTraceFlags(arg1: PGconn_struct | None, arg2: int) -> None: ...
 def PQencryptPasswordConn(
-    arg1: Optional[PGconn_struct],
+    arg1: PGconn_struct | None,
     arg2: bytes,
     arg3: bytes,
-    arg4: Optional[bytes],
+    arg4: bytes | None,
 ) -> bytes: ...
-def PQpipelineStatus(pgconn: Optional[PGconn_struct]) -> int: ...
-def PQenterPipelineMode(pgconn: Optional[PGconn_struct]) -> int: ...
-def PQexitPipelineMode(pgconn: Optional[PGconn_struct]) -> int: ...
-def PQpipelineSync(pgconn: Optional[PGconn_struct]) -> int: ...
-def PQsendFlushRequest(pgconn: Optional[PGconn_struct]) -> int: ...
+def PQpipelineStatus(pgconn: PGconn_struct | None) -> int: ...
+def PQenterPipelineMode(pgconn: PGconn_struct | None) -> int: ...
+def PQexitPipelineMode(pgconn: PGconn_struct | None) -> int: ...
+def PQpipelineSync(pgconn: PGconn_struct | None) -> int: ...
+def PQsendFlushRequest(pgconn: PGconn_struct | None) -> int: ...
+
+# Autogenerated section.
+# In order to refresh, run:
+#   python -m psycopg.pq._pq_ctypes
 
 # fmt: off
 # autogenerated: start
 def PQlibVersion() -> int: ...
 def PQconnectdb(arg1: bytes) -> PGconn_struct: ...
 def PQconnectStart(arg1: bytes) -> PGconn_struct: ...
-def PQconnectPoll(arg1: Optional[PGconn_struct]) -> int: ...
+def PQconnectPoll(arg1: PGconn_struct | None) -> int: ...
 def PQconndefaults() -> Sequence[PQconninfoOption_struct]: ...
 def PQconninfoFree(arg1: Sequence[PQconninfoOption_struct]) -> None: ...
-def PQconninfo(arg1: Optional[PGconn_struct]) -> Sequence[PQconninfoOption_struct]: ...
+def PQconninfo(arg1: PGconn_struct | None) -> Sequence[PQconninfoOption_struct]: ...
 def PQconninfoParse(arg1: bytes, arg2: _Pointer[c_char_p]) -> Sequence[PQconninfoOption_struct]: ...
-def PQfinish(arg1: Optional[PGconn_struct]) -> None: ...
-def PQreset(arg1: Optional[PGconn_struct]) -> None: ...
-def PQresetStart(arg1: Optional[PGconn_struct]) -> int: ...
-def PQresetPoll(arg1: Optional[PGconn_struct]) -> int: ...
+def PQfinish(arg1: PGconn_struct | None) -> None: ...
+def PQreset(arg1: PGconn_struct | None) -> None: ...
+def PQresetStart(arg1: PGconn_struct | None) -> int: ...
+def PQresetPoll(arg1: PGconn_struct | None) -> int: ...
 def PQping(arg1: bytes) -> int: ...
-def PQdb(arg1: Optional[PGconn_struct]) -> Optional[bytes]: ...
-def PQuser(arg1: Optional[PGconn_struct]) -> Optional[bytes]: ...
-def PQpass(arg1: Optional[PGconn_struct]) -> Optional[bytes]: ...
-def PQhost(arg1: Optional[PGconn_struct]) -> Optional[bytes]: ...
-def PQport(arg1: Optional[PGconn_struct]) -> Optional[bytes]: ...
-def PQtty(arg1: Optional[PGconn_struct]) -> Optional[bytes]: ...
-def PQoptions(arg1: Optional[PGconn_struct]) -> Optional[bytes]: ...
-def PQstatus(arg1: Optional[PGconn_struct]) -> int: ...
-def PQtransactionStatus(arg1: Optional[PGconn_struct]) -> int: ...
-def PQparameterStatus(arg1: Optional[PGconn_struct], arg2: bytes) -> Optional[bytes]: ...
-def PQprotocolVersion(arg1: Optional[PGconn_struct]) -> int: ...
-def PQserverVersion(arg1: Optional[PGconn_struct]) -> int: ...
-def PQsocket(arg1: Optional[PGconn_struct]) -> int: ...
-def PQbackendPID(arg1: Optional[PGconn_struct]) -> int: ...
-def PQconnectionNeedsPassword(arg1: Optional[PGconn_struct]) -> int: ...
-def PQconnectionUsedPassword(arg1: Optional[PGconn_struct]) -> int: ...
-def PQsslInUse(arg1: Optional[PGconn_struct]) -> int: ...
-def PQexec(arg1: Optional[PGconn_struct], arg2: bytes) -> PGresult_struct: ...
-def PQexecParams(arg1: Optional[PGconn_struct], arg2: bytes, arg3: int, arg4: _Pointer[c_uint], arg5: _Pointer[c_char_p], arg6: _Pointer[c_int], arg7: _Pointer[c_int], arg8: int) -> PGresult_struct: ...
-def PQdescribePrepared(arg1: Optional[PGconn_struct], arg2: bytes) -> PGresult_struct: ...
-def PQdescribePortal(arg1: Optional[PGconn_struct], arg2: bytes) -> PGresult_struct: ...
-def PQclosePrepared(arg1: Optional[PGconn_struct], arg2: bytes) -> PGresult_struct: ...
-def PQclosePortal(arg1: Optional[PGconn_struct], arg2: bytes) -> PGresult_struct: ...
-def PQresultStatus(arg1: Optional[PGresult_struct]) -> int: ...
-def PQresultErrorField(arg1: Optional[PGresult_struct], arg2: int) -> Optional[bytes]: ...
-def PQclear(arg1: Optional[PGresult_struct]) -> None: ...
-def PQntuples(arg1: Optional[PGresult_struct]) -> int: ...
-def PQnfields(arg1: Optional[PGresult_struct]) -> int: ...
-def PQfname(arg1: Optional[PGresult_struct], arg2: int) -> Optional[bytes]: ...
-def PQftable(arg1: Optional[PGresult_struct], arg2: int) -> int: ...
-def PQftablecol(arg1: Optional[PGresult_struct], arg2: int) -> int: ...
-def PQfformat(arg1: Optional[PGresult_struct], arg2: int) -> int: ...
-def PQftype(arg1: Optional[PGresult_struct], arg2: int) -> int: ...
-def PQfmod(arg1: Optional[PGresult_struct], arg2: int) -> int: ...
-def PQfsize(arg1: Optional[PGresult_struct], arg2: int) -> int: ...
-def PQbinaryTuples(arg1: Optional[PGresult_struct]) -> int: ...
-def PQgetisnull(arg1: Optional[PGresult_struct], arg2: int, arg3: int) -> int: ...
-def PQgetlength(arg1: Optional[PGresult_struct], arg2: int, arg3: int) -> int: ...
-def PQnparams(arg1: Optional[PGresult_struct]) -> int: ...
-def PQparamtype(arg1: Optional[PGresult_struct], arg2: int) -> int: ...
-def PQcmdStatus(arg1: Optional[PGresult_struct]) -> Optional[bytes]: ...
-def PQoidValue(arg1: Optional[PGresult_struct]) -> int: ...
-def PQescapeLiteral(arg1: Optional[PGconn_struct], arg2: bytes, arg3: int) -> Optional[bytes]: ...
-def PQescapeIdentifier(arg1: Optional[PGconn_struct], arg2: bytes, arg3: int) -> Optional[bytes]: ...
-def PQescapeByteaConn(arg1: Optional[PGconn_struct], arg2: bytes, arg3: int, arg4: _Pointer[c_ulong]) -> _Pointer[c_ubyte]: ...
+def PQdb(arg1: PGconn_struct | None) -> bytes | None: ...
+def PQuser(arg1: PGconn_struct | None) -> bytes | None: ...
+def PQpass(arg1: PGconn_struct | None) -> bytes | None: ...
+def PQhost(arg1: PGconn_struct | None) -> bytes | None: ...
+def PQport(arg1: PGconn_struct | None) -> bytes | None: ...
+def PQtty(arg1: PGconn_struct | None) -> bytes | None: ...
+def PQoptions(arg1: PGconn_struct | None) -> bytes | None: ...
+def PQstatus(arg1: PGconn_struct | None) -> int: ...
+def PQtransactionStatus(arg1: PGconn_struct | None) -> int: ...
+def PQparameterStatus(arg1: PGconn_struct | None, arg2: bytes) -> bytes | None: ...
+def PQprotocolVersion(arg1: PGconn_struct | None) -> int: ...
+def PQserverVersion(arg1: PGconn_struct | None) -> int: ...
+def PQsocket(arg1: PGconn_struct | None) -> int: ...
+def PQbackendPID(arg1: PGconn_struct | None) -> int: ...
+def PQconnectionNeedsPassword(arg1: PGconn_struct | None) -> int: ...
+def PQconnectionUsedPassword(arg1: PGconn_struct | None) -> int: ...
+def PQsslInUse(arg1: PGconn_struct | None) -> int: ...
+def PQexec(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
+def PQexecParams(arg1: PGconn_struct | None, arg2: bytes, arg3: int, arg4: _Pointer[c_uint], arg5: _Pointer[c_char_p], arg6: _Pointer[c_int], arg7: _Pointer[c_int], arg8: int) -> PGresult_struct: ...
+def PQdescribePrepared(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
+def PQdescribePortal(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
+def PQclosePrepared(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
+def PQclosePortal(arg1: PGconn_struct | None, arg2: bytes) -> PGresult_struct: ...
+def PQresultStatus(arg1: PGresult_struct | None) -> int: ...
+def PQresultErrorField(arg1: PGresult_struct | None, arg2: int) -> bytes | None: ...
+def PQclear(arg1: PGresult_struct | None) -> None: ...
+def PQntuples(arg1: PGresult_struct | None) -> int: ...
+def PQnfields(arg1: PGresult_struct | None) -> int: ...
+def PQfname(arg1: PGresult_struct | None, arg2: int) -> bytes | None: ...
+def PQftable(arg1: PGresult_struct | None, arg2: int) -> int: ...
+def PQftablecol(arg1: PGresult_struct | None, arg2: int) -> int: ...
+def PQfformat(arg1: PGresult_struct | None, arg2: int) -> int: ...
+def PQftype(arg1: PGresult_struct | None, arg2: int) -> int: ...
+def PQfmod(arg1: PGresult_struct | None, arg2: int) -> int: ...
+def PQfsize(arg1: PGresult_struct | None, arg2: int) -> int: ...
+def PQbinaryTuples(arg1: PGresult_struct | None) -> int: ...
+def PQgetisnull(arg1: PGresult_struct | None, arg2: int, arg3: int) -> int: ...
+def PQgetlength(arg1: PGresult_struct | None, arg2: int, arg3: int) -> int: ...
+def PQnparams(arg1: PGresult_struct | None) -> int: ...
+def PQparamtype(arg1: PGresult_struct | None, arg2: int) -> int: ...
+def PQcmdStatus(arg1: PGresult_struct | None) -> bytes | None: ...
+def PQoidValue(arg1: PGresult_struct | None) -> int: ...
+def PQescapeLiteral(arg1: PGconn_struct | None, arg2: bytes, arg3: int) -> bytes | None: ...
+def PQescapeIdentifier(arg1: PGconn_struct | None, arg2: bytes, arg3: int) -> bytes | None: ...
+def PQescapeByteaConn(arg1: PGconn_struct | None, arg2: bytes, arg3: int, arg4: _Pointer[c_ulong]) -> _Pointer[c_ubyte]: ...
 def PQescapeBytea(arg1: bytes, arg2: int, arg3: _Pointer[c_ulong]) -> _Pointer[c_ubyte]: ...
 def PQunescapeBytea(arg1: bytes, arg2: _Pointer[c_ulong]) -> _Pointer[c_ubyte]: ...
-def PQsendQuery(arg1: Optional[PGconn_struct], arg2: bytes) -> int: ...
-def PQsendQueryParams(arg1: Optional[PGconn_struct], arg2: bytes, arg3: int, arg4: _Pointer[c_uint], arg5: _Pointer[c_char_p], arg6: _Pointer[c_int], arg7: _Pointer[c_int], arg8: int) -> int: ...
-def PQsendDescribePrepared(arg1: Optional[PGconn_struct], arg2: bytes) -> int: ...
-def PQsendDescribePortal(arg1: Optional[PGconn_struct], arg2: bytes) -> int: ...
-def PQsendClosePrepared(arg1: Optional[PGconn_struct], arg2: bytes) -> int: ...
-def PQsendClosePortal(arg1: Optional[PGconn_struct], arg2: bytes) -> int: ...
-def PQgetResult(arg1: Optional[PGconn_struct]) -> PGresult_struct: ...
-def PQconsumeInput(arg1: Optional[PGconn_struct]) -> int: ...
-def PQisBusy(arg1: Optional[PGconn_struct]) -> int: ...
-def PQsetnonblocking(arg1: Optional[PGconn_struct], arg2: int) -> int: ...
-def PQisnonblocking(arg1: Optional[PGconn_struct]) -> int: ...
-def PQflush(arg1: Optional[PGconn_struct]) -> int: ...
-def PQsetSingleRowMode(arg1: Optional[PGconn_struct]) -> int: ...
-def PQsetChunkedRowsMode(arg1: Optional[PGconn_struct], arg2: int) -> int: ...
-def PQgetCancel(arg1: Optional[PGconn_struct]) -> PGcancel_struct: ...
-def PQfreeCancel(arg1: Optional[PGcancel_struct]) -> None: ...
-def PQputCopyData(arg1: Optional[PGconn_struct], arg2: bytes, arg3: int) -> int: ...
-def PQuntrace(arg1: Optional[PGconn_struct]) -> None: ...
+def PQsendQuery(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
+def PQsendQueryParams(arg1: PGconn_struct | None, arg2: bytes, arg3: int, arg4: _Pointer[c_uint], arg5: _Pointer[c_char_p], arg6: _Pointer[c_int], arg7: _Pointer[c_int], arg8: int) -> int: ...
+def PQsendDescribePrepared(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
+def PQsendDescribePortal(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
+def PQsendClosePrepared(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
+def PQsendClosePortal(arg1: PGconn_struct | None, arg2: bytes) -> int: ...
+def PQgetResult(arg1: PGconn_struct | None) -> PGresult_struct: ...
+def PQconsumeInput(arg1: PGconn_struct | None) -> int: ...
+def PQisBusy(arg1: PGconn_struct | None) -> int: ...
+def PQsetnonblocking(arg1: PGconn_struct | None, arg2: int) -> int: ...
+def PQisnonblocking(arg1: PGconn_struct | None) -> int: ...
+def PQflush(arg1: PGconn_struct | None) -> int: ...
+def PQsetSingleRowMode(arg1: PGconn_struct | None) -> int: ...
+def PQsetChunkedRowsMode(arg1: PGconn_struct | None, arg2: int) -> int: ...
+def PQgetCancel(arg1: PGconn_struct | None) -> PGcancel_struct: ...
+def PQfreeCancel(arg1: PGcancel_struct | None) -> None: ...
+def PQputCopyData(arg1: PGconn_struct | None, arg2: bytes, arg3: int) -> int: ...
+def PQuntrace(arg1: PGconn_struct | None) -> None: ...
 def PQfreemem(arg1: Any) -> None: ...
-def PQchangePassword(arg1: Optional[PGconn_struct], arg2: bytes, arg3: bytes) -> PGresult_struct: ...
-def PQmakeEmptyPGresult(arg1: Optional[PGconn_struct], arg2: int) -> PGresult_struct: ...
+def PQchangePassword(arg1: PGconn_struct | None, arg2: bytes, arg3: bytes) -> PGresult_struct: ...
+def PQmakeEmptyPGresult(arg1: PGconn_struct | None, arg2: int) -> PGresult_struct: ...
 def PQinitOpenSSL(arg1: int, arg2: int) -> None: ...
 # autogenerated: end
 # fmt: on
index 8b98c7d010e73629347cc085a56d402b6654f13c..0f6c29edf71d6c9e4c2bd3d9ad422020010a08bb 100644 (file)
@@ -4,7 +4,9 @@ Protocol objects to represent objects exposed by different pq implementations.
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Any, Callable, List, Optional, Protocol, Sequence, Tuple
+from __future__ import annotations
+
+from typing import Any, Callable, List, Protocol, Sequence, Tuple
 from typing import Union, TYPE_CHECKING
 
 from ._enums import Format, Trace
@@ -18,8 +20,8 @@ Buffer: TypeAlias = Union[bytes, bytearray, memoryview]
 
 
 class PGconn(Protocol):
-    notice_handler: Optional[Callable[["PGresult"], None]]
-    notify_handler: Optional[Callable[["PGnotify"], None]]
+    notice_handler: Callable[["PGresult"], None] | None
+    notify_handler: Callable[["PGnotify"], None] | None
 
     @classmethod
     def connect(cls, conninfo: bytes) -> "PGconn": ...
@@ -73,7 +75,7 @@ class PGconn(Protocol):
     @property
     def transaction_status(self) -> int: ...
 
-    def parameter_status(self, name: bytes) -> Optional[bytes]: ...
+    def parameter_status(self, name: bytes) -> bytes | None: ...
 
     @property
     def error_message(self) -> bytes: ...
@@ -103,18 +105,18 @@ class PGconn(Protocol):
     def exec_params(
         self,
         command: bytes,
-        param_values: Optional[Sequence[Optional[Buffer]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[Buffer | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> "PGresult": ...
 
     def send_query_params(
         self,
         command: bytes,
-        param_values: Optional[Sequence[Optional[Buffer]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[Buffer | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> None: ...
 
@@ -122,14 +124,14 @@ class PGconn(Protocol):
         self,
         name: bytes,
         command: bytes,
-        param_types: Optional[Sequence[int]] = None,
+        param_types: Sequence[int] | None = None,
     ) -> None: ...
 
     def send_query_prepared(
         self,
         name: bytes,
-        param_values: Optional[Sequence[Optional[Buffer]]],
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[Buffer | None] | None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> None: ...
 
@@ -137,14 +139,14 @@ class PGconn(Protocol):
         self,
         name: bytes,
         command: bytes,
-        param_types: Optional[Sequence[int]] = None,
+        param_types: Sequence[int] | None = None,
     ) -> "PGresult": ...
 
     def exec_prepared(
         self,
         name: bytes,
-        param_values: Optional[Sequence[Buffer]],
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[Buffer] | None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = 0,
     ) -> "PGresult": ...
 
@@ -164,7 +166,7 @@ class PGconn(Protocol):
 
     def send_close_portal(self, name: bytes) -> None: ...
 
-    def get_result(self) -> Optional["PGresult"]: ...
+    def get_result(self) -> "PGresult" | None: ...
 
     def consume_input(self) -> None: ...
 
@@ -186,11 +188,11 @@ class PGconn(Protocol):
 
     def get_cancel(self) -> "PGcancel": ...
 
-    def notifies(self) -> Optional["PGnotify"]: ...
+    def notifies(self) -> "PGnotify" | None: ...
 
     def put_copy_data(self, buffer: Buffer) -> int: ...
 
-    def put_copy_end(self, error: Optional[bytes] = None) -> int: ...
+    def put_copy_end(self, error: bytes | None = None) -> int: ...
 
     def get_copy_data(self, async_: int) -> Tuple[int, memoryview]: ...
 
@@ -201,7 +203,7 @@ class PGconn(Protocol):
     def untrace(self) -> None: ...
 
     def encrypt_password(
-        self, passwd: bytes, user: bytes, algorithm: Optional[bytes] = None
+        self, passwd: bytes, user: bytes, algorithm: bytes | None = None
     ) -> bytes: ...
 
     def change_password(self, user: bytes, passwd: bytes) -> None: ...
@@ -229,7 +231,7 @@ class PGresult(Protocol):
     @property
     def error_message(self) -> bytes: ...
 
-    def error_field(self, fieldcode: int) -> Optional[bytes]: ...
+    def error_field(self, fieldcode: int) -> bytes | None: ...
 
     @property
     def ntuples(self) -> int: ...
@@ -237,7 +239,7 @@ class PGresult(Protocol):
     @property
     def nfields(self) -> int: ...
 
-    def fname(self, column_number: int) -> Optional[bytes]: ...
+    def fname(self, column_number: int) -> bytes | None: ...
 
     def ftable(self, column_number: int) -> int: ...
 
@@ -254,7 +256,7 @@ class PGresult(Protocol):
     @property
     def binary_tuples(self) -> int: ...
 
-    def get_value(self, row_number: int, column_number: int) -> Optional[bytes]: ...
+    def get_value(self, row_number: int, column_number: int) -> bytes | None: ...
 
     @property
     def nparams(self) -> int: ...
@@ -262,10 +264,10 @@ class PGresult(Protocol):
     def param_type(self, param_number: int) -> int: ...
 
     @property
-    def command_status(self) -> Optional[bytes]: ...
+    def command_status(self) -> bytes | None: ...
 
     @property
-    def command_tuples(self) -> Optional[int]: ...
+    def command_tuples(self) -> int | None: ...
 
     @property
     def oid_value(self) -> int: ...
@@ -312,7 +314,7 @@ class Conninfo(Protocol):
 
 
 class Escaping(Protocol):
-    def __init__(self, conn: Optional[PGconn] = None): ...
+    def __init__(self, conn: PGconn | None = None): ...
 
     def escape_literal(self, data: Buffer) -> bytes: ...
 
index c671bf25f1233b6485efaddd0c2972e3529978fa..793c95d89c53a4324bcc689f46eba7886c711823 100644 (file)
@@ -4,12 +4,14 @@ Various functionalities to make easier to work with the libpq.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import re
 import os
 import sys
 import logging
 import ctypes.util
-from typing import cast, NamedTuple, Optional, Union
+from typing import cast, NamedTuple, Union
 
 from .abc import PGconn, PGresult
 from ._enums import ConnStatus, TransactionStatus, PipelineStatus
@@ -29,9 +31,9 @@ class PGnotify(NamedTuple):
 
 class ConninfoOption(NamedTuple):
     keyword: bytes
-    envvar: Optional[bytes]
-    compiled: Optional[bytes]
-    val: Optional[bytes]
+    envvar: bytes | None
+    compiled: bytes | None
+    val: bytes | None
     label: bytes
     dispchar: bytes
     dispsize: int
@@ -48,7 +50,7 @@ class PGresAttDesc(NamedTuple):
 
 
 @cache
-def find_libpq_full_path() -> Optional[str]:
+def find_libpq_full_path() -> str | None:
     if sys.platform == "win32":
         libname = ctypes.util.find_library("libpq.dll")
 
index eba9872c4ac51c36b8cff2627a9698e2ca5ed407..fc171e5ba7e6451c45c98bd34bfe1653f9eb681a 100644 (file)
@@ -8,6 +8,8 @@ implementation.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import sys
 import logging
 from os import getpid
@@ -15,7 +17,7 @@ from weakref import ref
 
 from ctypes import Array, POINTER, cast, string_at, create_string_buffer, byref
 from ctypes import addressof, c_char_p, c_int, c_size_t, c_ulong, c_void_p, py_object
-from typing import Any, Callable, List, Optional, Sequence, Tuple
+from typing import Any, Callable, List, Sequence, Tuple
 from typing import cast as t_cast, TYPE_CHECKING
 
 from .. import errors as e
@@ -78,9 +80,9 @@ class PGconn:
     )
 
     def __init__(self, pgconn_ptr: impl.PGconn_struct):
-        self._pgconn_ptr: Optional[impl.PGconn_struct] = pgconn_ptr
-        self.notice_handler: Optional[Callable[["abc.PGresult"], None]] = None
-        self.notify_handler: Optional[Callable[[PGnotify], None]] = None
+        self._pgconn_ptr: impl.PGconn_struct | None = pgconn_ptr
+        self.notice_handler: Callable[["abc.PGresult"], None] | None = None
+        self.notify_handler: Callable[[PGnotify], None] | None = None
 
         # Keep alive for the lifetime of PGconn
         self._self_ptr = py_object(ref(self))
@@ -128,7 +130,7 @@ class PGconn:
             PQfinish(p)
 
     @property
-    def pgconn_ptr(self) -> Optional[int]:
+    def pgconn_ptr(self) -> int | None:
         """The pointer to the underlying `!PGconn` structure, as integer.
 
         `!None` if the connection is closed.
@@ -211,7 +213,7 @@ class PGconn:
     def transaction_status(self) -> int:
         return impl.PQtransactionStatus(self._pgconn_ptr)
 
-    def parameter_status(self, name: bytes) -> Optional[bytes]:
+    def parameter_status(self, name: bytes) -> bytes | None:
         self._ensure_pgconn()
         return impl.PQparameterStatus(self._pgconn_ptr, name)
 
@@ -278,9 +280,9 @@ class PGconn:
     def exec_params(
         self,
         command: bytes,
-        param_values: Optional[Sequence[Optional["abc.Buffer"]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence["abc.Buffer" | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> "PGresult":
         args = self._query_params_args(
@@ -295,9 +297,9 @@ class PGconn:
     def send_query_params(
         self,
         command: bytes,
-        param_values: Optional[Sequence[Optional["abc.Buffer"]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence["abc.Buffer" | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> None:
         args = self._query_params_args(
@@ -313,9 +315,9 @@ class PGconn:
         self,
         name: bytes,
         command: bytes,
-        param_types: Optional[Sequence[int]] = None,
+        param_types: Sequence[int] | None = None,
     ) -> None:
-        atypes: Optional[Array[impl.Oid]]
+        atypes: Array[impl.Oid] | None
         if not param_types:
             nparams = 0
             atypes = None
@@ -332,8 +334,8 @@ class PGconn:
     def send_query_prepared(
         self,
         name: bytes,
-        param_values: Optional[Sequence[Optional["abc.Buffer"]]],
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence["abc.Buffer" | None] | None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> None:
         # repurpose this function with a cheeky replacement of query with name,
@@ -352,16 +354,16 @@ class PGconn:
     def _query_params_args(
         self,
         command: bytes,
-        param_values: Optional[Sequence[Optional["abc.Buffer"]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence["abc.Buffer" | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> Any:
         if not isinstance(command, bytes):
             raise TypeError(f"bytes expected, got {type(command)} instead")
 
-        aparams: Optional[Array[c_char_p]]
-        alenghts: Optional[Array[c_int]]
+        aparams: Array[c_char_p] | None
+        alenghts: Array[c_int] | None
         if param_values:
             nparams = len(param_values)
             aparams = (c_char_p * nparams)(
@@ -376,7 +378,7 @@ class PGconn:
             nparams = 0
             aparams = alenghts = None
 
-        atypes: Optional[Array[impl.Oid]]
+        atypes: Array[impl.Oid] | None
         if not param_types:
             atypes = None
         else:
@@ -412,7 +414,7 @@ class PGconn:
         self,
         name: bytes,
         command: bytes,
-        param_types: Optional[Sequence[int]] = None,
+        param_types: Sequence[int] | None = None,
     ) -> "PGresult":
         if not isinstance(name, bytes):
             raise TypeError(f"'name' must be bytes, got {type(name)} instead")
@@ -436,15 +438,15 @@ class PGconn:
     def exec_prepared(
         self,
         name: bytes,
-        param_values: Optional[Sequence["abc.Buffer"]],
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence["abc.Buffer"] | None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = 0,
     ) -> "PGresult":
         if not isinstance(name, bytes):
             raise TypeError(f"'name' must be bytes, got {type(name)} instead")
 
-        aparams: Optional[Array[c_char_p]]
-        alenghts: Optional[Array[c_int]]
+        aparams: Array[c_char_p] | None
+        alenghts: Array[c_int] | None
         if param_values:
             nparams = len(param_values)
             aparams = (c_char_p * nparams)(
@@ -557,7 +559,7 @@ class PGconn:
                 f"sending close portal failed: {error_message(self)}"
             )
 
-    def get_result(self) -> Optional["PGresult"]:
+    def get_result(self) -> "PGresult" | None:
         rv = impl.PQgetResult(self._pgconn_ptr)
         return PGresult(rv) if rv else None
 
@@ -618,7 +620,7 @@ class PGconn:
             raise e.OperationalError("couldn't create cancel object")
         return PGcancel(rv)
 
-    def notifies(self) -> Optional[PGnotify]:
+    def notifies(self) -> PGnotify | None:
         ptr = impl.PQnotifies(self._pgconn_ptr)
         if ptr:
             c = ptr.contents
@@ -636,7 +638,7 @@ class PGconn:
             raise e.OperationalError(f"sending copy data failed: {error_message(self)}")
         return rv
 
-    def put_copy_end(self, error: Optional[bytes] = None) -> int:
+    def put_copy_end(self, error: bytes | None = None) -> int:
         rv = impl.PQputCopyEnd(self._pgconn_ptr, error)
         if rv < 0:
             raise e.OperationalError(f"sending copy end failed: {error_message(self)}")
@@ -687,7 +689,7 @@ class PGconn:
         impl.PQuntrace(self._pgconn_ptr)
 
     def encrypt_password(
-        self, passwd: bytes, user: bytes, algorithm: Optional[bytes] = None
+        self, passwd: bytes, user: bytes, algorithm: bytes | None = None
     ) -> bytes:
         """
         Return the encrypted form of a PostgreSQL password.
@@ -768,9 +770,7 @@ class PGconn:
         if impl.PQsendFlushRequest(self._pgconn_ptr) == 0:
             raise e.OperationalError(f"flush request failed: {error_message(self)}")
 
-    def _call_bytes(
-        self, func: Callable[[impl.PGconn_struct], Optional[bytes]]
-    ) -> bytes:
+    def _call_bytes(self, func: Callable[[impl.PGconn_struct], bytes | None]) -> bytes:
         """
         Call one of the pgconn libpq functions returning a bytes pointer.
         """
@@ -809,7 +809,7 @@ class PGresult:
     __slots__ = ("_pgresult_ptr",)
 
     def __init__(self, pgresult_ptr: impl.PGresult_struct):
-        self._pgresult_ptr: Optional[impl.PGresult_struct] = pgresult_ptr
+        self._pgresult_ptr: impl.PGresult_struct | None = pgresult_ptr
 
     def __del__(self) -> None:
         self.clear()
@@ -825,7 +825,7 @@ class PGresult:
             PQclear(p)
 
     @property
-    def pgresult_ptr(self) -> Optional[int]:
+    def pgresult_ptr(self) -> int | None:
         """The pointer to the underlying `!PGresult` structure, as integer.
 
         `!None` if the result was cleared.
@@ -847,7 +847,7 @@ class PGresult:
     def error_message(self) -> bytes:
         return impl.PQresultErrorMessage(self._pgresult_ptr)
 
-    def error_field(self, fieldcode: int) -> Optional[bytes]:
+    def error_field(self, fieldcode: int) -> bytes | None:
         return impl.PQresultErrorField(self._pgresult_ptr, fieldcode)
 
     @property
@@ -858,7 +858,7 @@ class PGresult:
     def nfields(self) -> int:
         return impl.PQnfields(self._pgresult_ptr)
 
-    def fname(self, column_number: int) -> Optional[bytes]:
+    def fname(self, column_number: int) -> bytes | None:
         return impl.PQfname(self._pgresult_ptr, column_number)
 
     def ftable(self, column_number: int) -> int:
@@ -883,7 +883,7 @@ class PGresult:
     def binary_tuples(self) -> int:
         return impl.PQbinaryTuples(self._pgresult_ptr)
 
-    def get_value(self, row_number: int, column_number: int) -> Optional[bytes]:
+    def get_value(self, row_number: int, column_number: int) -> bytes | None:
         length: int = impl.PQgetlength(self._pgresult_ptr, row_number, column_number)
         if length:
             v = impl.PQgetvalue(self._pgresult_ptr, row_number, column_number)
@@ -902,11 +902,11 @@ class PGresult:
         return impl.PQparamtype(self._pgresult_ptr, param_number)
 
     @property
-    def command_status(self) -> Optional[bytes]:
+    def command_status(self) -> bytes | None:
         return impl.PQcmdStatus(self._pgresult_ptr)
 
     @property
-    def command_tuples(self) -> Optional[int]:
+    def command_tuples(self) -> int | None:
         rv = impl.PQcmdTuples(self._pgresult_ptr)
         return int(rv) if rv else None
 
@@ -934,7 +934,7 @@ class PGcancelConn:
     __slots__ = ("pgcancelconn_ptr",)
 
     def __init__(self, pgcancelconn_ptr: impl.PGcancelConn_struct):
-        self.pgcancelconn_ptr: Optional[impl.PGcancelConn_struct] = pgcancelconn_ptr
+        self.pgcancelconn_ptr: impl.PGcancelConn_struct | None = pgcancelconn_ptr
 
     def __del__(self) -> None:
         self.finish()
@@ -1011,7 +1011,7 @@ class PGcancel:
     __slots__ = ("pgcancel_ptr",)
 
     def __init__(self, pgcancel_ptr: impl.PGcancel_struct):
-        self.pgcancel_ptr: Optional[impl.PGcancel_struct] = pgcancel_ptr
+        self.pgcancel_ptr: impl.PGcancel_struct | None = pgcancel_ptr
 
     def __del__(self) -> None:
         self.free()
@@ -1103,7 +1103,7 @@ class Escaping:
     Utility object to escape strings for SQL interpolation.
     """
 
-    def __init__(self, conn: Optional[PGconn] = None):
+    def __init__(self, conn: PGconn | None = None):
         self.conn = conn
 
     def escape_literal(self, data: "abc.Buffer") -> bytes:
index d0984da7e0f5947a62a0cd48ff48dae312aaea3a..52211e23bab7253cdea3e3e6a52c97ace1c3bd08 100644 (file)
@@ -4,7 +4,9 @@ psycopg raw queries cursors
 
 # Copyright (C) 2023 The Psycopg Team
 
-from typing import Optional, TYPE_CHECKING
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
 
 from .abc import ConnectionType, Query, Params
 from .sql import Composable
@@ -22,7 +24,7 @@ if TYPE_CHECKING:
 
 
 class PostgresRawQuery(PostgresQuery):
-    def convert(self, query: Query, vars: Optional[Params]) -> None:
+    def convert(self, query: Query, vars: Params | None) -> None:
         if isinstance(query, str):
             bquery = query.encode(self._encoding)
         elif isinstance(query, Composable):
@@ -34,7 +36,7 @@ class PostgresRawQuery(PostgresQuery):
         self._want_formats = self._order = None
         self.dump(vars)
 
-    def dump(self, vars: Optional[Params]) -> None:
+    def dump(self, vars: Params | None) -> None:
         if vars is not None:
             if not PostgresQuery.is_params_sequence(vars):
                 raise TypeError("raw queries require a sequence of parameters")
index 07e0dbcaf294c9361a3c4e5c245c7e26691ceee5..25c9383865627d87c676294f0f1656c3f4ea57f0 100644 (file)
@@ -4,8 +4,10 @@ psycopg row factories
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 import functools
-from typing import Any, Callable, Dict, List, Optional, NamedTuple, NoReturn
+from typing import Any, Callable, Dict, List, NamedTuple, NoReturn
 from typing import TYPE_CHECKING, Protocol, Sequence, Tuple, Type
 from collections import namedtuple
 
@@ -239,7 +241,7 @@ def no_result(values: Sequence[Any]) -> NoReturn:
     raise e.InterfaceError("the cursor doesn't have a result")
 
 
-def _get_names(cursor: "BaseCursor[Any, Any]") -> Optional[List[str]]:
+def _get_names(cursor: "BaseCursor[Any, Any]") -> List[str] | None:
     res = cursor.pgresult
     if not res:
         return None
@@ -254,7 +256,7 @@ def _get_names(cursor: "BaseCursor[Any, Any]") -> Optional[List[str]]:
     ]
 
 
-def _get_nfields(res: "PGresult") -> Optional[int]:
+def _get_nfields(res: "PGresult") -> int | None:
     """
     Return the number of columns in a result, if it returns tuples else None
 
index 2f5f44739d96ac1be8d3720a239351885a4076f8..76f5ad35554330c33f7a74509b282c37e142b3ab 100644 (file)
@@ -4,8 +4,10 @@ psycopg server-side cursor objects.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 from typing import Any, AsyncIterator, List, Iterable, Iterator
-from typing import Optional, TYPE_CHECKING, overload
+from typing import TYPE_CHECKING, overload
 from warnings import warn
 
 from . import pq
@@ -43,7 +45,7 @@ class ServerCursorMixin(BaseCursor[ConnectionType, Row]):
     def __init__(
         self,
         name: str,
-        scrollable: Optional[bool],
+        scrollable: bool | None,
         withhold: bool,
     ):
         self._name = name
@@ -65,7 +67,7 @@ class ServerCursorMixin(BaseCursor[ConnectionType, Row]):
         return self._name
 
     @property
-    def scrollable(self) -> Optional[bool]:
+    def scrollable(self) -> bool | None:
         """
         Whether the cursor is scrollable or not.
 
@@ -82,7 +84,7 @@ class ServerCursorMixin(BaseCursor[ConnectionType, Row]):
         return self._withhold
 
     @property
-    def rownumber(self) -> Optional[int]:
+    def rownumber(self) -> int | None:
         """Index of the next row to fetch in the current result.
 
         `!None` if there is no result to fetch.
@@ -97,8 +99,8 @@ class ServerCursorMixin(BaseCursor[ConnectionType, Row]):
     def _declare_gen(
         self,
         query: Query,
-        params: Optional[Params] = None,
-        binary: Optional[bool] = None,
+        params: Params | None = None,
+        binary: bool | None = None,
     ) -> PQGen[None]:
         """Generator implementing `ServerCursor.execute()`."""
 
@@ -159,7 +161,7 @@ class ServerCursorMixin(BaseCursor[ConnectionType, Row]):
         query = sql.SQL("CLOSE {}").format(sql.Identifier(self._name))
         yield from self._conn._exec_command(query)
 
-    def _fetch_gen(self, num: Optional[int]) -> PQGen[List[Row]]:
+    def _fetch_gen(self, num: int | None) -> PQGen[List[Row]]:
         if self.closed:
             raise e.InterfaceError("the cursor is closed")
         # If we are stealing the cursor, make sure we know its shape
@@ -220,7 +222,7 @@ class ServerCursor(ServerCursorMixin["Connection[Any]", Row], Cursor[Row]):
         connection: "Connection[Row]",
         name: str,
         *,
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ): ...
 
@@ -231,7 +233,7 @@ class ServerCursor(ServerCursorMixin["Connection[Any]", Row], Cursor[Row]):
         name: str,
         *,
         row_factory: RowFactory[Row],
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ): ...
 
@@ -240,8 +242,8 @@ class ServerCursor(ServerCursorMixin["Connection[Any]", Row], Cursor[Row]):
         connection: "Connection[Any]",
         name: str,
         *,
-        row_factory: Optional[RowFactory[Row]] = None,
-        scrollable: Optional[bool] = None,
+        row_factory: RowFactory[Row] | None = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ):
         Cursor.__init__(
@@ -271,9 +273,9 @@ class ServerCursor(ServerCursorMixin["Connection[Any]", Row], Cursor[Row]):
     def execute(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        binary: Optional[bool] = None,
+        binary: bool | None = None,
         **kwargs: Any,
     ) -> Self:
         """
@@ -304,7 +306,7 @@ class ServerCursor(ServerCursorMixin["Connection[Any]", Row], Cursor[Row]):
         """Method not implemented for server-side cursors."""
         raise e.NotSupportedError("executemany not supported on server-side cursors")
 
-    def fetchone(self) -> Optional[Row]:
+    def fetchone(self) -> Row | None:
         with self._conn.lock:
             recs = self._conn.wait(self._fetch_gen(1))
         if recs:
@@ -359,7 +361,7 @@ class AsyncServerCursor(
         connection: "AsyncConnection[Row]",
         name: str,
         *,
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ): ...
 
@@ -370,7 +372,7 @@ class AsyncServerCursor(
         name: str,
         *,
         row_factory: AsyncRowFactory[Row],
-        scrollable: Optional[bool] = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ): ...
 
@@ -379,8 +381,8 @@ class AsyncServerCursor(
         connection: "AsyncConnection[Any]",
         name: str,
         *,
-        row_factory: Optional[AsyncRowFactory[Row]] = None,
-        scrollable: Optional[bool] = None,
+        row_factory: AsyncRowFactory[Row] | None = None,
+        scrollable: bool | None = None,
         withhold: bool = False,
     ):
         AsyncCursor.__init__(
@@ -407,9 +409,9 @@ class AsyncServerCursor(
     async def execute(
         self,
         query: Query,
-        params: Optional[Params] = None,
+        params: Params | None = None,
         *,
-        binary: Optional[bool] = None,
+        binary: bool | None = None,
         **kwargs: Any,
     ) -> Self:
         if kwargs:
@@ -436,7 +438,7 @@ class AsyncServerCursor(
     ) -> None:
         raise e.NotSupportedError("executemany not supported on server-side cursors")
 
-    async def fetchone(self) -> Optional[Row]:
+    async def fetchone(self) -> Row | None:
         async with self._conn.lock:
             recs = await self._conn.wait(self._fetch_gen(1))
         if recs:
index a94f77f6efcf517703c56a25b6db96b26396c5bd..c27b6657a8fc63cb77f43759458c475f657fbe77 100644 (file)
@@ -4,10 +4,12 @@ SQL composition utility module
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import codecs
 import string
 from abc import ABC, abstractmethod
-from typing import Any, Iterator, Iterable, List, Optional, Sequence, Union
+from typing import Any, Iterator, Iterable, List, Sequence, Union
 
 from .pq import Escaping
 from .abc import AdaptContext
@@ -17,7 +19,7 @@ from ._encodings import conn_encoding
 from ._transformer import Transformer
 
 
-def quote(obj: Any, context: Optional[AdaptContext] = None) -> str:
+def quote(obj: Any, context: AdaptContext | None = None) -> str:
     """
     Adapt a Python object to a quoted SQL string.
 
@@ -55,7 +57,7 @@ class Composable(ABC):
         return f"{self.__class__.__name__}({self._obj!r})"
 
     @abstractmethod
-    def as_bytes(self, context: Optional[AdaptContext] = None) -> bytes:
+    def as_bytes(self, context: AdaptContext | None = None) -> bytes:
         """
         Return the value of the object as bytes.
 
@@ -69,7 +71,7 @@ class Composable(ABC):
         """
         raise NotImplementedError
 
-    def as_string(self, context: Optional[AdaptContext] = None) -> str:
+    def as_string(self, context: AdaptContext | None = None) -> str:
         """
         Return the value of the object as string.
 
@@ -130,7 +132,7 @@ class Composed(Composable):
         seq = [obj if isinstance(obj, Composable) else Literal(obj) for obj in seq]
         super().__init__(seq)
 
-    def as_bytes(self, context: Optional[AdaptContext] = None) -> bytes:
+    def as_bytes(self, context: AdaptContext | None = None) -> bytes:
         return b"".join(obj.as_bytes(context) for obj in self._obj)
 
     def __iter__(self) -> Iterator[Composable]:
@@ -200,10 +202,10 @@ class SQL(Composable):
         if not isinstance(obj, str):
             raise TypeError(f"SQL values must be strings, got {obj!r} instead")
 
-    def as_string(self, context: Optional[AdaptContext] = None) -> str:
+    def as_string(self, context: AdaptContext | None = None) -> str:
         return self._obj
 
-    def as_bytes(self, context: Optional[AdaptContext] = None) -> bytes:
+    def as_bytes(self, context: AdaptContext | None = None) -> bytes:
         conn = context.connection if context else None
         enc = conn_encoding(conn)
         return self._obj.encode(enc)
@@ -244,7 +246,7 @@ class SQL(Composable):
 
         """
         rv: List[Composable] = []
-        autonum: Optional[int] = 0
+        autonum: int | None = 0
         # TODO: this is probably not the right way to whitelist pre
         # pyre complains. Will wait for mypy to complain too to fix.
         pre: LiteralString
@@ -362,7 +364,7 @@ class Identifier(Composable):
     def __repr__(self) -> str:
         return f"{self.__class__.__name__}({', '.join(map(repr, self._obj))})"
 
-    def as_bytes(self, context: Optional[AdaptContext] = None) -> bytes:
+    def as_bytes(self, context: AdaptContext | None = None) -> bytes:
         conn = context.connection if context else None
         if conn:
             esc = Escaping(conn.pgconn)
@@ -400,7 +402,7 @@ class Literal(Composable):
 
     """
 
-    def as_bytes(self, context: Optional[AdaptContext] = None) -> bytes:
+    def as_bytes(self, context: AdaptContext | None = None) -> bytes:
         tx = Transformer.from_context(context)
         return tx.as_literal(self._obj)
 
@@ -459,11 +461,11 @@ class Placeholder(Composable):
 
         return f"{self.__class__.__name__}({', '.join(parts)})"
 
-    def as_string(self, context: Optional[AdaptContext] = None) -> str:
+    def as_string(self, context: AdaptContext | None = None) -> str:
         code = self._format.value
         return f"%({self._obj}){code}" if self._obj else f"%{code}"
 
-    def as_bytes(self, context: Optional[AdaptContext] = None) -> bytes:
+    def as_bytes(self, context: AdaptContext | None = None) -> bytes:
         conn = context.connection if context else None
         enc = conn_encoding(conn)
         return self.as_string(context).encode(enc)
index 56b7104459468369f0f2603b73b83299e2be3889..da9f9804893dfdb0bd7b0756b0ee3eff27f90025 100644 (file)
@@ -4,10 +4,12 @@ Transaction context managers returned by Connection.transaction()
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import logging
 
 from types import TracebackType
-from typing import Generic, Iterator, Optional, Type, Union, TYPE_CHECKING
+from typing import Generic, Iterator, Type, Union, TYPE_CHECKING
 
 from . import pq
 from . import sql
@@ -57,7 +59,7 @@ class BaseTransaction(Generic[ConnectionType]):
     def __init__(
         self,
         connection: ConnectionType,
-        savepoint_name: Optional[str] = None,
+        savepoint_name: str | None = None,
         force_rollback: bool = False,
     ):
         self._conn = connection
@@ -69,7 +71,7 @@ class BaseTransaction(Generic[ConnectionType]):
         self._stack_index = -1
 
     @property
-    def savepoint_name(self) -> Optional[str]:
+    def savepoint_name(self) -> str | None:
         """
         The name of the savepoint; `!None` if handling the main transaction.
         """
@@ -101,9 +103,9 @@ class BaseTransaction(Generic[ConnectionType]):
 
     def _exit_gen(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> PQGen[bool]:
         if not exc_val and not self.force_rollback:
             yield from self._commit_gen()
@@ -133,7 +135,7 @@ class BaseTransaction(Generic[ConnectionType]):
         for command in self._get_commit_commands():
             yield from self._conn._exec_command(command)
 
-    def _rollback_gen(self, exc_val: Optional[BaseException]) -> PQGen[bool]:
+    def _rollback_gen(self, exc_val: BaseException | None) -> PQGen[bool]:
         if isinstance(exc_val, Rollback):
             logger.debug(f"{self._conn}: Explicit rollback from: ", exc_info=True)
 
@@ -214,7 +216,7 @@ class BaseTransaction(Generic[ConnectionType]):
         self._stack_index = self._conn._num_transactions
         self._conn._num_transactions += 1
 
-    def _pop_savepoint(self, action: str) -> Optional[Exception]:
+    def _pop_savepoint(self, action: str) -> Exception | None:
         """
         Pop the transaction from the connection transactions stack.
 
@@ -248,9 +250,9 @@ class Transaction(BaseTransaction["Connection[Any]"]):
 
     def __exit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> bool:
         if self.pgconn.status == OK:
             with self._conn.lock:
@@ -277,9 +279,9 @@ class AsyncTransaction(BaseTransaction["AsyncConnection[Any]"]):
 
     async def __aexit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> bool:
         if self.pgconn.status == OK:
             async with self._conn.lock:
index 23afc7d9f83597799095ccab24fffcabe3697976..a795c6d3f82fff1eba33c28980b01361bb1f2ea7 100644 (file)
@@ -4,10 +4,12 @@ Adapters for arrays
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import re
 import struct
 from math import prod
-from typing import Any, cast, Callable, List, Optional, Pattern, Set, Tuple, Type
+from typing import Any, cast, Callable, List, Pattern, Set, Tuple, Type
 
 from .. import pq
 from .. import errors as e
@@ -34,12 +36,12 @@ PQ_BINARY = pq.Format.BINARY
 class BaseListDumper(RecursiveDumper):
     element_oid = INVALID_OID
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         if cls is NoneType:
             cls = list
 
         super().__init__(cls, context)
-        self.sub_dumper: Optional[Dumper] = None
+        self.sub_dumper: Dumper | None = None
         if self.element_oid and context:
             sdclass = context.adapters.get_dumper_by_oid(self.element_oid, self.format)
             self.sub_dumper = sdclass(NoneType, context)
@@ -153,7 +155,7 @@ class ListDumper(BaseListDumper):
     # backslash-escaped.
     _re_esc = re.compile(rb'(["\\])')
 
-    def dump(self, obj: List[Any]) -> Optional[Buffer]:
+    def dump(self, obj: List[Any]) -> Buffer | None:
         tokens: List[Buffer] = []
         needs_quotes = _get_needs_quotes_regexp(self.delimiter).search
 
@@ -187,7 +189,7 @@ class ListDumper(BaseListDumper):
 
         return b"".join(tokens)
 
-    def _dump_item(self, item: Any) -> Optional[Buffer]:
+    def _dump_item(self, item: Any) -> Buffer | None:
         if self.sub_dumper:
             return self.sub_dumper.dump(item)
         else:
@@ -245,7 +247,7 @@ class ListBinaryDumper(BaseListDumper):
 
         return dumper
 
-    def dump(self, obj: List[Any]) -> Optional[Buffer]:
+    def dump(self, obj: List[Any]) -> Buffer | None:
         # Postgres won't take unknown for element oid: fall back on text
         sub_oid = self.sub_dumper and self.sub_dumper.oid or TEXT_OID
 
@@ -310,7 +312,7 @@ class ArrayBinaryLoader(RecursiveLoader):
         return _load_binary(data, self._tx)
 
 
-def register_array(info: TypeInfo, context: Optional[AdaptContext] = None) -> None:
+def register_array(info: TypeInfo, context: AdaptContext | None = None) -> None:
     if not info.array_oid:
         raise ValueError(f"the type info {info} doesn't describe an array")
 
index c056793541e5a16193220bc225dde33c7765e4cc..8f367b80e27aab25a2139bbf885134066da6a57b 100644 (file)
@@ -4,8 +4,9 @@ Adapters for booleans.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 from .. import _oids
-from typing import Optional
 from ..pq import Format
 from ..abc import AdaptContext
 from ..adapt import Buffer, Dumper, Loader
@@ -14,7 +15,7 @@ from ..adapt import Buffer, Dumper, Loader
 class BoolDumper(Dumper):
     oid = _oids.BOOL_OID
 
-    def dump(self, obj: bool) -> Optional[Buffer]:
+    def dump(self, obj: bool) -> Buffer | None:
         return b"t" if obj else b"f"
 
     def quote(self, obj: bool) -> Buffer:
@@ -25,7 +26,7 @@ class BoolBinaryDumper(Dumper):
     format = Format.BINARY
     oid = _oids.BOOL_OID
 
-    def dump(self, obj: bool) -> Optional[Buffer]:
+    def dump(self, obj: bool) -> Buffer | None:
         return b"\x01" if obj else b"\x00"
 
 
index 174727cfbde46dd1b982fef92af212dd92b71962..6dd8642c60179ee4514dcd4886b61b90ed7a163b 100644 (file)
@@ -4,10 +4,12 @@ Support for composite types adaptation.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import re
 import struct
 from collections import namedtuple
-from typing import Any, Callable, cast, Dict, Iterator, List, Optional
+from typing import Any, Callable, cast, Dict, Iterator, List
 from typing import NamedTuple, Sequence, Tuple, Type, TYPE_CHECKING
 
 from .. import pq
@@ -48,7 +50,7 @@ class CompositeInfo(TypeInfo):
         self.field_names = field_names
         self.field_types = field_types
         # Will be set by register() if the `factory` is a type
-        self.python_type: Optional[type] = None
+        self.python_type: type | None = None
 
     @classmethod
     def _get_info_query(cls, conn: "BaseConnection[Any]") -> abc.Query:
@@ -119,7 +121,7 @@ class TupleDumper(SequenceDumper):
     # Should be this, but it doesn't work
     # oid = _oids.RECORD_OID
 
-    def dump(self, obj: Tuple[Any, ...]) -> Optional[Buffer]:
+    def dump(self, obj: Tuple[Any, ...]) -> Buffer | None:
         return self._dump_sequence(obj, b"(", b")", b",")
 
 
@@ -129,7 +131,7 @@ class TupleBinaryDumper(Dumper):
     # Subclasses must set this info
     _field_types: Tuple[int, ...]
 
-    def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, cls: type, context: abc.AdaptContext | None = None):
         super().__init__(cls, context)
 
         # Note: this class is not a RecursiveDumper because it would use the
@@ -142,7 +144,7 @@ class TupleBinaryDumper(Dumper):
         nfields = len(self._field_types)
         self._formats = (PyFormat.from_pq(self.format),) * nfields
 
-    def dump(self, obj: Tuple[Any, ...]) -> Optional[Buffer]:
+    def dump(self, obj: Tuple[Any, ...]) -> Buffer | None:
         out = bytearray(pack_len(len(obj)))
         adapted = self._tx.dump_sequence(obj, self._formats)
         for i in range(len(obj)):
@@ -158,11 +160,11 @@ class TupleBinaryDumper(Dumper):
 
 
 class BaseCompositeLoader(Loader):
-    def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, oid: int, context: abc.AdaptContext | None = None):
         super().__init__(oid, context)
         self._tx = Transformer(context)
 
-    def _parse_record(self, data: abc.Buffer) -> Iterator[Optional[bytes]]:
+    def _parse_record(self, data: abc.Buffer) -> Iterator[bytes | None]:
         """
         Split a non-empty representation of a composite type into components.
 
@@ -208,7 +210,7 @@ class RecordLoader(BaseCompositeLoader):
 class RecordBinaryLoader(Loader):
     format = pq.Format.BINARY
 
-    def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, oid: int, context: abc.AdaptContext | None = None):
         super().__init__(oid, context)
         self._ctx = context
         # Cache a transformer for each sequence of oid found.
@@ -272,8 +274,8 @@ class CompositeBinaryLoader(RecordBinaryLoader):
 
 def register_composite(
     info: CompositeInfo,
-    context: Optional[abc.AdaptContext] = None,
-    factory: Optional[Callable[..., Any]] = None,
+    context: abc.AdaptContext | None = None,
+    factory: Callable[..., Any] | None = None,
 ) -> None:
     """Register the adapters to load and dump a composite type.
 
index b3bfa1b8be00e90c950c8aa3cbc6e1e103be38c1..55f8e92594d4bc19f08bd3c360e51187b174f4be 100644 (file)
@@ -4,10 +4,12 @@ Adapters for date/time types.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import re
 import struct
 from datetime import date, datetime, time, timedelta, timezone
-from typing import Any, Callable, cast, Optional, Tuple, TYPE_CHECKING
+from typing import Any, Callable, cast, Tuple, TYPE_CHECKING
 
 from .. import _oids
 from ..pq import Format
@@ -40,7 +42,7 @@ _py_date_min_days = date.min.toordinal()
 class DateDumper(Dumper):
     oid = _oids.DATE_OID
 
-    def dump(self, obj: date) -> Optional[Buffer]:
+    def dump(self, obj: date) -> Buffer | None:
         # NOTE: whatever the PostgreSQL DateStyle input format (DMY, MDY, YMD)
         # the YYYY-MM-DD is always understood correctly.
         return str(obj).encode()
@@ -50,7 +52,7 @@ class DateBinaryDumper(Dumper):
     format = Format.BINARY
     oid = _oids.DATE_OID
 
-    def dump(self, obj: date) -> Optional[Buffer]:
+    def dump(self, obj: date) -> Buffer | None:
         days = obj.toordinal() - _pg_date_epoch_days
         return pack_int4(days)
 
@@ -77,7 +79,7 @@ class _BaseTimeDumper(Dumper):
 
 
 class _BaseTimeTextDumper(_BaseTimeDumper):
-    def dump(self, obj: time) -> Optional[Buffer]:
+    def dump(self, obj: time) -> Buffer | None:
         return str(obj).encode()
 
 
@@ -94,7 +96,7 @@ class TimeDumper(_BaseTimeTextDumper):
 class TimeTzDumper(_BaseTimeTextDumper):
     oid = _oids.TIMETZ_OID
 
-    def dump(self, obj: time) -> Optional[Buffer]:
+    def dump(self, obj: time) -> Buffer | None:
         self._get_offset(obj)
         return super().dump(obj)
 
@@ -103,7 +105,7 @@ class TimeBinaryDumper(_BaseTimeDumper):
     format = Format.BINARY
     oid = _oids.TIME_OID
 
-    def dump(self, obj: time) -> Optional[Buffer]:
+    def dump(self, obj: time) -> Buffer | None:
         us = obj.microsecond + 1_000_000 * (
             obj.second + 60 * (obj.minute + 60 * obj.hour)
         )
@@ -120,7 +122,7 @@ class TimeTzBinaryDumper(_BaseTimeDumper):
     format = Format.BINARY
     oid = _oids.TIMETZ_OID
 
-    def dump(self, obj: time) -> Optional[Buffer]:
+    def dump(self, obj: time) -> Buffer | None:
         us = obj.microsecond + 1_000_000 * (
             obj.second + 60 * (obj.minute + 60 * obj.hour)
         )
@@ -142,7 +144,7 @@ class _BaseDatetimeDumper(Dumper):
 
 
 class _BaseDatetimeTextDumper(_BaseDatetimeDumper):
-    def dump(self, obj: datetime) -> Optional[Buffer]:
+    def dump(self, obj: datetime) -> Buffer | None:
         # NOTE: whatever the PostgreSQL DateStyle input format (DMY, MDY, YMD)
         # the YYYY-MM-DD is always understood correctly.
         return str(obj).encode()
@@ -166,7 +168,7 @@ class DatetimeBinaryDumper(_BaseDatetimeDumper):
     format = Format.BINARY
     oid = _oids.TIMESTAMPTZ_OID
 
-    def dump(self, obj: datetime) -> Optional[Buffer]:
+    def dump(self, obj: datetime) -> Buffer | None:
         delta = obj - _pg_datetimetz_epoch
         micros = delta.microseconds + 1_000_000 * (86_400 * delta.days + delta.seconds)
         return pack_int8(micros)
@@ -182,7 +184,7 @@ class DatetimeNoTzBinaryDumper(_BaseDatetimeDumper):
     format = Format.BINARY
     oid = _oids.TIMESTAMP_OID
 
-    def dump(self, obj: datetime) -> Optional[Buffer]:
+    def dump(self, obj: datetime) -> Buffer | None:
         delta = obj - _pg_datetime_epoch
         micros = delta.microseconds + 1_000_000 * (86_400 * delta.days + delta.seconds)
         return pack_int8(micros)
@@ -191,14 +193,14 @@ class DatetimeNoTzBinaryDumper(_BaseDatetimeDumper):
 class TimedeltaDumper(Dumper):
     oid = _oids.INTERVAL_OID
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
         if _get_intervalstyle(self.connection) == b"sql_standard":
             self._dump_method = self._dump_sql
         else:
             self._dump_method = self._dump_any
 
-    def dump(self, obj: timedelta) -> Optional[Buffer]:
+    def dump(self, obj: timedelta) -> Buffer | None:
         return self._dump_method(self, obj)
 
     @staticmethod
@@ -222,7 +224,7 @@ class TimedeltaBinaryDumper(Dumper):
     format = Format.BINARY
     oid = _oids.INTERVAL_OID
 
-    def dump(self, obj: timedelta) -> Optional[Buffer]:
+    def dump(self, obj: timedelta) -> Buffer | None:
         micros = 1_000_000 * obj.seconds + obj.microseconds
         return _pack_interval(micros, obj.days, 0)
 
@@ -232,7 +234,7 @@ class DateLoader(Loader):
     _ORDER_DMY = 1
     _ORDER_MDY = 2
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         ds = _get_datestyle(self.connection)
         if ds.startswith(b"I"):  # ISO
@@ -411,7 +413,7 @@ class TimestampLoader(Loader):
     _ORDER_PGDM = 3
     _ORDER_PGMD = 4
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
 
         ds = _get_datestyle(self.connection)
@@ -493,7 +495,7 @@ class TimestamptzLoader(Loader):
         """
     )
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         self._timezone = get_tzinfo(self.connection.pgconn if self.connection else None)
 
@@ -565,7 +567,7 @@ class TimestamptzLoader(Loader):
 class TimestamptzBinaryLoader(Loader):
     format = Format.BINARY
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         self._timezone = get_tzinfo(self.connection.pgconn if self.connection else None)
 
@@ -610,7 +612,7 @@ class IntervalLoader(Loader):
         re.VERBOSE,
     )
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         if _get_intervalstyle(self.connection) == b"postgres":
             self._load_method = self._load_postgres
@@ -676,7 +678,7 @@ class IntervalBinaryLoader(Loader):
             raise DataError(f"can't parse interval: {e}") from None
 
 
-def _get_datestyle(conn: Optional["BaseConnection[Any]"]) -> bytes:
+def _get_datestyle(conn: "BaseConnection[Any]" | None) -> bytes:
     if conn:
         ds = conn.pgconn.parameter_status(b"DateStyle")
         if ds:
@@ -685,7 +687,7 @@ def _get_datestyle(conn: Optional["BaseConnection[Any]"]) -> bytes:
     return b"ISO, DMY"
 
 
-def _get_intervalstyle(conn: Optional["BaseConnection[Any]"]) -> bytes:
+def _get_intervalstyle(conn: "BaseConnection[Any]" | None) -> bytes:
     if conn:
         ints = conn.pgconn.parameter_status(b"IntervalStyle")
         if ints:
@@ -695,7 +697,7 @@ def _get_intervalstyle(conn: Optional["BaseConnection[Any]"]) -> bytes:
 
 
 def _get_timestamp_load_error(
-    conn: Optional["BaseConnection[Any]"], data: Buffer, ex: Optional[Exception] = None
+    conn: "BaseConnection[Any]" | None, data: Buffer, ex: Exception | None = None
 ) -> Exception:
     s = bytes(data).decode("utf8", "replace")
 
index 04616419d19286f3d23acb0a22832e1a646c49f0..0ae3d951779558862899994236278891ea7009e9 100644 (file)
@@ -2,8 +2,10 @@
 Adapters for the enum type.
 """
 
+from __future__ import annotations
+
 from enum import Enum
-from typing import Any, Dict, Generic, Optional, Mapping, Sequence
+from typing import Any, Dict, Generic, Mapping, Sequence
 from typing import Tuple, Type, Union, cast, TYPE_CHECKING
 
 from .. import sql
@@ -46,7 +48,7 @@ class EnumInfo(TypeInfo):
         super().__init__(name, oid, array_oid)
         self.labels = labels
         # Will be set by register_enum()
-        self.enum: Optional[Type[Enum]] = None
+        self.enum: Type[Enum] | None = None
 
     @classmethod
     def _get_info_query(cls, conn: "BaseConnection[Any]") -> Query:
@@ -98,7 +100,7 @@ class _BaseEnumDumper(Dumper, Generic[E]):
     enum: Type[E]
     _dump_map: EnumDumpMap[E]
 
-    def dump(self, value: E) -> Optional[Buffer]:
+    def dump(self, value: E) -> Buffer | None:
         return self._dump_map[value]
 
 
@@ -107,11 +109,11 @@ class EnumDumper(Dumper):
     Dumper for a generic Enum class
     """
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
         self._encoding = conn_encoding(self.connection)
 
-    def dump(self, value: E) -> Optional[Buffer]:
+    def dump(self, value: E) -> Buffer | None:
         return value.name.encode(self._encoding)
 
 
@@ -121,8 +123,8 @@ class EnumBinaryDumper(EnumDumper):
 
 def register_enum(
     info: EnumInfo,
-    context: Optional[AdaptContext] = None,
-    enum: Optional[Type[E]] = None,
+    context: AdaptContext | None = None,
+    enum: Type[E] | None = None,
     *,
     mapping: EnumMapping[E] = None,
 ) -> None:
@@ -209,7 +211,7 @@ def _make_load_map(
     info: EnumInfo,
     enum: Type[E],
     mapping: EnumMapping[E],
-    context: Optional[AdaptContext],
+    context: AdaptContext | None,
 ) -> _HEnumLoadMap[E]:
     enc = conn_encoding(context.connection if context else None)
     rv = []
@@ -237,7 +239,7 @@ def _make_dump_map(
     info: EnumInfo,
     enum: Type[E],
     mapping: EnumMapping[E],
-    context: Optional[AdaptContext],
+    context: AdaptContext | None,
 ) -> _HEnumDumpMap[E]:
     enc = conn_encoding(context.connection if context else None)
     rv = []
index 2c52f79f1ba193e49e35fb0ef92c7558ddabfb0a..526c0a688556a2a49ac1e355b73cc4522c89d306 100644 (file)
@@ -4,8 +4,10 @@ Dict to hstore adaptation
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 import re
-from typing import Dict, List, Optional, Type
+from typing import Dict, List, Type
 
 from .. import errors as e
 from .. import postgres
@@ -35,11 +37,11 @@ _re_hstore = re.compile(
 )
 
 
-Hstore: TypeAlias = Dict[str, Optional[str]]
+Hstore: TypeAlias = Dict[str, str | None]
 
 
 class BaseHstoreDumper(RecursiveDumper):
-    def dump(self, obj: Hstore) -> Optional[Buffer]:
+    def dump(self, obj: Hstore) -> Buffer | None:
         if not obj:
             return b""
 
@@ -96,7 +98,7 @@ class HstoreLoader(RecursiveLoader):
         return rv
 
 
-def register_hstore(info: TypeInfo, context: Optional[AdaptContext] = None) -> None:
+def register_hstore(info: TypeInfo, context: AdaptContext | None = None) -> None:
     """Register the adapters to load and dump hstore.
 
     :param info: The object with the information about the hstore type.
index 7ac2be63f179973fff3cc9db27713940330a1df8..8e2422de48d52e15736a2166fbaa515e65e18c83 100644 (file)
@@ -4,8 +4,10 @@ Adapters for JSON types.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import json
-from typing import Any, Callable, Dict, Optional, Tuple, Type, Union
+from typing import Any, Callable, Dict, Tuple, Type, Union
 
 from .. import abc
 from .. import _oids
@@ -20,7 +22,7 @@ JsonLoadsFunction = Callable[[Union[str, bytes]], Any]
 
 
 def set_json_dumps(
-    dumps: JsonDumpsFunction, context: Optional[abc.AdaptContext] = None
+    dumps: JsonDumpsFunction, context: abc.AdaptContext | None = None
 ) -> None:
     """
     Set the JSON serialisation function to store JSON objects in the database.
@@ -59,7 +61,7 @@ def set_json_dumps(
 
 
 def set_json_loads(
-    loads: JsonLoadsFunction, context: Optional[abc.AdaptContext] = None
+    loads: JsonLoadsFunction, context: abc.AdaptContext | None = None
 ) -> None:
     """
     Set the JSON parsing function to fetch JSON objects from the database.
@@ -114,7 +116,7 @@ def _make_loader(base: Type[Loader], loads: JsonLoadsFunction) -> Type[Loader]:
 class _JsonWrapper:
     __slots__ = ("obj", "dumps")
 
-    def __init__(self, obj: Any, dumps: Optional[JsonDumpsFunction] = None):
+    def __init__(self, obj: Any, dumps: JsonDumpsFunction | None = None):
         self.obj = obj
         self.dumps = dumps
 
@@ -138,11 +140,11 @@ class _JsonDumper(Dumper):
     # set_json_dumps) or by a subclass.
     _dumps: JsonDumpsFunction = json.dumps
 
-    def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, cls: type, context: abc.AdaptContext | None = None):
         super().__init__(cls, context)
         self.dumps = self.__class__._dumps
 
-    def dump(self, obj: Any) -> Optional[Buffer]:
+    def dump(self, obj: Any) -> Buffer | None:
         if isinstance(obj, _JsonWrapper):
             dumps = obj.dumps or self.dumps
             obj = obj.obj
@@ -171,7 +173,7 @@ class JsonbBinaryDumper(_JsonDumper):
     format = Format.BINARY
     oid = _oids.JSONB_OID
 
-    def dump(self, obj: Any) -> Optional[Buffer]:
+    def dump(self, obj: Any) -> Buffer | None:
         obj_bytes = super().dump(obj)
         if obj_bytes is not None:
             return b"\x01" + obj_bytes
@@ -184,7 +186,7 @@ class _JsonLoader(Loader):
     # set_json_loads) or by a subclass.
     _loads: JsonLoadsFunction = json.loads
 
-    def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None):
+    def __init__(self, oid: int, context: abc.AdaptContext | None = None):
         super().__init__(oid, context)
         self.loads = self.__class__._loads
 
index d37681009f60484588ed81a7d4e9db04e37c84b1..5704c80015cb1aae30b3ba40d09d80e05237e513 100644 (file)
@@ -4,9 +4,11 @@ Support for multirange types adaptation.
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 from decimal import Decimal
 from typing import Any, Generic, List, Iterable, MutableSequence
-from typing import Optional, Type, Union, overload, TYPE_CHECKING
+from typing import Type, Union, overload, TYPE_CHECKING
 from datetime import date, datetime
 
 from .. import sql
@@ -183,9 +185,9 @@ class TimestamptzMultirange(Multirange[datetime]):
 
 
 class BaseMultirangeDumper(RecursiveDumper):
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
-        self.sub_dumper: Optional[Dumper] = None
+        self.sub_dumper: Dumper | None = None
         self._adapt_format = PyFormat.from_pq(self.format)
 
     def get_key(self, obj: Multirange[Any], format: PyFormat) -> DumperKey:
@@ -256,7 +258,7 @@ class MultirangeDumper(BaseMultirangeDumper):
     The dumper can upgrade to one specific for a different range type.
     """
 
-    def dump(self, obj: Multirange[Any]) -> Optional[Buffer]:
+    def dump(self, obj: Multirange[Any]) -> Buffer | None:
         if not obj:
             return b"{}"
 
@@ -277,7 +279,7 @@ class MultirangeDumper(BaseMultirangeDumper):
 class MultirangeBinaryDumper(BaseMultirangeDumper):
     format = Format.BINARY
 
-    def dump(self, obj: Multirange[Any]) -> Optional[Buffer]:
+    def dump(self, obj: Multirange[Any]) -> Buffer | None:
         item = self._get_item(obj)
         if item is not None:
             dump = self._tx.get_dumper(item, self._adapt_format).dump
@@ -295,7 +297,7 @@ class MultirangeBinaryDumper(BaseMultirangeDumper):
 class BaseMultirangeLoader(RecursiveLoader, Generic[T]):
     subtype_oid: int
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         self._load = self._tx.get_loader(self.subtype_oid, format=self.format).load
 
@@ -366,7 +368,7 @@ class MultirangeBinaryLoader(BaseMultirangeLoader[T]):
 
 
 def register_multirange(
-    info: MultirangeInfo, context: Optional[AdaptContext] = None
+    info: MultirangeInfo, context: AdaptContext | None = None
 ) -> None:
     """Register the adapters to load and dump a multirange type.
 
index b8fc992040a6a5f6bf9f796d4ec2eb060865bffe..593b272e9ad46a00133b98516e1f187654610662 100644 (file)
@@ -4,7 +4,9 @@ Adapters for network types.
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Callable, Optional, Type, Union, TYPE_CHECKING
+from __future__ import annotations
+
+from typing import Callable, Type, Union, TYPE_CHECKING
 
 from .. import _oids
 from ..pq import Format
@@ -52,14 +54,14 @@ class _LazyIpaddress:
 class InterfaceDumper(Dumper):
     oid = _oids.INET_OID
 
-    def dump(self, obj: Interface) -> Optional[Buffer]:
+    def dump(self, obj: Interface) -> Buffer | None:
         return str(obj).encode()
 
 
 class NetworkDumper(Dumper):
     oid = _oids.CIDR_OID
 
-    def dump(self, obj: Network) -> Optional[Buffer]:
+    def dump(self, obj: Network) -> Buffer | None:
         return str(obj).encode()
 
 
@@ -69,7 +71,7 @@ class _AIBinaryDumper(Dumper):
 
 
 class AddressBinaryDumper(_AIBinaryDumper):
-    def dump(self, obj: Address) -> Optional[Buffer]:
+    def dump(self, obj: Address) -> Buffer | None:
         packed = obj.packed
         family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6
         head = bytes((family, obj.max_prefixlen, 0, len(packed)))
@@ -77,7 +79,7 @@ class AddressBinaryDumper(_AIBinaryDumper):
 
 
 class InterfaceBinaryDumper(_AIBinaryDumper):
-    def dump(self, obj: Interface) -> Optional[Buffer]:
+    def dump(self, obj: Interface) -> Buffer | None:
         packed = obj.packed
         family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6
         head = bytes((family, obj.network.prefixlen, 0, len(packed)))
@@ -90,11 +92,11 @@ class InetBinaryDumper(_AIBinaryDumper, _LazyIpaddress):
     Used when looking up by oid.
     """
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
         self._ensure_module()
 
-    def dump(self, obj: Union[Address, Interface]) -> Optional[Buffer]:
+    def dump(self, obj: Union[Address, Interface]) -> Buffer | None:
         packed = obj.packed
         family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6
         if isinstance(obj, (IPv4Interface, IPv6Interface)):
@@ -110,7 +112,7 @@ class NetworkBinaryDumper(Dumper):
     format = Format.BINARY
     oid = _oids.CIDR_OID
 
-    def dump(self, obj: Network) -> Optional[Buffer]:
+    def dump(self, obj: Network) -> Buffer | None:
         packed = obj.network_address.packed
         family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6
         head = bytes((family, obj.prefixlen, 1, len(packed)))
@@ -118,7 +120,7 @@ class NetworkBinaryDumper(Dumper):
 
 
 class _LazyIpaddressLoader(Loader, _LazyIpaddress):
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         self._ensure_module()
 
index b65f6315b2ffee1d6a117a64f38efe4fd718a96c..1669abb8d803936e32031bd864ce55c53737662d 100644 (file)
@@ -4,7 +4,7 @@ Adapters for None.
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Optional
+from __future__ import annotations
 
 from ..abc import AdaptContext, NoneType, Buffer
 from ..adapt import Dumper
@@ -16,7 +16,7 @@ class NoneDumper(Dumper):
     quote(), so it can be used in sql composition.
     """
 
-    def dump(self, obj: None) -> Optional[Buffer]:
+    def dump(self, obj: None) -> Buffer | None:
         raise NotImplementedError("NULL is passed to Postgres in other ways")
 
     def quote(self, obj: None) -> Buffer:
index 4bfef8e2fbe24db40267077234c52a52b28371f7..c3ece299150115c6820b1158c56e414e466dfd6d 100644 (file)
@@ -4,11 +4,13 @@ Adapters for numeric types.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import sys
 import struct
 from abc import ABC, abstractmethod
 from math import log
-from typing import Any, Callable, DefaultDict, Dict, Optional, Tuple, Union
+from typing import Any, Callable, DefaultDict, Dict, Tuple, Union
 from typing import cast, TYPE_CHECKING
 from decimal import Decimal, DefaultContext, Context
 
@@ -38,7 +40,7 @@ if TYPE_CHECKING:
 
 
 class _IntDumper(Dumper):
-    def dump(self, obj: Any) -> Optional[Buffer]:
+    def dump(self, obj: Any) -> Buffer | None:
         return str(obj).encode()
 
     def quote(self, obj: Any) -> Buffer:
@@ -49,7 +51,7 @@ class _IntDumper(Dumper):
 
 
 class _IntOrSubclassDumper(_IntDumper):
-    def dump(self, obj: Any) -> Optional[Buffer]:
+    def dump(self, obj: Any) -> Buffer | None:
         t = type(obj)
         # Convert to int in order to dump IntEnum or numpy.integer correctly
         if t is not int:
@@ -61,7 +63,7 @@ class _IntOrSubclassDumper(_IntDumper):
 class _SpecialValuesDumper(Dumper):
     _special: Dict[bytes, bytes] = {}
 
-    def dump(self, obj: Any) -> Optional[Buffer]:
+    def dump(self, obj: Any) -> Buffer | None:
         return str(obj).encode()
 
     def quote(self, obj: Any) -> Buffer:
@@ -95,21 +97,21 @@ class FloatBinaryDumper(Dumper):
     format = Format.BINARY
     oid = _oids.FLOAT8_OID
 
-    def dump(self, obj: float) -> Optional[Buffer]:
+    def dump(self, obj: float) -> Buffer | None:
         return pack_float8(obj)
 
 
 class Float4BinaryDumper(FloatBinaryDumper):
     oid = _oids.FLOAT4_OID
 
-    def dump(self, obj: float) -> Optional[Buffer]:
+    def dump(self, obj: float) -> Buffer | None:
         return pack_float4(obj)
 
 
 class DecimalDumper(_SpecialValuesDumper):
     oid = _oids.NUMERIC_OID
 
-    def dump(self, obj: Decimal) -> Optional[Buffer]:
+    def dump(self, obj: Decimal) -> Buffer | None:
         return dump_decimal_to_text(obj)
 
     _special = {
@@ -140,7 +142,7 @@ class OidDumper(_IntOrSubclassDumper):
 
 
 class IntDumper(Dumper):
-    def dump(self, obj: Any) -> Optional[Buffer]:
+    def dump(self, obj: Any) -> Buffer | None:
         raise TypeError(
             f"{type(self).__name__} is a dispatcher to other dumpers:"
             " dump() is not supposed to be called"
@@ -170,21 +172,21 @@ class IntDumper(Dumper):
 class Int2BinaryDumper(Int2Dumper):
     format = Format.BINARY
 
-    def dump(self, obj: int) -> Optional[Buffer]:
+    def dump(self, obj: int) -> Buffer | None:
         return pack_int2(obj)
 
 
 class Int4BinaryDumper(Int4Dumper):
     format = Format.BINARY
 
-    def dump(self, obj: int) -> Optional[Buffer]:
+    def dump(self, obj: int) -> Buffer | None:
         return pack_int4(obj)
 
 
 class Int8BinaryDumper(Int8Dumper):
     format = Format.BINARY
 
-    def dump(self, obj: int) -> Optional[Buffer]:
+    def dump(self, obj: int) -> Buffer | None:
         return pack_int8(obj)
 
 
@@ -196,14 +198,14 @@ BIT_PER_PGDIGIT = log(2) / log(10_000)
 class IntNumericBinaryDumper(IntNumericDumper):
     format = Format.BINARY
 
-    def dump(self, obj: int) -> Optional[Buffer]:
+    def dump(self, obj: int) -> Buffer | None:
         return dump_int_to_numeric_binary(obj)
 
 
 class OidBinaryDumper(OidDumper):
     format = Format.BINARY
 
-    def dump(self, obj: int) -> Optional[Buffer]:
+    def dump(self, obj: int) -> Buffer | None:
         return pack_uint4(obj)
 
 
@@ -356,7 +358,7 @@ class DecimalBinaryDumper(Dumper):
     format = Format.BINARY
     oid = _oids.NUMERIC_OID
 
-    def dump(self, obj: Decimal) -> Optional[Buffer]:
+    def dump(self, obj: Decimal) -> Buffer | None:
         return dump_decimal_to_numeric_binary(obj)
 
 
@@ -371,7 +373,7 @@ class _MixedNumericDumper(Dumper, ABC):
     # If numpy is available, the dumped object might be a numpy integer too
     int_classes: Union[type, Tuple[type, ...]] = ()
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
 
         # Verify if numpy is available. If it is, we might have to dump
@@ -385,13 +387,11 @@ class _MixedNumericDumper(Dumper, ABC):
                 _MixedNumericDumper.int_classes = int
 
     @abstractmethod
-    def dump(
-        self, obj: Union[Decimal, int, "numpy.integer[Any]"]
-    ) -> Optional[Buffer]: ...
+    def dump(self, obj: Union[Decimal, int, "numpy.integer[Any]"]) -> Buffer | None: ...
 
 
 class NumericDumper(_MixedNumericDumper):
-    def dump(self, obj: Union[Decimal, int, "numpy.integer[Any]"]) -> Optional[Buffer]:
+    def dump(self, obj: Union[Decimal, int, "numpy.integer[Any]"]) -> Buffer | None:
         if isinstance(obj, self.int_classes):
             return str(obj).encode()
         elif isinstance(obj, Decimal):
@@ -405,7 +405,7 @@ class NumericDumper(_MixedNumericDumper):
 class NumericBinaryDumper(_MixedNumericDumper):
     format = Format.BINARY
 
-    def dump(self, obj: Union[Decimal, int, "numpy.integer[Any]"]) -> Optional[Buffer]:
+    def dump(self, obj: Union[Decimal, int, "numpy.integer[Any]"]) -> Buffer | None:
         if type(obj) is int:
             return dump_int_to_numeric_binary(obj)
         elif isinstance(obj, Decimal):
index dba34139cbc2fc9c39f8b372d1f6715b7957cf04..20b375aa27977812fc7dcb85bc01e8c5eda3a284 100644 (file)
@@ -4,8 +4,10 @@ Support for range types adaptation.
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
+
 import re
-from typing import Any, Dict, Generic, List, Optional, Type, Tuple
+from typing import Any, Dict, Generic, List, Type, Tuple
 from typing import cast, TYPE_CHECKING
 from decimal import Decimal
 from datetime import date, datetime
@@ -84,8 +86,8 @@ class Range(Generic[T]):
 
     def __init__(
         self,
-        lower: Optional[T] = None,
-        upper: Optional[T] = None,
+        lower: T | None = None,
+        upper: T | None = None,
         bounds: str = "[)",
         empty: bool = False,
     ):
@@ -129,12 +131,12 @@ class Range(Generic[T]):
         return "".join(items)
 
     @property
-    def lower(self) -> Optional[T]:
+    def lower(self) -> T | None:
         """The lower bound of the range. `!None` if empty or unbound."""
         return self._lower
 
     @property
-    def upper(self) -> Optional[T]:
+    def upper(self) -> T | None:
         """The upper bound of the range. `!None` if empty or unbound."""
         return self._upper
 
@@ -285,9 +287,9 @@ class TimestamptzRange(Range[datetime]):
 
 
 class BaseRangeDumper(RecursiveDumper):
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
-        self.sub_dumper: Optional[Dumper] = None
+        self.sub_dumper: Dumper | None = None
         self._adapt_format = PyFormat.from_pq(self.format)
 
     def get_key(self, obj: Range[Any], format: PyFormat) -> DumperKey:
@@ -354,7 +356,7 @@ class RangeDumper(BaseRangeDumper):
     The dumper can upgrade to one specific for a different range type.
     """
 
-    def dump(self, obj: Range[Any]) -> Optional[Buffer]:
+    def dump(self, obj: Range[Any]) -> Buffer | None:
         item = self._get_item(obj)
         if item is not None:
             dump = self._tx.get_dumper(item, self._adapt_format).dump
@@ -401,7 +403,7 @@ _re_esc = re.compile(rb"([\\\"])")
 class RangeBinaryDumper(BaseRangeDumper):
     format = Format.BINARY
 
-    def dump(self, obj: Range[Any]) -> Optional[Buffer]:
+    def dump(self, obj: Range[Any]) -> Buffer | None:
         item = self._get_item(obj)
         if item is not None:
             dump = self._tx.get_dumper(item, self._adapt_format).dump
@@ -459,7 +461,7 @@ class BaseRangeLoader(RecursiveLoader, Generic[T]):
 
     subtype_oid: int
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         self._load = self._tx.get_loader(self.subtype_oid, format=self.format).load
 
@@ -557,7 +559,7 @@ def load_range_binary(data: Buffer, load: LoadFunc) -> Range[Any]:
     return Range(min, max, lb + ub)
 
 
-def register_range(info: RangeInfo, context: Optional[AdaptContext] = None) -> None:
+def register_range(info: RangeInfo, context: AdaptContext | None = None) -> None:
     """Register the adapters to load and dump a range type.
 
     :param info: The object with the information about the range to register.
index 5714454137e2759db3f9b33aac183587db66e3a4..107ad520c598ee586172c6487fcc3e5b3455f23d 100644 (file)
@@ -2,7 +2,9 @@
 Adapters for PostGIS geometries
 """
 
-from typing import Optional, Type
+from __future__ import annotations
+
+from typing import Type
 
 from .. import postgres
 from ..abc import AdaptContext, Buffer
@@ -11,7 +13,6 @@ from ..pq import Format
 from .._compat import cache
 from .._typeinfo import TypeInfo
 
-
 try:
     from shapely.wkb import loads, dumps
     from shapely.geometry.base import BaseGeometry
@@ -43,16 +44,16 @@ class GeometryLoader(Loader):
 class BaseGeometryBinaryDumper(Dumper):
     format = Format.BINARY
 
-    def dump(self, obj: "BaseGeometry") -> Optional[Buffer]:
+    def dump(self, obj: "BaseGeometry") -> Buffer | None:
         return dumps(obj)  # type: ignore
 
 
 class BaseGeometryDumper(Dumper):
-    def dump(self, obj: "BaseGeometry") -> Optional[Buffer]:
+    def dump(self, obj: "BaseGeometry") -> Buffer | None:
         return dumps(obj, hex=True).encode()  # type: ignore
 
 
-def register_shapely(info: TypeInfo, context: Optional[AdaptContext] = None) -> None:
+def register_shapely(info: TypeInfo, context: AdaptContext | None = None) -> None:
     """Register Shapely dumper and loaders."""
 
     # A friendly error warning instead of an AttributeError in case fetch()
index 88548180aac385fc9f047d1a65528aedb54b6d3b..2d17a94fcb7b6819449cee03e73d65b855e1735f 100644 (file)
@@ -4,7 +4,9 @@ Adapters for textual types.
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Optional, Union, TYPE_CHECKING
+from __future__ import annotations
+
+from typing import Union, TYPE_CHECKING
 
 from .. import _oids
 from ..pq import Format, Escaping
@@ -18,7 +20,7 @@ if TYPE_CHECKING:
 
 
 class _BaseStrDumper(Dumper):
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
         enc = conn_encoding(self.connection)
         self._encoding = enc if enc != "ascii" else "utf-8"
@@ -33,7 +35,7 @@ class _StrBinaryDumper(_BaseStrDumper):
 
     format = Format.BINARY
 
-    def dump(self, obj: str) -> Optional[Buffer]:
+    def dump(self, obj: str) -> Buffer | None:
         # the server will raise DataError subclass if the string contains 0x00
         return obj.encode(self._encoding)
 
@@ -45,7 +47,7 @@ class _StrDumper(_BaseStrDumper):
     Subclasses shall specify the oids of real types (text, varchar, name...).
     """
 
-    def dump(self, obj: str) -> Optional[Buffer]:
+    def dump(self, obj: str) -> Buffer | None:
         if "\x00" in obj:
             raise DataError("PostgreSQL text fields cannot contain NUL (0x00) bytes")
         else:
@@ -103,7 +105,7 @@ class StrDumperUnknown(_StrDumper):
 
 
 class TextLoader(Loader):
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         enc = conn_encoding(self.connection)
         self._encoding = enc if enc != "ascii" else ""
@@ -128,11 +130,11 @@ class BytesDumper(Dumper):
     oid = _oids.BYTEA_OID
     _qprefix = b""
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         super().__init__(cls, context)
         self._esc = Escaping(self.connection.pgconn if self.connection else None)
 
-    def dump(self, obj: Buffer) -> Optional[Buffer]:
+    def dump(self, obj: Buffer) -> Buffer | None:
         return self._esc.escape_bytea(obj)
 
     def quote(self, obj: Buffer) -> Buffer:
@@ -167,14 +169,14 @@ class BytesBinaryDumper(Dumper):
     format = Format.BINARY
     oid = _oids.BYTEA_OID
 
-    def dump(self, obj: Buffer) -> Optional[Buffer]:
+    def dump(self, obj: Buffer) -> Buffer | None:
         return obj
 
 
 class ByteaLoader(Loader):
     _escaping: "EscapingProto"
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         if not hasattr(self.__class__, "_escaping"):
             self.__class__._escaping = Escaping()
index df4509ee595b4831bec2043e8d2ec2ab54d0c6b2..fb9485d8e6e790470930b99478b1d51126b5e931 100644 (file)
@@ -4,7 +4,9 @@ Adapters for the UUID type.
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Callable, Optional, TYPE_CHECKING
+from __future__ import annotations
+
+from typing import Callable, TYPE_CHECKING
 
 from .. import _oids
 from ..pq import Format
@@ -21,19 +23,19 @@ UUID: Callable[..., "uuid.UUID"] = None  # type: ignore[assignment]
 class UUIDDumper(Dumper):
     oid = _oids.UUID_OID
 
-    def dump(self, obj: "uuid.UUID") -> Optional[Buffer]:
+    def dump(self, obj: "uuid.UUID") -> Buffer | None:
         return obj.hex.encode()
 
 
 class UUIDBinaryDumper(UUIDDumper):
     format = Format.BINARY
 
-    def dump(self, obj: "uuid.UUID") -> Optional[Buffer]:
+    def dump(self, obj: "uuid.UUID") -> Buffer | None:
         return obj.bytes
 
 
 class UUIDLoader(Loader):
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         super().__init__(oid, context)
         global UUID
         if UUID is None:
index 1247a8dd3cc10d8857a446f5cb8dc2628ea7d4cb..0a808346ef81795374d28be476269adc974ca07b 100644 (file)
@@ -8,13 +8,13 @@ These functions are designed to consume the generators returned by the
 
 # Copyright (C) 2020 The Psycopg Team
 
+from __future__ import annotations
 
 import os
 import sys
 import select
 import logging
 import selectors
-from typing import Optional
 from asyncio import get_event_loop, wait_for, Event, TimeoutError
 from selectors import DefaultSelector
 
@@ -34,7 +34,7 @@ READY_RW = Ready.RW
 logger = logging.getLogger(__name__)
 
 
-def wait_selector(gen: PQGen[RV], fileno: int, interval: Optional[float] = None) -> RV:
+def wait_selector(gen: PQGen[RV], fileno: int, interval: float | None = None) -> RV:
     """
     Wait for a generator using the best strategy available.
 
@@ -68,7 +68,7 @@ def wait_selector(gen: PQGen[RV], fileno: int, interval: Optional[float] = None)
         return rv
 
 
-def wait_conn(gen: PQGenConn[RV], interval: Optional[float] = None) -> RV:
+def wait_conn(gen: PQGenConn[RV], interval: float | None = None) -> RV:
     """
     Wait for a connection generator using the best strategy available.
 
@@ -103,9 +103,7 @@ def wait_conn(gen: PQGenConn[RV], interval: Optional[float] = None) -> RV:
         return rv
 
 
-async def wait_async(
-    gen: PQGen[RV], fileno: int, interval: Optional[float] = None
-) -> RV:
+async def wait_async(gen: PQGen[RV], fileno: int, interval: float | None = None) -> RV:
     """
     Coroutine waiting for a generator to complete.
 
@@ -166,7 +164,7 @@ async def wait_async(
         return rv
 
 
-async def wait_conn_async(gen: PQGenConn[RV], interval: Optional[float] = None) -> RV:
+async def wait_conn_async(gen: PQGenConn[RV], interval: float | None = None) -> RV:
     """
     Coroutine waiting for a connection generator to complete.
 
@@ -227,7 +225,7 @@ async def wait_conn_async(gen: PQGenConn[RV], interval: Optional[float] = None)
 # Specialised implementation of wait functions.
 
 
-def wait_select(gen: PQGen[RV], fileno: int, interval: Optional[float] = None) -> RV:
+def wait_select(gen: PQGen[RV], fileno: int, interval: float | None = None) -> RV:
     """
     Wait for a generator using select where supported.
 
@@ -272,7 +270,7 @@ else:
     _epoll_evmasks = {}
 
 
-def wait_epoll(gen: PQGen[RV], fileno: int, interval: Optional[float] = None) -> RV:
+def wait_epoll(gen: PQGen[RV], fileno: int, interval: float | None = None) -> RV:
     """
     Wait for a generator using epoll where supported.
 
@@ -327,7 +325,7 @@ else:
     _poll_evmasks = {}
 
 
-def wait_poll(gen: PQGen[RV], fileno: int, interval: Optional[float] = None) -> RV:
+def wait_poll(gen: PQGen[RV], fileno: int, interval: float | None = None) -> RV:
     """
     Wait for a generator using poll where supported.
 
index 7ff2994eb84707ea50012ff2a998d06093d905ea..50834c6b491cabb009f4785aa78d0546050a5d5d 100644 (file)
@@ -7,7 +7,7 @@ information. Will submit a bug.
 
 # Copyright (C) 2020 The Psycopg Team
 
-from typing import Any, List, Optional, Sequence, Tuple
+from typing import Any, List, Sequence, Tuple
 
 from psycopg import pq, abc, BaseConnection
 from psycopg.rows import Row, RowMaker
@@ -16,38 +16,36 @@ from psycopg.pq.abc import PGcancelConn, PGconn, PGresult
 from psycopg._compat import Deque
 
 class Transformer(abc.AdaptContext):
-    types: Optional[Tuple[int, ...]]
-    formats: Optional[List[pq.Format]]
-    def __init__(self, context: Optional[abc.AdaptContext] = None): ...
+    types: Tuple[int, ...] | None
+    formats: List[pq.Format] | None
+    def __init__(self, context: abc.AdaptContext | None = None): ...
     @classmethod
-    def from_context(cls, context: Optional[abc.AdaptContext]) -> "Transformer": ...
+    def from_context(cls, context: abc.AdaptContext | None) -> "Transformer": ...
     @property
-    def connection(self) -> Optional[BaseConnection[Any]]: ...
+    def connection(self) -> BaseConnection[Any] | None: ...
     @property
     def encoding(self) -> str: ...
     @property
     def adapters(self) -> AdaptersMap: ...
     @property
-    def pgresult(self) -> Optional[PGresult]: ...
+    def pgresult(self) -> PGresult | None: ...
     def set_pgresult(
         self,
-        result: Optional["PGresult"],
+        result: "PGresult" | None,
         *,
         set_loaders: bool = True,
-        format: Optional[pq.Format] = None,
+        format: pq.Format | None = None,
     ) -> None: ...
     def set_dumper_types(self, types: Sequence[int], format: pq.Format) -> None: ...
     def set_loader_types(self, types: Sequence[int], format: pq.Format) -> None: ...
     def dump_sequence(
         self, params: Sequence[Any], formats: Sequence[PyFormat]
-    ) -> Sequence[Optional[abc.Buffer]]: ...
+    ) -> Sequence[abc.Buffer | None]: ...
     def as_literal(self, obj: Any) -> bytes: ...
     def get_dumper(self, obj: Any, format: PyFormat) -> abc.Dumper: ...
     def load_rows(self, row0: int, row1: int, make_row: RowMaker[Row]) -> List[Row]: ...
-    def load_row(self, row: int, make_row: RowMaker[Row]) -> Optional[Row]: ...
-    def load_sequence(
-        self, record: Sequence[Optional[abc.Buffer]]
-    ) -> Tuple[Any, ...]: ...
+    def load_row(self, row: int, make_row: RowMaker[Row]) -> Row | None: ...
+    def load_sequence(self, record: Sequence[abc.Buffer | None]) -> Tuple[Any, ...]: ...
     def get_loader(self, oid: int, format: pq.Format) -> abc.Loader: ...
 
 # Generators
@@ -58,20 +56,20 @@ def cancel(
 def execute(pgconn: PGconn) -> abc.PQGen[List[PGresult]]: ...
 def send(pgconn: PGconn) -> abc.PQGen[None]: ...
 def fetch_many(pgconn: PGconn) -> abc.PQGen[List[PGresult]]: ...
-def fetch(pgconn: PGconn) -> abc.PQGen[Optional[PGresult]]: ...
+def fetch(pgconn: PGconn) -> abc.PQGen[PGresult | None]: ...
 def pipeline_communicate(
     pgconn: PGconn, commands: Deque[abc.PipelineCommand]
 ) -> abc.PQGen[List[List[PGresult]]]: ...
 def wait_c(
-    gen: abc.PQGen[abc.RV], fileno: int, interval: Optional[float] = None
+    gen: abc.PQGen[abc.RV], fileno: int, interval: float | None = None
 ) -> abc.RV: ...
 
 # Copy support
 def format_row_text(
-    row: Sequence[Any], tx: abc.Transformer, out: Optional[bytearray] = None
+    row: Sequence[Any], tx: abc.Transformer, out: bytearray | None = None
 ) -> bytearray: ...
 def format_row_binary(
-    row: Sequence[Any], tx: abc.Transformer, out: Optional[bytearray] = None
+    row: Sequence[Any], tx: abc.Transformer, out: bytearray | None = None
 ) -> bytearray: ...
 def parse_row_text(data: abc.Buffer, tx: abc.Transformer) -> Tuple[Any, ...]: ...
 def parse_row_binary(data: abc.Buffer, tx: abc.Transformer) -> Tuple[Any, ...]: ...
index e32ef19d1d104dfd6b1e1b21a5ee1993d3d127bf..3f587d2c4129ee210b71f0ea49734bbbec4634f1 100644 (file)
@@ -35,7 +35,7 @@ cdef class CDumper:
 
     oid = oids.INVALID_OID
 
-    def __cinit__(self, cls, context: Optional[AdaptContext] = None):
+    def __cinit__(self, cls, context: AdaptContext | None = None):
         self.cls = cls
         conn = context.connection if context is not None else None
         self._pgconn = conn.pgconn if conn is not None else None
@@ -58,7 +58,7 @@ cdef class CDumper:
         """
         raise NotImplementedError()
 
-    def dump(self, obj) -> Optional[Buffer]:
+    def dump(self, obj) -> Buffer | None:
         """Return the Postgres representation of *obj* as Python array of bytes"""
         cdef rv = PyByteArray_FromStringAndSize("", 0)
         cdef Py_ssize_t length = self.cdump(obj, rv, 0)
@@ -148,7 +148,7 @@ cdef class CLoader:
     cdef public libpq.Oid oid
     cdef pq.PGconn _pgconn
 
-    def __cinit__(self, libpq.Oid oid, context: Optional[AdaptContext] = None):
+    def __cinit__(self, libpq.Oid oid, context: AdaptContext | None = None):
         self.oid = oid
         conn = context.connection if context is not None else None
         self._pgconn = conn.pgconn if conn is not None else None
@@ -167,5 +167,5 @@ cdef class _CRecursiveLoader(CLoader):
 
     cdef Transformer _tx
 
-    def __cinit__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __cinit__(self, oid: int, context: AdaptContext | None = None):
         self._tx = Transformer.from_context(context)
index df06b1d1cbe23702700e3b5f822513588cc696a4..df210f698d1ee83fd75d64cf8317335f796cab71 100644 (file)
@@ -198,7 +198,7 @@ def fetch_many(pq.PGconn pgconn) -> PQGen[List[PGresult]]:
     return results
 
 
-def fetch(pq.PGconn pgconn) -> PQGen[Optional[PGresult]]:
+def fetch(pq.PGconn pgconn) -> PQGen[PGresult | None]:
     """
     Generator retrieving a single result from the database without blocking.
 
index a4fbe498e27dcee9873d6028ae3f3273e532a54b..c9849551eee4f278d882628d0fcfdf426bd96434 100644 (file)
@@ -19,7 +19,7 @@ from cpython.bytes cimport PyBytes_AS_STRING
 from cpython.tuple cimport PyTuple_New, PyTuple_SET_ITEM
 from cpython.object cimport PyObject, PyObject_CallFunctionObjArgs
 
-from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple
+from typing import Any, Dict, Iterable, List, Sequence, Tuple
 
 from psycopg import errors as e
 from psycopg.pq import Format as PqFormat
@@ -98,7 +98,7 @@ cdef class Transformer:
 
     cdef dict _oid_types
 
-    def __cinit__(self, context: Optional["AdaptContext"] = None):
+    def __cinit__(self, context: "AdaptContext" | None = None):
         if context is not None:
             self.adapters = context.adapters
             self.connection = context.connection
@@ -111,7 +111,7 @@ cdef class Transformer:
         self._none_oid = -1
 
     @classmethod
-    def from_context(cls, context: Optional["AdaptContext"]):
+    def from_context(cls, context: "AdaptContext" | None):
         """
         Return a Transformer from an AdaptContext.
 
@@ -126,7 +126,7 @@ cdef class Transformer:
         return self._encoding
 
     @property
-    def pgresult(self) -> Optional[PGresult]:
+    def pgresult(self) -> PGresult | None:
         return self._pgresult
 
     cpdef set_pgresult(
@@ -493,7 +493,7 @@ cdef class Transformer:
                 Py_DECREF(<object>brecord)
         return records
 
-    def load_row(self, int row, object make_row) -> Optional[Row]:
+    def load_row(self, int row, object make_row) -> Row | None:
         if self._pgresult is None:
             return None
 
@@ -537,7 +537,7 @@ cdef class Transformer:
                 make_row, <PyObject *>record, NULL)
         return record
 
-    cpdef object load_sequence(self, record: Sequence[Optional[Buffer]]):
+    cpdef object load_sequence(self, record: Sequence[Buffer | None]):
         cdef Py_ssize_t nfields = len(record)
         out = PyTuple_New(nfields)
         cdef PyObject *loader  # borrowed RowLoader
index 6117abd1e474447cb07bd46dcc097be9e70ede06..86e6910aa12de0d7003cb7a20a6fd14381bda80e 100644 (file)
@@ -87,7 +87,7 @@ cdef class PGconn:
             self._pgconn_ptr = NULL
 
     @property
-    def pgconn_ptr(self) -> Optional[int]:
+    def pgconn_ptr(self) -> int | None:
         if self._pgconn_ptr:
             return <long long><void *>self._pgconn_ptr
         else:
@@ -162,7 +162,7 @@ cdef class PGconn:
     def transaction_status(self) -> int:
         return libpq.PQtransactionStatus(self._pgconn_ptr)
 
-    def parameter_status(self, const char *name) -> Optional[bytes]:
+    def parameter_status(self, const char *name) -> bytes | None:
         _ensure_pgconn(self)
         cdef const char *rv = libpq.PQparameterStatus(self._pgconn_ptr, name)
         if rv is not NULL:
@@ -226,9 +226,9 @@ cdef class PGconn:
     def exec_params(
         self,
         const char *command,
-        param_values: Optional[Sequence[Optional[bytes]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[bytes | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         int result_format = PqFormat.TEXT,
     ) -> PGresult:
         _ensure_pgconn(self)
@@ -254,9 +254,9 @@ cdef class PGconn:
     def send_query_params(
         self,
         const char *command,
-        param_values: Optional[Sequence[Optional[bytes]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[bytes | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         int result_format = PqFormat.TEXT,
     ) -> None:
         _ensure_pgconn(self)
@@ -284,7 +284,7 @@ cdef class PGconn:
         self,
         const char *name,
         const char *command,
-        param_types: Optional[Sequence[int]] = None,
+        param_types: Sequence[int] | None = None,
     ) -> None:
         _ensure_pgconn(self)
 
@@ -310,8 +310,8 @@ cdef class PGconn:
     def send_query_prepared(
         self,
         const char *name,
-        param_values: Optional[Sequence[Optional[bytes]]],
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[bytes | None] | None,
+        param_formats: Sequence[int] | None = None,
         int result_format = PqFormat.TEXT,
     ) -> None:
         _ensure_pgconn(self)
@@ -339,7 +339,7 @@ cdef class PGconn:
         self,
         const char *name,
         const char *command,
-        param_types: Optional[Sequence[int]] = None,
+        param_types: Sequence[int] | None = None,
     ) -> PGresult:
         _ensure_pgconn(self)
 
@@ -363,8 +363,8 @@ cdef class PGconn:
     def exec_prepared(
         self,
         const char *name,
-        param_values: Optional[Sequence[bytes]],
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[bytes] | None,
+        param_formats: Sequence[int] | None = None,
         int result_format = PqFormat.TEXT,
     ) -> PGresult:
         _ensure_pgconn(self)
@@ -463,7 +463,7 @@ cdef class PGconn:
                 f"sending close prepared failed: {error_message(self)}"
             )
 
-    def get_result(self) -> Optional["PGresult"]:
+    def get_result(self) -> "PGresult" | None:
         cdef libpq.PGresult *pgresult = libpq.PQgetResult(self._pgconn_ptr)
         if pgresult is NULL:
             return None
@@ -539,7 +539,7 @@ cdef class PGconn:
             raise e.OperationalError(f"sending copy data failed: {error_message(self)}")
         return rv
 
-    def put_copy_end(self, error: Optional[bytes] = None) -> int:
+    def put_copy_end(self, error: bytes | None = None) -> int:
         cdef int rv
         cdef const char *cerr = NULL
         if error is not None:
@@ -710,9 +710,9 @@ cdef void notice_receiver(void *arg, const libpq.PGresult *res_ptr) with gil:
 
 
 cdef (Py_ssize_t, libpq.Oid *, char * const*, int *, int *) _query_params_args(
-    list param_values: Optional[Sequence[Optional[bytes]]],
-    param_types: Optional[Sequence[int]],
-    list param_formats: Optional[Sequence[int]],
+    list param_values: Sequence[bytes | None] | None,
+    param_types: Sequence[int] | None,
+    list param_formats: Sequence[int] | None,
 ) except *:
     cdef int i
 
index 6df42e8e3166824c2af197e9b06668992daa37f6..696d44ff19b8c00ac675533211cc46d932d58fa2 100644 (file)
@@ -36,7 +36,7 @@ cdef class PGresult:
             self._pgresult_ptr = NULL
 
     @property
-    def pgresult_ptr(self) -> Optional[int]:
+    def pgresult_ptr(self) -> int | None:
         if self._pgresult_ptr:
             return <long long><void *>self._pgresult_ptr
         else:
@@ -50,7 +50,7 @@ cdef class PGresult:
     def error_message(self) -> bytes:
         return libpq.PQresultErrorMessage(self._pgresult_ptr)
 
-    def error_field(self, int fieldcode) -> Optional[bytes]:
+    def error_field(self, int fieldcode) -> bytes | None:
         cdef char * rv = libpq.PQresultErrorField(self._pgresult_ptr, fieldcode)
         if rv is not NULL:
             return rv
@@ -65,7 +65,7 @@ cdef class PGresult:
     def nfields(self) -> int:
         return libpq.PQnfields(self._pgresult_ptr)
 
-    def fname(self, int column_number) -> Optional[bytes]:
+    def fname(self, int column_number) -> bytes | None:
         cdef char *rv = libpq.PQfname(self._pgresult_ptr, column_number)
         if rv is not NULL:
             return rv
@@ -94,7 +94,7 @@ cdef class PGresult:
     def binary_tuples(self) -> int:
         return libpq.PQbinaryTuples(self._pgresult_ptr)
 
-    def get_value(self, int row_number, int column_number) -> Optional[bytes]:
+    def get_value(self, int row_number, int column_number) -> bytes | None:
         cdef int crow = row_number
         cdef int ccol = column_number
         cdef int length = libpq.PQgetlength(self._pgresult_ptr, crow, ccol)
@@ -117,7 +117,7 @@ cdef class PGresult:
         return libpq.PQparamtype(self._pgresult_ptr, param_number)
 
     @property
-    def command_status(self) -> Optional[bytes]:
+    def command_status(self) -> bytes | None:
         cdef char *rv = libpq.PQcmdStatus(self._pgresult_ptr)
         if rv is not NULL:
             return rv
@@ -125,7 +125,7 @@ cdef class PGresult:
             return None
 
     @property
-    def command_tuples(self) -> Optional[int]:
+    def command_tuples(self) -> int | None:
         cdef char *rv = libpq.PQcmdTuples(self._pgresult_ptr)
         if rv is NULL:
             return None
index 5b3a7c387f30b132e1b6f30b6b0842fe92b0a014..a3d8d908849fde0bafe3232431b65a052d9f1385 100644 (file)
@@ -28,7 +28,7 @@ cdef class BoolDumper(CDumper):
 
         return 1
 
-    def quote(self, obj: bool) -> Optional[Buffer]:
+    def quote(self, obj: bool) -> Buffer | None:
         if obj is True:
             return b"true"
         elif obj is False:
index c11e7b11c26e23afc858a8727c390c3d230c8ce5..2e1f1eee315391815537bb04a0779abfcb006e51 100644 (file)
@@ -310,7 +310,7 @@ cdef class TimedeltaDumper(CDumper):
     oid = oids.INTERVAL_OID
     cdef int _style
 
-    def __cinit__(self, cls, context: Optional[AdaptContext] = None):
+    def __cinit__(self, cls, context: AdaptContext | None = None):
 
         cdef const char *ds = _get_intervalstyle(self._pgconn)
         if ds[0] == b's':  # sql_standard
@@ -371,7 +371,7 @@ cdef class DateLoader(CLoader):
     format = PQ_TEXT
     cdef int _order
 
-    def __cinit__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __cinit__(self, oid: int, context: AdaptContext | None = None):
 
         cdef const char *ds = _get_datestyle(self._pgconn)
         if ds[0] == b'I':  # ISO
@@ -576,7 +576,7 @@ cdef class TimestampLoader(CLoader):
     format = PQ_TEXT
     cdef int _order
 
-    def __cinit__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __cinit__(self, oid: int, context: AdaptContext | None = None):
 
         cdef const char *ds = _get_datestyle(self._pgconn)
         if ds[0] == b'I':  # ISO
@@ -714,7 +714,7 @@ cdef class TimestampBinaryLoader(CLoader):
 cdef class _BaseTimestamptzLoader(CLoader):
     cdef object _time_zone
 
-    def __cinit__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __cinit__(self, oid: int, context: AdaptContext | None = None):
         self._time_zone = _timezone_from_connection(self._pgconn)
 
 
@@ -724,7 +724,7 @@ cdef class TimestamptzLoader(_BaseTimestamptzLoader):
     format = PQ_TEXT
     cdef int _order
 
-    def __cinit__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __cinit__(self, oid: int, context: AdaptContext | None = None):
 
         cdef const char *ds = _get_datestyle(self._pgconn)
         if ds[0] == b'I':  # ISO
@@ -871,7 +871,7 @@ cdef class IntervalLoader(CLoader):
     format = PQ_TEXT
     cdef int _style
 
-    def __cinit__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __cinit__(self, oid: int, context: AdaptContext | None = None):
 
         cdef const char *ds = _get_intervalstyle(self._pgconn)
         if ds[0] == b'p' and ds[8] == 0:  # postgres
@@ -1096,7 +1096,7 @@ cdef object _timezone_from_seconds(int sec, __cache={}):
 
 
 cdef object _get_timestamp_load_error(
-    pq.PGconn pgconn, const char *data, ex: Optional[Exception] = None
+    pq.PGconn pgconn, const char *data, ex: Exception | None = None
 ):
     s = bytes(data).decode("utf8", "replace")
 
index f2f2c2ac1e5216c29cd1e128d9faf26abde124d4..bf19895233bfedcfa22e3bd8e0059ca25dc872ea 100644 (file)
@@ -55,7 +55,7 @@ cdef class _IntDumper(CDumper):
     cdef Py_ssize_t cdump(self, obj, bytearray rv, Py_ssize_t offset) except -1:
         return dump_int_to_text(obj, rv, offset)
 
-    def quote(self, obj) -> Optional[Buffer]:
+    def quote(self, obj) -> Buffer | None:
         cdef Py_ssize_t length
 
         rv = PyByteArray_FromStringAndSize("", 0)
@@ -311,7 +311,7 @@ cdef class _FloatDumper(CDumper):
         PyMem_Free(out)
         return length
 
-    def quote(self, obj) -> Optional[Buffer]:
+    def quote(self, obj) -> Buffer | None:
         value = bytes(self.dump(obj))
         cdef PyObject *ptr = PyDict_GetItem(_special_float, value)
         if ptr != NULL:
@@ -417,7 +417,7 @@ cdef class DecimalDumper(CDumper):
     cdef Py_ssize_t cdump(self, obj, bytearray rv, Py_ssize_t offset) except -1:
         return dump_decimal_to_text(obj, rv, offset)
 
-    def quote(self, obj) -> Optional[Buffer]:
+    def quote(self, obj) -> Buffer | None:
         value = bytes(self.dump(obj))
         cdef PyObject *ptr = PyDict_GetItem(_special_decimal, value)
         if ptr != NULL:
@@ -524,7 +524,7 @@ cdef class _MixedNumericDumper(CDumper):
 
     oid = oids.NUMERIC_OID
 
-    def __cinit__(self, cls, context: Optional[AdaptContext] = None):
+    def __cinit__(self, cls, context: AdaptContext | None = None):
         global _int_classes
 
         if _int_classes is None:
index 170b17b7db36d5af83a6535702f6f19c559cddaa..f1b8b64f43bb0425359b9c6d0a84ccc2e4316a25 100644 (file)
@@ -30,7 +30,7 @@ cdef class _BaseStrDumper(CDumper):
     cdef char *encoding
     cdef bytes _bytes_encoding  # needed to keep `encoding` alive
 
-    def __cinit__(self, cls, context: Optional[AdaptContext] = None):
+    def __cinit__(self, cls, context: AdaptContext | None = None):
 
         self.is_utf8 = 0
         self.encoding = "utf-8"
@@ -138,7 +138,7 @@ cdef class _TextLoader(CLoader):
     cdef char *encoding
     cdef bytes _bytes_encoding  # needed to keep `encoding` alive
 
-    def __cinit__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __cinit__(self, oid: int, context: AdaptContext | None = None):
 
         self.is_utf8 = 0
         self.encoding = "utf-8"
index 9169f759cb80cdb1f9dff13d332e0595a731e81c..7629d1c460d161375662e6c0c8dde82d6fc4da39 100644 (file)
@@ -4,11 +4,13 @@ Task for Scheduler and AsyncScheduler
 
 # Copyright (C) 2023 The Psycopg Team
 
-from typing import Any, Callable, Optional
+from __future__ import annotations
+
+from typing import Any, Callable
 from dataclasses import dataclass, field
 
 
 @dataclass(order=True)
 class Task:
     time: float
-    action: Optional[Callable[[], Any]] = field(compare=False)
+    action: Callable[[], Any] | None = field(compare=False)
index 5b0c839918a6d3df01d61ab559ad9195f9993689..b2946ee0a1722e75a9c02d3f61c62075c90d9247 100644 (file)
@@ -4,9 +4,11 @@ psycopg connection pool base class and functionalities.
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 from time import monotonic
 from random import random
-from typing import Any, Dict, Optional, Tuple, TYPE_CHECKING
+from typing import Any, Dict, Tuple, TYPE_CHECKING
 
 from psycopg import errors as e
 
@@ -44,10 +46,10 @@ class BasePool:
         self,
         conninfo: str = "",
         *,
-        kwargs: Optional[Dict[str, Any]],
+        kwargs: Dict[str, Any] | None,
         min_size: int,
-        max_size: Optional[int],
-        name: Optional[str],
+        max_size: int | None,
+        name: str | None,
         timeout: float,
         max_waiting: int,
         max_lifetime: float,
@@ -116,7 +118,7 @@ class BasePool:
         """`!True` if the pool is closed."""
         return self._closed
 
-    def _check_size(self, min_size: int, max_size: Optional[int]) -> Tuple[int, int]:
+    def _check_size(self, min_size: int, max_size: int | None) -> Tuple[int, int]:
         if max_size is None:
             max_size = min_size
 
index 0be5d614820e927a59de563db0d86716fc2cc279..fd3b4f4620b833af55e2135baefda9e5cb2dee9e 100644 (file)
@@ -10,7 +10,7 @@ Psycopg null connection pool module (sync version).
 from __future__ import annotations
 
 import logging
-from typing import Any, cast, Dict, Optional, Type
+from typing import Any, cast, Dict, Type
 
 from psycopg import Connection
 from psycopg.pq import TransactionStatus
@@ -32,20 +32,20 @@ class NullConnectionPool(_BaseNullConnectionPool, ConnectionPool[CT]):
         conninfo: str = "",
         *,
         connection_class: Type[CT] = cast(Type[CT], Connection),
-        kwargs: Optional[Dict[str, Any]] = None,
+        kwargs: Dict[str, Any] | None = None,
         min_size: int = 0,
-        max_size: Optional[int] = None,
+        max_size: int | None = None,
         open: bool | None = None,
-        configure: Optional[ConnectionCB[CT]] = None,
-        check: Optional[ConnectionCB[CT]] = None,
-        reset: Optional[ConnectionCB[CT]] = None,
-        name: Optional[str] = None,
+        configure: ConnectionCB[CT] | None = None,
+        check: ConnectionCB[CT] | None = None,
+        reset: ConnectionCB[CT] | None = None,
+        name: str | None = None,
         timeout: float = 30.0,
         max_waiting: int = 0,
         max_lifetime: float = 60 * 60.0,
         max_idle: float = 10 * 60.0,
         reconnect_timeout: float = 5 * 60.0,
-        reconnect_failed: Optional[ConnectFailedCB] = None,
+        reconnect_failed: ConnectFailedCB | None = None,
         num_workers: int = 3,
     ):  # Note: min_size default value changed to 0.
 
@@ -97,11 +97,11 @@ class NullConnectionPool(_BaseNullConnectionPool, ConnectionPool[CT]):
 
         logger.info("pool %r is ready to use", self.name)
 
-    def _get_ready_connection(self, timeout: Optional[float]) -> Optional[CT]:
+    def _get_ready_connection(self, timeout: float | None) -> CT | None:
         if timeout is not None and timeout <= 0.0:
             raise PoolTimeout()
 
-        conn: Optional[CT] = None
+        conn: CT | None = None
         if self.max_size == 0 or self._nconns < self.max_size:
             # Create a new connection for the client
             try:
@@ -132,7 +132,7 @@ class NullConnectionPool(_BaseNullConnectionPool, ConnectionPool[CT]):
             self._nconns -= 1
             return True
 
-    def resize(self, min_size: int, max_size: Optional[int] = None) -> None:
+    def resize(self, min_size: int, max_size: int | None = None) -> None:
         """Change the size of the pool during runtime.
 
         Only *max_size* can be changed; *min_size* must remain 0.
index a9baa8e12e115873984e8d9dab466a3b53ab0a2e..4cac69230395b83d53376ca15e0482cf8175d0ea 100644 (file)
@@ -7,7 +7,7 @@ Psycopg null connection pool module (async version).
 from __future__ import annotations
 
 import logging
-from typing import Any, cast, Dict, Optional, Type
+from typing import Any, cast, Dict, Type
 
 from psycopg import AsyncConnection
 from psycopg.pq import TransactionStatus
@@ -28,20 +28,20 @@ class AsyncNullConnectionPool(_BaseNullConnectionPool, AsyncConnectionPool[ACT])
         conninfo: str = "",
         *,
         connection_class: Type[ACT] = cast(Type[ACT], AsyncConnection),
-        kwargs: Optional[Dict[str, Any]] = None,
+        kwargs: Dict[str, Any] | None = None,
         min_size: int = 0,  # Note: min_size default value changed to 0.
-        max_size: Optional[int] = None,
+        max_size: int | None = None,
         open: bool | None = None,
-        configure: Optional[AsyncConnectionCB[ACT]] = None,
-        check: Optional[AsyncConnectionCB[ACT]] = None,
-        reset: Optional[AsyncConnectionCB[ACT]] = None,
-        name: Optional[str] = None,
+        configure: AsyncConnectionCB[ACT] | None = None,
+        check: AsyncConnectionCB[ACT] | None = None,
+        reset: AsyncConnectionCB[ACT] | None = None,
+        name: str | None = None,
         timeout: float = 30.0,
         max_waiting: int = 0,
         max_lifetime: float = 60 * 60.0,
         max_idle: float = 10 * 60.0,
         reconnect_timeout: float = 5 * 60.0,
-        reconnect_failed: Optional[AsyncConnectFailedCB] = None,
+        reconnect_failed: AsyncConnectFailedCB | None = None,
         num_workers: int = 3,
     ):
         super().__init__(
@@ -92,11 +92,11 @@ class AsyncNullConnectionPool(_BaseNullConnectionPool, AsyncConnectionPool[ACT])
 
         logger.info("pool %r is ready to use", self.name)
 
-    async def _get_ready_connection(self, timeout: Optional[float]) -> Optional[ACT]:
+    async def _get_ready_connection(self, timeout: float | None) -> ACT | None:
         if timeout is not None and timeout <= 0.0:
             raise PoolTimeout()
 
-        conn: Optional[ACT] = None
+        conn: ACT | None = None
         if self.max_size == 0 or self._nconns < self.max_size:
             # Create a new connection for the client
             try:
@@ -128,7 +128,7 @@ class AsyncNullConnectionPool(_BaseNullConnectionPool, AsyncConnectionPool[ACT])
             self._nconns -= 1
             return True
 
-    async def resize(self, min_size: int, max_size: Optional[int] = None) -> None:
+    async def resize(self, min_size: int, max_size: int | None = None) -> None:
         """Change the size of the pool during runtime.
 
         Only *max_size* can be changed; *min_size* must remain 0.
index 4a086827c0b7959cc8abb72d710be18cc3c343e3..f8ae79d796af7a3f088198983cbea056164da1f7 100644 (file)
@@ -15,7 +15,7 @@ from abc import ABC, abstractmethod
 from time import monotonic
 from types import TracebackType
 from typing import Any, Iterator, cast, Dict, Generic, List
-from typing import Optional, Type
+from typing import Type
 from weakref import ref
 from contextlib import contextmanager
 
@@ -43,20 +43,20 @@ class ConnectionPool(Generic[CT], BasePool):
         conninfo: str = "",
         *,
         connection_class: Type[CT] = cast(Type[CT], Connection),
-        kwargs: Optional[Dict[str, Any]] = None,
+        kwargs: Dict[str, Any] | None = None,
         min_size: int = 4,
-        max_size: Optional[int] = None,
+        max_size: int | None = None,
         open: bool | None = None,
-        configure: Optional[ConnectionCB[CT]] = None,
-        check: Optional[ConnectionCB[CT]] = None,
-        reset: Optional[ConnectionCB[CT]] = None,
-        name: Optional[str] = None,
+        configure: ConnectionCB[CT] | None = None,
+        check: ConnectionCB[CT] | None = None,
+        reset: ConnectionCB[CT] | None = None,
+        name: str | None = None,
         timeout: float = 30.0,
         max_waiting: int = 0,
         max_lifetime: float = 60 * 60.0,
         max_idle: float = 10 * 60.0,
         reconnect_timeout: float = 5 * 60.0,
-        reconnect_failed: Optional[ConnectFailedCB] = None,
+        reconnect_failed: ConnectFailedCB | None = None,
         num_workers: int = 3,
     ):
         self.connection_class = connection_class
@@ -75,9 +75,9 @@ class ConnectionPool(Generic[CT], BasePool):
         self._waiting = Deque[WaitingClient[CT]]()
 
         # to notify that the pool is full
-        self._pool_full_event: Optional[Event] = None
+        self._pool_full_event: Event | None = None
 
-        self._sched_runner: Optional[Worker] = None
+        self._sched_runner: Worker | None = None
         self._workers: List[Worker] = []
 
         super().__init__(
@@ -153,7 +153,7 @@ class ConnectionPool(Generic[CT], BasePool):
         logger.info("pool %r is ready to use", self.name)
 
     @contextmanager
-    def connection(self, timeout: Optional[float] = None) -> Iterator[CT]:
+    def connection(self, timeout: float | None = None) -> Iterator[CT]:
         """Context manager to obtain a connection from the pool.
 
         Return the connection immediately if available, otherwise wait up to
@@ -175,7 +175,7 @@ class ConnectionPool(Generic[CT], BasePool):
             t1 = monotonic()
             self._stats[self._USAGE_MS] += int(1000.0 * (t1 - t0))
 
-    def getconn(self, timeout: Optional[float] = None) -> CT:
+    def getconn(self, timeout: float | None = None) -> CT:
         """Obtain a connection from the pool.
 
         You should preferably use `connection()`. Use this function only if
@@ -262,12 +262,12 @@ class ConnectionPool(Generic[CT], BasePool):
         conn._pool = self
         return conn
 
-    def _get_ready_connection(self, timeout: Optional[float]) -> Optional[CT]:
+    def _get_ready_connection(self, timeout: float | None) -> CT | None:
         """Return a connection, if the client deserves one."""
         if timeout is not None and timeout <= 0.0:
             raise PoolTimeout()
 
-        conn: Optional[CT] = None
+        conn: CT | None = None
         if self._pool:
             # Take a connection ready out of the pool
             conn = self._pool.popleft()
@@ -467,13 +467,13 @@ class ConnectionPool(Generic[CT], BasePool):
 
     def __exit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         self.close()
 
-    def resize(self, min_size: int, max_size: Optional[int] = None) -> None:
+    def resize(self, min_size: int, max_size: int | None = None) -> None:
         """Change the size of the pool during runtime."""
         min_size, max_size = self._check_size(min_size, max_size)
 
@@ -586,7 +586,7 @@ class ConnectionPool(Generic[CT], BasePool):
                     "task run %s failed: %s: %s", task, ex.__class__.__name__, ex
                 )
 
-    def _connect(self, timeout: Optional[float] = None) -> CT:
+    def _connect(self, timeout: float | None = None) -> CT:
         """Return a new connection configured for the pool."""
         self._stats[self._CONNECTIONS_NUM] += 1
         kwargs = self.kwargs
@@ -619,7 +619,7 @@ class ConnectionPool(Generic[CT], BasePool):
         return conn
 
     def _add_connection(
-        self, attempt: Optional[AttemptWithBackoff], growing: bool = False
+        self, attempt: AttemptWithBackoff | None, growing: bool = False
     ) -> None:
         """Try to connect and add the connection to the pool.
 
@@ -788,7 +788,7 @@ class ConnectionPool(Generic[CT], BasePool):
                 conn.close()
 
     def _shrink_pool(self) -> None:
-        to_close: Optional[CT] = None
+        to_close: CT | None = None
 
         with self._lock:
             # Reset the min number of connections used
@@ -823,8 +823,8 @@ class WaitingClient(Generic[CT]):
     __slots__ = ("conn", "error", "_cond")
 
     def __init__(self) -> None:
-        self.conn: Optional[CT] = None
-        self.error: Optional[BaseException] = None
+        self.conn: CT | None = None
+        self.error: BaseException | None = None
 
         # The WaitingClient behaves in a way similar to an Event, but we need
         # to notify reliably the flagger that the waiter has "accepted" the
@@ -939,7 +939,7 @@ class AddConnection(MaintenanceTask):
     def __init__(
         self,
         pool: ConnectionPool[Any],
-        attempt: Optional[AttemptWithBackoff] = None,
+        attempt: AttemptWithBackoff | None = None,
         growing: bool = False,
     ):
         super().__init__(pool)
index ac6925aed76ad95d35eb0740303992f4f4ca4fa4..45000b6ec9a92504a0f0ce86e66d4d59e4e4adbc 100644 (file)
@@ -12,7 +12,7 @@ from abc import ABC, abstractmethod
 from time import monotonic
 from types import TracebackType
 from typing import Any, AsyncIterator, cast, Dict, Generic, List
-from typing import Optional, Type
+from typing import Type
 from weakref import ref
 from contextlib import asynccontextmanager
 
@@ -42,20 +42,20 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
         conninfo: str = "",
         *,
         connection_class: Type[ACT] = cast(Type[ACT], AsyncConnection),
-        kwargs: Optional[Dict[str, Any]] = None,
+        kwargs: Dict[str, Any] | None = None,
         min_size: int = 4,
-        max_size: Optional[int] = None,
+        max_size: int | None = None,
         open: bool | None = None,
-        configure: Optional[AsyncConnectionCB[ACT]] = None,
-        check: Optional[AsyncConnectionCB[ACT]] = None,
-        reset: Optional[AsyncConnectionCB[ACT]] = None,
-        name: Optional[str] = None,
+        configure: AsyncConnectionCB[ACT] | None = None,
+        check: AsyncConnectionCB[ACT] | None = None,
+        reset: AsyncConnectionCB[ACT] | None = None,
+        name: str | None = None,
         timeout: float = 30.0,
         max_waiting: int = 0,
         max_lifetime: float = 60 * 60.0,
         max_idle: float = 10 * 60.0,
         reconnect_timeout: float = 5 * 60.0,
-        reconnect_failed: Optional[AsyncConnectFailedCB] = None,
+        reconnect_failed: AsyncConnectFailedCB | None = None,
         num_workers: int = 3,
     ):
         self.connection_class = connection_class
@@ -74,9 +74,9 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
         self._waiting = Deque[WaitingClient[ACT]]()
 
         # to notify that the pool is full
-        self._pool_full_event: Optional[AEvent] = None
+        self._pool_full_event: AEvent | None = None
 
-        self._sched_runner: Optional[AWorker] = None
+        self._sched_runner: AWorker | None = None
         self._workers: List[AWorker] = []
 
         super().__init__(
@@ -176,7 +176,7 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
         logger.info("pool %r is ready to use", self.name)
 
     @asynccontextmanager
-    async def connection(self, timeout: Optional[float] = None) -> AsyncIterator[ACT]:
+    async def connection(self, timeout: float | None = None) -> AsyncIterator[ACT]:
         """Context manager to obtain a connection from the pool.
 
         Return the connection immediately if available, otherwise wait up to
@@ -198,7 +198,7 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
             t1 = monotonic()
             self._stats[self._USAGE_MS] += int(1000.0 * (t1 - t0))
 
-    async def getconn(self, timeout: Optional[float] = None) -> ACT:
+    async def getconn(self, timeout: float | None = None) -> ACT:
         """Obtain a connection from the pool.
 
         You should preferably use `connection()`. Use this function only if
@@ -286,12 +286,12 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
         conn._pool = self
         return conn
 
-    async def _get_ready_connection(self, timeout: Optional[float]) -> Optional[ACT]:
+    async def _get_ready_connection(self, timeout: float | None) -> ACT | None:
         """Return a connection, if the client deserves one."""
         if timeout is not None and timeout <= 0.0:
             raise PoolTimeout()
 
-        conn: Optional[ACT] = None
+        conn: ACT | None = None
         if self._pool:
             # Take a connection ready out of the pool
             conn = self._pool.popleft()
@@ -499,13 +499,13 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
 
     async def __aexit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
+        exc_type: Type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
     ) -> None:
         await self.close()
 
-    async def resize(self, min_size: int, max_size: Optional[int] = None) -> None:
+    async def resize(self, min_size: int, max_size: int | None = None) -> None:
         """Change the size of the pool during runtime."""
         min_size, max_size = self._check_size(min_size, max_size)
 
@@ -634,7 +634,7 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
                     "task run %s failed: %s: %s", task, ex.__class__.__name__, ex
                 )
 
-    async def _connect(self, timeout: Optional[float] = None) -> ACT:
+    async def _connect(self, timeout: float | None = None) -> ACT:
         """Return a new connection configured for the pool."""
         self._stats[self._CONNECTIONS_NUM] += 1
         kwargs = self.kwargs
@@ -668,7 +668,7 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
         return conn
 
     async def _add_connection(
-        self, attempt: Optional[AttemptWithBackoff], growing: bool = False
+        self, attempt: AttemptWithBackoff | None, growing: bool = False
     ) -> None:
         """Try to connect and add the connection to the pool.
 
@@ -844,7 +844,7 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
                 await conn.close()
 
     async def _shrink_pool(self) -> None:
-        to_close: Optional[ACT] = None
+        to_close: ACT | None = None
 
         async with self._lock:
             # Reset the min number of connections used
@@ -880,8 +880,8 @@ class WaitingClient(Generic[ACT]):
     __slots__ = ("conn", "error", "_cond")
 
     def __init__(self) -> None:
-        self.conn: Optional[ACT] = None
-        self.error: Optional[BaseException] = None
+        self.conn: ACT | None = None
+        self.error: BaseException | None = None
 
         # The WaitingClient behaves in a way similar to an Event, but we need
         # to notify reliably the flagger that the waiter has "accepted" the
@@ -995,7 +995,7 @@ class AddConnection(MaintenanceTask):
     def __init__(
         self,
         pool: AsyncConnectionPool[Any],
-        attempt: Optional[AttemptWithBackoff] = None,
+        attempt: AttemptWithBackoff | None = None,
         growing: bool = False,
     ):
         super().__init__(pool)
index 40954b99605dc42388525e83f329cd50fa3ca59f..4a5181d63d660cd9bc69878204573e45d09bf555 100644 (file)
@@ -15,10 +15,12 @@ Tasks are called "Task", not "Event", here, because we actually make use of
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 import logging
 from time import monotonic
 from heapq import heappush, heappop
-from typing import Any, Callable, List, Optional
+from typing import Any, Callable, List
 
 from ._task import Task
 from ._acompat import Lock, Event
@@ -35,7 +37,7 @@ class Scheduler:
 
     EMPTY_QUEUE_TIMEOUT = 600.0
 
-    def enter(self, delay: float, action: Optional[Callable[[], Any]]) -> Task:
+    def enter(self, delay: float, action: Callable[[], Any] | None) -> Task:
         """Enter a new task in the queue delayed in the future.
 
         Schedule a `!None` to stop the execution.
@@ -43,7 +45,7 @@ class Scheduler:
         time = monotonic() + delay
         return self.enterabs(time, action)
 
-    def enterabs(self, time: float, action: Optional[Callable[[], Any]]) -> Task:
+    def enterabs(self, time: float, action: Callable[[], Any] | None) -> Task:
         """Enter a new task in the queue at an absolute time.
 
         Schedule a `!None` to stop the execution.
index c9fdbad79c90944e94a33c4a7015caf9470cb547..d43ef1d2efc0af2ed4e96f4c7f79783bae65d176 100644 (file)
@@ -12,10 +12,12 @@ Tasks are called "Task", not "Event", here, because we actually make use of
 
 # Copyright (C) 2021 The Psycopg Team
 
+from __future__ import annotations
+
 import logging
 from time import monotonic
 from heapq import heappush, heappop
-from typing import Any, Callable, List, Optional
+from typing import Any, Callable, List
 
 from ._task import Task
 from ._acompat import ALock, AEvent
@@ -31,7 +33,7 @@ class AsyncScheduler:
 
     EMPTY_QUEUE_TIMEOUT = 600.0
 
-    async def enter(self, delay: float, action: Optional[Callable[[], Any]]) -> Task:
+    async def enter(self, delay: float, action: Callable[[], Any] | None) -> Task:
         """Enter a new task in the queue delayed in the future.
 
         Schedule a `!None` to stop the execution.
@@ -39,7 +41,7 @@ class AsyncScheduler:
         time = monotonic() + delay
         return await self.enterabs(time, action)
 
-    async def enterabs(self, time: float, action: Optional[Callable[[], Any]]) -> Task:
+    async def enterabs(self, time: float, action: Callable[[], Any] | None) -> Task:
         """Enter a new task in the queue at an absolute time.
 
         Schedule a `!None` to stop the execution.
index a184e6aa418124cd03082d48b964fd5241bb4198..5c0444a501878793e16ddf07f819c3b8ec05c1eb 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 from psycopg import pq
 from psycopg.abc import Dumper, Loader, AdaptContext, PyFormat, Buffer
@@ -17,7 +17,7 @@ class MyStrDumper:
     format = pq.Format.TEXT
     oid = 25  # text
 
-    def __init__(self, cls: type, context: Optional[AdaptContext] = None):
+    def __init__(self, cls: type, context: AdaptContext | None = None):
         self._cls = cls
 
     def dump(self, obj: str) -> bytes:
@@ -38,7 +38,7 @@ class MyStrDumper:
 class MyTextLoader:
     format = pq.Format.TEXT
 
-    def __init__(self, oid: int, context: Optional[AdaptContext] = None):
+    def __init__(self, oid: int, context: AdaptContext | None = None):
         pass
 
     def load(self, data: Buffer) -> str:
index 37f7c15a8adedaab7a4733ad9ad4f1b035c8102d..554293f3d0f562016c84aee89a5146616cf91cbc 100644 (file)
@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 import pytest
 
@@ -53,7 +53,7 @@ def check_crdb_version(got, mark):
 is_crdb = CrdbConnection.is_crdb
 
 
-def crdb_skip_message(reason: Optional[str]) -> str:
+def crdb_skip_message(reason: str | None) -> str:
     msg = ""
     if reason:
         msg = reason
index 0c3fe0c8e2971fcdfdd2b411f9a39c1256fa0e8a..cfa0ae143e6034576da16db627571c8d8c45340c 100644 (file)
@@ -1,10 +1,11 @@
+from __future__ import annotations
+
 import io
 import os
 import sys
 import pytest
 import logging
 from contextlib import contextmanager
-from typing import Optional
 
 import psycopg
 from psycopg import pq
@@ -17,7 +18,7 @@ from .utils import check_postgres_version
 
 # Set by warm_up_database() the first time the dsn fixture is used
 pg_version: int
-crdb_version: Optional[int]
+crdb_version: int | None
 
 
 def pytest_addoption(parser):
index e302d22e5aed413ebe215a663dd3fdd648017dfb..0256a94d5cac9ee93844f15e9d604c52b30b52b7 100644 (file)
@@ -1,10 +1,12 @@
+from __future__ import annotations
+
 import datetime as dt
 import importlib
 import ipaddress
 from math import isnan
 from uuid import UUID
 from random import choice, random, randrange
-from typing import Any, List, Optional, Set, Tuple, Union
+from typing import Any, List, Set, Tuple, Union
 from decimal import Decimal
 from contextlib import contextmanager, asynccontextmanager
 
@@ -42,7 +44,7 @@ class Faker:
         self.records = []
 
         self._schema = None
-        self._types: Optional[List[type]] = None
+        self._types: List[type] | None = None
         self._types_names = None
         self._makers = {}
         self.table_name = sql.Identifier("fake_table")
index 74cc04d1f8635f6b3a1ab6b9eccafe00757edb7f..ff05f0b01f48b2968258759f975c1f03d13f5928 100644 (file)
@@ -8,12 +8,14 @@ handled by execute() calls when pgconn socket is read-ready, which
 happens when the output buffer is full.
 """
 
+from __future__ import annotations
+
 import argparse
 import asyncio
 import logging
 from contextlib import contextmanager
 from functools import partial
-from typing import Any, Iterator, Optional, Sequence, Tuple
+from typing import Any, Iterator, Sequence, Tuple
 
 from psycopg import AsyncConnection, Connection
 from psycopg import pq, waiting
@@ -36,7 +38,7 @@ class LoggingPGconn:
         self._logger = logger
 
         def log_notice(result: pq.abc.PGresult) -> None:
-            def get_field(field: DiagnosticField) -> Optional[str]:
+            def get_field(field: DiagnosticField) -> str | None:
                 value = result.error_field(field)
                 return value.decode("utf-8", "replace") if value else None
 
@@ -68,9 +70,9 @@ class LoggingPGconn:
     def send_query_params(
         self,
         command: bytes,
-        param_values: Optional[Sequence[Optional[bytes]]],
-        param_types: Optional[Sequence[int]] = None,
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[bytes | None] | None,
+        param_types: Sequence[int] | None = None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> None:
         self._pgconn.send_query_params(
@@ -81,8 +83,8 @@ class LoggingPGconn:
     def send_query_prepared(
         self,
         name: bytes,
-        param_values: Optional[Sequence[Optional[bytes]]],
-        param_formats: Optional[Sequence[int]] = None,
+        param_values: Sequence[bytes | None] | None,
+        param_formats: Sequence[int] | None = None,
         result_format: int = Format.TEXT,
     ) -> None:
         self._pgconn.send_query_prepared(
@@ -94,12 +96,12 @@ class LoggingPGconn:
         self,
         name: bytes,
         command: bytes,
-        param_types: Optional[Sequence[int]] = None,
+        param_types: Sequence[int] | None = None,
     ) -> None:
         self._pgconn.send_prepare(name, command, param_types)
         self._logger.info("prepare %s as '%s'", command.decode(), name.decode())
 
-    def get_result(self) -> Optional[pq.abc.PGresult]:
+    def get_result(self) -> pq.abc.PGresult | None:
         r = self._pgconn.get_result()
         if r is not None:
             self._logger.info("got %s result", pq.ExecStatus(r.status).name)
index 688be1a1216b93f7c569a56e7b9fcaea98cddfff..aaddd04387eaea77bb0a9f163aee12fe3295a14a 100644 (file)
@@ -1,6 +1,8 @@
+from __future__ import annotations
+
 import datetime as dt
 from types import ModuleType
-from typing import Any, List, Optional
+from typing import Any, List
 
 import pytest
 
@@ -521,12 +523,12 @@ class MyStr(str):
 
 
 class StrNoneDumper(StrDumper):
-    def dump(self, obj: str) -> Optional[Buffer]:
+    def dump(self, obj: str) -> Buffer | None:
         return super().dump(obj) if obj else None
 
 
 class StrNoneBinaryDumper(StrBinaryDumper):
-    def dump(self, obj: str) -> Optional[Buffer]:
+    def dump(self, obj: str) -> Buffer | None:
         return super().dump(obj) if obj else None
 
 
index efafd0bb4ca6bfac241bcef21c991a2eb2ab62b6..76555aac329b05d46e396df924db9b4f1da06966 100644 (file)
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import os
 
 import pytest
@@ -233,15 +235,15 @@ obj = {curs}
     [
         (
             "conn.cursor()",
-            "Optional[Tuple[Any, ...]]",
+            "Tuple[Any, ...] | None",
         ),
         (
             "conn.cursor(row_factory=rows.dict_row)",
-            "Optional[Dict[str, Any]]",
+            "Dict[str, Any] | None",
         ),
         (
             "conn.cursor(row_factory=thing_row)",
-            "Optional[Thing]",
+            "Thing | None",
         ),
     ],
 )
@@ -371,11 +373,11 @@ class MyCursor(psycopg.{cur_base_class}[Row]):
 
 
 def _test_reveal(stmts, type, mypy):
-    ignore = "" if type.startswith("Optional") else "# type: ignore[assignment]"
+    ignore = "" if type.endswith("| None") else "# type: ignore[assignment]"
     stmts = "\n".join(f"    {line}" for line in stmts.splitlines())
 
     src = f"""\
-from typing import Any, Callable, Dict, List, NamedTuple, Optional, Sequence
+from typing import Any, Callable, Dict, List, NamedTuple, Sequence
 from typing import Tuple, Union
 import psycopg
 from psycopg import rows
index 9a71aaebbba3e84f3a90e9b3e365730229dffd00..9af20a045e5e627c0e27a1a34b1ac64f118dc82c 100644 (file)
@@ -1,6 +1,7 @@
+from __future__ import annotations
+
 import enum
 from math import isnan, isinf, exp
-from typing import Optional
 from decimal import Decimal
 
 import pytest
@@ -80,7 +81,7 @@ def test_int_none(conn, fmt_in):
     Base: type = Int8Dumper if fmt_in == PyFormat.TEXT else Int8BinaryDumper
 
     class MyDumper(Base):  # type: ignore
-        def dump(self, obj: int) -> Optional[Buffer]:
+        def dump(self, obj: int) -> Buffer | None:
             if not obj:
                 return None
             else:
index a26ca49b49e2928b7538420c2de5c94553287ab7..139c92a216853a5ff6a71d6caac6310a424af8cb 100644 (file)
@@ -3,7 +3,7 @@
 from __future__ import annotations
 
 from dataclasses import dataclass
-from typing import Any, Callable, Dict, Optional, Sequence, Tuple, Union
+from typing import Any, Callable, Dict, Sequence, Tuple, Union
 
 from psycopg import Connection, Cursor, ServerCursor, connect, rows
 from psycopg import AsyncConnection, AsyncCursor, AsyncServerCursor
@@ -45,12 +45,12 @@ def check_row_factory_cursor() -> None:
 
     cur1: Cursor[Any]
     cur1 = conn.cursor()
-    r1: Optional[Any]
+    r1: Any | None
     r1 = cur1.fetchone()
     r1 is not None
 
     cur2: Cursor[int]
-    r2: Optional[int]
+    r2: int | None
     with conn.cursor(row_factory=int_row_factory) as cur2:
         cur2.execute("select 1")
         r2 = cur2.fetchone()
@@ -70,12 +70,12 @@ async def async_check_row_factory_cursor() -> None:
 
     cur1: AsyncCursor[Any]
     cur1 = conn.cursor()
-    r1: Optional[Any]
+    r1: Any | None
     r1 = await cur1.fetchone()
     r1 is not None
 
     cur2: AsyncCursor[int]
-    r2: Optional[int]
+    r2: int | None
     async with conn.cursor(row_factory=int_row_factory) as cur2:
         await cur2.execute("select 1")
         r2 = await cur2.fetchone()
@@ -95,7 +95,7 @@ def check_row_factory_connection() -> None:
     """
     conn1: Connection[int]
     cur1: Cursor[int]
-    r1: Optional[int]
+    r1: int | None
     conn1 = connect(row_factory=int_row_factory)
     cur1 = conn1.execute("select 1")
     r1 = cur1.fetchone()
@@ -105,7 +105,7 @@ def check_row_factory_connection() -> None:
 
     conn2: Connection[Person]
     cur2: Cursor[Person]
-    r2: Optional[Person]
+    r2: Person | None
     conn2 = connect(row_factory=Person.row_factory)
     cur2 = conn2.execute("select * from persons")
     r2 = cur2.fetchone()
@@ -114,7 +114,7 @@ def check_row_factory_connection() -> None:
         cur2.execute("select 2")
 
     cur3: Cursor[Tuple[Any, ...]]
-    r3: Optional[Tuple[Any, ...]]
+    r3: Tuple[Any, ...] | None
     conn3 = connect()
     cur3 = conn3.execute("select 3")
     with conn3.cursor() as cur3:
@@ -129,7 +129,7 @@ async def async_check_row_factory_connection() -> None:
     """
     conn1: AsyncConnection[int]
     cur1: AsyncCursor[int]
-    r1: Optional[int]
+    r1: int | None
     conn1 = await AsyncConnection.connect(row_factory=int_row_factory)
     cur1 = await conn1.execute("select 1")
     r1 = await cur1.fetchone()
@@ -139,7 +139,7 @@ async def async_check_row_factory_connection() -> None:
 
     conn2: AsyncConnection[Person]
     cur2: AsyncCursor[Person]
-    r2: Optional[Person]
+    r2: Person | None
     conn2 = await AsyncConnection.connect(row_factory=Person.row_factory)
     cur2 = await conn2.execute("select * from persons")
     r2 = await cur2.fetchone()
@@ -148,7 +148,7 @@ async def async_check_row_factory_connection() -> None:
         await cur2.execute("select 2")
 
     cur3: AsyncCursor[Tuple[Any, ...]]
-    r3: Optional[Tuple[Any, ...]]
+    r3: Tuple[Any, ...] | None
     conn3 = await AsyncConnection.connect()
     cur3 = await conn3.execute("select 3")
     async with conn3.cursor() as cur3:
index 8eef880bd33cd2a2f13280d22308782af22de7c8..c2a97307aa6b3ec59e39c82e89dddb875bc5c955 100644 (file)
@@ -1,7 +1,9 @@
+from __future__ import annotations
+
 import re
 import sys
 import operator
-from typing import Callable, Optional, Tuple
+from typing import Callable, Tuple
 from contextlib import contextmanager
 
 
@@ -70,7 +72,7 @@ class VersionCheck:
         self,
         *,
         skip: bool = False,
-        op: Optional[str] = None,
+        op: str | None = None,
         version_tuple: Tuple[int, ...] = (),
         whose: str = "(wanted)",
         postgres_rule: bool = False,
@@ -105,10 +107,10 @@ class VersionCheck:
             skip=skip, op=op, version_tuple=version_tuple, postgres_rule=postgres_rule
         )
 
-    def get_skip_message(self, version: Optional[int]) -> Optional[str]:
+    def get_skip_message(self, version: int | None) -> str | None:
         got_tuple = self._parse_int_version(version)
 
-        msg: Optional[str] = None
+        msg: str | None = None
         if self.skip:
             if got_tuple:
                 if not self.version_tuple:
@@ -147,7 +149,7 @@ class VersionCheck:
         op = getattr(operator, self._OP_NAMES[self.op])
         return op(got_tuple, version_tuple)
 
-    def _parse_int_version(self, version: Optional[int]) -> Tuple[int, ...]:
+    def _parse_int_version(self, version: int | None) -> Tuple[int, ...]:
         if version is None:
             return ()
         version, ver_fix = divmod(version, 100)