19
19
20
20
import psycopg
21
21
from psycopg import sql as sql
22
+ from psycopg .adapt import Buffer , Loader
22
23
from psycopg .rows import dict_row
23
24
from psycopg .errors import (
24
25
FeatureNotSupported as FeatureNotSupported ,
34
35
35
36
Connection = psycopg .Connection [Dict [str , Any ]]
36
37
38
+ class BytesLoader (Loader ):
39
+ def load (self , data : Buffer ) -> bytes :
40
+ if isinstance (data , memoryview ):
41
+ return bytes (data )
42
+ return data
43
+
37
44
def connect (* args : Any , ** kwargs : Any ) -> Connection :
38
45
return psycopg .connect (* args , autocommit = True , row_factory = dict_row , ** kwargs )
39
46
@@ -51,19 +58,27 @@ def execute(
51
58
conn .execute (query , args , prepare = True )
52
59
53
60
@overload
54
- def cursor (conn : Connection , mkrow : Callable [..., Row ]) -> psycopg .Cursor [Row ]:
61
+ def cursor (
62
+ conn : Connection , mkrow : Callable [..., Row ], text_as_bytes : bool
63
+ ) -> psycopg .Cursor [Row ]:
55
64
...
56
65
57
66
@overload
58
- def cursor (conn : Connection , mkrow : None ) -> psycopg .Cursor [psycopg .rows .DictRow ]:
67
+ def cursor (
68
+ conn : Connection , mkrow : None , text_as_bytes : bool
69
+ ) -> psycopg .Cursor [psycopg .rows .DictRow ]:
59
70
...
60
71
61
72
def cursor (
62
- conn : Connection , mkrow : Optional [Callable [..., Row ]]
73
+ conn : Connection , mkrow : Optional [Callable [..., Row ]], text_as_bytes : bool
63
74
) -> Union [psycopg .Cursor [psycopg .rows .DictRow ], psycopg .Cursor [Row ]]:
64
75
if mkrow is not None :
65
- return conn .cursor (row_factory = psycopg .rows .kwargs_row (mkrow ))
66
- return conn .cursor ()
76
+ cur = conn .cursor (row_factory = psycopg .rows .kwargs_row (mkrow ))
77
+ else :
78
+ cur = conn .cursor () # type: ignore[assignment]
79
+ if text_as_bytes :
80
+ cur .adapters .register_loader ("text" , BytesLoader )
81
+ return cur
67
82
68
83
@overload
69
84
def fetchone (
@@ -72,6 +87,7 @@ def fetchone(
72
87
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
73
88
* ,
74
89
mkrow : Callable [..., Row ],
90
+ text_as_bytes : bool = False ,
75
91
) -> Row :
76
92
...
77
93
@@ -80,6 +96,8 @@ def fetchone(
80
96
conn : Connection ,
81
97
query : Union [str , sql .Composed ],
82
98
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
99
+ * ,
100
+ text_as_bytes : bool = False ,
83
101
) -> Dict [str , Any ]:
84
102
...
85
103
@@ -89,8 +107,9 @@ def fetchone(
89
107
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
90
108
* ,
91
109
mkrow : Optional [Callable [..., Row ]] = None ,
110
+ text_as_bytes : bool = False ,
92
111
) -> Union [Dict [str , Any ], Row ]:
93
- with cursor (conn , mkrow ) as cur :
112
+ with cursor (conn , mkrow , text_as_bytes ) as cur :
94
113
row = cur .execute (query , args , prepare = True ).fetchone ()
95
114
assert row is not None
96
115
return row
@@ -102,6 +121,7 @@ def fetchall(
102
121
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
103
122
* ,
104
123
mkrow : Callable [..., Row ],
124
+ text_as_bytes : bool = False ,
105
125
) -> List [Row ]:
106
126
...
107
127
@@ -110,6 +130,8 @@ def fetchall(
110
130
conn : Connection ,
111
131
query : Union [str , sql .Composed ],
112
132
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
133
+ * ,
134
+ text_as_bytes : bool = False ,
113
135
) -> List [Dict [str , Any ]]:
114
136
...
115
137
@@ -118,13 +140,15 @@ def fetchall(
118
140
query : Union [str , sql .Composed ],
119
141
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
120
142
* ,
143
+ text_as_bytes : bool = False ,
121
144
mkrow : Optional [Callable [..., Row ]] = None ,
122
145
) -> Union [List [Dict [str , Any ]], List [Row ]]:
123
- with cursor (conn , mkrow ) as cur :
146
+ with cursor (conn , mkrow , text_as_bytes ) as cur :
124
147
return cur .execute (query , args , prepare = True ).fetchall ()
125
148
126
149
except ImportError :
127
150
import psycopg2
151
+ import psycopg2 .extensions
128
152
from psycopg2 .extras import DictCursor
129
153
from psycopg2 import sql as sql # type: ignore[no-redef]
130
154
from psycopg2 .errors import ( # type: ignore[no-redef]
@@ -170,8 +194,11 @@ def fetchone( # type: ignore[no-redef]
170
194
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
171
195
* ,
172
196
mkrow : Optional [Callable [..., Row ]] = None ,
197
+ text_as_bytes : bool = False ,
173
198
) -> Union [Dict [str , Any ], Row ]:
174
199
with conn .cursor () as cur :
200
+ if text_as_bytes :
201
+ psycopg2 .extensions .register_type (psycopg2 .extensions .BYTES , cur )
175
202
cur .execute (query , args )
176
203
row = cur .fetchone ()
177
204
assert row is not None
@@ -185,8 +212,11 @@ def fetchall( # type: ignore[no-redef]
185
212
args : Union [None , Sequence [Any ], Dict [str , Any ]] = None ,
186
213
* ,
187
214
mkrow : Optional [Callable [..., Row ]] = None ,
215
+ text_as_bytes : bool = False ,
188
216
) -> Union [List [Dict [str , Any ]], List [Row ]]:
189
217
with conn .cursor () as cur :
218
+ if text_as_bytes :
219
+ psycopg2 .extensions .register_type (psycopg2 .extensions .BYTES , cur )
190
220
cur .execute (query , args )
191
221
rows = cur .fetchall ()
192
222
if mkrow is not None :
0 commit comments