mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-10 19:16:34 +03:00
connect() supports generic keyword arguments passed to the dsn
This commit is contained in:
parent
4254fb8566
commit
d2b67364fd
|
@ -20,7 +20,7 @@ The module interface respects the standard defined in the |DBAPI|_.
|
||||||
|
|
||||||
Create a new database session and return a new `connection` object.
|
Create a new database session and return a new `connection` object.
|
||||||
|
|
||||||
You can specify the connection parameters either as a string::
|
The connection parameters can be specified either as a string::
|
||||||
|
|
||||||
conn = psycopg2.connect("dbname=test user=postgres password=secret")
|
conn = psycopg2.connect("dbname=test user=postgres password=secret")
|
||||||
|
|
||||||
|
@ -28,17 +28,23 @@ The module interface respects the standard defined in the |DBAPI|_.
|
||||||
|
|
||||||
conn = psycopg2.connect(database="test", user="postgres", password="secret")
|
conn = psycopg2.connect(database="test", user="postgres", password="secret")
|
||||||
|
|
||||||
The full list of available parameters is:
|
The basic connection parameters are:
|
||||||
|
|
||||||
- `!dbname` -- the database name (only in dsn string)
|
- `!dbname` -- the database name (only in dsn string)
|
||||||
- `!database` -- the database name (only as keyword argument)
|
- `!database` -- the database name (only as keyword argument)
|
||||||
- `!user` -- user name used to authenticate
|
- `!user` -- user name used to authenticate
|
||||||
- `!password` -- password used to authenticate
|
- `!password` -- password used to authenticate
|
||||||
- `!host` -- database host address (defaults to UNIX socket if not provided)
|
- `!host` -- database host address (defaults to UNIX socket if not provided)
|
||||||
- `!port` -- connection port number (defaults to 5432 if not provided)
|
- `!port` -- connection port number (defaults to 5432 if not provided)
|
||||||
- `!sslmode` -- `SSL TCP/IP negotiation`__ mode
|
|
||||||
|
|
||||||
.. __: http://www.postgresql.org/docs/9.0/static/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS
|
Any other connection parameter supported by the client library/server can
|
||||||
|
be passed either in the connection string or as keyword. See the
|
||||||
|
PostgreSQL documentation for a complete `list of supported parameters`__.
|
||||||
|
Also note that the same parameters can be passed to the client library
|
||||||
|
using `environment variables`__.
|
||||||
|
|
||||||
|
.. __: http://www.postgresql.org/docs/9.1/static/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS
|
||||||
|
.. __: http://www.postgresql.org/docs/9.1/static/libpq-envars.html
|
||||||
|
|
||||||
Using the *connection_factory* parameter a different class or
|
Using the *connection_factory* parameter a different class or
|
||||||
connections factory can be specified. It should be a callable object
|
connections factory can be specified. It should be a callable object
|
||||||
|
@ -48,6 +54,10 @@ The module interface respects the standard defined in the |DBAPI|_.
|
||||||
Using *async*\=1 an asynchronous connection will be created: see
|
Using *async*\=1 an asynchronous connection will be created: see
|
||||||
:ref:`async-support` to know about advantages and limitations.
|
:ref:`async-support` to know about advantages and limitations.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.4.3
|
||||||
|
any keyword argument is passed to the connection. Previously only the
|
||||||
|
basic parameters (plus `!sslmode`) were supported as keywords.
|
||||||
|
|
||||||
.. extension::
|
.. extension::
|
||||||
|
|
||||||
The parameters *connection_factory* and *async* are Psycopg extensions
|
The parameters *connection_factory* and *async* are Psycopg extensions
|
||||||
|
|
|
@ -73,7 +73,7 @@ from psycopg2._psycopg import Error, Warning, DataError, DatabaseError, Programm
|
||||||
from psycopg2._psycopg import IntegrityError, InterfaceError, InternalError
|
from psycopg2._psycopg import IntegrityError, InterfaceError, InternalError
|
||||||
from psycopg2._psycopg import NotSupportedError, OperationalError
|
from psycopg2._psycopg import NotSupportedError, OperationalError
|
||||||
|
|
||||||
from psycopg2._psycopg import connect, apilevel, threadsafety, paramstyle
|
from psycopg2._psycopg import _connect, apilevel, threadsafety, paramstyle
|
||||||
from psycopg2._psycopg import __version__
|
from psycopg2._psycopg import __version__
|
||||||
|
|
||||||
from psycopg2 import tz
|
from psycopg2 import tz
|
||||||
|
@ -97,5 +97,64 @@ else:
|
||||||
_ext.register_adapter(Decimal, Adapter)
|
_ext.register_adapter(Decimal, Adapter)
|
||||||
del Decimal, Adapter
|
del Decimal, Adapter
|
||||||
|
|
||||||
|
|
||||||
|
def connect(dsn=None,
|
||||||
|
database=None, user=None, password=None, host=None, port=None,
|
||||||
|
connection_factory=None, async=False, **kwargs):
|
||||||
|
"""
|
||||||
|
Create a new database connection.
|
||||||
|
|
||||||
|
The connection parameters can be specified either as a string:
|
||||||
|
|
||||||
|
conn = psycopg2.connect("dbname=test user=postgres password=secret")
|
||||||
|
|
||||||
|
or using a set of keyword arguments:
|
||||||
|
|
||||||
|
conn = psycopg2.connect(database="test", user="postgres", password="secret")
|
||||||
|
|
||||||
|
The basic connection parameters are:
|
||||||
|
|
||||||
|
- *dbname*: the database name (only in dsn string)
|
||||||
|
- *database*: the database name (only as keyword argument)
|
||||||
|
- *user*: user name used to authenticate
|
||||||
|
- *password*: password used to authenticate
|
||||||
|
- *host*: database host address (defaults to UNIX socket if not provided)
|
||||||
|
- *port*: connection port number (defaults to 5432 if not provided)
|
||||||
|
|
||||||
|
Using the *connection_factory* parameter a different class or connections
|
||||||
|
factory can be specified. It should be a callable object taking a dsn
|
||||||
|
argument.
|
||||||
|
|
||||||
|
Using *async*=True an asynchronous connection will be created.
|
||||||
|
|
||||||
|
Any other keyword parameter will be passed to the underlying client
|
||||||
|
library: the list of supported parameter depends on the library version.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if dsn is None:
|
||||||
|
items = []
|
||||||
|
if database is not None:
|
||||||
|
items.append(('dbname', database))
|
||||||
|
if user is not None:
|
||||||
|
items.append(('user', user))
|
||||||
|
if password is not None:
|
||||||
|
items.append(('password', password))
|
||||||
|
if host is not None:
|
||||||
|
items.append(('host', host))
|
||||||
|
if port is not None:
|
||||||
|
items.append(('port', port))
|
||||||
|
|
||||||
|
items.extend(
|
||||||
|
[(k, v) for (k, v) in kwargs.iteritems() if v is not None])
|
||||||
|
dsn = " ".join(["%s=%s" % item for item in items])
|
||||||
|
|
||||||
|
if not dsn:
|
||||||
|
raise InterfaceError('missing dsn and no parameters')
|
||||||
|
|
||||||
|
return _connect(dsn,
|
||||||
|
connection_factory=connection_factory, async=async)
|
||||||
|
|
||||||
|
|
||||||
__all__ = filter(lambda k: not k.startswith('_'), locals().keys())
|
__all__ = filter(lambda k: not k.startswith('_'), locals().keys())
|
||||||
|
|
||||||
|
|
|
@ -75,177 +75,43 @@ HIDDEN PyObject *psyco_DescriptionType = NULL;
|
||||||
|
|
||||||
/** connect module-level function **/
|
/** connect module-level function **/
|
||||||
#define psyco_connect_doc \
|
#define psyco_connect_doc \
|
||||||
"connect(dsn, ...) -- Create a new database connection.\n\n" \
|
"_connect(dsn, [connection_factory], [async]) -- New database connection.\n\n"
|
||||||
"This function supports two different but equivalent sets of arguments.\n" \
|
|
||||||
"A single data source name or ``dsn`` string can be used to specify the\n" \
|
|
||||||
"connection parameters, as follows::\n\n" \
|
|
||||||
" psycopg2.connect(\"dbname=xxx user=xxx ...\")\n\n" \
|
|
||||||
"If ``dsn`` is not provided it is possible to pass the parameters as\n" \
|
|
||||||
"keyword arguments; e.g.::\n\n" \
|
|
||||||
" psycopg2.connect(database='xxx', user='xxx', ...)\n\n" \
|
|
||||||
"The full list of available parameters is:\n\n" \
|
|
||||||
"- ``dbname`` -- database name (only in 'dsn')\n" \
|
|
||||||
"- ``database`` -- database name (only as keyword argument)\n" \
|
|
||||||
"- ``host`` -- host address (defaults to UNIX socket if not provided)\n" \
|
|
||||||
"- ``port`` -- port number (defaults to 5432 if not provided)\n" \
|
|
||||||
"- ``user`` -- user name used to authenticate\n" \
|
|
||||||
"- ``password`` -- password used to authenticate\n" \
|
|
||||||
"- ``sslmode`` -- SSL mode (see PostgreSQL documentation)\n\n" \
|
|
||||||
"- ``async`` -- if the connection should provide asynchronous API\n\n" \
|
|
||||||
"If the ``connection_factory`` keyword argument is not provided this\n" \
|
|
||||||
"function always return an instance of the `connection` class.\n" \
|
|
||||||
"Else the given sub-class of `extensions.connection` will be used to\n" \
|
|
||||||
"instantiate the connection object.\n\n" \
|
|
||||||
":return: New database connection\n" \
|
|
||||||
":rtype: `extensions.connection`"
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
_psyco_connect_fill_dsn(char *dsn, const char *kw, const char *v, size_t i)
|
|
||||||
{
|
|
||||||
strcpy(&dsn[i], kw); i += strlen(kw);
|
|
||||||
strcpy(&dsn[i], v); i += strlen(v);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
|
psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
|
||||||
{
|
{
|
||||||
PyObject *conn = NULL, *factory = NULL;
|
PyObject *conn = NULL;
|
||||||
PyObject *pyport = NULL;
|
PyObject *factory = NULL;
|
||||||
|
const char *dsn = NULL;
|
||||||
size_t idsn=-1;
|
|
||||||
int iport=-1;
|
|
||||||
const char *dsn_static = NULL;
|
|
||||||
char *dsn_dynamic=NULL;
|
|
||||||
const char *database=NULL, *user=NULL, *password=NULL;
|
|
||||||
const char *host=NULL, *sslmode=NULL;
|
|
||||||
char port[16];
|
|
||||||
int async = 0;
|
int async = 0;
|
||||||
|
|
||||||
static char *kwlist[] = {"dsn", "database", "host", "port",
|
static char *kwlist[] = {"dsn", "connection_factory", "async", NULL};
|
||||||
"user", "password", "sslmode",
|
|
||||||
"connection_factory", "async", NULL};
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sssOsssOi", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|Oi", kwlist,
|
||||||
&dsn_static, &database, &host, &pyport,
|
&dsn, &factory, &async)) {
|
||||||
&user, &password, &sslmode,
|
|
||||||
&factory, &async)) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
Dprintf("psyco_connect: dsn = '%s', async = %d", dsn, async);
|
||||||
if (pyport && PyString_Check(pyport)) {
|
|
||||||
PyObject *pyint = PyInt_FromString(PyString_AsString(pyport), NULL, 10);
|
/* allocate connection, fill with errors and return it */
|
||||||
if (!pyint) goto fail;
|
if (factory == NULL || factory == Py_None) {
|
||||||
/* Must use PyInt_AsLong rather than PyInt_AS_LONG, because
|
factory = (PyObject *)&connectionType;
|
||||||
* PyInt_FromString can return a PyLongObject: */
|
|
||||||
iport = PyInt_AsLong(pyint);
|
|
||||||
Py_DECREF(pyint);
|
|
||||||
if (iport == -1 && PyErr_Occurred())
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
else if (pyport && PyInt_Check(pyport)) {
|
|
||||||
iport = PyInt_AsLong(pyport);
|
|
||||||
if (iport == -1 && PyErr_Occurred())
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (pyport && PyUnicode_Check(pyport)) {
|
|
||||||
PyObject *pyint = PyObject_CallFunction((PyObject*)&PyLong_Type,
|
|
||||||
"Oi", pyport, 10);
|
|
||||||
if (!pyint) goto fail;
|
|
||||||
iport = PyLong_AsLong(pyint);
|
|
||||||
Py_DECREF(pyint);
|
|
||||||
if (iport == -1 && PyErr_Occurred())
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
else if (pyport && PyLong_Check(pyport)) {
|
|
||||||
iport = PyLong_AsLong(pyport);
|
|
||||||
if (iport == -1 && PyErr_Occurred())
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (pyport != NULL) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "port must be a string or int");
|
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iport > 0)
|
/* Here we are breaking the connection.__init__ interface defined
|
||||||
PyOS_snprintf(port, 16, "%d", iport);
|
* by psycopg2. So, if not requiring an async conn, avoid passing
|
||||||
|
* the async parameter. */
|
||||||
if (dsn_static == NULL) {
|
/* TODO: would it be possible to avoid an additional parameter
|
||||||
size_t l = 46; /* len(" dbname= user= password= host= port= sslmode=\0") */
|
* to the conn constructor? A subclass? (but it would require mixins
|
||||||
|
* to further subclass) Another dsn parameter (but is not really
|
||||||
if (database) l += strlen(database);
|
* a connection parameter that can be configured) */
|
||||||
if (host) l += strlen(host);
|
if (!async) {
|
||||||
if (iport > 0) l += strlen(port);
|
|
||||||
if (user) l += strlen(user);
|
|
||||||
if (password) l += strlen(password);
|
|
||||||
if (sslmode) l += strlen(sslmode);
|
|
||||||
|
|
||||||
dsn_dynamic = malloc(l*sizeof(char));
|
|
||||||
if (dsn_dynamic == NULL) {
|
|
||||||
PyErr_SetString(InterfaceError, "dynamic dsn allocation failed");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
idsn = 0;
|
|
||||||
if (database)
|
|
||||||
idsn = _psyco_connect_fill_dsn(dsn_dynamic, " dbname=", database, idsn);
|
|
||||||
if (host)
|
|
||||||
idsn = _psyco_connect_fill_dsn(dsn_dynamic, " host=", host, idsn);
|
|
||||||
if (iport > 0)
|
|
||||||
idsn = _psyco_connect_fill_dsn(dsn_dynamic, " port=", port, idsn);
|
|
||||||
if (user)
|
|
||||||
idsn = _psyco_connect_fill_dsn(dsn_dynamic, " user=", user, idsn);
|
|
||||||
if (password)
|
|
||||||
idsn = _psyco_connect_fill_dsn(dsn_dynamic, " password=", password, idsn);
|
|
||||||
if (sslmode)
|
|
||||||
idsn = _psyco_connect_fill_dsn(dsn_dynamic, " sslmode=", sslmode, idsn);
|
|
||||||
|
|
||||||
if (idsn > 0) {
|
|
||||||
dsn_dynamic[idsn] = '\0';
|
|
||||||
memmove(dsn_dynamic, &dsn_dynamic[1], idsn);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PyErr_SetString(InterfaceError, "missing dsn and no parameters");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const char *dsn = (dsn_static != NULL ? dsn_static : dsn_dynamic);
|
|
||||||
Dprintf("psyco_connect: dsn = '%s', async = %d", dsn, async);
|
|
||||||
|
|
||||||
/* allocate connection, fill with errors and return it */
|
|
||||||
if (factory == NULL) factory = (PyObject *)&connectionType;
|
|
||||||
/* Here we are breaking the connection.__init__ interface defined
|
|
||||||
* by psycopg2. So, if not requiring an async conn, avoid passing
|
|
||||||
* the async parameter. */
|
|
||||||
/* TODO: would it be possible to avoid an additional parameter
|
|
||||||
* to the conn constructor? A subclass? (but it would require mixins
|
|
||||||
* to further subclass) Another dsn parameter (but is not really
|
|
||||||
* a connection parameter that can be configured) */
|
|
||||||
if (!async) {
|
|
||||||
conn = PyObject_CallFunction(factory, "s", dsn);
|
conn = PyObject_CallFunction(factory, "s", dsn);
|
||||||
} else {
|
} else {
|
||||||
conn = PyObject_CallFunction(factory, "si", dsn, async);
|
conn = PyObject_CallFunction(factory, "si", dsn, async);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
goto cleanup;
|
|
||||||
fail:
|
|
||||||
assert (PyErr_Occurred());
|
|
||||||
if (conn != NULL) {
|
|
||||||
Py_DECREF(conn);
|
|
||||||
conn = NULL;
|
|
||||||
}
|
|
||||||
/* Fall through to cleanup: */
|
|
||||||
cleanup:
|
|
||||||
if (dsn_dynamic != NULL) {
|
|
||||||
free(dsn_dynamic);
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,7 +620,7 @@ exit:
|
||||||
/** method table and module initialization **/
|
/** method table and module initialization **/
|
||||||
|
|
||||||
static PyMethodDef psycopgMethods[] = {
|
static PyMethodDef psycopgMethods[] = {
|
||||||
{"connect", (PyCFunction)psyco_connect,
|
{"_connect", (PyCFunction)psyco_connect,
|
||||||
METH_VARARGS|METH_KEYWORDS, psyco_connect_doc},
|
METH_VARARGS|METH_KEYWORDS, psyco_connect_doc},
|
||||||
{"adapt", (PyCFunction)psyco_microprotocols_adapt,
|
{"adapt", (PyCFunction)psyco_microprotocols_adapt,
|
||||||
METH_VARARGS, psyco_microprotocols_adapt_doc},
|
METH_VARARGS, psyco_microprotocols_adapt_doc},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user