Added several ConnectionInfo attributes

This commit is contained in:
Daniele Varrazzo 2018-10-12 03:25:35 +01:00
parent 9ddf59959f
commit 0a04c8892d
4 changed files with 179 additions and 10 deletions

View File

@ -159,7 +159,13 @@ introspection etc.
.. versionadded:: 2.8
.. autoattribute:: dbname
.. autoattribute:: user
.. autoattribute:: password
.. autoattribute:: host
.. autoattribute:: port
.. autoattribute:: options
.. autoattribute:: status

View File

@ -29,6 +29,79 @@
#include "psycopg/conninfo.h"
static const char connInfoType_doc[] =
"Details about the native PostgreSQL database connection.\n"
"\n"
"This class exposes several `informative functions`__ about the status\n"
"of the libpq connection.\n"
"\n"
"Objects of this class are exposed as the `connection.info` attribute.\n"
"\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html";
static const char dbname_doc[] =
"The database name of the connection.\n"
"\n"
"Wrapper for the `PQdb()`__ function.\n"
"\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html"
"#LIBPQ-PQDB";
static PyObject *
dbname_get(connInfoObject *self)
{
const char *val;
val = PQdb(self->conn->pgconn);
if (!val) {
Py_RETURN_NONE;
}
return conn_text_from_chars(self->conn, val);
}
static const char user_doc[] =
"The user name of the connection.\n"
"\n"
"Wrapper for the `PQuser()`__ function.\n"
"\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html"
"#LIBPQ-PQUSER";
static PyObject *
user_get(connInfoObject *self)
{
const char *val;
val = PQuser(self->conn->pgconn);
if (!val) {
Py_RETURN_NONE;
}
return conn_text_from_chars(self->conn, val);
}
static const char password_doc[] =
"The password of the connection.\n"
"\n"
".. seealso:: libpq docs for `PQpass()`__ for details.\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html"
"#LIBPQ-PQPASS";
static PyObject *
password_get(connInfoObject *self)
{
const char *val;
val = PQpass(self->conn->pgconn);
if (!val) {
Py_RETURN_NONE;
}
return conn_text_from_chars(self->conn, val);
}
static const char host_doc[] =
"The server host name of the connection.\n"
"\n"
@ -53,8 +126,71 @@ host_get(connInfoObject *self)
}
static const char port_doc[] =
"The port of the connection.\n"
"\n"
".. seealso:: libpq docs for `PQport()`__ for details.\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html"
"#LIBPQ-PQPORT";
static PyObject *
port_get(connInfoObject *self)
{
const char *val;
val = PQport(self->conn->pgconn);
if (!val || !val[0]) {
Py_RETURN_NONE;
}
return PyInt_FromString((char *)val, NULL, 10);
}
static const char options_doc[] =
"The command-line options passed in the the connection request.\n"
"\n"
".. seealso:: libpq docs for `PQoptions()`__ for details.\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html"
"#LIBPQ-PQOPTIONS";
static PyObject *
options_get(connInfoObject *self)
{
const char *val;
val = PQoptions(self->conn->pgconn);
if (!val) {
Py_RETURN_NONE;
}
return conn_text_from_chars(self->conn, val);
}
static const char status_doc[] =
"Return the status of the connection.\n"
"\n"
".. seealso:: libpq docs for `PQstatus()`__ for details.\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html"
"#LIBPQ-PQSTATUS";
static PyObject *
status_get(connInfoObject *self)
{
ConnStatusType val;
val = PQstatus(self->conn->pgconn);
return PyInt_FromLong((long)val);
}
static struct PyGetSetDef connInfoObject_getsets[] = {
{ "dbname", (getter)dbname_get, NULL, (char *)dbname_doc },
{ "user", (getter)user_get, NULL, (char *)user_doc },
{ "password", (getter)password_get, NULL, (char *)password_doc },
{ "host", (getter)host_get, NULL, (char *)host_doc },
{ "port", (getter)port_get, NULL, (char *)port_doc },
{ "options", (getter)options_get, NULL, (char *)options_doc },
{ "status", (getter)status_get, NULL, (char *)status_doc },
{NULL}
};
@ -95,16 +231,6 @@ conninfo_dealloc(connInfoObject* self)
/* object type */
static const char connInfoType_doc[] =
"Details about the native PostgreSQL database connection.\n"
"\n"
"This class exposes several `informative functions`__ about the status\n"
"of the libpq connection.\n"
"\n"
"Objects of this class are exposed as the `connection.info` attribute.\n"
"\n"
".. __: https://www.postgresql.org/docs/current/static/libpq-status.html";
PyTypeObject connInfoType = {
PyVarObject_HEAD_INIT(NULL, 0)
"psycopg2.extensions.ConnectionInfo",

View File

@ -78,6 +78,7 @@ typedef unsigned long Py_uhash_t;
#define PyInt_Check PyLong_Check
#define PyInt_AsLong PyLong_AsLong
#define PyInt_FromLong PyLong_FromLong
#define PyInt_FromString PyLong_FromString
#define PyInt_FromSsize_t PyLong_FromSsize_t
#define PyExc_StandardError PyExc_Exception
#define PyString_FromFormat PyUnicode_FromFormat

View File

@ -1683,14 +1683,50 @@ while True:
class TestConnectionInfo(ConnectingTestCase):
def setUp(self):
ConnectingTestCase.setUp(self)
class BrokenConn(psycopg2.extensions.connection):
def __init__(self, *args, **kwargs):
# don't call superclass
pass
# A "broken" connection
self.bconn = self.connect(connection_factory=BrokenConn)
def test_dbname(self):
self.assert_(isinstance(self.conn.info.dbname, str))
self.assert_(self.bconn.info.dbname is None)
def test_user(self):
self.assert_(isinstance(self.conn.info.user, str))
self.assert_(self.bconn.info.user is None)
def test_password(self):
self.assert_(isinstance(self.conn.info.password, str))
self.assert_(self.bconn.info.password is None)
def test_host(self):
expected = dbhost if dbhost else "/"
self.assertIn(expected, self.conn.info.host)
self.assert_(self.bconn.info.host is None)
def test_host_readonly(self):
with self.assertRaises(AttributeError):
self.conn.info.host = 'override'
def test_port(self):
self.assert_(isinstance(self.conn.info.port, int))
self.assert_(self.bconn.info.port is None)
def test_options(self):
self.assert_(isinstance(self.conn.info.options, str))
self.assert_(self.bconn.info.options is None)
def test_status(self):
self.assertEqual(self.conn.info.status, 0)
self.assertEqual(self.bconn.info.status, 1)
def test_suite():
return unittest.TestLoader().loadTestsFromName(__name__)