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 doc/psycopg2.txt
scripts/pypi_docs_upload.py scripts/pypi_docs_upload.py
env env
.idea
.tox .tox
/rel /rel
/wheels /wheels

View File

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

View File

@ -59,7 +59,7 @@ between 8.1 and 10 are included in the module.
>>> try: >>> try:
... cur.execute("SELECT ouch FROM aargh;") ... cur.execute("SELECT ouch FROM aargh;")
... except Exception, e: ... except Exception as e:
... pass ... pass
... ...
>>> errorcodes.lookup(e.pgcode[:2]) >>> 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. 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 - Python 3 versions from 3.2 to 3.6
- PostgreSQL server versions from 7.4 to 10 - PostgreSQL server versions from 7.4 to 10
- PostgreSQL client library version from 9.1 - PostgreSQL client library version from 9.1

View File

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

View File

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

View File

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

View File

@ -196,7 +196,7 @@ def _get_json_oids(conn_or_curs, name='json'):
r = curs.fetchone() r = curs.fetchone()
# revert the status of the connection as before the command # 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() conn.rollback()
if not r: if not r:

View File

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

View File

@ -172,7 +172,7 @@ class SQL(Composable):
Example:: 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.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]),
... sql.Identifier('table')) ... sql.Identifier('table'))
>>> print(query.as_string(conn)) >>> print(query.as_string(conn))

View File

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

View File

@ -31,8 +31,8 @@
#include <stringobject.h> #include <stringobject.h>
#endif #endif
#if PY_VERSION_HEX < 0x02060000 #if PY_VERSION_HEX < 0x02070000
# error "psycopg requires Python >= 2.6" # error "psycopg requires Python >= 2.7"
#endif #endif
/* hash() return size changed around version 3.2a4 on 64bit platforms. Before /* 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; typedef unsigned long Py_uhash_t;
#endif #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: */ /* FORMAT_CODE_PY_SSIZE_T is for Py_ssize_t: */
#define FORMAT_CODE_PY_SSIZE_T "%" PY_FORMAT_SIZE_T "d" #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 # DECLARE zz INSENSITIVE SCROLL CURSOR WITH HOLD FOR
# SELECT now(); # SELECT now();
# FOR READ ONLY;""", async = 1) # FOR READ ONLY;""", async = 1)
curs.execute("SELECT now() AS foo", async=1); curs.execute("SELECT now() AS foo", async=1)
sleep(curs) sleep(curs)
print curs.fetchall() print curs.fetchall()
#curs.execute(""" #curs.execute("""
# FETCH FORWARD 1 FROM zz;""", async = 1) # 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() print curs.fetchall()
curs.execute("SELECT now() AS bar"); curs.execute("SELECT now() AS bar")
sleep(curs) sleep(curs)

View File

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

View File

@ -43,7 +43,7 @@ def main():
dump(i, opt) dump(i, opt)
f1 = open('debug-%02d.txt' % (opt.nruns - 1)).readlines() 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, for line in difflib.unified_diff(f1, f2,
"run %d" % (opt.nruns - 1), "run %d" % opt.nruns): "run %d" % (opt.nruns - 1), "run %d" % opt.nruns):
sys.stdout.write(line) sys.stdout.write(line)
@ -52,7 +52,7 @@ def main():
if opt.objs: if opt.objs:
f1 = open('objs-%02d.txt' % (opt.nruns - 1)).readlines() 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, for line in difflib.unified_diff(f1, f2,
"run %d" % (opt.nruns - 1), "run %d" % opt.nruns): "run %d" % (opt.nruns - 1), "run %d" % opt.nruns):
sys.stdout.write(line) 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 License :: OSI Approved :: Zope Public License
Programming Language :: Python Programming Language :: Python
Programming Language :: Python :: 2 Programming Language :: Python :: 2
Programming Language :: Python :: 2.6
Programming Language :: Python :: 2.7 Programming Language :: Python :: 2.7
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Programming Language :: Python :: 3.2 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 # Support unicode paths, if this version of Python provides the
# necessary infrastructure: # necessary infrastructure:
if sys.version_info[0] < 3 \ if sys.version_info[0] < 3:
and hasattr(sys, 'getfilesystemencoding'):
pg_config_path = pg_config_path.encode( pg_config_path = pg_config_path.encode(
sys.getfilesystemencoding()) sys.getfilesystemencoding())
@ -297,7 +295,7 @@ class psycopg_build_ext(build_ext):
# For Python versions that use MSVC compiler 2008, re-insert the # For Python versions that use MSVC compiler 2008, re-insert the
# manifest into the resulting .pyd file. # 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() platform = get_platform()
# Default to the x86 manifest # Default to the x86 manifest
manifest = '_psycopg.vc9.x86.manifest' manifest = '_psycopg.vc9.x86.manifest'
@ -319,7 +317,6 @@ class psycopg_build_ext(build_ext):
def finalize_win32(self): def finalize_win32(self):
"""Finalize build system configuration on win32 platform.""" """Finalize build system configuration on win32 platform."""
sysVer = sys.version_info[:2]
# Add compiler-specific arguments: # Add compiler-specific arguments:
extra_compiler_args = [] extra_compiler_args = []
@ -335,17 +332,6 @@ class psycopg_build_ext(build_ext):
# API code. # API code.
extra_compiler_args.append('-fno-strict-aliasing') 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 for extension in ext: # ext is a global list of Extension objects
extension.extra_compile_args.extend(extra_compiler_args) extension.extra_compile_args.extend(extra_compiler_args)
# End of add-compiler-specific arguments section. # 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 # *at least* PostgreSQL 7.4 is available (this is the only
# 7.x series supported by psycopg 2) # 7.x series supported by psycopg 2)
pgversion = pg_config_helper.query("version").split()[1] pgversion = pg_config_helper.query("version").split()[1]
except: except Exception:
pgversion = "7.4.0" pgversion = "7.4.0"
verre = re.compile( verre = re.compile(
@ -619,7 +605,7 @@ try:
f = open("README.rst") f = open("README.rst")
readme = f.read() readme = f.read()
f.close() f.close()
except: except Exception:
print("failed to read readme: ignoring...") print("failed to read readme: ignoring...")
readme = __doc__ readme = __doc__
@ -633,6 +619,7 @@ setup(name="psycopg2",
download_url=download_url, download_url=download_url,
license="LGPL with exceptions or ZPL", license="LGPL with exceptions or ZPL",
platforms=["any"], platforms=["any"],
python_requires='>=2.7,!=3.0.*,!=3.1.*',
description=readme.split("\n")[0], description=readme.split("\n")[0],
long_description="\n".join(readme.split("\n")[2:]).lstrip(), long_description="\n".join(readme.split("\n")[2:]).lstrip(),
classifiers=[x for x in classifiers.split("\n") if x], classifiers=[x for x in classifiers.split("\n") if x],

View File

@ -762,7 +762,7 @@ class DatabaseAPI20Test(unittest.TestCase):
names=cur.fetchall() names=cur.fetchall()
assert len(names) == len(self.samples) assert len(names) == len(self.samples)
s=cur.nextset() 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: finally:
self.help_nextset_tearDown(cur) self.help_nextset_tearDown(cur)

View File

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

View File

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

View File

@ -463,9 +463,9 @@ def _has_lo64(conn):
% conn.server_version) % conn.server_version)
if 'lo64' not in psycopg2.__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): def skip_if_no_lo64(f):

View File

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

View File

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

View File

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

View File

@ -32,37 +32,8 @@ from functools import wraps
from testconfig import dsn, repl_dsn from testconfig import dsn, repl_dsn
if hasattr(unittest, 'skipIf'): skip = unittest.skip
skip = unittest.skip skipIf = unittest.skipIf
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
# Silence warnings caused by the stubbornness of the Python unittest # Silence warnings caused by the stubbornness of the Python unittest
# maintainers # maintainers
@ -382,16 +353,6 @@ def skip_if_green(reason):
skip_copy_if_green = skip_if_green("copy in async mode currently not supported") 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): def skip_if_windows(f):
"""Skip a test if run on windows""" """Skip a test if run on windows"""
@wraps(f) @wraps(f)

View File

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