Merge branch 'rm-eol'

Fix #626, close #628.
This commit is contained in:
Daniele Varrazzo 2017-11-28 16:27:41 +00:00
commit 3e52b5445b
29 changed files with 89 additions and 156 deletions

View File

@ -15,7 +15,7 @@ environment:
# http://www.appveyor.com/docs/installed-software#python # http://www.appveyor.com/docs/installed-software#python
# Py 2.7 = VS Ver. 9.0 (VS 2008) # Py 2.7 = VS Ver. 9.0 (VS 2008)
# Py 3.3, 3.4 = VS Ver. 10.0 (VS 2010) # Py 3.4 = VS Ver. 10.0 (VS 2010)
# Py 3.5, 3.6 = VS Ver. 14.0 (VS 2015) # Py 3.5, 3.6 = VS Ver. 14.0 (VS 2015)
- PYTHON: C:\Python27-x64 - PYTHON: C:\Python27-x64
@ -51,15 +51,6 @@ environment:
PYTHON_ARCH: 32 PYTHON_ARCH: 32
VS_VER: 10.0 VS_VER: 10.0
- PYTHON: C:\Python33-x64
DISTUTILS_USE_SDK: '1'
PYTHON_ARCH: 64
VS_VER: 10.0
- PYTHON: C:\Python33
PYTHON_ARCH: 32
VS_VER: 10.0
PSYCOPG2_TESTDB: psycopg2_test PSYCOPG2_TESTDB: psycopg2_test
PSYCOPG2_TESTDB_USER: postgres PSYCOPG2_TESTDB_USER: postgres
PSYCOPG2_TESTDB_PASSWORD: Password12! PSYCOPG2_TESTDB_PASSWORD: Password12!

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,11 +7,8 @@ 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.2
install: install:
- python setup.py install - python setup.py install

8
NEWS
View File

@ -1,6 +1,14 @@
Current release Current release
--------------- ---------------
What's new in psycopg 2.8
-------------------------
Other changes:
- Dropped support for Python 2.6, 3.2, 3.3.
What's new in psycopg 2.7.4 What's new in psycopg 2.7.4
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^

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,8 +17,8 @@ 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.4 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

@ -457,14 +457,12 @@ the connection or globally: see the function
Binary adaptation Binary adaptation
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
Python types representing binary objects are converted into Python types representing binary objects are converted into PostgreSQL binary
PostgreSQL binary string syntax, suitable for :sql:`bytea` fields. Such string syntax, suitable for :sql:`bytea` fields. Such types are `buffer`
types are `buffer` (only available in Python 2), `memoryview` (available (only available in Python 2), `memoryview`, `bytearray`, and `bytes` (only in
from Python 2.7), `bytearray` (available from Python 2.6) and `bytes` Python 3: the name is available in Python 2 but it's only an alias for the
(only from Python 3: the name is available from Python 2.6 but it's only an type `!str`). Any object implementing the `Revised Buffer Protocol`__ should
alias for the type `!str`). Any object implementing the `Revised Buffer be usable as binary type. Received data is returned as `!buffer` (in Python 2)
Protocol`__ should be usable as binary type where the protocol is supported
(i.e. from Python 2.6). Received data is returned as `!buffer` (in Python 2)
or `!memoryview` (in Python 3). or `!memoryview` (in Python 3).
.. __: http://www.python.org/dev/peps/pep-3118/ .. __: http://www.python.org/dev/peps/pep-3118/

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

@ -194,7 +194,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

@ -181,11 +181,8 @@ class Range(object):
return self.__gt__(other) return self.__gt__(other)
def __getstate__(self): def __getstate__(self):
return dict( return {slot: getattr(self, slot)
(slot, getattr(self, slot)) for slot in self.__slots__ if hasattr(self, slot)}
for slot in self.__slots__
if hasattr(self, slot)
)
def __setstate__(self, state): def __setstate__(self, state):
for slot, value in state.items(): for slot, value in state.items():

View File

@ -163,7 +163,7 @@ def make_dsn(dsn=None, **kwargs):
kwargs['dbname'] = kwargs.pop('database') kwargs['dbname'] = kwargs.pop('database')
# Drop the None arguments # Drop the None arguments
kwargs = dict((k, v) for (k, v) in kwargs.iteritems() if v is not None) kwargs = {k: v for (k, v) in kwargs.iteritems() if v is not None}
if dsn is not None: if dsn is not None:
tmp = parse_dsn(dsn) tmp = parse_dsn(dsn)

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

@ -203,12 +203,12 @@ class SQL(Composable):
:rtype: `Composed` :rtype: `Composed`
The method is similar to the Python `str.format()` method: the string The method is similar to the Python `str.format()` method: the string
template supports auto-numbered (``{}``, only available from Python template supports auto-numbered (``{}``), numbered (``{0}``,
2.7), numbered (``{0}``, ``{1}``...), and named placeholders ``{1}``...), and named placeholders (``{name}``), with positional
(``{name}``), with positional arguments replacing the numbered arguments replacing the numbered placeholders and keywords replacing
placeholders and keywords replacing the named ones. However placeholder the named ones. However placeholder modifiers (``{0!r}``, ``{0:<10}``)
modifiers (``{0!r}``, ``{0:<10}``) are not supported. Only are not supported. Only `!Composable` objects can be passed to the
`!Composable` objects can be passed to the template. template.
Example:: Example::

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,10 @@
#include <stringobject.h> #include <stringobject.h>
#endif #endif
#if PY_VERSION_HEX < 0x02060000 #if ((PY_VERSION_HEX < 0x02070000) \
# error "psycopg requires Python >= 2.6" || ((PY_VERSION_HEX >= 0x03000000) \
&& (PY_VERSION_HEX < 0x03040000)) )
# error "psycopg requires Python 2.7 or 3.4+"
#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 +46,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,11 +76,8 @@ 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.3
Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.6
@ -215,8 +212,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 +293,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 == (2, 7):
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 +315,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 +330,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 +398,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 +603,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 +617,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.*,!=3.2.*,!=3.3.*',
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

@ -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'))
@ -91,7 +90,6 @@ class SqlFormatTests(ConnectingTestCase):
def test_compose_badnargs(self): def test_compose_badnargs(self):
self.assertRaises(IndexError, sql.SQL("select {0};").format) self.assertRaises(IndexError, sql.SQL("select {0};").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

@ -365,9 +365,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,38 +32,6 @@ from functools import wraps
from testconfig import dsn, repl_dsn 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
# Silence warnings caused by the stubbornness of the Python unittest # Silence warnings caused by the stubbornness of the Python unittest
# maintainers # maintainers
# http://bugs.python.org/issue9424 # http://bugs.python.org/issue9424

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