From 6c57e4a648cbd5ff81db425978e007f5961e2e77 Mon Sep 17 00:00:00 2001 From: Oleksandr Shulgin Date: Mon, 1 Jun 2015 10:16:07 +0200 Subject: [PATCH] Add parse_dsn module function Calls PQconninfoParse to parse the dsn into a list of keyword and value structs, then constructs a dictionary from that. Can be useful when one needs to alter some part of the the connection string reliably, but doesn't want to get into all the details of parsing a dsn string: quoting, URL format, etc. --- doc/src/module.rst | 12 ++++++++++++ lib/__init__.py | 2 +- psycopg/psycopgmodule.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/doc/src/module.rst b/doc/src/module.rst index 8de9f87e..36073a23 100644 --- a/doc/src/module.rst +++ b/doc/src/module.rst @@ -78,6 +78,7 @@ The module interface respects the standard defined in the |DBAPI|_. .. seealso:: + - `parse_dsn` - libpq `connection string syntax`__ - libpq supported `connection parameters`__ - libpq supported `environment variables`__ @@ -91,6 +92,17 @@ The module interface respects the standard defined in the |DBAPI|_. The parameters *connection_factory* and *async* are Psycopg extensions to the |DBAPI|. +.. function:: parse_dsn(dsn) + + Parse connection string into a dictionary of keywords and values. + + Uses libpq's ``PQconninfoParse`` to parse the string according to + accepted format(s) and check for supported keywords. + + Example:: + + >>> psycopg2.parse_dsn('dbname=test user=postgres password=secret') + {'password': 'secret', 'user': 'postgres', 'dbname': 'test'} .. data:: apilevel diff --git a/lib/__init__.py b/lib/__init__.py index cf8c06ae..27b9d172 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -56,7 +56,7 @@ from psycopg2._psycopg import Error, Warning, DataError, DatabaseError, Programm from psycopg2._psycopg import IntegrityError, InterfaceError, InternalError from psycopg2._psycopg import NotSupportedError, OperationalError -from psycopg2._psycopg import _connect, apilevel, threadsafety, paramstyle +from psycopg2._psycopg import _connect, parse_dsn, apilevel, threadsafety, paramstyle from psycopg2._psycopg import __version__ from psycopg2 import tz diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index 61e2de57..d8f893cc 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -112,6 +112,44 @@ psyco_connect(PyObject *self, PyObject *args, PyObject *keywds) return conn; } +#define psyco_parse_dsn_doc \ +"parse_dsn(dsn) -- Parse database connection string.\n\n" + +static PyObject * +psyco_parse_dsn(PyObject *self, PyObject *args) +{ + char *dsn, *err; + PQconninfoOption *options = NULL, *o; + PyObject *res = NULL, *value; + + if (!PyArg_ParseTuple(args, "s", &dsn)) { + return NULL; + } + + options = PQconninfoParse(dsn, &err); + if (!options) { + PyErr_Format(PyExc_RuntimeError, "PQconninfoParse: %s: %s", dsn, err); + PQfreemem(err); + return NULL; + } + + res = PyDict_New(); + for (o = options; o->keyword != NULL; o++) { + if (o->val != NULL) { + value = PyString_FromString(o->val); + if (value == NULL || PyDict_SetItemString(res, o->keyword, value) != 0) { + Py_DECREF(res); + res = NULL; + break; + } + } + } + + PQconninfoFree(options); + + return res; +} + /** type registration **/ #define psyco_register_type_doc \ "register_type(obj, conn_or_curs) -> None -- register obj with psycopg type system\n\n" \ @@ -695,6 +733,8 @@ error: static PyMethodDef psycopgMethods[] = { {"_connect", (PyCFunction)psyco_connect, METH_VARARGS|METH_KEYWORDS, psyco_connect_doc}, + {"parse_dsn", (PyCFunction)psyco_parse_dsn, + METH_VARARGS, psyco_parse_dsn_doc}, {"adapt", (PyCFunction)psyco_microprotocols_adapt, METH_VARARGS, psyco_microprotocols_adapt_doc},