Skip to content

Commit a9a40a3

Browse files
author
James William Pye
committed
Add test for 'namedtuples execution method'.
Also, this namedtuple module is needed for the RowTypeFactory test.
1 parent 4d72304 commit a9a40a3

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

postgresql/test/test_driver.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,5 +1682,17 @@ def testRowTypeFactory(self):
16821682
self.failUnlessEqual(composite_results.foo, 1)
16831683
self.failUnlessEqual(composite_results.bar, 2)
16841684

1685+
@pg_tmp
1686+
def testNamedTuples(self):
1687+
from ..types.namedtuple import namedtuples
1688+
ps = namedtuples(prepare('select 1 as foo, 2 as bar, $1::text as param'))
1689+
r = list(ps("hello"))[0]
1690+
self.failUnlessEqual(r[0], 1)
1691+
self.failUnlessEqual(r.foo, 1)
1692+
self.failUnlessEqual(r[1], 2)
1693+
self.failUnlessEqual(r.bar, 2)
1694+
self.failUnlessEqual(r[2], "hello")
1695+
self.failUnlessEqual(r.param, "hello")
1696+
16851697
if __name__ == '__main__':
16861698
unittest.main()

postgresql/types/namedtuple.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
##
2+
# .types.namedtuple - return rows as namedtuples
3+
##
4+
"""
5+
Factories for namedtuple row representation.
6+
"""
7+
from collections import namedtuple
8+
9+
#: Global namedtuple type cache.
10+
cache = {}
11+
12+
# Build and cache the namedtuple's produced.
13+
def _factory(colnames : [str], namedtuple = namedtuple) -> tuple:
14+
global cache
15+
# Provide some normalization.
16+
# Anything beyond this can just get renamed.
17+
colnames = tuple([
18+
x.replace(' ', '_') for x in colnames
19+
])
20+
try:
21+
return cache[colnames]
22+
except KeyError:
23+
NT = namedtuple('row', colnames, rename = True)
24+
cache[colnames] = NT
25+
return NT
26+
27+
def NamedTupleFactory(attribute_map):
28+
"""
29+
Alternative db.typio.RowFactory for producing namedtuple's instead of
30+
postgresql.types.Row() instances.
31+
32+
To install::
33+
34+
>>> from postgresql.types.namedtuple import NamedTupleFactory
35+
>>> import postgresql
36+
>>> db = postgresql.open(...)
37+
>>> db.typio.RowTypeFactory(NamedTupleFactory)
38+
39+
And **all** Rows produced by that connection will be namedtuple()'s.
40+
This includes composites.
41+
"""
42+
colnames = list(attribute_map.items())
43+
colnames.sort(key = lambda x: x[1])
44+
return lambda y: _factory((x[0] for x in colnames))(*y)
45+
46+
from itertools import chain, starmap
47+
48+
def namedtuples(stmt, from_iter = chain.from_iterable, map = starmap):
49+
"""
50+
Alternative to the .rows() execution method.
51+
52+
Use::
53+
54+
>>> from postgresql.types.namedtuple import namedtuples
55+
>>> ps = namedtuples(db.prepare(...))
56+
>>> for nt in ps(...):
57+
... nt.a_column_name
58+
59+
This effectively selects the execution method to be used with the statement.
60+
"""
61+
NT = _factory(stmt.column_names)
62+
# build the execution "method"
63+
chunks = stmt.chunks
64+
def rows_as_namedtuples(*args, **kw):
65+
return map(NT, from_iter(chunks(*args, **kw))) # starmap
66+
return rows_as_namedtuples
67+
68+
del chain, starmap

0 commit comments

Comments
 (0)