Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parse_dsn module function #321

Merged
merged 5 commits into from Oct 1, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions doc/src/module.rst
Expand Up @@ -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`__
Expand All @@ -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)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should be exposed by psycopg2.extensions, not the main module.

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

Expand Down
2 changes: 1 addition & 1 deletion lib/__init__.py
Expand Up @@ -56,7 +56,7 @@
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
Expand Down
40 changes: 40 additions & 0 deletions psycopg/psycopgmodule.c
Expand Up @@ -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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better: parse_dsn(dsn) -> dict. Also I don't think you need the \n's. Even better put all the documentation here and use autodoc to get it in the docs.


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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error is wrong. The dsn shouldn't be printed back as it may contain passwords that may end up in the logs. It shoud be a ProgrammingError if the dsn is wrong (with a human error message such as "error parsing the dsn: %s" % err) or an OperationalError if err is null as that's a memory allocation error according to the docs).

PQfreemem(err);
return NULL;
}

res = PyDict_New();
for (o = options; o->keyword != NULL; o++) {
if (o->val != NULL) {
value = PyString_FromString(o->val);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it work ok on Python3? Probably you need a function like Text_FromUTF8 -- see psycopg/python.h and example of usage all around the lib.

if (value == NULL || PyDict_SetItemString(res, o->keyword, value) != 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is terrible, separate the error check from PyString_FromString from the SetItemString!

It is also a reference leak: SetItemString doesn't steal the reference. value must be decref'd.

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" \
Expand Down Expand Up @@ -695,6 +733,8 @@ psyco_make_description_type(void)
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},

Expand Down