From: Daniele Varrazzo Date: Sat, 14 Mar 2020 04:44:08 +0000 (+1300) Subject: Added PQconn.get_defaults() wrapping PQconndefault/PQconninfoFree X-Git-Tag: 3.0.dev0~732 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=011161e9703cf13947196853e95ed5d38a3d2270;p=thirdparty%2Fpsycopg.git Added PQconn.get_defaults() wrapping PQconndefault/PQconninfoFree --- diff --git a/psycopg3/_pq_ctypes.py b/psycopg3/_pq_ctypes.py index 04b12e683..d2a0f188c 100644 --- a/psycopg3/_pq_ctypes.py +++ b/psycopg3/_pq_ctypes.py @@ -22,6 +22,18 @@ class PGconn_struct(Structure): PGconn_ptr = POINTER(PGconn_struct) +class PQconninfoOption_struct(Structure): + _fields_ = [ + ("keyword", c_char_p), + ("envvar", c_char_p), + ("compiled", c_char_p), + ("val", c_char_p), + ("label", c_char_p), + ("dispatcher", c_char_p), + ("dispsize", c_int), + ] + + # Function definitions as explained in PostgreSQL 12 documentation # 33.1. Database Connection Control Functions @@ -45,6 +57,14 @@ PQconnectPoll = pq.PQconnectPoll PQconnectPoll.argtypes = [PGconn_ptr] PQconnectPoll.restype = c_int +PQconndefaults = pq.PQconndefaults +PQconndefaults.argtypes = [] +PQconndefaults.restype = POINTER(PQconninfoOption_struct) + +PQconninfoFree = pq.PQconninfoFree +PQconninfoFree.argtypes = [POINTER(PQconninfoOption_struct)] +PQconninfoFree.restype = None + # 33.2. Connection Status Functions diff --git a/psycopg3/pq_ctypes.py b/psycopg3/pq_ctypes.py index db1abbfac..b85480b42 100644 --- a/psycopg3/pq_ctypes.py +++ b/psycopg3/pq_ctypes.py @@ -8,8 +8,9 @@ implementation. # Copyright (C) 2020 The Psycopg Team -from .pq_enums import ConnStatus, PostgresPollingStatus +from collections import namedtuple +from .pq_enums import ConnStatus, PostgresPollingStatus from . import _pq_ctypes as impl @@ -45,6 +46,33 @@ class PGconn: rv = impl.PQconnectPoll(self.pgconn_ptr) return PostgresPollingStatus(rv) + @classmethod + def get_defaults(cls): + opts = impl.PQconndefaults() + if not opts: + raise MemoryError("couldn't allocate connection defaults") + + def gets(opt, kw): + rv = getattr(opt, kw) + if rv is not None: + rv = rv.decode("utf8", "replace") + return rv + + try: + rv = [] + skws = "keyword envvar compiled val label dispatcher".split() + for opt in opts: + if not opt.keyword: + break + d = {kw: gets(opt, kw) for kw in skws} + d["dispsize"] = opt.dispsize + rv.append(ConninfoOption(**d)) + + finally: + impl.PQconninfoFree(opts) + + return rv + @property def status(self): rv = impl.PQstatus(self.pgconn_ptr) @@ -58,3 +86,8 @@ class PGconn: @property def socket(self): return impl.PQsocket(self.pgconn_ptr) + + +ConninfoOption = namedtuple( + "ConninfoOption", "keyword envvar compiled val label dispatcher dispsize" +) diff --git a/tests/test_pq.py b/tests/test_pq.py index e6f3169a6..539584a07 100644 --- a/tests/test_pq.py +++ b/tests/test_pq.py @@ -58,3 +58,14 @@ def test_connect_async_bad(pq, dsn): assert False, rv assert conn.status == ConnStatus.CONNECTION_BAD + + +def test_defaults(pq): + defs = pq.PGconn.get_defaults() + assert len(defs) > 20 + port = [d for d in defs if d.keyword == "port"][0] + assert port.envvar == "PGPORT" + assert port.compiled == "5432" + assert port.label == "Database-Port" + assert port.dispatcher == "" + assert port.dispsize == 6