From: Daniele Varrazzo Date: Sat, 14 Mar 2020 05:09:14 +0000 (+1300) Subject: Added PGconn.info wrapping PQconninfo X-Git-Tag: 3.0.dev0~731 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dd62d6d11fafb06bb0cedb62816aa60a9e791d42;p=thirdparty%2Fpsycopg.git Added PGconn.info wrapping PQconninfo --- diff --git a/psycopg3/_pq_ctypes.py b/psycopg3/_pq_ctypes.py index d2a0f188c..78bcd22cd 100644 --- a/psycopg3/_pq_ctypes.py +++ b/psycopg3/_pq_ctypes.py @@ -19,9 +19,6 @@ class PGconn_struct(Structure): _fields_ = [] -PGconn_ptr = POINTER(PGconn_struct) - - class PQconninfoOption_struct(Structure): _fields_ = [ ("keyword", c_char_p), @@ -34,6 +31,10 @@ class PQconninfoOption_struct(Structure): ] +PGconn_ptr = POINTER(PGconn_struct) +PQconninfoOption_ptr = POINTER(PQconninfoOption_struct) + + # Function definitions as explained in PostgreSQL 12 documentation # 33.1. Database Connection Control Functions @@ -59,12 +60,16 @@ PQconnectPoll.restype = c_int PQconndefaults = pq.PQconndefaults PQconndefaults.argtypes = [] -PQconndefaults.restype = POINTER(PQconninfoOption_struct) +PQconndefaults.restype = PQconninfoOption_ptr PQconninfoFree = pq.PQconninfoFree -PQconninfoFree.argtypes = [POINTER(PQconninfoOption_struct)] +PQconninfoFree.argtypes = [PQconninfoOption_ptr] PQconninfoFree.restype = None +PQconninfo = pq.PQconninfo +PQconninfo.argtypes = [PGconn_ptr] +PQconninfo.restype = PQconninfoOption_ptr + # 33.2. Connection Status Functions diff --git a/psycopg3/pq_ctypes.py b/psycopg3/pq_ctypes.py index b85480b42..8a37b45b5 100644 --- a/psycopg3/pq_ctypes.py +++ b/psycopg3/pq_ctypes.py @@ -51,27 +51,20 @@ class PGconn: 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)) - + return _conninfoopts_from_array(opts) finally: impl.PQconninfoFree(opts) - return rv + @property + def info(self): + opts = impl.PQconninfo(self.pgconn_ptr) + if not opts: + raise MemoryError("couldn't allocate connection info") + try: + return _conninfoopts_from_array(opts) + finally: + impl.PQconninfoFree(opts) @property def status(self): @@ -91,3 +84,22 @@ class PGconn: ConninfoOption = namedtuple( "ConninfoOption", "keyword envvar compiled val label dispatcher dispsize" ) + + +def _conninfoopts_from_array(opts): + def gets(opt, kw): + rv = getattr(opt, kw) + if rv is not None: + rv = rv.decode("utf8", "replace") + return rv + + 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)) + + return rv diff --git a/tests/test_pq.py b/tests/test_pq.py index 539584a07..3c8aa1d84 100644 --- a/tests/test_pq.py +++ b/tests/test_pq.py @@ -1,3 +1,4 @@ +import os from select import select import pytest @@ -61,11 +62,33 @@ def test_connect_async_bad(pq, dsn): def test_defaults(pq): - defs = pq.PGconn.get_defaults() + oldport = os.environ.get("PGPORT") + try: + os.environ["PGPORT"] = "15432" + defs = pq.PGconn.get_defaults() + finally: + if oldport is not None: + os.environ["PGPORT"] = oldport + else: + del os.environ["PGPORT"] + 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.val == "15432" assert port.label == "Database-Port" assert port.dispatcher == "" assert port.dispsize == 6 + + +def test_info(pq, dsn): + conn = pq.PGconn.connectdb(dsn) + info = conn.info + assert len(info) > 20 + dbname = [d for d in info if d.keyword == "dbname"][0] + assert dbname.envvar == "PGDATABASE" + assert dbname.val == "psycopg3_test" # TODO: parse from dsn + assert dbname.label == "Database-Name" + assert dbname.dispatcher == "" + assert dbname.dispsize == 20