Name can be passed as None to cursor()

Makes invocation from subclasses and generic code easier.

Code simplified by using default values for keyword arguments
and avoiding needless conversions back and forth between Python and C
strings. Also added connection type check to cursor's init.
This commit is contained in:
Daniele Varrazzo 2012-04-11 17:32:10 +01:00
parent c63891af8d
commit 27421f1e41
3 changed files with 41 additions and 27 deletions

View File

@ -42,7 +42,7 @@
/* cursor method - allocate a new cursor */
#define psyco_conn_cursor_doc \
"cursor(name=None, cursor_factory=extensions.cursor, withhold=None) -- new cursor\n\n" \
"cursor(name=None, cursor_factory=extensions.cursor, withhold=False) -- new cursor\n\n" \
"Return a new cursor.\n\nThe ``cursor_factory`` argument can be used to\n" \
"create non-standard cursors by passing a class different from the\n" \
"default. Note that the new class *should* be a sub-class of\n" \
@ -50,26 +50,26 @@
":rtype: `extensions.cursor`"
static PyObject *
psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds)
psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs)
{
const char *name = NULL;
PyObject *obj, *factory = NULL, *withhold = NULL;
PyObject *obj;
PyObject *name = Py_None;
PyObject *factory = (PyObject *)&cursorType;
PyObject *withhold = Py_False;
static char *kwlist[] = {"name", "cursor_factory", "withhold", NULL};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sOO", kwlist,
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO", kwlist,
&name, &factory, &withhold)) {
return NULL;
}
if (withhold != NULL) {
if (PyObject_IsTrue(withhold) && name == NULL) {
PyErr_SetString(ProgrammingError,
"'withhold=True can be specified only for named cursors");
return NULL;
}
if (PyObject_IsTrue(withhold) && (name == Py_None)) {
PyErr_SetString(ProgrammingError,
"'withhold=True can be specified only for named cursors");
return NULL;
}
EXC_IF_CONN_CLOSED(self);
if (self->status != CONN_STATUS_READY &&
@ -80,31 +80,28 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds)
return NULL;
}
if (name != NULL && self->async == 1) {
if (name != Py_None && self->async == 1) {
PyErr_SetString(ProgrammingError,
"asynchronous connections "
"cannot produce named cursors");
return NULL;
}
Dprintf("psyco_conn_cursor: new cursor for connection at %p", self);
Dprintf("psyco_conn_cursor: parameters: name = %s", name);
Dprintf("psyco_conn_cursor: new %s cursor for connection at %p",
(name == Py_None ? "unnamed" : "named"), self);
if (factory == NULL) factory = (PyObject *)&cursorType;
if (name)
obj = PyObject_CallFunction(factory, "Os", self, name);
else
obj = PyObject_CallFunctionObjArgs(factory, self, NULL);
if (!(obj = PyObject_CallFunctionObjArgs(factory, self, name, NULL))) {
return NULL;
}
if (obj == NULL) return NULL;
if (PyObject_IsInstance(obj, (PyObject *)&cursorType) == 0) {
PyErr_SetString(PyExc_TypeError,
"cursor factory must be subclass of psycopg2._psycopg.cursor");
Py_DECREF(obj);
return NULL;
}
if (withhold != NULL && PyObject_IsTrue(withhold))
if (PyObject_IsTrue(withhold))
((cursorObject*)obj)->withhold = 1;
Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = "

View File

@ -1808,15 +1808,28 @@ cursor_dealloc(PyObject* obj)
}
static int
cursor_init(PyObject *obj, PyObject *args, PyObject *kwds)
cursor_init(PyObject *obj, PyObject *args, PyObject *kwargs)
{
const char *name = NULL;
PyObject *conn;
PyObject *name = Py_None;
const char *cname;
if (!PyArg_ParseTuple(args, "O|s", &conn, &name))
static char *kwlist[] = {"conn", "name", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist,
&connectionType, &conn, &name)) {
return -1;
}
return cursor_setup((cursorObject *)obj, (connectionObject *)conn, name);
if (name == Py_None) {
cname = NULL;
} else {
if (!(cname = Bytes_AsString(name))) {
return -1;
}
}
return cursor_setup((cursorObject *)obj, (connectionObject *)conn, cname);
}
static PyObject *

View File

@ -165,6 +165,10 @@ class CursorTests(unittest.TestCase):
del curs
self.assert_(w() is None)
def test_null_name(self):
curs = self.conn.cursor(None)
self.assertEqual(curs.name, None)
def test_invalid_name(self):
curs = self.conn.cursor()
curs.execute("create temp table invname (data int);")