Changeset 980 for trunk


Ignore:
Timestamp:
Apr 22, 2019, 10:44:58 AM (5 months ago)
Author:
cito
Message:

Query methods for getting single rows and columns

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/docs/contents/changelog.rst

    r978 r980  
    44Version 5.1 (2019-mm-dd)
    55------------------------
    6 - Support for prepared statements has been added to the classic API.
    7 - DB wrapper objects based on existing connections can now be closed and
    8   reopened properly (but the underlying connection will not be affected).
    9 - The query objects in the classic API can now be used as iterators
    10   and will then yield the rows as tuples, similar to query.getresult().
    11   Thanks to Justin Pryzby for the proposal and most of the implementation.
    12 - Added methods query.dictiter() and query.namediter() to the classic API
    13   which work like query.dictresult() and query.namedresult() except that
    14   they return iterators instead of lists.
    15 - Deprecated query.ntuples() in the classic API, since len(query) can now
    16   be used and returns the same number.
    17 - Added pg.get/set_namediter and deprecated pg.get/set_namedresult.
     6- Changes in the classic PyGreSQL module (pg):
     7    - Support for prepared statements.
     8    - DB wrapper objects based on existing connections can now be closed and
     9      reopened properly (but the underlying connection will not be affected).
     10    - The query object can now be used as iterator and will then yield the
     11      rows as tuples, similar to query.getresult().
     12      Thanks to Justin Pryzby for the proposal and most of the implementation.
     13    - Deprecated query.ntuples() in the classic API, since len(query) can now
     14      be used and returns the same number.
     15    - The i-th row from the result can now be accessed as the `query[i]`.
     16    - New method query.scalarresult() that gets only the first field of each
     17      row as a list of scalar values.
     18    - New methods query.one(), query.onenamed(), query.onedict() and
     19      query.onescalar() that fetch only one row from the result or None if
     20      there is no more row, similar to cursor.fetchone() method in DB-API 2.
     21    - New methods query.single(), query.singlenamed(), query.singledict() and
     22      query.singlescalar() that fetch only one row from the result, and raise
     23      an error when the result does not have exactly one row.
     24    - New methods query.dictiter(), query.namediter() and query.scalariter()
     25      returning the same values as query.dictresult(), query.namedresult()
     26      and query.salarresult(), but as iterables instead of lists. This avoids
     27      creating a Python list of all results and can be slightly more efficient.
     28    - Removed pg.get/set_namedresult. You can configure the named tuples
     29      factory with the pg.set_row_factory_size() function and change the
     30      implementation with pg.set_query_helps(), but this is not recommended
     31      and this function is not part of the official API.
    1832
    1933Vesion 5.0.7 (2019-mm-dd)
  • trunk/docs/contents/pg/module.rst

    r978 r980  
    309309which does exactly the same.
    310310
    311 get/set_namediter -- conversion to named tuples
    312 -----------------------------------------------
    313 
    314 .. function:: get_namediter()
    315 
    316     Get the generator that converts to named tuples
    317 
    318 This returns the function used by PyGreSQL to construct the result of the
    319 :meth:`Query.namediter` and :meth:`Query.namedresult` methods.
    320 
    321 .. versionadded:: 5.1
    322 
    323 .. function:: set_namediter(func)
    324 
    325     Set a generator that will convert to named tuples
    326 
    327     :param func: the generator to be used to convert results to named tuples
    328 
    329 You can use this if you want to create different kinds of named tuples
    330 returned by the :meth:`Query.namediter` and :meth:`Query.namedresult` methods.
    331 If you set this function to *None*, then normal tuples will be used.
    332 
    333 .. versionadded:: 5.1
    334 
    335 get/set_namedresult -- conversion to named tuples
    336 -------------------------------------------------
    337 
    338 .. function:: get_namedresult()
    339 
    340     Get the generator that converts to named tuples
    341 
    342 .. deprecated:: 5.1
    343    Use :func:`get_namediter` instead.
    344 
    345 .. function:: set_namedresult(func)
    346 
    347     Set a generator that will convert to named tuples
    348 
    349     :param func: the generator to be used to convert results to named tuples
    350 
    351 .. deprecated:: 5.1
    352    Use :func:`set_namediter` instead.
    353 
    354311get/set_decimal -- decimal type to be used for numeric values
    355312-------------------------------------------------------------
  • trunk/docs/contents/pg/query.rst

    r978 r980  
    77
    88The :class:`Query` object returned by :meth:`Connection.query` and
    9 :meth:`DB.query` can be used as an iterator returning rows as tuples.
     9:meth:`DB.query` can be used as an iterable returning rows as tuples.
    1010You can also directly access row tuples using their index, and get
    11 the number of rows with the :func:`len` function. The :class:`Query`
    12 class also provides the following methods for accessing the results
    13 of the query:
     11the number of rows with the :func:`len` function.
     12The :class:`Query` class also provides the following methods for accessing
     13the results of the query:
    1414
    1515getresult -- get query values as list of tuples
     
    3636an iterable sequence, i.e. you can iterate over the :class:`Query`
    3737object to get the same tuples as returned by :meth:`Query.getresult`.
     38This is slightly more efficient than getting the full list of results,
     39but note that the full result is always fetched from the server anyway
     40when the query is executed.
     41
    3842You can also call :func:`len` on a query to find the number of rows
    3943in the result, and access row tuples using their index directly on
    4044the :class:`Query` object.
    4145
    42 dictresult -- get query values as list of dictionaries
    43 ------------------------------------------------------
     46dictresult/dictiter -- get query values as dictionaries
     47-------------------------------------------------------
    4448
    4549.. method:: Query.dictresult()
     
    6165type columns as Python lists.
    6266
    63 namedresult -- get query values as list of named tuples
    64 -------------------------------------------------------
     67.. method:: Query.dictiter()
     68
     69    Get query values as iterable of dictionaries
     70
     71    :returns: result values as an iterable of dictionaries
     72    :rtype: iterable
     73    :raises TypeError: too many (any) parameters
     74    :raises MemoryError: internal memory error
     75
     76This method returns query results as an iterable of dictionaries which have
     77the field names as keys. This is slightly more efficient than getting the full
     78list of results as dictionaries, but note that the full result is always
     79fetched from the server anyway when the query is executed.
     80
     81If the query has duplicate field names, you will get the value for the
     82field with the highest index in the query.
     83
     84.. versionadded:: 5.1
     85
     86namedresult/namediter -- get query values a named tuples
     87--------------------------------------------------------
    6588
    6689.. method:: Query.namedresult()
     
    86109.. versionadded:: 4.1
    87110
    88 dictiter -- get query values as iterator of dictionaries
    89 --------------------------------------------------------
    90 
    91 .. method:: Query.dictiter()
    92 
    93     Get query values as iterator of dictionaries
    94 
    95     :returns: result values as an iterator of dictionaries
    96     :rtype: iterator
    97     :raises TypeError: too many (any) parameters
    98     :raises MemoryError: internal memory error
    99 
    100 This method returns query results as an iterator of dictionaries which have
    101 the field names as keys.
    102 
    103 If the query has duplicate field names, you will get the value for the
    104 field with the highest index in the query.
    105 
    106 .. versionadded:: 5.1
    107 
    108 namediter -- get query values as iterator of named tuples
    109 ---------------------------------------------------------
    110 
    111111.. method:: Query.namediter()
    112112
    113     Get query values as iterator of named tuples
    114 
    115     :returns: result values as an iterator of named tuples
    116     :rtype: iterator
     113    Get query values as iterable of named tuples
     114
     115    :returns: result values as an iterable of named tuples
     116    :rtype: iterable
    117117    :raises TypeError: too many (any) parameters
    118118    :raises TypeError: named tuples not supported
    119119    :raises MemoryError: internal memory error
    120120
    121 This method returns query results as an iterator of named tuples with
    122 proper field names.
     121This method returns query results as an iterable of named tuples with
     122proper field names. This is slightly more efficient than getting the full
     123list of results as named tuples, but note that the full result is always
     124fetched from the server anyway when the query is executed.
    123125
    124126Column names in the database that are not valid as field names for
     
    128130.. versionadded:: 5.1
    129131
     132scalarresult/scalariter -- get query values as scalars
     133------------------------------------------------------
     134
     135.. method:: Query.scalarresult()
     136
     137    Get first fields from query result as list of scalar values
     138
     139    :returns: first fields from result as a list of scalar values
     140    :rtype: list
     141    :raises TypeError: too many (any) parameters
     142    :raises MemoryError: internal memory error
     143
     144This method returns the first fields from the query results as a list of
     145scalar values in the order returned by the server.
     146
     147.. versionadded:: 5.1
     148
     149.. method:: Query.scalariter()
     150
     151    Get first fields from query result as iterable of scalar values
     152
     153    :returns: first fields from result as an iterable of scalar values
     154    :rtype: list
     155    :raises TypeError: too many (any) parameters
     156    :raises MemoryError: internal memory error
     157
     158This method returns the first fields from the query results as an iterable
     159of scalar values in the order returned by the server. This is slightly more
     160efficient than getting the full list of results as rows or scalar values,
     161but note that the full result is always fetched from the server anyway when
     162the query is executed.
     163
     164.. versionadded:: 5.1
     165
     166one/onedict/onenamed/onescalar -- get one result of a query
     167-----------------------------------------------------------
     168
     169.. method:: Query.one()
     170
     171    Get one row from the result of a query as a tuple
     172
     173    :returns: next row from the query results as a tuple of fields
     174    :rtype: tuple or None
     175    :raises TypeError: too many (any) parameters
     176    :raises MemoryError: internal memory error
     177
     178Returns only one row from the result as a tuple of fields.
     179
     180This method can be called multiple times to return more rows.
     181It returns None if the result does not contain one more row.
     182
     183.. versionadded:: 5.1
     184
     185.. method:: Query.onedict()
     186
     187    Get one row from the result of a query as a dictionary
     188
     189    :returns: next row from the query results as a dictionary
     190    :rtype: dict or None
     191    :raises TypeError: too many (any) parameters
     192    :raises MemoryError: internal memory error
     193
     194Returns only one row from the result as a dictionary with the field names
     195used as the keys.
     196
     197This method can be called multiple times to return more rows.
     198It returns None if the result does not contain one more row.
     199
     200.. versionadded:: 5.1
     201
     202.. method:: Query.onenamed()
     203
     204    Get one row from the result of a query as named tuple
     205
     206    :returns: next row from the query results as a named tuple
     207    :rtype: named tuple or None
     208    :raises TypeError: too many (any) parameters
     209    :raises MemoryError: internal memory error
     210
     211Returns only one row from the result as a named tuple with proper field names.
     212
     213Column names in the database that are not valid as field names for
     214named tuples (particularly, names starting with an underscore) are
     215automatically renamed to valid positional names.
     216
     217This method can be called multiple times to return more rows.
     218It returns None if the result does not contain one more row.
     219
     220.. versionadded:: 5.1
     221
     222.. method:: Query.onescalar()
     223
     224    Get one row from the result of a query as scalar value
     225
     226    :returns: next row from the query results as a scalar value
     227    :rtype: type of first field or None
     228    :raises TypeError: too many (any) parameters
     229    :raises MemoryError: internal memory error
     230
     231Returns the first field of the next row from the result as a scalar value.
     232
     233This method can be called multiple times to return more rows as scalars.
     234It returns None if the result does not contain one more row.
     235
     236.. versionadded:: 5.1
     237
     238single/singledict/singlenamed/singlescalar -- get single result of a query
     239--------------------------------------------------------------------------
     240
     241.. method:: Query.single()
     242
     243    Get single row from the result of a query as a tuple
     244
     245    :returns: single row from the query results as a tuple of fields
     246    :rtype: tuple
     247        :raises ProgrammingError: result does not have exactly one row
     248    :raises TypeError: too many (any) parameters
     249    :raises MemoryError: internal memory error
     250
     251Returns a single row from the result as a tuple of fields.
     252
     253This method returns the same single row when called multiple times.
     254It raises a ProgrammingError if the result does not have exactly one row.
     255
     256.. versionadded:: 5.1
     257
     258.. method:: Query.singledict()
     259
     260    Get single row from the result of a query as a dictionary
     261
     262    :returns: single row from the query results as a dictionary
     263    :rtype: dict
     264        :raises ProgrammingError: result does not have exactly one row
     265    :raises TypeError: too many (any) parameters
     266    :raises MemoryError: internal memory error
     267
     268Returns a single row from the result as a dictionary with the field names
     269used as the keys.
     270
     271This method returns the same single row when called multiple times.
     272It raises a ProgrammingError if the result does not have exactly one row.
     273
     274.. versionadded:: 5.1
     275
     276.. method:: Query.singlenamed()
     277
     278    Get single row from the result of a query as named tuple
     279
     280    :returns: single row from the query results as a named tuple
     281    :rtype: named tuple
     282        :raises ProgrammingError: result does not have exactly one row
     283    :raises TypeError: too many (any) parameters
     284    :raises MemoryError: internal memory error
     285
     286Returns single row from the result as a named tuple with proper field names.
     287
     288Column names in the database that are not valid as field names for
     289named tuples (particularly, names starting with an underscore) are
     290automatically renamed to valid positional names.
     291
     292This method returns the same single row when called multiple times.
     293It raises a ProgrammingError if the result does not have exactly one row.
     294
     295.. versionadded:: 5.1
     296
     297.. method:: Query.singlescalar()
     298
     299    Get single row from the result of a query as scalar value
     300
     301    :returns: single row from the query results as a scalar value
     302    :rtype: type of first field
     303        :raises ProgrammingError: result does not have exactly one row
     304    :raises TypeError: too many (any) parameters
     305    :raises MemoryError: internal memory error
     306
     307Returns the first field of a single row from the result as a scalar value.
     308
     309This method returns the same single row as scalar when called multiple times.
     310It raises a ProgrammingError if the result does not have exactly one row.
     311
     312.. versionadded:: 5.1
    130313
    131314listfields -- list fields names of previous query result
  • trunk/docs/contents/tutorial.rst

    r978 r980  
    108108
    109109In PyGreSQL 5.1 and newer, you can also use the :class:`Query` instance
    110 directly as an iterator that yields the rows as tuples, and you can use
    111 the methods :meth:`Query.dictiter` or :meth:`Query.namediter` to get
    112 iterators yielding the rows as dictionaries or named tuples.
     110directly as an iterable that yields the rows as tuples, and there are also
     111methods that return iterables for rows as dictionaries, named tuples or
     112scalar values. Other methods like :meth:`Query.one` or :meth:`Query.onescalar`
     113return only one row or only the first field of that row. You can get the
     114number of rows with the :func:`len` function.
    113115
    114116Using the method :meth:`DB.get_as_dict`, you can easily import the whole table
  • trunk/pg.py

    r978 r980  
    13121312
    13131313
     1314# Helper functions used by the query object
     1315
    13141316def _dictiter(q):
    13151317    """Get query result as an iterator of dictionaries."""
     
    13261328
    13271329
     1330def _namednext(q):
     1331    """Get next row from query result as a named tuple."""
     1332    return _row_factory(q.listfields())(next(q))
     1333
     1334
     1335def _scalariter(q):
     1336    """Get query result as an iterator of scalar values."""
     1337    for r in q:
     1338        yield r[0]
     1339
     1340
    13281341class _MemoryQuery:
    13291342    """Class that embodies a given query result."""
     
    13651378# Initialize the C module
    13661379
    1367 set_dictiter(_dictiter)
    1368 set_namediter(_namediter)
    13691380set_decimal(Decimal)
    13701381set_jsondecode(jsondecode)
     1382set_query_helpers(_dictiter, _namediter, _namednext, _scalariter)
    13711383
    13721384
     
    26792691        rows = map(getrow, res)
    26802692        if keytuple or rowtuple:
    2681             namedresult = get_namedresult()
    2682             if namedresult:
    2683                 if keytuple:
    2684                     keys = namedresult(_MemoryQuery(keys, keyname))
    2685                 if rowtuple:
    2686                     fields = [f for f in fields if f not in keyset]
    2687                     rows = namedresult(_MemoryQuery(rows, fields))
     2693            if keytuple:
     2694                keys = _namediter(_MemoryQuery(keys, keyname))
     2695            if rowtuple:
     2696                fields = [f for f in fields if f not in keyset]
     2697                rows = _namediter(_MemoryQuery(rows, fields))
    26882698        return cls(zip(keys, rows))
    26892699
  • trunk/pgmodule.c

    r978 r980  
    9292                                *dictiter = NULL, /* function for getting named results */
    9393                                *namediter = NULL, /* function for getting named results */
     94                                *namednext = NULL, /* function for getting one named result */
     95                                *scalariter = NULL, /* function for getting scalar results */
    9496                                *jsondecode = NULL; /* function for decoding json strings */
    9597static const char *date_format = NULL; /* date format that is always assumed */
     
    48314833        row_tuple = queryGetRowAsTuple(self);
    48324834        if (row_tuple) ++self->current_row;
    4833     return row_tuple;
     4835        return row_tuple;
     4836}
     4837
     4838/* Retrieves one row from the result as a tuple. */
     4839static char queryOne__doc__[] =
     4840"one() -- Get one row from the result of a query\n\n"
     4841"Only one row from the result is returned as a tuple of fields.\n"
     4842"This method can be called multiple times to return more rows.\n"
     4843"It returns None if the result does not contain one more row.\n";
     4844
     4845static PyObject *
     4846queryOne(queryObject *self, PyObject *noargs)
     4847{
     4848        PyObject *row_tuple;
     4849
     4850        if (self->current_row >= self->max_row) {
     4851                Py_INCREF(Py_None); return Py_None;
     4852        }
     4853
     4854        row_tuple = queryGetRowAsTuple(self);
     4855        if (row_tuple) ++self->current_row;
     4856        return row_tuple;
     4857}
     4858
     4859/* Retrieves the single row from the result as a tuple. */
     4860static char querySingle__doc__[] =
     4861"single() -- Get the result of a query as single row\n\n"
     4862"The single row from the query result is returned as a tuple of fields.\n"
     4863"This method returns the same single row when called multiple times.\n"
     4864"It raises a ProgrammingError if the result does not have exactly one row.\n";
     4865
     4866static PyObject *
     4867querySingle(queryObject *self, PyObject *noargs)
     4868{
     4869        PyObject *row_tuple;
     4870
     4871        if (self->max_row != 1) {
     4872                set_error_msg(ProgrammingError,
     4873                        self->max_row ? "Multiple results found" : "No result found");
     4874                return NULL;
     4875        }
     4876
     4877        self->current_row = 0;
     4878        row_tuple = queryGetRowAsTuple(self);
     4879        if (row_tuple) ++self->current_row;
     4880        return row_tuple;
    48344881}
    48354882
     
    49004947}
    49014948
     4949/* Retrieve one row from the result as a dictionary. */
     4950static char queryOnedict__doc__[] =
     4951"onedict() -- Get one row from the result of a query\n\n"
     4952"Only one row from the result is returned as a dictionary with\n"
     4953"the field names used as the keys.\n"
     4954"This method can be called multiple times to return more rows.\n"
     4955"It returns None if the result does not contain one more row.\n";
     4956
     4957static PyObject *
     4958queryOnedict(queryObject *self, PyObject *noargs)
     4959{
     4960        PyObject *row_dict;
     4961
     4962        if (self->current_row >= self->max_row) {
     4963                Py_INCREF(Py_None); return Py_None;
     4964        }
     4965
     4966        row_dict = queryGetRowAsDict(self);
     4967        if (row_dict) ++self->current_row;
     4968        return row_dict;
     4969}
     4970
     4971/* Retrieve the single row from the result as a dictionary. */
     4972static char querySingledict__doc__[] =
     4973"singledict() -- Get the result of a query as single row\n\n"
     4974"The single row from the query result is returned as a dictionary with\n"
     4975"the field names used as the keys.\n"
     4976"This method returns the same single row when called multiple times.\n"
     4977"It raises a ProgrammingError if the result does not have exactly one row.\n";
     4978
     4979static PyObject *
     4980querySingledict(queryObject *self, PyObject *noargs)
     4981{
     4982        PyObject *row_dict;
     4983
     4984        if (self->max_row != 1) {
     4985                set_error_msg(ProgrammingError,
     4986                        self->max_row ? "Multiple results found" : "No result found");
     4987                return NULL;
     4988        }
     4989
     4990        self->current_row = 0;
     4991        row_dict = queryGetRowAsDict(self);
     4992        if (row_dict) ++self->current_row;
     4993        return row_dict;
     4994}
     4995
    49024996/* Retrieve the last query result as a list of dictionaries. */
    49034997static char queryDictresult__doc__[] =
     
    49275021}
    49285022
    4929 /* retrieves last result as iterator of dictionaries */
     5023/* Retrieve last result as iterator of dictionaries. */
    49305024static char queryDictiter__doc__[] =
    49315025"dictiter() -- Get the result of a query\n\n"
     
    49365030queryDictiter(queryObject *self, PyObject *noargs)
    49375031{
    4938         if (dictiter) {
    4939                 return PyObject_CallFunction(dictiter, "(O)", self);
    4940         }
    4941         return queryGetIter(self);
    4942 }
    4943 
    4944 
    4945 /* retrieves last result as list of named tuples */
     5032        if (!dictiter)
     5033                return queryDictresult(self, noargs);
     5034
     5035        return PyObject_CallFunction(dictiter, "(O)", self);
     5036}
     5037
     5038/* Retrieve one row from the result as a named tuple. */
     5039static char queryOnenamed__doc__[] =
     5040"onenamed() -- Get one row from the result of a query\n\n"
     5041"Only one row from the result is returned as a named tuple of fields.\n"
     5042"This method can be called multiple times to return more rows.\n"
     5043"It returns None if the result does not contain one more row.\n";
     5044
     5045static PyObject *
     5046queryOnenamed(queryObject *self, PyObject *noargs)
     5047{
     5048        if (!namednext)
     5049                return queryOne(self, noargs);
     5050
     5051        if (self->current_row >= self->max_row) {
     5052                Py_INCREF(Py_None); return Py_None;
     5053        }
     5054
     5055        return PyObject_CallFunction(namednext, "(O)", self);
     5056}
     5057
     5058/* Retrieve the single row from the result as a tuple. */
     5059static char querySinglenamed__doc__[] =
     5060"singlenamed() -- Get the result of a query as single row\n\n"
     5061"The single row from the query result is returned as a named tuple of fields.\n"
     5062"This method returns the same single row when called multiple times.\n"
     5063"It raises a ProgrammingError if the result does not have exactly one row.\n";
     5064
     5065static PyObject *
     5066querySinglenamed(queryObject *self, PyObject *noargs)
     5067{
     5068        if (!namednext)
     5069                return querySingle(self, noargs);
     5070
     5071        if (self->max_row != 1) {
     5072                set_error_msg(ProgrammingError,
     5073                        self->max_row ? "Multiple results found" : "No result found");
     5074                return NULL;
     5075        }
     5076
     5077        self->current_row = 0;
     5078        return PyObject_CallFunction(namednext, "(O)", self);
     5079}
     5080
     5081/* Retrieve last result as list of named tuples. */
    49465082static char queryNamedresult__doc__[] =
    49475083"namedresult() -- Get the result of a query\n\n"
     
    49525088queryNamedresult(queryObject *self, PyObject *noargs)
    49535089{
    4954         if (namediter) {
    4955                 PyObject* res = PyObject_CallFunction(namediter, "(O)", self);
    4956                 if (res && PyList_Check(res))
    4957                         return res;
    4958                 PyObject *res_list = PySequence_List(res);
    4959                 Py_DECREF(res);
    4960                 return res_list;
    4961         }
    4962         return queryGetresult(self, noargs);
    4963 }
    4964 
    4965 /* retrieves last result as iterator of named tuples */
     5090        PyObject   *res, *res_list;
     5091
     5092        if (!namediter)
     5093                return queryGetresult(self, noargs);
     5094
     5095        res = PyObject_CallFunction(namediter, "(O)", self);
     5096        if (!res) return NULL;
     5097        if (PyList_Check(res)) return res;
     5098        res_list = PySequence_List(res);
     5099        Py_DECREF(res);
     5100        return res_list;
     5101}
     5102
     5103/* Retrieve last result as iterator of named tuples. */
    49665104static char queryNamediter__doc__[] =
    49675105"namediter() -- Get the result of a query\n\n"
     
    49725110queryNamediter(queryObject *self, PyObject *noargs)
    49735111{
    4974         if (namediter) {
    4975                 PyObject* res = PyObject_CallFunction(namediter, "(O)", self);
    4976                 if (res && !PyList_Check(res))
    4977                         return res;
    4978                 PyObject* res_iter = (Py_TYPE(res)->tp_iter)((PyObject *)self);
    4979                 Py_DECREF(res);
    4980                 return res_iter;
    4981         }
    4982         return queryGetIter(self);
     5112        PyObject   *res, *res_iter;
     5113
     5114        if (!namediter)
     5115                return queryGetIter(self);
     5116
     5117        res = PyObject_CallFunction(namediter, "(O)", self);
     5118        if (!res) return NULL;
     5119        if (!PyList_Check(res)) return res;
     5120        res_iter = (Py_TYPE(res)->tp_iter)((PyObject *)self);
     5121        Py_DECREF(res);
     5122        return res_iter;
     5123}
     5124
     5125/* Retrieve the last query result as a list of scalar values. */
     5126static char queryScalarresult__doc__[] =
     5127"scalarresult() -- Get query result as scalars\n\n"
     5128"The result is returned as a list of scalar values where the values\n"
     5129"are the first fields of the rows in the order returned by the server.\n";
     5130
     5131static PyObject *
     5132queryScalarresult(queryObject *self, PyObject *noargs)
     5133{
     5134        PyObject   *result_list;
     5135
     5136        if (!self->num_fields) {
     5137                set_error_msg(ProgrammingError, "No fields in result");
     5138                return NULL;
     5139        }
     5140
     5141        if (!(result_list = PyList_New(self->max_row))) return NULL;
     5142
     5143        for (self->current_row = 0; self->current_row < self->max_row;
     5144                ++self->current_row)
     5145        {
     5146                PyObject   *value = getValueInColumn(self, 0);
     5147                if (!value)
     5148                {
     5149                        Py_DECREF(result_list); return NULL;
     5150                }
     5151                PyList_SET_ITEM(result_list, self->current_row, value);
     5152        }
     5153
     5154        return result_list;
     5155}
     5156
     5157/* Retrieve the last query result as iterator of scalar values. */
     5158static char queryScalariter__doc__[] =
     5159"scalariter() -- Get query result as scalars\n\n"
     5160"The result is returned as an iterator of scalar values where the values\n"
     5161"are the first fields of the rows in the order returned by the server.\n";
     5162
     5163static PyObject *
     5164queryScalariter(queryObject *self, PyObject *noargs)
     5165{
     5166        if (!scalariter)
     5167                return queryScalarresult(self, noargs);
     5168
     5169        if (!self->num_fields) {
     5170                set_error_msg(ProgrammingError, "No fields in result");
     5171                return NULL;
     5172        }
     5173
     5174        return PyObject_CallFunction(scalariter, "(O)", self);
     5175}
     5176
     5177/* Retrieve one result as scalar value. */
     5178static char queryOnescalar__doc__[] =
     5179"onescalar() -- Get one scalar value from the result of a query\n\n"
     5180"Returns the first field of the next row from the result as a scalar value.\n"
     5181"This method can be called multiple times to return more rows as scalars.\n"
     5182"It returns None if the result does not contain one more row.\n";
     5183
     5184static PyObject *
     5185queryOnescalar(queryObject *self, PyObject *noargs)
     5186{
     5187        PyObject *value;
     5188
     5189        if (!self->num_fields) {
     5190                set_error_msg(ProgrammingError, "No fields in result");
     5191                return NULL;
     5192        }
     5193
     5194        if (self->current_row >= self->max_row) {
     5195                Py_INCREF(Py_None); return Py_None;
     5196        }
     5197
     5198        value = getValueInColumn(self, 0);
     5199        if (value) ++self->current_row;
     5200        return value;
     5201}
     5202
     5203/* Retrieves the single row from the result as a tuple. */
     5204static char querySinglescalar__doc__[] =
     5205"singlescalar() -- Get scalar value from single result of a query\n\n"
     5206"Returns the first field of the next row from the result as a scalar value.\n"
     5207"This method returns the same single row when called multiple times.\n"
     5208"It raises a ProgrammingError if the result does not have exactly one row.\n";
     5209
     5210static PyObject *
     5211querySinglescalar(queryObject *self, PyObject *noargs)
     5212{
     5213        PyObject *value;
     5214
     5215        if (!self->num_fields) {
     5216                set_error_msg(ProgrammingError, "No fields in result");
     5217                return NULL;
     5218        }
     5219
     5220        if (self->max_row != 1) {
     5221                set_error_msg(ProgrammingError,
     5222                        self->max_row ? "Multiple results found" : "No result found");
     5223                return NULL;
     5224        }
     5225
     5226        self->current_row = 0;
     5227        value = getValueInColumn(self, 0);
     5228        if (value) ++self->current_row;
     5229        return value;
    49835230}
    49845231
     
    51455392        {"namediter", (PyCFunction) queryNamediter, METH_NOARGS,
    51465393                        queryNamediter__doc__},
     5394        {"one", (PyCFunction) queryOne, METH_NOARGS, queryOne__doc__},
     5395        {"single", (PyCFunction) querySingle, METH_NOARGS, querySingle__doc__},
     5396        {"onedict", (PyCFunction) queryOnedict, METH_NOARGS,
     5397                queryOnedict__doc__},
     5398        {"singledict", (PyCFunction) querySingledict, METH_NOARGS,
     5399                querySingledict__doc__},
     5400        {"onenamed", (PyCFunction) queryOnenamed, METH_NOARGS,
     5401                queryOnenamed__doc__},
     5402        {"singlenamed", (PyCFunction) querySinglenamed, METH_NOARGS,
     5403                querySinglenamed__doc__},
     5404        {"scalarresult", (PyCFunction) queryScalarresult, METH_NOARGS,
     5405                        queryScalarresult__doc__},
     5406        {"scalariter", (PyCFunction) queryScalariter, METH_NOARGS,
     5407                        queryScalariter__doc__},
     5408        {"onescalar", (PyCFunction) queryOnescalar, METH_NOARGS,
     5409                        queryOnescalar__doc__},
     5410        {"singlescalar", (PyCFunction) querySinglescalar, METH_NOARGS,
     5411                        querySinglescalar__doc__},
    51475412        {"fieldname", (PyCFunction) queryFieldname, METH_VARARGS,
    51485413                         queryFieldname__doc__},
     
    55995864}
    56005865
    5601 /* get dict result factory */
    5602 static char pgGetDictiter__doc__[] =
    5603 "get_dictiter() -- get the generator used for getting dict results";
    5604 
    5605 static PyObject *
    5606 pgGetDictiter(PyObject *self, PyObject *noargs)
    5607 {
    5608         PyObject *ret;
    5609 
    5610         ret = dictiter ? dictiter : Py_None;
    5611         Py_INCREF(ret);
    5612 
    5613         return ret;
    5614 }
    5615 
    5616 /* set dict result factory */
    5617 static char pgSetDictiter__doc__[] =
    5618 "set_dictiter(func) -- set a generator to be used for getting dict results";
    5619 
    5620 static PyObject *
    5621 pgSetDictiter(PyObject *self, PyObject *func)
    5622 {
    5623         PyObject *ret = NULL;
    5624 
    5625         if (func == Py_None)
    5626         {
    5627                 Py_XDECREF(dictiter); dictiter = NULL;
    5628                 Py_INCREF(Py_None); ret = Py_None;
    5629         }
    5630         else if (PyCallable_Check(func))
    5631         {
    5632                 Py_XINCREF(func); Py_XDECREF(dictiter); dictiter = func;
    5633                 Py_INCREF(Py_None); ret = Py_None;
    5634         }
    5635         else
    5636                 PyErr_SetString(PyExc_TypeError,
    5637                         "Function set_dictiter() expects"
    5638                          " a callable or None as argument");
    5639 
    5640         return ret;
    5641 }
    5642 
    5643 /* get named result factory */
    5644 static char pgGetNamediter__doc__[] =
    5645 "get_namediter() -- get the generator used for getting named results";
    5646 
    5647 static PyObject *
    5648 pgGetNamediter(PyObject *self, PyObject *noargs)
    5649 {
    5650         PyObject *ret;
    5651 
    5652         ret = namediter ? namediter : Py_None;
    5653         Py_INCREF(ret);
    5654 
    5655         return ret;
    5656 }
    5657 
    5658 /* set named result factory */
    5659 static char pgSetNamediter__doc__[] =
    5660 "set_namediter(func) -- set a generator to be used for getting named results";
    5661 
    5662 static PyObject *
    5663 pgSetNamediter(PyObject *self, PyObject *func)
    5664 {
    5665         PyObject *ret = NULL;
    5666 
    5667         if (func == Py_None)
    5668         {
    5669                 Py_XDECREF(namediter); namediter = NULL;
    5670                 Py_INCREF(Py_None); ret = Py_None;
    5671         }
    5672         else if (PyCallable_Check(func))
    5673         {
    5674                 Py_XINCREF(func); Py_XDECREF(namediter); namediter = func;
    5675                 Py_INCREF(Py_None); ret = Py_None;
    5676         }
    5677         else
    5678                 PyErr_SetString(PyExc_TypeError,
    5679                         "Function set_namediter() expects"
    5680                          " a callable or None as argument");
    5681 
    5682         return ret;
     5866/* set query helper functions */
     5867
     5868static char pgSetQueryHelpers__doc__[] =
     5869"set_query_helpers(*helpers) -- set internal query helper functions";
     5870
     5871static PyObject *
     5872pgSetQueryHelpers(PyObject *self, PyObject *args)
     5873{
     5874        /* gets arguments */
     5875        if (!PyArg_ParseTuple(args, "O!O!O!O!",
     5876                &PyFunction_Type, &dictiter,
     5877                &PyFunction_Type, &namediter,
     5878                &PyFunction_Type, &namednext,
     5879                &PyFunction_Type, &scalariter)) return NULL;
     5880
     5881        Py_INCREF(Py_None);
     5882        return Py_None;
    56835883}
    56845884
     
    61676367        {"get_array", (PyCFunction) pgGetArray, METH_NOARGS, pgGetArray__doc__},
    61686368        {"set_array", (PyCFunction) pgSetArray, METH_VARARGS, pgSetArray__doc__},
     6369        {"set_query_helpers", (PyCFunction) pgSetQueryHelpers, METH_VARARGS,
     6370                        pgSetQueryHelpers__doc__},
    61696371        {"get_bytea_escaped", (PyCFunction) pgGetByteaEscaped, METH_NOARGS,
    61706372                pgGetByteaEscaped__doc__},
    61716373        {"set_bytea_escaped", (PyCFunction) pgSetByteaEscaped, METH_VARARGS,
    61726374                pgSetByteaEscaped__doc__},
    6173         {"get_dictiter", (PyCFunction) pgGetDictiter, METH_NOARGS,
    6174                         pgGetDictiter__doc__},
    6175         {"set_dictiter", (PyCFunction) pgSetDictiter, METH_O,
    6176                         pgSetDictiter__doc__},
    6177         {"get_namediter", (PyCFunction) pgGetNamediter, METH_NOARGS,
    6178                         pgGetNamediter__doc__},
    6179         {"set_namediter", (PyCFunction) pgSetNamediter, METH_O,
    6180                         pgSetNamediter__doc__},
    6181         /* get/set_namedresult is deprecated, use get/set_namediter */
    6182         {"get_namedresult", (PyCFunction) pgGetNamediter, METH_NOARGS,
    6183                         pgGetNamediter__doc__},
    6184         {"set_namedresult", (PyCFunction) pgSetNamediter, METH_O,
    6185                         pgSetNamediter__doc__},
    61866375        {"get_jsondecode", (PyCFunction) pgGetJsondecode, METH_NOARGS,
    61876376                        pgGetJsondecode__doc__},
  • trunk/tests/test_classic_connection.py

    r978 r980  
    11671167        self.assertNotIn((5,), r)
    11681168
     1169    def testDictIterate(self):
     1170        r = self.c.query("select generate_series(3,5) as n").dictiter()
     1171        self.assertNotIsInstance(r, (list, tuple))
     1172        self.assertIsInstance(r, Iterable)
     1173        r = list(r)
     1174        self.assertEqual(r, [dict(n=3), dict(n=4), dict(n=5)])
     1175        self.assertIsInstance(r[1], dict)
     1176
     1177    def testDictIterateTwoColumns(self):
     1178        r = self.c.query("select 1 as one, 2 as two"
     1179            " union select 3 as one, 4 as two").dictiter()
     1180        self.assertIsInstance(r, Iterable)
     1181        r = list(r)
     1182        self.assertEqual(r, [dict(one=1, two=2), dict(one=3, two=4)])
     1183
     1184    def testDictNext(self):
     1185        r = self.c.query("select generate_series(7,9) as n").dictiter()
     1186        self.assertEqual(next(r), dict(n=7))
     1187        self.assertEqual(next(r), dict(n=8))
     1188        self.assertEqual(next(r), dict(n=9))
     1189        self.assertRaises(StopIteration, next, r)
     1190
     1191    def testDictContains(self):
     1192        r = self.c.query("select generate_series(7,9) as n").dictiter()
     1193        self.assertIn(dict(n=8), r)
     1194        self.assertNotIn(dict(n=5), r)
     1195
    11691196    def testNamedIterate(self):
    11701197        r = self.c.query("select generate_series(3,5) as number").namediter()
     
    12021229        self.assertNotIn((5,), r)
    12031230
    1204     def testDictIterate(self):
    1205         r = self.c.query("select generate_series(3,5) as n").dictiter()
     1231    def testScalarIterate(self):
     1232        r = self.c.query("select generate_series(3,5)").scalariter()
    12061233        self.assertNotIsInstance(r, (list, tuple))
    12071234        self.assertIsInstance(r, Iterable)
    12081235        r = list(r)
    1209         self.assertEqual(r, [dict(n=3), dict(n=4), dict(n=5)])
    1210         self.assertIsInstance(r[1], dict)
    1211 
    1212     def testDictIterateTwoColumns(self):
    1213         r = self.c.query("select 1 as one, 2 as two"
    1214             " union select 3 as one, 4 as two").dictiter()
     1236        self.assertEqual(r, [3, 4, 5])
     1237        self.assertIsInstance(r[1], int)
     1238
     1239    def testScalarIterateTwoColumns(self):
     1240        r = self.c.query("select 1, 2 union select 3, 4").scalariter()
    12151241        self.assertIsInstance(r, Iterable)
    12161242        r = list(r)
    1217         self.assertEqual(r, [dict(one=1, two=2), dict(one=3, two=4)])
    1218 
    1219     def testDictNext(self):
    1220         r = self.c.query("select generate_series(7,9) as n").dictiter()
    1221         self.assertEqual(next(r), dict(n=7))
    1222         self.assertEqual(next(r), dict(n=8))
    1223         self.assertEqual(next(r), dict(n=9))
     1243        self.assertEqual(r, [1, 3])
     1244
     1245    def testScalarNext(self):
     1246        r = self.c.query("select generate_series(7,9)").scalariter()
     1247        self.assertEqual(next(r), 7)
     1248        self.assertEqual(next(r), 8)
     1249        self.assertEqual(next(r), 9)
    12241250        self.assertRaises(StopIteration, next, r)
    12251251
    1226     def testNamedContains(self):
    1227         r = self.c.query("select generate_series(7,9) as n").dictiter()
    1228         self.assertIn(dict(n=8), r)
    1229         self.assertNotIn(dict(n=5), r)
     1252    def testScalarContains(self):
     1253        r = self.c.query("select generate_series(7,9)").scalariter()
     1254        self.assertIn(8, r)
     1255        self.assertNotIn(5, r)
     1256
     1257
     1258class TestQueryOneSingleScalar(unittest.TestCase):
     1259    """Test the query methods for getting single rows and columns."""
     1260
     1261    def setUp(self):
     1262        self.c = connect()
     1263
     1264    def tearDown(self):
     1265        self.c.close()
     1266
     1267    def testOneWithEmptyQuery(self):
     1268        q = self.c.query("select 0 where false")
     1269        self.assertIsNone(q.one())
     1270
     1271    def testOneWithSingleRow(self):
     1272        q = self.c.query("select 1, 2")
     1273        r = q.one()
     1274        self.assertIsInstance(r, tuple)
     1275        self.assertEqual(r, (1, 2))
     1276        self.assertEqual(q.one(), None)
     1277
     1278    def testOneWithTwoRows(self):
     1279        q = self.c.query("select 1, 2 union select 3, 4")
     1280        self.assertEqual(q.one(), (1, 2))
     1281        self.assertEqual(q.one(), (3, 4))
     1282        self.assertEqual(q.one(), None)
     1283
     1284    def testOneDictWithEmptyQuery(self):
     1285        q = self.c.query("select 0 where false")
     1286        self.assertIsNone(q.onedict())
     1287
     1288    def testOneDictWithSingleRow(self):
     1289        q = self.c.query("select 1 as one, 2 as two")
     1290        r = q.onedict()
     1291        self.assertIsInstance(r, dict)
     1292        self.assertEqual(r, dict(one=1, two=2))
     1293        self.assertEqual(q.onedict(), None)
     1294
     1295    def testOneDictWithTwoRows(self):
     1296        q = self.c.query(
     1297            "select 1 as one, 2 as two union select 3 as one, 4 as two")
     1298        self.assertEqual(q.onedict(), dict(one=1, two=2))
     1299        self.assertEqual(q.onedict(), dict(one=3, two=4))
     1300        self.assertEqual(q.onedict(), None)
     1301
     1302    def testOneNamedWithEmptyQuery(self):
     1303        q = self.c.query("select 0 where false")
     1304        self.assertIsNone(q.onenamed())
     1305
     1306    def testOneNamedWithSingleRow(self):
     1307        q = self.c.query("select 1 as one, 2 as two")
     1308        r = q.onenamed()
     1309        self.assertEqual(r._fields, ('one', 'two'))
     1310        self.assertEqual(r.one, 1)
     1311        self.assertEqual(r.two, 2)
     1312        self.assertEqual(r, (1, 2))
     1313        self.assertEqual(q.onenamed(), None)
     1314
     1315    def testOneNamedWithTwoRows(self):
     1316        q = self.c.query(
     1317            "select 1 as one, 2 as two union select 3 as one, 4 as two")
     1318        r = q.onenamed()
     1319        self.assertEqual(r._fields, ('one', 'two'))
     1320        self.assertEqual(r.one, 1)
     1321        self.assertEqual(r.two, 2)
     1322        self.assertEqual(r, (1, 2))
     1323        r = q.onenamed()
     1324        self.assertEqual(r._fields, ('one', 'two'))
     1325        self.assertEqual(r.one, 3)
     1326        self.assertEqual(r.two, 4)
     1327        self.assertEqual(r, (3, 4))
     1328        self.assertEqual(q.onenamed(), None)
     1329
     1330    def testOneScalarWithEmptyQuery(self):
     1331        q = self.c.query("select 0 where false")
     1332        self.assertIsNone(q.onescalar())
     1333
     1334    def testOneScalarWithSingleRow(self):
     1335        q = self.c.query("select 1, 2")
     1336        r = q.onescalar()
     1337        self.assertIsInstance(r, int)
     1338        self.assertEqual(r, 1)
     1339        self.assertEqual(q.onescalar(), None)
     1340
     1341    def testOneScalarWithTwoRows(self):
     1342        q = self.c.query("select 1, 2 union select 3, 4")
     1343        self.assertEqual(q.onescalar(), 1)
     1344        self.assertEqual(q.onescalar(), 3)
     1345        self.assertEqual(q.onescalar(), None)
     1346
     1347    def testSingleWithEmptyQuery(self):
     1348        q = self.c.query("select 0 where false")
     1349        try:
     1350            q.single()
     1351        except pg.ProgrammingError as e:
     1352            r = str(e)
     1353        else:
     1354            r = None
     1355        self.assertEqual(r, 'No result found')
     1356
     1357    def testSingleWithSingleRow(self):
     1358        q = self.c.query("select 1, 2")
     1359        r = q.single()
     1360        self.assertIsInstance(r, tuple)
     1361        self.assertEqual(r, (1, 2))
     1362        r = q.single()
     1363        self.assertIsInstance(r, tuple)
     1364        self.assertEqual(r, (1, 2))
     1365
     1366    def testSingleWithTwoRows(self):
     1367        q = self.c.query("select 1, 2 union select 3, 4")
     1368        try:
     1369            q.single()
     1370        except pg.ProgrammingError as e:
     1371            r = str(e)
     1372        else:
     1373            r = None
     1374        self.assertEqual(r, 'Multiple results found')
     1375
     1376    def testSingleDictWithEmptyQuery(self):
     1377        q = self.c.query("select 0 where false")
     1378        try:
     1379            q.singledict()
     1380        except pg.ProgrammingError as e:
     1381            r = str(e)
     1382        else:
     1383            r = None
     1384        self.assertEqual(r, 'No result found')
     1385
     1386    def testSingleDictWithSingleRow(self):
     1387        q = self.c.query("select 1 as one, 2 as two")
     1388        r = q.singledict()
     1389        self.assertIsInstance(r, dict)
     1390        self.assertEqual(r, dict(one=1, two=2))
     1391        r = q.singledict()
     1392        self.assertIsInstance(r, dict)
     1393        self.assertEqual(r, dict(one=1, two=2))
     1394
     1395    def testSingleDictWithTwoRows(self):
     1396        q = self.c.query("select 1, 2 union select 3, 4")
     1397        try:
     1398            q.singledict()
     1399        except pg.ProgrammingError as e:
     1400            r = str(e)
     1401        else:
     1402            r = None
     1403        self.assertEqual(r, 'Multiple results found')
     1404
     1405    def testSingleNamedWithEmptyQuery(self):
     1406        q = self.c.query("select 0 where false")
     1407        try:
     1408            q.singlenamed()
     1409        except pg.ProgrammingError as e:
     1410            r = str(e)
     1411        else:
     1412            r = None
     1413        self.assertEqual(r, 'No result found')
     1414
     1415    def testSingleNamedWithSingleRow(self):
     1416        q = self.c.query("select 1 as one, 2 as two")
     1417        r = q.singlenamed()
     1418        self.assertEqual(r._fields, ('one', 'two'))
     1419        self.assertEqual(r.one, 1)
     1420        self.assertEqual(r.two, 2)
     1421        self.assertEqual(r, (1, 2))
     1422        r = q.singlenamed()
     1423        self.assertEqual(r._fields, ('one', 'two'))
     1424        self.assertEqual(r.one, 1)
     1425        self.assertEqual(r.two, 2)
     1426        self.assertEqual(r, (1, 2))
     1427
     1428    def testSingleNamedWithTwoRows(self):
     1429        q = self.c.query("select 1, 2 union select 3, 4")
     1430        try:
     1431            q.singlenamed()
     1432        except pg.ProgrammingError as e:
     1433            r = str(e)
     1434        else:
     1435            r = None
     1436        self.assertEqual(r, 'Multiple results found')
     1437
     1438    def testSingleScalarWithEmptyQuery(self):
     1439        q = self.c.query("select 0 where false")
     1440        try:
     1441            q.singlescalar()
     1442        except pg.ProgrammingError as e:
     1443            r = str(e)
     1444        else:
     1445            r = None
     1446        self.assertEqual(r, 'No result found')
     1447
     1448    def testSingleScalarWithSingleRow(self):
     1449        q = self.c.query("select 1, 2")
     1450        r = q.singlescalar()
     1451        self.assertIsInstance(r, int)
     1452        self.assertEqual(r, 1)
     1453        r = q.singlescalar()
     1454        self.assertIsInstance(r, int)
     1455        self.assertEqual(r, 1)
     1456
     1457    def testSingleWithTwoRows(self):
     1458        q = self.c.query("select 1, 2 union select 3, 4")
     1459        try:
     1460            q.singlescalar()
     1461        except pg.ProgrammingError as e:
     1462            r = str(e)
     1463        else:
     1464            r = None
     1465        self.assertEqual(r, 'Multiple results found')
     1466
     1467    def testScalarResult(self):
     1468        q = self.c.query("select 1, 2 union select 3, 4")
     1469        r = q.scalarresult()
     1470        self.assertIsInstance(r, list)
     1471        self.assertEqual(r, [1, 3])
     1472
     1473    def testScalarIter(self):
     1474        q = self.c.query("select 1, 2 union select 3, 4")
     1475        r = q.scalariter()
     1476        self.assertNotIsInstance(r, (list, tuple))
     1477        self.assertIsInstance(r, Iterable)
     1478        r = list(r)
     1479        self.assertEqual(r, [1, 3])
    12301480
    12311481
     
    19952245        self.assertEqual(r, b'data')
    19962246
    1997     def testGetDictditer(self):
    1998         dictiter = pg.get_dictiter()
    1999         # error if a parameter is passed
    2000         self.assertRaises(TypeError, pg.get_dictiter, dictiter)
    2001         self.assertIs(dictiter, pg._dictiter)  # the default setting
    2002 
    2003     def testSetDictiter(self):
    2004         dictiter = pg.get_dictiter()
    2005         self.assertTrue(callable(dictiter))
    2006 
    2007         query = self.c.query
    2008 
    2009         r = query("select 1 as x, 2 as y").dictiter()
    2010         self.assertNotIsInstance(r, list)
    2011         r = next(r)
    2012         self.assertIsInstance(r, dict)
    2013         self.assertEqual(r, dict(x=1, y=2))
    2014 
    2015         def listiter(q):
    2016             for row in q:
    2017                 yield list(row)
    2018 
    2019         pg.set_dictiter(listiter)
    2020         try:
    2021             r = pg.get_dictiter()
    2022             self.assertIs(r, listiter)
    2023             r = query("select 1 as x, 2 as y").dictiter()
    2024             self.assertNotIsInstance(r, list)
    2025             r = next(r)
    2026             self.assertIsInstance(r, list)
    2027             self.assertEqual(r, [1, 2])
    2028             self.assertNotIsInstance(r, dict)
    2029         finally:
    2030             pg.set_dictiter(dictiter)
    2031 
    2032         r = pg.get_dictiter()
    2033         self.assertIs(r, dictiter)
    2034 
    2035     def testGetNamediter(self):
    2036         namediter = pg.get_namediter()
    2037         # error if a parameter is passed
    2038         self.assertRaises(TypeError, pg.get_namediter, namediter)
    2039         self.assertIs(namediter, pg._namediter)  # the default setting
    2040 
    2041     def testSetNamediter(self):
    2042         namediter = pg.get_namediter()
    2043         self.assertTrue(callable(namediter))
    2044 
    2045         query = self.c.query
    2046 
    2047         r = query("select 1 as x, 2 as y").namediter()
    2048         self.assertNotIsInstance(r, list)
    2049         r = next(r)
    2050         self.assertIsInstance(r, tuple)
    2051         self.assertEqual(r, (1, 2))
    2052         self.assertIsNot(type(r), tuple)
    2053         self.assertEqual(r._fields, ('x', 'y'))
    2054         self.assertEqual(r._asdict(), {'x': 1, 'y': 2})
    2055         self.assertEqual(r.__class__.__name__, 'Row')
    2056         r = query("select 1 as x, 2 as y").namedresult()
    2057         self.assertIsInstance(r, list)
    2058         r = r[0]
    2059         self.assertIsInstance(r, tuple)
    2060         self.assertEqual(r, (1, 2))
    2061         self.assertIsNot(type(r), tuple)
    2062         self.assertEqual(r._fields, ('x', 'y'))
    2063         self.assertEqual(r._asdict(), {'x': 1, 'y': 2})
    2064         self.assertEqual(r.__class__.__name__, 'Row')
    2065 
    2066         def listiter(q):
    2067             for row in q:
    2068                 yield list(row)
    2069 
    2070         pg.set_namediter(listiter)
    2071         try:
    2072             r = pg.get_namediter()
    2073             self.assertIs(r, listiter)
    2074             r = query("select 1 as x, 2 as y").namediter()
    2075             self.assertNotIsInstance(r, list)
    2076             r = next(r)
    2077             self.assertIsInstance(r, list)
    2078             self.assertEqual(r, [1, 2])
    2079             self.assertIsNot(type(r), tuple)
    2080             self.assertFalse(hasattr(r, '_fields'))
    2081             self.assertNotEqual(r.__class__.__name__, 'Row')
    2082             r = query("select 1 as x, 2 as y").namedresult()
    2083             self.assertIsInstance(r, list)
    2084             r = r[0]
    2085             self.assertIsInstance(r, list)
    2086             self.assertEqual(r, [1, 2])
    2087             self.assertIsNot(type(r), tuple)
    2088             self.assertFalse(hasattr(r, '_fields'))
    2089             self.assertNotEqual(r.__class__.__name__, 'Row')
    2090         finally:
    2091             pg.set_namediter(namediter)
    2092 
    2093         r = pg.get_namediter()
    2094         self.assertIs(r, namediter)
    2095 
    2096     def testGetNamedresult(self):  # deprecated
    2097         namedresult = pg.get_namedresult()
    2098         # error if a parameter is passed
    2099         self.assertRaises(TypeError, pg.get_namedresult, namedresult)
    2100         self.assertIs(namedresult, pg._namediter)  # the default setting
    2101 
    2102     def testSetNamedresult(self):  # deprecated
    2103         namedresult = pg.get_namedresult()
    2104         self.assertTrue(callable(namedresult))
    2105 
    2106         query = self.c.query
    2107 
    2108         r = query("select 1 as x, 2 as y").namedresult()[0]
    2109         self.assertIsInstance(r, tuple)
    2110         self.assertEqual(r, (1, 2))
    2111         self.assertIsNot(type(r), tuple)
    2112         self.assertEqual(r._fields, ('x', 'y'))
    2113         self.assertEqual(r._asdict(), {'x': 1, 'y': 2})
    2114         self.assertEqual(r.__class__.__name__, 'Row')
    2115 
    2116         def listresult(q):
    2117             return [list(row) for row in q.getresult()]
    2118 
    2119         pg.set_namedresult(listresult)
    2120         try:
    2121             r = pg.get_namedresult()
    2122             self.assertIs(r, listresult)
    2123             r = query("select 1 as x, 2 as y").namedresult()[0]
    2124             self.assertIsInstance(r, list)
    2125             self.assertEqual(r, [1, 2])
    2126             self.assertIsNot(type(r), tuple)
    2127             self.assertFalse(hasattr(r, '_fields'))
    2128             self.assertNotEqual(r.__class__.__name__, 'Row')
    2129         finally:
    2130             pg.set_namedresult(namedresult)
    2131 
    2132         r = pg.get_namedresult()
    2133         self.assertIs(r, namedresult)
    2134 
    21352247    def testSetRowFactorySize(self):
    21362248        try:
  • trunk/tests/test_classic_dbwrapper.py

    r969 r980  
    41404140        not_bytea_escaped = not pg.get_bytea_escaped()
    41414141        cls.set_option('bytea_escaped', not_bytea_escaped)
    4142         cls.set_option('namedresult', None)
    41434142        cls.set_option('jsondecode', None)
    41444143        db = DB()
     
    41514150        super(TestDBClassNonStdOpts, cls).tearDownClass()
    41524151        cls.reset_option('jsondecode')
    4153         cls.reset_option('namedresult')
    41544152        cls.reset_option('bool')
    41554153        cls.reset_option('array')
     
    41684166
    41694167class TestDBClassAdapter(unittest.TestCase):
    4170     """Test the adapter object associatd with the DB class."""
     4168    """Test the adapter object associated with the DB class."""
    41714169
    41724170    def setUp(self):
  • trunk/tests/test_classic_functions.py

    r978 r980  
    10061006        self.assertIs(r, bytea_escaped)
    10071007
    1008     def testGetDictiter(self):
    1009         r = pg.get_dictiter()
    1010         self.assertTrue(callable(r))
    1011         self.assertIs(r, pg._dictiter)
    1012 
    1013     def testSetDictiter(self):
    1014         dictiter = pg.get_dictiter()
    1015         try:
    1016             pg.set_dictiter(None)
    1017             r = pg.get_dictiter()
    1018             self.assertIsNone(r)
    1019             f = lambda q: q
    1020             pg.set_dictiter(f)
    1021             r = pg.get_dictiter()
    1022             self.assertIs(r, f)
    1023             self.assertRaises(TypeError, pg.set_dictiter, 'invalid')
    1024         finally:
    1025             pg.set_dictiter(dictiter)
    1026         r = pg.get_dictiter()
    1027         self.assertIs(r, dictiter)
    1028 
    1029     def testGetNamediter(self):
    1030         r = pg.get_namediter()
    1031         self.assertTrue(callable(r))
    1032         self.assertIs(r, pg._namediter)
    1033 
    1034     def testSetNamediter(self):
    1035         namediter = pg.get_namediter()
    1036         try:
    1037             pg.set_namediter(None)
    1038             r = pg.get_namediter()
    1039             self.assertIsNone(r)
    1040             f = lambda q: q
    1041             pg.set_namediter(f)
    1042             r = pg.get_namediter()
    1043             self.assertIs(r, f)
    1044             self.assertRaises(TypeError, pg.set_namediter, 'invalid')
    1045         finally:
    1046             pg.set_namediter(namediter)
    1047         r = pg.get_namediter()
    1048         self.assertIs(r, namediter)
    1049 
    1050     def testGetNamedresult(self):  # deprecated
    1051         r = pg.get_namedresult()
    1052         self.assertTrue(callable(r))
    1053         self.assertIs(r, pg._namediter)
    1054 
    1055     def testSetNamedresult(self):  # deprecated
    1056         namedresult = pg.get_namedresult()
    1057         try:
    1058             pg.set_namedresult(None)
    1059             r = pg.get_namedresult()
    1060             self.assertIsNone(r)
    1061             f = lambda q: q.getresult()
    1062             pg.set_namedresult(f)
    1063             r = pg.get_namedresult()
    1064             self.assertIs(r, f)
    1065             self.assertRaises(TypeError, pg.set_namedresult, 'invalid')
    1066         finally:
    1067             pg.set_namedresult(namedresult)
    1068         r = pg.get_namedresult()
    1069         self.assertIs(r, namedresult)
    1070 
    10711008    def testGetJsondecode(self):
    10721009        r = pg.get_jsondecode()
Note: See TracChangeset for help on using the changeset viewer.