This commit is contained in:
Hugo 2017-11-28 09:02:24 +00:00 committed by GitHub
commit 550ee0b679
25 changed files with 72 additions and 140 deletions

1
.gitignore vendored
View File

@ -11,6 +11,7 @@ doc/html/*
doc/psycopg2.txt
scripts/pypi_docs_upload.py
env
.idea
.tox
/rel
/wheels

View File

@ -7,7 +7,6 @@ language: python
python:
- 2.7
- 3.6
- 2.6
- 3.5
- 3.4
- 3.3

View File

@ -59,7 +59,7 @@ between 8.1 and 10 are included in the module.
>>> try:
... cur.execute("SELECT ouch FROM aargh;")
... except Exception, e:
... except Exception as e:
... pass
...
>>> errorcodes.lookup(e.pgcode[:2])

View File

@ -17,7 +17,7 @@ The current `!psycopg2` implementation supports:
..
NOTE: keep consistent with setup.py and the /features/ page.
- Python 2 versions from 2.6 to 2.7
- Python version 2.7
- Python 3 versions from 3.2 to 3.6
- PostgreSQL server versions from 7.4 to 10
- PostgreSQL client library version from 9.1

View File

@ -27,9 +27,9 @@ import psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dsn:", DSN
print("Opening connection using dsn:", DSN)
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
print("Encoding for this connection is", conn.encoding)
curs = conn.cursor()
try:
@ -51,16 +51,16 @@ io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy')
print "1) Copy %d records from file object " % len(data) + \
"using defaults (sep: \\t and null = \\N)"
print("1) Copy %d records from file object " % len(data) +
"using defaults (sep: \\t and null = \\N)")
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select returned %d rows" % len(rows)
print(" Select returned %d rows" % len(rows))
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
print(" %s %s\t%s" % (r[0], r[1], r[2]))
curs.execute("delete from test_copy")
conn.commit()
@ -75,15 +75,15 @@ io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy', ':')
print "2) Copy %d records from file object using sep = :" % len(data)
print("2) Copy %d records from file object using sep = :" % len(data))
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select returned %d rows" % len(rows)
print(" Select returned %d rows" % len(rows))
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
print(" %s %s\t%s" % (r[0], r[1], r[2]))
curs.execute("delete from test_copy")
conn.commit()
@ -98,15 +98,15 @@ io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy', null='NULL')
print "3) Copy %d records from file object using null = NULL" % len(data)
print("3) Copy %d records from file object using null = NULL" % len(data))
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select using cursor returned %d rows" % len(rows)
print(" Select using cursor returned %d rows" % len(rows))
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
print(" %s %s\t%s" % (r[0], r[1], r[2]))
curs.execute("delete from test_copy")
conn.commit()
@ -119,16 +119,16 @@ io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy', ':', 'NULL')
print "4) Copy %d records from file object " % len(data) + \
"using sep = : and null = NULL"
print("4) Copy %d records from file object " % len(data) +
"using sep = : and null = NULL")
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select using cursor returned %d rows" % len(rows)
print(" Select using cursor returned %d rows" % len(rows))
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
print(" %s %s\t%s" % (r[0], r[1], r[2]))
curs.execute("delete from test_copy")
conn.commit()
@ -141,20 +141,20 @@ data.write('\n'.join(['Tom\tJenkins\t37',
data.seek(0)
curs.copy_from(data, 'test_copy')
print "5) Copy 3 records from StringIO object using defaults"
print("5) Copy 3 records from StringIO object using defaults")
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select using cursor returned %d rows" % len(rows)
print(" Select using cursor returned %d rows" % len(rows))
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
print(" %s %s\t%s" % (r[0], r[1], r[2]))
curs.execute("delete from test_copy")
conn.commit()
# simple error test
print "6) About to raise an error"
print("6) About to raise an error")
data = StringIO.StringIO()
data.write('\n'.join(['Tom\tJenkins\t37',
'Madonna\t\N\t45',
@ -163,9 +163,9 @@ data.seek(0)
try:
curs.copy_from(data, 'test_copy')
except StandardError, err:
except StandardError as err:
conn.rollback()
print " Caught error (as expected):\n", err
print(" Caught error (as expected):\n", err)
conn.rollback()

View File

@ -25,9 +25,9 @@ import psycopg2.extensions
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dsn:", DSN
print("Opening connection using dsn:", DSN)
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
print("Encoding for this connection is", conn.encoding)
class NoDataError(psycopg2.ProgrammingError):
@ -52,12 +52,12 @@ class Cursor(psycopg2.extensions.cursor):
curs = conn.cursor(cursor_factory=Cursor)
curs.execute("SELECT 1 AS foo")
print "Result of fetchone():", curs.fetchone()
print("Result of fetchone():", curs.fetchone())
# now let's raise the exception
try:
curs.fetchone()
except NoDataError, err:
print "Exception caught:", err
except NoDataError as err:
print("Exception caught:", err)
conn.rollback()

View File

@ -84,7 +84,7 @@ def insert_func(conn_or_pool, rows):
try:
c.execute("INSERT INTO test_threads VALUES (%s, %s, %s)",
(str(i), i, float(i)))
except psycopg2.ProgrammingError, err:
except psycopg2.ProgrammingError as err:
print name, ": an error occurred; skipping this insert"
print err
conn.commit()
@ -112,10 +112,10 @@ def select_func(conn_or_pool, z):
if MODE == 1:
conn_or_pool.putconn(conn)
s = name + ": number of rows fetched: " + str(len(l))
print s
except psycopg2.ProgrammingError, err:
print name, ": an error occurred; skipping this select"
print err
print(s)
except psycopg2.ProgrammingError as err:
print(name, ": an error occurred; skipping this select")
print(err)
## create the connection pool or the connections
if MODE == 0:
@ -129,14 +129,14 @@ else:
## create the threads
threads = []
print "Creating INSERT threads:"
print("Creating INSERT threads:")
for name in INSERT_THREADS:
t = threading.Thread(None, insert_func, 'Thread-'+name,
(conn_insert, ROWS))
t.setDaemon(0)
threads.append(t)
print "Creating SELECT threads:"
print("Creating SELECT threads:")
for name in SELECT_THREADS:
t = threading.Thread(None, select_func, 'Thread-'+name,
(conn_select, SELECT_DIV))
@ -150,12 +150,12 @@ for t in threads:
# and wait for them to finish
for t in threads:
t.join()
print t.getName(), "exited OK"
print(t.getName(), "exited OK")
conn.commit()
curs.execute("SELECT count(name) FROM test_threads")
print "Inserted", curs.fetchone()[0], "rows."
print("Inserted", curs.fetchone()[0], "rows.")
curs.execute("DROP TABLE test_threads")
conn.commit()

View File

@ -196,7 +196,7 @@ def _get_json_oids(conn_or_curs, name='json'):
r = curs.fetchone()
# revert the status of the connection as before the command
if (conn_status != STATUS_IN_TRANSACTION and not conn.autocommit):
if conn_status != STATUS_IN_TRANSACTION and not conn.autocommit:
conn.rollback()
if not r:

View File

@ -264,7 +264,7 @@ class RealDictCursor(DictCursorBase):
class RealDictRow(dict):
"""A `!dict` subclass representing a data record."""
__slots__ = ('_column_mapping')
__slots__ = '_column_mapping'
def __init__(self, cursor):
dict.__init__(self)
@ -280,7 +280,7 @@ class RealDictRow(dict):
return dict.__setitem__(self, name, value)
def __getstate__(self):
return (self.copy(), self._column_mapping[:])
return self.copy(), self._column_mapping[:]
def __setstate__(self, data):
self.update(data[0])

View File

@ -172,7 +172,7 @@ class SQL(Composable):
Example::
>>> query = sql.SQL("select {0} from {1}").format(
>>> query = sql.SQL("select {} from {}").format(
... sql.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]),
... sql.Identifier('table'))
>>> print(query.as_string(conn))

View File

@ -75,7 +75,7 @@ class FixedOffsetTimezone(datetime.tzinfo):
def __getinitargs__(self):
offset_mins = self._offset.seconds // 60 + self._offset.days * 24 * 60
return (offset_mins, self._name)
return offset_mins, self._name
def utcoffset(self, dt):
return self._offset

View File

@ -31,8 +31,8 @@
#include <stringobject.h>
#endif
#if PY_VERSION_HEX < 0x02060000
# error "psycopg requires Python >= 2.6"
#if PY_VERSION_HEX < 0x02070000
# error "psycopg requires Python >= 2.7"
#endif
/* hash() return size changed around version 3.2a4 on 64bit platforms. Before
@ -44,14 +44,6 @@ typedef long Py_hash_t;
typedef unsigned long Py_uhash_t;
#endif
/* Macros defined in Python 2.6 */
#ifndef Py_REFCNT
#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size)
#define PyVarObject_HEAD_INIT(x,n) PyObject_HEAD_INIT(x) n,
#endif
/* FORMAT_CODE_PY_SSIZE_T is for Py_ssize_t: */
#define FORMAT_CODE_PY_SSIZE_T "%" PY_FORMAT_SIZE_T "d"

View File

@ -22,15 +22,15 @@ def sleep(curs):
# DECLARE zz INSENSITIVE SCROLL CURSOR WITH HOLD FOR
# SELECT now();
# FOR READ ONLY;""", async = 1)
curs.execute("SELECT now() AS foo", async=1);
curs.execute("SELECT now() AS foo", async=1)
sleep(curs)
print curs.fetchall()
#curs.execute("""
# FETCH FORWARD 1 FROM zz;""", async = 1)
curs.execute("SELECT now() AS bar", async=1);
curs.execute("SELECT now() AS bar", async=1)
print curs.fetchall()
curs.execute("SELECT now() AS bar");
curs.execute("SELECT now() AS bar")
sleep(curs)

View File

@ -6,7 +6,7 @@ class B(object):
print "ga called", attr
return object.__getattribute__(self, attr)
def _sqlquote(self):
if self._o == True:
if self._o:
return 'It is True'
else:
return 'It is False'

View File

@ -43,7 +43,7 @@ def main():
dump(i, opt)
f1 = open('debug-%02d.txt' % (opt.nruns - 1)).readlines()
f2 = open('debug-%02d.txt' % (opt.nruns)).readlines()
f2 = open('debug-%02d.txt' % opt.nruns).readlines()
for line in difflib.unified_diff(f1, f2,
"run %d" % (opt.nruns - 1), "run %d" % opt.nruns):
sys.stdout.write(line)
@ -52,7 +52,7 @@ def main():
if opt.objs:
f1 = open('objs-%02d.txt' % (opt.nruns - 1)).readlines()
f2 = open('objs-%02d.txt' % (opt.nruns)).readlines()
f2 = open('objs-%02d.txt' % opt.nruns).readlines()
for line in difflib.unified_diff(f1, f2,
"run %d" % (opt.nruns - 1), "run %d" % opt.nruns):
sys.stdout.write(line)

View File

@ -76,7 +76,6 @@ License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
License :: OSI Approved :: Zope Public License
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.6
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.2
@ -215,8 +214,7 @@ or with the pg_config option in 'setup.cfg'.
# Support unicode paths, if this version of Python provides the
# necessary infrastructure:
if sys.version_info[0] < 3 \
and hasattr(sys, 'getfilesystemencoding'):
if sys.version_info[0] < 3:
pg_config_path = pg_config_path.encode(
sys.getfilesystemencoding())
@ -297,7 +295,7 @@ class psycopg_build_ext(build_ext):
# For Python versions that use MSVC compiler 2008, re-insert the
# manifest into the resulting .pyd file.
if self.compiler_is_msvc() and sysVer in ((2, 6), (2, 7), (3, 0), (3, 1), (3, 2)):
if self.compiler_is_msvc() and sysVer in ((2, 7), (3, 0), (3, 1), (3, 2)):
platform = get_platform()
# Default to the x86 manifest
manifest = '_psycopg.vc9.x86.manifest'
@ -319,7 +317,6 @@ class psycopg_build_ext(build_ext):
def finalize_win32(self):
"""Finalize build system configuration on win32 platform."""
sysVer = sys.version_info[:2]
# Add compiler-specific arguments:
extra_compiler_args = []
@ -335,17 +332,6 @@ class psycopg_build_ext(build_ext):
# API code.
extra_compiler_args.append('-fno-strict-aliasing')
# Force correct C runtime library linkage:
if sysVer <= (2, 3):
# Yes: 'msvcr60', rather than 'msvcrt', is the correct value
# on the line below:
self.libraries.append('msvcr60')
elif sysVer in ((2, 4), (2, 5)):
self.libraries.append('msvcr71')
# Beyond Python 2.5, we take our chances on the default C runtime
# library, because we don't know what compiler those future
# versions of Python will use.
for extension in ext: # ext is a global list of Extension objects
extension.extra_compile_args.extend(extra_compiler_args)
# End of add-compiler-specific arguments section.
@ -414,7 +400,7 @@ class psycopg_build_ext(build_ext):
# *at least* PostgreSQL 7.4 is available (this is the only
# 7.x series supported by psycopg 2)
pgversion = pg_config_helper.query("version").split()[1]
except:
except Exception:
pgversion = "7.4.0"
verre = re.compile(
@ -619,7 +605,7 @@ try:
f = open("README.rst")
readme = f.read()
f.close()
except:
except Exception:
print("failed to read readme: ignoring...")
readme = __doc__
@ -633,6 +619,7 @@ setup(name="psycopg2",
download_url=download_url,
license="LGPL with exceptions or ZPL",
platforms=["any"],
python_requires='>=2.7,!=3.0.*,!=3.1.*',
description=readme.split("\n")[0],
long_description="\n".join(readme.split("\n")[2:]).lstrip(),
classifiers=[x for x in classifiers.split("\n") if x],

View File

@ -762,7 +762,7 @@ class DatabaseAPI20Test(unittest.TestCase):
names=cur.fetchall()
assert len(names) == len(self.samples)
s=cur.nextset()
assert s == None,'No more return sets, should return None'
assert s is None, 'No more return sets, should return None'
finally:
self.help_nextset_tearDown(cur)

View File

@ -352,8 +352,7 @@ class ParseDsnTestCase(ConnectingTestCase):
"DSN with quoting parsed")
# Can't really use assertRaisesRegexp() here since we need to
# make sure that secret is *not* exposed in the error messgage
# (and it also requires python >= 2.7).
# make sure that secret is *not* exposed in the error message.
raised = False
try:
# unterminated quote after dbname:

View File

@ -27,8 +27,7 @@ import pickle
import psycopg2
import psycopg2.extensions
from testutils import (unittest, ConnectingTestCase, skip_before_postgres,
skip_if_no_getrefcount, slow, skip_if_no_superuser,
skip_if_windows)
slow, skip_if_no_superuser, skip_if_windows)
import psycopg2.extras
@ -105,7 +104,6 @@ class CursorTests(ConnectingTestCase):
self.assertEqual(b'SELECT 10.3;',
cur.mogrify("SELECT %s;", (Decimal("10.3"),)))
@skip_if_no_getrefcount
def test_mogrify_leak_on_multiple_reference(self):
# issue #81: reference leak when a parameter value is referenced
# more than once from a dict.

View File

@ -463,9 +463,9 @@ def _has_lo64(conn):
% conn.server_version)
if 'lo64' not in psycopg2.__version__:
return (False, "this psycopg build doesn't support the lo64 API")
return False, "this psycopg build doesn't support the lo64 API"
return (True, "this server and build support the lo64 API")
return True, "this server and build support the lo64 API"
def skip_if_no_lo64(f):

View File

@ -32,7 +32,6 @@ from psycopg2 import sql
class SqlFormatTests(ConnectingTestCase):
@skip_before_python(2, 7)
def test_pos(self):
s = sql.SQL("select {} from {}").format(
sql.Identifier('field'), sql.Identifier('table'))
@ -41,7 +40,7 @@ class SqlFormatTests(ConnectingTestCase):
self.assertEqual(s1, 'select "field" from "table"')
def test_pos_spec(self):
s = sql.SQL("select {0} from {1}").format(
s = sql.SQL("select {} from {}").format(
sql.Identifier('field'), sql.Identifier('table'))
s1 = s.as_string(self.conn)
self.assert_(isinstance(s1, str))
@ -61,14 +60,14 @@ class SqlFormatTests(ConnectingTestCase):
self.assertEqual(s1, 'select "field" from "table"')
def test_unicode(self):
s = sql.SQL(u"select {0} from {1}").format(
s = sql.SQL(u"select {} from {}").format(
sql.Identifier(u'field'), sql.Identifier('table'))
s1 = s.as_string(self.conn)
self.assert_(isinstance(s1, unicode))
self.assertEqual(s1, u'select "field" from "table"')
def test_compose_literal(self):
s = sql.SQL("select {0};").format(sql.Literal(dt.date(2016, 12, 31)))
s = sql.SQL("select {};").format(sql.Literal(dt.date(2016, 12, 31)))
s1 = s.as_string(self.conn)
self.assertEqual(s1, "select '2016-12-31'::date;")
@ -78,20 +77,19 @@ class SqlFormatTests(ConnectingTestCase):
self.assertEqual(s1, "select foo;")
def test_percent_escape(self):
s = sql.SQL("42 % {0}").format(sql.Literal(7))
s = sql.SQL("42 % {}").format(sql.Literal(7))
s1 = s.as_string(self.conn)
self.assertEqual(s1, "42 % 7")
def test_braces_escape(self):
s = sql.SQL("{{{0}}}").format(sql.Literal(7))
s = sql.SQL("{{{}}}").format(sql.Literal(7))
self.assertEqual(s.as_string(self.conn), "{7}")
s = sql.SQL("{{1,{0}}}").format(sql.Literal(7))
self.assertEqual(s.as_string(self.conn), "{1,7}")
def test_compose_badnargs(self):
self.assertRaises(IndexError, sql.SQL("select {0};").format)
self.assertRaises(IndexError, sql.SQL("select {};").format)
@skip_before_python(2, 7)
def test_compose_badnargs_auto(self):
self.assertRaises(IndexError, sql.SQL("select {};").format)
self.assertRaises(ValueError, sql.SQL("select {} {1};").format, 10, 20)

View File

@ -295,7 +295,6 @@ class TypesBasicTests(ConnectingTestCase):
else:
self.assertEqual(memoryview, type(o2))
@testutils.skip_before_python(2, 7)
def testAdaptMemoryview(self):
o1 = memoryview(bytearray(range(256)))
o2 = self.execute("select %s;", (o1,))

View File

@ -366,9 +366,7 @@ class HstoreTestCase(ConnectingTestCase):
from psycopg2.extras import register_hstore
register_hstore(self.conn)
ds = []
ds.append({})
ds.append({'a': 'b', 'c': None})
ds = [{}, {'a': 'b', 'c': None}]
ab = map(chr, range(32, 128))
ds.append(dict(zip(ab, ab)))

View File

@ -32,37 +32,8 @@ from functools import wraps
from testconfig import dsn, repl_dsn
if hasattr(unittest, 'skipIf'):
skip = unittest.skip
skipIf = unittest.skipIf
else:
import warnings
def skipIf(cond, msg):
def skipIf_(f):
@wraps(f)
def skipIf__(self):
if cond:
with warnings.catch_warnings():
warnings.simplefilter('always', UserWarning)
warnings.warn(msg)
return
else:
return f(self)
return skipIf__
return skipIf_
def skip(msg):
return skipIf(True, msg)
def skipTest(self, msg):
with warnings.catch_warnings():
warnings.simplefilter('always', UserWarning)
warnings.warn(msg)
return
unittest.TestCase.skipTest = skipTest
skip = unittest.skip
skipIf = unittest.skipIf
# Silence warnings caused by the stubbornness of the Python unittest
# maintainers
@ -382,16 +353,6 @@ def skip_if_green(reason):
skip_copy_if_green = skip_if_green("copy in async mode currently not supported")
def skip_if_no_getrefcount(f):
@wraps(f)
def skip_if_no_getrefcount_(self):
if not hasattr(sys, 'getrefcount'):
return self.skipTest('skipped, no sys.getrefcount()')
else:
return f(self)
return skip_if_no_getrefcount_
def skip_if_windows(f):
"""Skip a test if run on windows"""
@wraps(f)

View File

@ -4,7 +4,7 @@
# and then run "tox" from this directory.
[tox]
envlist = py26, py27
envlist = py27
[testenv]
commands = make check