Changeset 447


Ignore:
Timestamp:
Oct 16, 2012, 3:16:05 PM (7 years ago)
Author:
cito
Message:

Added a namedresult() method to the classic API.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/docs/changelog.txt

    r446 r447  
    1010  This an effective way to pass arbitrary or unknown data without worrying
    1111  about SQL injection or syntax errors (contribution by Patrick TJ McPhee).
     12- The classic API now supports a method namedresult() in addition to
     13  getresult() and dictresult(), which returns the rows of the result
     14  as named tuples if these are supported (Python 2.6 or higher).
    1215- The execute() and executemany() methods now return the cursor object,
    1316  so you can now write statements like "for row in cursor.execute(...)"
  • trunk/docs/pg.txt

    r446 r447  
    7575
    7676Exceptions raised:
    77   :Type: bad argument type, or too many arguments
     77  :TypeError: bad argument type, or too many arguments
    7878  :SyntaxError: duplicate argument definition
    7979  :pg.InternalError: some error occurred during pg connection definition
     
    385385  used by PyGreSQL to hold PostgreSQL numeric values. The default class
    386386  is decimal.Decimal if available, otherwise the float type is used.
     387 
     388set_namedresult -- set a function that will convert to named tuples
     389-------------------------------------------------------------------
     390Syntax::
     391
     392  set_namedresult(func)
     393
     394Parameters:
     395  :func: the function to be used to convert results to named tuples
     396
     397Description:
     398  You can use this if you want to create different kinds of named tuples.
     399 
    387400
    388401Module constants
     
    448461  string. If it is a statement that returns rows as a result (usually a select
    449462  statement, but maybe also an "insert/update ... returning" statement), this
    450   method returns a `pgqueryobject` that can be accessed via the `getresult()`
    451   or `dictresult()` method or simply printed. Otherwise, it returns `None`.
     463  method returns a `pgqueryobject` that can be accessed via the `getresult()`,
     464  `dictresult()` or `namedresult()` methods or simply printed. Otherwise, it
     465  returns `None`.
    452466
    453467  The query may optionally contain positional parameters of the form `$1`,
     
    11591173
    11601174Exceptions raised:
    1161   :TypeError: too many parameters
     1175  :TypeError: too many (any) parameters
    11621176  :MemoryError: internal memory error
    11631177
     
    11801194
    11811195Exceptions raised:
    1182   :TypeError: too many parameters
     1196  :TypeError: too many (any) parameters
    11831197  :MemoryError: internal memory error
    11841198
     
    11881202  used as the dictionary index.
    11891203
     1204namedresult - get query values as list of named tuples
     1205------------------------------------------------------
     1206Syntax::
     1207
     1208  namedresult()
     1209
     1210Parameters:
     1211  None
     1212
     1213Return type:
     1214  :list: result values as a list of named tuples
     1215
     1216Exceptions raised:
     1217  :TypeError: too many (any) parameters
     1218  :TypeError: named tuples not supported
     1219  :MemoryError: internal memory error
     1220
     1221Description:
     1222  This method returns the list of the values returned by the query
     1223  with each row returned as a named tuple with proper field names.
    11901224
    11911225listfields - lists fields names of previous query result
  • trunk/module/pg.py

    r446 r447  
    1313This pg module implements some basic database management stuff.
    1414It includes the _pg module and builds on it, providing the higher
    15 level wrapper class named DB with addtional functionality.
     15level wrapper class named DB with additional functionality.
    1616This is known as the "classic" ("old style") PyGreSQL interface.
    1717For a DB-API 2 compliant interface use the newer pgdb module.
     
    2727    from decimal import Decimal
    2828    set_decimal(Decimal)
    29 except ImportError:
    30     pass  # Python < 2.4
     29except ImportError:  # Python < 2.4
     30    pass
     31try:
     32    from collections import namedtuple
     33except ImportError:  # Python < 2.6
     34    namedtuple = None
    3135
    3236
     
    97101
    98102
     103if namedtuple:
     104
     105    def _namedresult(q):
     106        """Get query result as named tuples."""
     107        row = namedtuple('Row', q.listfields())
     108        return [row(*r) for r in q.getresult()]
     109
     110    set_namedresult(_namedresult)
     111
     112
    99113def _db_error(msg, cls=DatabaseError):
    100114    """Returns DatabaseError with empty sqlstate attribute."""
  • trunk/module/pgmodule.c

    r446 r447  
    117117int *get_type_array(PGresult *result, int nfields);
    118118
    119 static PyObject *decimal = NULL; /* decimal type */
     119static PyObject *decimal = NULL, /* decimal type */
     120                                *namedresult = NULL; /* function for getting named results */
     121
    120122
    121123/* --------------------------------------------------------------------- */
     
    20932095static char pgquery_getresult__doc__[] =
    20942096"getresult() -- Gets the result of a query.  The result is returned "
    2095 "as a list of rows, each one a list of fields in the order returned "
     2097"as a list of rows, each one a tuple of fields in the order returned "
    20962098"by the server.";
    20972099
     
    22372239        {
    22382240                PyErr_SetString(PyExc_TypeError,
    2239                         "method getresult() takes no parameters.");
     2241                        "method dictresult() takes no parameters.");
    22402242                return NULL;
    22412243        }
     
    23392341        /* returns list */
    23402342        return reslist;
     2343}
     2344
     2345/* retrieves last result as named tuples */
     2346static char pgquery_namedresult__doc__[] =
     2347"namedresult() -- Gets the result of a query.  The result is returned "
     2348"as a list of rows, each one a tuple of fields in the order returned "
     2349"by the server.";
     2350
     2351static PyObject *
     2352pgquery_namedresult(pgqueryobject *self, PyObject *args)
     2353{
     2354        PyObject   *arglist,
     2355                           *ret;
     2356
     2357        /* checks args (args == NULL for an internal call) */
     2358        if (args && !PyArg_ParseTuple(args, ""))
     2359        {
     2360                PyErr_SetString(PyExc_TypeError,
     2361                        "method namedresult() takes no parameters.");
     2362                return NULL;
     2363        }
     2364
     2365        if (!namedresult)
     2366        {
     2367                PyErr_SetString(PyExc_TypeError,
     2368                        "named tuples are not supported.");
     2369                return NULL;
     2370        }
     2371
     2372        arglist = Py_BuildValue("(O)", self);
     2373        ret = PyObject_CallObject(namedresult, arglist);
     2374        Py_DECREF(arglist);
     2375
     2376        if (ret == NULL)
     2377            return NULL;
     2378
     2379        return ret;
    23412380}
    23422381
     
    34943533        {"dictresult", (PyCFunction) pgquery_dictresult, METH_VARARGS,
    34953534                        pgquery_dictresult__doc__},
     3535        {"namedresult", (PyCFunction) pgquery_namedresult, METH_VARARGS,
     3536                        pgquery_namedresult__doc__},
    34963537        {"fieldname", (PyCFunction) pgquery_fieldname, METH_VARARGS,
    34973538                         pgquery_fieldname__doc__},
     
    36423683}
    36433684
     3685/* set named result */
     3686static char set_namedresult__doc__[] =
     3687"set_namedresult(cls) -- set a function to be used for getting named results.";
     3688
     3689static PyObject *
     3690set_namedresult(PyObject *self, PyObject *args)
     3691{
     3692    PyObject *ret = NULL;
     3693    PyObject *func;
     3694
     3695    if (PyArg_ParseTuple(args, "O", &func))
     3696    {
     3697        if (PyCallable_Check(func)) {
     3698            Py_XINCREF(func); Py_XDECREF(namedresult); namedresult = func;
     3699            Py_INCREF(Py_None); ret = Py_None;
     3700        }
     3701        else
     3702            PyErr_SetString(PyExc_TypeError, "parameter must be callable");
     3703    }
     3704    return ret;
     3705}
     3706
    36443707#ifdef DEFAULT_VARS
    36453708
     
    39994062        {"set_decimal", (PyCFunction) set_decimal, METH_VARARGS,
    40004063                        set_decimal__doc__},
     4064        {"set_namedresult", (PyCFunction) set_namedresult, METH_VARARGS,
     4065                        set_namedresult__doc__},
    40014066
    40024067#ifdef DEFAULT_VARS
  • trunk/module/test_pg.py

    r446 r447  
    5353except ImportError:  # Python < 2.4
    5454    Decimal = float
     55try:
     56    from collections import namedtuple
     57except ImportError:  # Python < 2.6
     58    namedtuple = None
    5559
    5660
     
    486490        self.assertEqual(r, result)
    487491
     492    def testNamedresult(self):
     493        if namedtuple:
     494            q = "select 0 as alias0"
     495            result = [(0,)]
     496            r = self.c.query(q).namedresult()
     497            self.assertEqual(r, result)
     498            v = r[0]
     499            self.assertEqual(v._fields, ('alias0',))
     500            self.assertEqual(v.alias0, 0)
     501
    488502    def testGet3Cols(self):
    489503        q = "select 1,2,3"
     
    497511        r = self.c.query(q).dictresult()
    498512        self.assertEqual(r, result)
     513
     514    def testGet3NamedCols(self):
     515        if namedtuple:
     516            q = "select 1 as a,2 as b,3 as c"
     517            result = [(1, 2, 3)]
     518            r = self.c.query(q).namedresult()
     519            self.assertEqual(r, result)
     520            v = r[0]
     521            self.assertEqual(v._fields, ('a', 'b', 'c'))
     522            self.assertEqual(v.b, 2)
    499523
    500524    def testGet3Rows(self):
     
    510534        r = self.c.query(q).dictresult()
    511535        self.assertEqual(r, result)
     536
     537    def testGet3NamedRows(self):
     538        if namedtuple:
     539            q = "select 3 as alias3" \
     540                " union select 1 union select 2 order by 1"
     541            result = [(1,), (2,), (3,)]
     542            r = self.c.query(q).namedresult()
     543            self.assertEqual(r, result)
     544            for v in r:
     545                self.assertEqual(v._fields, ('alias3',))
    512546
    513547    def testDictresultNames(self):
     
    520554        r = self.c.query(q).dictresult()
    521555        self.assertEqual(r, result)
     556
     557    def testNamedresultNames(self):
     558        if namedtuple:
     559            q = "select 'MixedCase' as MixedCaseAlias"
     560            result = [('MixedCase',)]
     561            r = self.c.query(q).namedresult()
     562            self.assertEqual(r, result)
     563            v = r[0]
     564            self.assertEqual(v._fields, ('mixedcasealias',))
     565            self.assertEqual(v.mixedcasealias, 'MixedCase')
     566            q = "select 'MixedCase' as \"MixedCaseAlias\""
     567            r = self.c.query(q).namedresult()
     568            self.assertEqual(r, result)
     569            v = r[0]
     570            self.assertEqual(v._fields, ('MixedCaseAlias',))
     571            self.assertEqual(v.MixedCaseAlias, 'MixedCase')
    522572
    523573    def testBigGetresult(self):
Note: See TracChangeset for help on using the changeset viewer.