Merge branch 'namedtuple-invalid-identifiers'

This commit is contained in:
Daniele Varrazzo 2018-01-29 03:31:10 +00:00
commit 9e6b22cc3b
3 changed files with 21 additions and 1 deletions

2
NEWS
View File

@ -20,6 +20,8 @@ What's new in psycopg 2.7.4
- Moving away from installing the wheel package by default. - Moving away from installing the wheel package by default.
Packages installed from wheel raise a warning on import. Added package Packages installed from wheel raise a warning on import. Added package
``psycopg2-binary`` to install from wheel instead (:ticket:`#543`). ``psycopg2-binary`` to install from wheel instead (:ticket:`#543`).
- Convert fields names into valid Python identifiers in
`~psycopg2.extras.NamedTupleCursor` (:ticket:`#211`).
- Fixed Solaris 10 support (:ticket:`#532`). - Fixed Solaris 10 support (:ticket:`#532`).
- `cursor.mogrify()` can be called on closed cursors (:ticket:`#579`). - `cursor.mogrify()` can be called on closed cursors (:ticket:`#579`).
- Fixed setting session characteristics in corner cases on autocommit - Fixed setting session characteristics in corner cases on autocommit

View File

@ -363,7 +363,17 @@ class NamedTupleCursor(_cursor):
return return
def _make_nt(self): def _make_nt(self):
return namedtuple("Record", [d[0] for d in self.description or ()]) def f(s):
# NOTE: Python 3 actually allows unicode chars in fields
s = _re.sub('[^a-zA-Z0-9_]', '_', s)
# Python identifier cannot start with numbers, namedtuple fields
# cannot start with underscore. So...
if _re.match('^[0-9_]', s):
s = 'f' + s
return s
return namedtuple("Record", [f(d[0]) for d in self.description or ()])
class LoggingConnection(_connection): class LoggingConnection(_connection):

View File

@ -349,6 +349,14 @@ class NamedTupleCursorTest(ConnectingTestCase):
curs.execute("update nttest set s = s") curs.execute("update nttest set s = s")
self.assertRaises(psycopg2.ProgrammingError, curs.fetchall) self.assertRaises(psycopg2.ProgrammingError, curs.fetchall)
def test_bad_col_names(self):
curs = self.conn.cursor()
curs.execute('select 1 as "foo.bar_baz", 2 as "?column?", 3 as "3"')
rv = curs.fetchone()
self.assertEqual(rv.foo_bar_baz, 1)
self.assertEqual(rv.f_column_, 2)
self.assertEqual(rv.f3, 3)
def test_minimal_generation(self): def test_minimal_generation(self):
# Instrument the class to verify it gets called the minimum number of times. # Instrument the class to verify it gets called the minimum number of times.
from psycopg2.extras import NamedTupleCursor from psycopg2.extras import NamedTupleCursor