Skip to content

Commit e5594aa

Browse files
authored
Annotations for psycopg2.ConnectionInfo (#7834)
* Annotations for psycopg2.ConnectionInfo These annotations come from the documentation here: https://www.psycopg.org/docs/extensions.html#psycopg2.extensions.ConnectionInfo If there was doubt, I referred to the libpq documentation cited by psycopg2's docs. I wasn't completely sure about `dsn_parameters`. Psycopg2's docs list it as an `dict`, and the example suggests it's a `dict[str, str]` at that. From psycopg2's source I found https://github.com/psycopg/psycopg2/blob/1d3a89a0bba621dc1cc9b32db6d241bd2da85ad1/psycopg/conninfo_type.c#L183-L206 which is implemented here: https://github.com/psycopg/psycopg2/blob/1d3a89a0bba621dc1cc9b32db6d241bd2da85ad1/psycopg/utils.c#L251-L279 I'm no expert in CPython's API, but this looks to me like it's building a `dict[str, str]`. Additionally, the libpq docs https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNINFO https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PQCONNDEFAULTS show that the underlying data just consists of strings. Additionally, I'm pretty sure from this chunk of source https://github.com/psycopg/psycopg2/blob/1d3a89a0bba621dc1cc9b32db6d241bd2da85ad1/psycopg/conninfo_type.c#L581-L598 That `ConnectionInfo.__init__` takes one positional-only argument, which must be a `psycopg2.connection`. But I don't think users are intended to be constructing this type, so I've not added that annotation. * Annotate `connection.info` and related attributes * Make ConnectionInfo attributes properties According to https://github.com/psycopg/psycopg2/blob/1d3a89a0bba621dc1cc9b32db6d241bd2da85ad1/psycopg/conninfo_type.c#L534-L563 * Mark connection attributes as readonly according to https://github.com/psycopg/psycopg2/blob/8ef195f2ff187454cc709d7857235676bb4176ee/psycopg/connection_type.c#L1244 * Explain why some properties aren't `T | None`
1 parent 0198d75 commit e5594aa

File tree

1 file changed

+82
-35
lines changed

1 file changed

+82
-35
lines changed

stubs/psycopg2/psycopg2/_psycopg.pyi

Lines changed: 82 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -157,27 +157,63 @@ class Column:
157157
def __setstate__(self, state): ...
158158

159159
class ConnectionInfo:
160-
backend_pid: Any
161-
dbname: Any
162-
dsn_parameters: Any
163-
error_message: Any
164-
host: Any
165-
needs_password: Any
166-
options: Any
167-
password: Any
168-
port: Any
169-
protocol_version: Any
170-
server_version: Any
171-
socket: Any
172-
ssl_attribute_names: Any
173-
ssl_in_use: Any
174-
status: Any
175-
transaction_status: Any
176-
used_password: Any
177-
user: Any
160+
# Note: the following properties can be None if their corresponding libpq function
161+
# returns NULL. They're not annotated as such, because this is very unlikely in
162+
# practice---the psycopg2 docs [1] don't even mention this as a possibility!
163+
#
164+
# - db_name
165+
# - user
166+
# - password
167+
# - host
168+
# - port
169+
# - options
170+
#
171+
# (To prove this, one needs to inspect the psycopg2 source code [2], plus the
172+
# documentation [3] and source code [4] of the corresponding libpq calls.)
173+
#
174+
# [1]: https://www.psycopg.org/docs/extensions.html#psycopg2.extensions.ConnectionInfo
175+
# [2]: https://github.com/psycopg/psycopg2/blob/1d3a89a0bba621dc1cc9b32db6d241bd2da85ad1/psycopg/conninfo_type.c#L52 and below
176+
# [3]: https://www.postgresql.org/docs/current/libpq-status.html
177+
# [4]: https://github.com/postgres/postgres/blob/b39838889e76274b107935fa8e8951baf0e8b31b/src/interfaces/libpq/fe-connect.c#L6754 and below
178+
@property
179+
def backend_pid(self) -> int: ...
180+
@property
181+
def dbname(self) -> str: ...
182+
@property
183+
def dsn_parameters(self) -> dict[str, str]: ...
184+
@property
185+
def error_message(self) -> str | None: ...
186+
@property
187+
def host(self) -> str: ...
188+
@property
189+
def needs_password(self) -> bool: ...
190+
@property
191+
def options(self) -> str: ...
192+
@property
193+
def password(self) -> str: ...
194+
@property
195+
def port(self) -> int: ...
196+
@property
197+
def protocol_version(self) -> int: ...
198+
@property
199+
def server_version(self) -> int: ...
200+
@property
201+
def socket(self) -> int: ...
202+
@property
203+
def ssl_attribute_names(self) -> list[str]: ...
204+
@property
205+
def ssl_in_use(self) -> bool: ...
206+
@property
207+
def status(self) -> int: ...
208+
@property
209+
def transaction_status(self) -> int: ...
210+
@property
211+
def used_password(self) -> bool: ...
212+
@property
213+
def user(self) -> str: ...
178214
def __init__(self, *args, **kwargs) -> None: ...
179-
def parameter_status(self, *args, **kwargs): ...
180-
def ssl_attribute(self, *args, **kwargs): ...
215+
def parameter_status(self, name: str) -> str | None: ...
216+
def ssl_attribute(self, name: str) -> str | None: ...
181217

182218
class DataError(psycopg2.DatabaseError): ...
183219
class DatabaseError(psycopg2.Error): ...
@@ -334,24 +370,35 @@ class connection:
334370
OperationalError: Any
335371
ProgrammingError: Any
336372
Warning: Any
337-
async_: Any
373+
@property
374+
def async_(self) -> Any: ...
338375
autocommit: Any
339-
binary_types: Any
340-
closed: Any
376+
@property
377+
def binary_types(self) -> Any: ...
378+
@property
379+
def closed(self) -> Any: ...
341380
cursor_factory: Callable[..., _cursor]
342381
deferrable: Any
343-
dsn: Any
344-
encoding: Any
345-
info: Any
382+
@property
383+
def dsn(self) -> Any: ...
384+
@property
385+
def encoding(self) -> Any: ...
386+
@property
387+
def info(self) -> ConnectionInfo: ...
346388
isolation_level: Any
347389
notices: Any
348390
notifies: Any
349-
pgconn_ptr: Any
350-
protocol_version: Any
391+
@property
392+
def pgconn_ptr(self) -> Any: ...
393+
@property
394+
def protocol_version(self) -> int: ...
351395
readonly: Any
352-
server_version: Any
353-
status: Any
354-
string_types: Any
396+
@property
397+
def server_version(self) -> int: ...
398+
@property
399+
def status(self) -> Any: ...
400+
@property
401+
def string_types(self) -> Any: ...
355402
def __init__(self, *args, **kwargs) -> None: ...
356403
def cancel(self, *args, **kwargs): ...
357404
def close(self, *args, **kwargs): ...
@@ -361,11 +408,11 @@ class connection:
361408
@overload
362409
def cursor(self, name=..., cursor_factory: Callable[..., _T_cur] = ..., scrollable=..., withhold=...) -> _T_cur: ...
363410
def fileno(self, *args, **kwargs): ...
364-
def get_backend_pid(self, *args, **kwargs): ...
365-
def get_dsn_parameters(self, *args, **kwargs): ...
411+
def get_backend_pid(self) -> int: ...
412+
def get_dsn_parameters(self) -> dict[str, str]: ...
366413
def get_native_connection(self, *args, **kwargs): ...
367-
def get_parameter_status(self, parameter): ...
368-
def get_transaction_status(self): ...
414+
def get_parameter_status(self, parameter: str) -> str | None: ...
415+
def get_transaction_status(self) -> int: ...
369416
def isexecuting(self, *args, **kwargs): ...
370417
def lobject(self, oid=..., mode=..., new_oid=..., new_file=..., lobject_factory=...): ...
371418
def poll(self, *args, **kwargs): ...

0 commit comments

Comments
 (0)