Merge branch 'conn-get-parameters'

This commit is contained in:
Daniele Varrazzo 2016-07-01 20:12:01 +01:00
commit 7566af145b
7 changed files with 99 additions and 19 deletions

1
NEWS
View File

@ -18,6 +18,7 @@ New features:
customized replacing them with any object exposing an `!append()` method
(:ticket:`#326`).
- Added `~psycopg2.extensions.quote_ident()` function (:ticket:`#359`).
- Added `~connection.get_dsn_parameters()` connection method (:ticket:`#364`).
What's new in psycopg 2.6.2

View File

@ -568,6 +568,29 @@ The ``connection`` class
.. versionadded:: 2.0.12
.. index::
pair: Connection; Parameters
.. method:: get_dsn_parameters()
Get the effective dsn parameters for the connection as a dictionary.
The *password* parameter is removed from the result.
Example::
>>> conn.get_dsn_parameters()
{'dbname': 'test', 'user': 'postgres', 'port': '5432', 'sslmode': 'prefer'}
Requires libpq >= 9.3.
.. seealso:: libpq docs for `PQconninfo()`__ for details.
.. __: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNINFO
.. versionadded:: 2.7
.. index::
pair: Transaction; Status

View File

@ -733,6 +733,37 @@ psyco_conn_get_parameter_status(connectionObject *self, PyObject *args)
return conn_text_from_chars(self, val);
}
/* get_dsn_parameters method - Get connection parameters */
#define psyco_conn_get_dsn_parameters_doc \
"get_dsn_parameters() -- Get effective connection parameters.\n\n"
static PyObject *
psyco_conn_get_dsn_parameters(connectionObject *self)
{
#if PG_VERSION_NUM >= 90300
PyObject *res = NULL;
PQconninfoOption *options = NULL;
EXC_IF_CONN_CLOSED(self);
if (!(options = PQconninfo(self->pgconn))) {
PyErr_NoMemory();
goto exit;
}
res = psycopg_dict_from_conninfo_options(options, /* include_password = */ 0);
exit:
PQconninfoFree(options);
return res;
#else
PyErr_SetString(NotSupportedError, "PQconninfo not available in libpq < 9.3");
return NULL;
#endif
}
/* lobject method - allocate a new lobject */
@ -977,6 +1008,8 @@ static struct PyMethodDef connectionObject_methods[] = {
METH_NOARGS, psyco_conn_get_transaction_status_doc},
{"get_parameter_status", (PyCFunction)psyco_conn_get_parameter_status,
METH_VARARGS, psyco_conn_get_parameter_status_doc},
{"get_dsn_parameters", (PyCFunction)psyco_conn_get_dsn_parameters,
METH_NOARGS, psyco_conn_get_dsn_parameters_doc},
{"get_backend_pid", (PyCFunction)psyco_conn_get_backend_pid,
METH_NOARGS, psyco_conn_get_backend_pid_doc},
{"lobject", (PyCFunction)psyco_conn_lobject,

View File

@ -131,6 +131,9 @@ STEALS(1) HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj);
STEALS(1) HIDDEN PyObject * psycopg_ensure_text(PyObject *obj);
HIDDEN PyObject *psycopg_dict_from_conninfo_options(PQconninfoOption *options,
int include_password);
/* Exceptions docstrings */
#define Error_doc \
"Base class for error exceptions."

View File

@ -119,8 +119,8 @@ static PyObject *
psyco_parse_dsn(PyObject *self, PyObject *args, PyObject *kwargs)
{
char *err = NULL;
PQconninfoOption *options = NULL, *o;
PyObject *dict = NULL, *res = NULL, *dsn;
PQconninfoOption *options = NULL;
PyObject *res = NULL, *dsn;
static char *kwlist[] = {"dsn", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &dsn)) {
@ -141,26 +141,10 @@ psyco_parse_dsn(PyObject *self, PyObject *args, PyObject *kwargs)
goto exit;
}
if (!(dict = PyDict_New())) { goto exit; }
for (o = options; o->keyword != NULL; o++) {
if (o->val != NULL) {
PyObject *value;
if (!(value = Text_FromUTF8(o->val))) { goto exit; }
if (PyDict_SetItemString(dict, o->keyword, value) != 0) {
Py_DECREF(value);
goto exit;
}
Py_DECREF(value);
}
}
/* success */
res = dict;
dict = NULL;
res = psycopg_dict_from_conninfo_options(options, /* include_password = */ 1);
exit:
PQconninfoFree(options); /* safe on null */
Py_XDECREF(dict);
Py_XDECREF(dsn);
return res;

View File

@ -247,3 +247,32 @@ psycopg_is_text_file(PyObject *f)
}
}
/* Make a dict out of PQconninfoOption array */
PyObject *
psycopg_dict_from_conninfo_options(PQconninfoOption *options, int include_password)
{
PyObject *dict, *res = NULL;
PQconninfoOption *o;
if (!(dict = PyDict_New())) { goto exit; }
for (o = options; o->keyword != NULL; o++) {
if (o->val != NULL &&
(include_password || strcmp(o->keyword, "password") != 0)) {
PyObject *value;
if (!(value = Text_FromUTF8(o->val))) { goto exit; }
if (PyDict_SetItemString(dict, o->keyword, value) != 0) {
Py_DECREF(value);
goto exit;
}
Py_DECREF(value);
}
}
res = dict;
dict = NULL;
exit:
Py_XDECREF(dict);
return res;
}

View File

@ -446,6 +446,13 @@ class MakeDsnTestCase(ConnectingTestCase):
self.assertRaises(psycopg2.ProgrammingError,
ext.make_dsn, url, nosuch="param")
@skip_before_libpq(9, 3)
def test_get_dsn_parameters(self):
conn = self.connect()
d = conn.get_dsn_parameters()
self.assertEqual(d['dbname'], dbname) # the only param we can check reliably
self.assertNotIn('password', d)
class IsolationLevelsTestCase(ConnectingTestCase):