--- /dev/null
+"""
+Simplify access to the _psycopg module
+"""
+
+# Copyright (C) 2021 The Psycopg Team
+
+from . import pq
+
+# Note: "c" must the first attempt so that mypy associates the variable the
+# right module interface. It will not result Optional, but hey.
+if pq.__impl__ == "c":
+ from psycopg_c import _psycopg
+elif pq.__impl__ == "binary":
+ from psycopg_binary import _psycopg # type: ignore
+elif pq.__impl__ == "python":
+ _psycopg = None # type: ignore
+else:
+ raise ImportError(
+ f"can't find _psycopg optimised module in {pq.__impl__!r}"
+ )
--- /dev/null
+"""
+Wrappers for numeric types.
+"""
+
+# Copyright (C) 2020-2021 The Psycopg Team
+
+# Wrappers to force numbers to be cast as specific PostgreSQL types
+
+# These types are implemented here but exposed by `psycopg.types.numeric`.
+# They are defined here to avoid a circular import.
+_MODULE = "psycopg.types.numeric"
+
+
+class Int2(int):
+
+ __module__ = _MODULE
+
+ def __new__(cls, arg: int) -> "Int2":
+ return super().__new__(cls, arg)
+
+
+class Int4(int):
+
+ __module__ = _MODULE
+
+ def __new__(cls, arg: int) -> "Int4":
+ return super().__new__(cls, arg)
+
+
+class Int8(int):
+
+ __module__ = _MODULE
+
+ def __new__(cls, arg: int) -> "Int8":
+ return super().__new__(cls, arg)
+
+
+class IntNumeric(int):
+
+ __module__ = _MODULE
+
+ def __new__(cls, arg: int) -> "IntNumeric":
+ return super().__new__(cls, arg)
+
+
+class Oid(int):
+
+ __module__ = _MODULE
+
+ def __new__(cls, arg: int) -> "Oid":
+ return super().__new__(cls, arg)
from ._enums import Format as Format
from .oids import postgres_types
from .proto import AdaptContext, Buffer as Buffer
+from ._cmodule import _psycopg
from ._typeinfo import TypesRegistry
if TYPE_CHECKING:
f"dumpers should be registered on classes, got {cls} instead"
)
- if pq.__impl__ != "python":
+ if _psycopg:
dumper = self._get_optimised(dumper)
# Register the dumper both as its format and as default
f"loaders should be registered on oid, got {oid} instead"
)
- if pq.__impl__ != "python":
+ if _psycopg:
loader = self._get_optimised(loader)
fmt = loader.format
# Check if the class comes from psycopg.types and there is a class
# with the same name in psycopg_c._psycopg.
from psycopg import types
- from psycopg_c import _psycopg
if cls.__module__.startswith(types.__name__):
new = cast(Type[RV], getattr(_psycopg, cls.__name__, None))
Transformer: Type[proto.Transformer]
# Override it with fast object if available
-if pq.__impl__ == "c":
- from psycopg_c import _psycopg
-
+if _psycopg:
Transformer = _psycopg.Transformer
else:
from . import _transform
from .proto import Query, RV
from .compat import asynccontextmanager
from .cursor import Cursor, AsyncCursor
+from ._cmodule import _psycopg
from .conninfo import _conninfo_connect_timeout, ConnectionInfo
from .generators import notifies
from ._preparing import PrepareManager
from .pq.proto import PGconn, PGresult
from .pool.base import BasePool
-if pq.__impl__ == "c":
- from psycopg_c import _psycopg
-
+if _psycopg:
connect = _psycopg.connect
execute = _psycopg.execute
from .adapt import Format
from .proto import ConnectionType, PQGen, Transformer
from .compat import create_task
+from ._cmodule import _psycopg
from .generators import copy_from, copy_to, copy_end
if TYPE_CHECKING:
# Override functions with fast versions if available
-if pq.__impl__ == "c":
- from psycopg_c import _psycopg
-
+if _psycopg:
format_row_text = _psycopg.format_row_text
format_row_binary = _psycopg.format_row_binary
parse_row_text = _psycopg.parse_row_text
from .proto import ConnectionType, Query, Params, PQGen
from .compat import asynccontextmanager
from ._column import Column
+from ._cmodule import _psycopg
from ._queries import PostgresQuery
from ._preparing import Prepare
execute: Callable[["PGconn"], PQGen[List["PGresult"]]]
-if pq.__impl__ == "c":
- from psycopg_c import _psycopg
-
+if _psycopg:
execute = _psycopg.execute
else:
from .._struct import pack_int8, unpack_int8
from .._struct import pack_float8, unpack_float4, unpack_float8
-
-# Wrappers to force numbers to be cast as specific PostgreSQL types
-
-
-class Int2(int):
- def __new__(cls, arg: int) -> "Int2":
- return super().__new__(cls, arg)
-
-
-class Int4(int):
- def __new__(cls, arg: int) -> "Int4":
- return super().__new__(cls, arg)
-
-
-class Int8(int):
- def __new__(cls, arg: int) -> "Int8":
- return super().__new__(cls, arg)
-
-
-class IntNumeric(int):
- def __new__(cls, arg: int) -> "IntNumeric":
- return super().__new__(cls, arg)
-
-
-class Oid(int):
- def __new__(cls, arg: int) -> "Oid":
- return super().__new__(cls, arg)
+# Exposed here
+from .._wrappers import (
+ Int2 as Int2,
+ Int4 as Int4,
+ Int8 as Int8,
+ IntNumeric as IntNumeric,
+ Oid as Oid,
+)
class _NumberDumper(Dumper):
from psycopg_c._psycopg cimport endian
from psycopg import errors as e
-
-from psycopg.types.numeric import Int2, Int4, Int8, IntNumeric
+from psycopg._wrappers import Int2, Int4, Int8, IntNumeric
cdef extern from "Python.h":
# work around https://github.com/cython/cython/issues/3909
from psycopg import pq
from psycopg.adapt import Transformer, Format, Dumper, Loader
from psycopg.oids import postgres_types as builtins, TEXT_OID
+from psycopg._cmodule import _psycopg
@pytest.mark.parametrize(
assert cur.fetchone()[0] == 20
-@pytest.mark.skipif(psycopg.pq.__impl__ == "python", reason="C module test")
+@pytest.mark.skipif(_psycopg is None, reason="C module test")
def test_optimised_adapters():
- from psycopg_c import _psycopg
-
# All the optimised adapters available
c_adapters = {}
for n in dir(_psycopg):