pypyodbc
pypyodbc copied to clipboard
NamedTupleRow broken
Summary
Setting row_type_callable
to NamedTupleRow
causes data retrieval to fail in the constructor for the local Row
class inside the global NamedTupleRow
function.
Repro
Here's my repro case (tweak as necessary to adjust to your environment):
#!/usr/bin/env python
"""Repro case for pypyodbc.NamedTupleRow bug
"""
from argparse import ArgumentParser
from pypyodbc import connect, NamedTupleRow
parser = ArgumentParser()
parser.add_argument("--host", required=True)
parser.add_argument("--port", required=True)
parser.add_argument("--database", required=True)
parser.add_argument("--driver", required=True)
opts = parser.parse_args()
parms = dict(
Driver=opts.driver,
Server="{},{}".format(opts.host, opts.port),
Database=opts.database,
Trusted_Connection="yes",
)
parms = ";".join(["{}={}".format(*p) for p in parms.items()])
conn = connect(parms)
cursor = conn.cursor(row_type_callable=NamedTupleRow)
cursor.execute("CREATE TABLE #t (i INT)")
cursor.execute("INSERT INTO #t (i) VALUES (42)")
cursor.execute("SELECT * FROM #t")
row = cursor.fetchone()
print(row.i)
Output
And here's what happens:
$ python repro.py --host test-host --port 52300 --database test-db \
> --driver "{ODBC Driver 17 for SQL Server}"
Traceback (most recent call last):
File "repro.py", line 27, in <module>
row = cursor.fetchone()
File "D:\Python\lib\site-packages\pypyodbc.py", line 1930, in fetchone
return self._row_type(value_list)
File "D:\Python\lib\site-packages\pypyodbc.py", line 1079, in __new__
return super(Row, cls).__new__(cls, *iterable)
TypeError: __new__() takes 1 positional argument but 2 were given
Environment
Reproducible with Python 3.7.4 as well as 2.7.13 with pypyodbc-1.3.5
on various flavors of Windows Server.
Unit test using free data source
In case you don't have access to SQL Server (and to nudge the project in the direction of using real unit tests):
#!/usr/bin/env python
"""Tests for pypyodbc package
"""
from unittest import TestCase, main
from pypyodbc import connect, NamedTupleRow
class Tests(TestCase):
"""Base class for unit tests"""
CONNECTION_STRING = "Driver=SQLite3 ODBC Driver;Database=:memory:"
class CursorTests(Tests):
"""Tests of the cursor object"""
def test_dictionary_rows(self):
"""Ensure that the cursor can provide rows indexable by column name"""
conn = connect(self.CONNECTION_STRING)
cursor = conn.cursor(row_type_callable=None)
cursor.execute("CREATE TABLE t (i INT)")
cursor.execute("INSERT INTO t (i) VALUES (42)")
cursor.execute("SELECT * FROM t")
row = cursor.fetchone()
cursor.execute("DROP TABLE t")
self.assertEqual(row["i"], 42)
def test_named_tuple_rows(self):
"""Ensure that the cursor can provide rows with column attributes"""
conn = connect(self.CONNECTION_STRING)
cursor = conn.cursor(row_type_callable=NamedTupleRow)
cursor.execute("CREATE TABLE t (i INT)")
cursor.execute("INSERT INTO t (i) VALUES (42)")
cursor.execute("SELECT * FROM t")
row = cursor.fetchone()
cursor.execute("DROP TABLE t")
self.assertEqual(row.i, 42)
if __name__ == "__main__":
main()
Test results
$ python tests/pypyodbc_tests.py -v
test_dictionary_rows (__main__.CursorTests)
Ensure that the cursor can provide rows indexable by column name ... ok
test_named_tuple_rows (__main__.CursorTests)
Ensure that the cursor can provide rows with column attributes ... ERROR
======================================================================
ERROR: test_named_tuple_rows (__main__.CursorTests)
Ensure that the cursor can provide rows with column attributes
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests/pypyodbc_tests.py", line 34, in test_named_tuple_rows
row = cursor.fetchone()
File "D:\Python\lib\site-packages\pypyodbc.py", line 1930, in fetchone
return self._row_type(value_list)
File "D:\Python\lib\site-packages\pypyodbc.py", line 1079, in __new__
return super(Row, cls).__new__(cls, *iterable)
TypeError: __new__() takes 1 positional argument but 2 were given
----------------------------------------------------------------------
Ran 2 tests in 0.026s
FAILED (errors=1)