diff options
| author | Jon Dufresne <jon.dufresne@gmail.com> | 2017-12-10 18:35:41 -0800 |
|---|---|---|
| committer | Jon Dufresne <jon.dufresne@gmail.com> | 2017-12-11 20:26:58 -0800 |
| commit | 8ad2098b74ee90f341e69937a1503e29decf4594 (patch) | |
| tree | ca6bb581c11fcb1a4cbe56b24aa9b83662293f3a /lib | |
| parent | f35465231f76039fae8677d48beacbdd2479095a (diff) | |
| download | psycopg2-8ad2098b74ee90f341e69937a1503e29decf4594.tar.gz | |
Drop 2to3 build step; make all code compatible with all Pythons
Make all library code compatible with both Python 2 and Python 3. Helps
move to modern Python idioms. Can now write for Python 3 (with
workarounds for Python 2) instead of the other way around.
In the future, when it is eventually time to drop Python 2, the library
will be in a better position to remove workarounds
Added a very small comparability module compat.py where required. It
includes definitions for:
- text_type -- A type. str on Python 3. unicode on Python 2.
- string_types -- A tuple. Contains only str on Python 3. Contains str &
unicode on Python 2.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/_ipaddress.py | 5 | ||||
| -rw-r--r-- | lib/_range.py | 11 | ||||
| -rw-r--r-- | lib/compat.py | 10 | ||||
| -rw-r--r-- | lib/errorcodes.py | 2 | ||||
| -rw-r--r-- | lib/extensions.py | 6 | ||||
| -rw-r--r-- | lib/extras.py | 14 | ||||
| -rw-r--r-- | lib/pool.py | 4 | ||||
| -rw-r--r-- | lib/sql.py | 9 |
8 files changed, 39 insertions, 22 deletions
diff --git a/lib/_ipaddress.py b/lib/_ipaddress.py index ee05a26..beb2fb3 100644 --- a/lib/_ipaddress.py +++ b/lib/_ipaddress.py @@ -25,6 +25,7 @@ from psycopg2.extensions import ( new_type, new_array_type, register_type, register_adapter, QuotedString) +from psycopg2.compat import text_type # The module is imported on register_ipaddress ipaddress = None @@ -76,13 +77,13 @@ def cast_interface(s, cur=None): if s is None: return None # Py2 version force the use of unicode. meh. - return ipaddress.ip_interface(unicode(s)) + return ipaddress.ip_interface(text_type(s)) def cast_network(s, cur=None): if s is None: return None - return ipaddress.ip_network(unicode(s)) + return ipaddress.ip_network(text_type(s)) def adapt_ipaddress(obj): diff --git a/lib/_range.py b/lib/_range.py index c1facc0..fd15a76 100644 --- a/lib/_range.py +++ b/lib/_range.py @@ -29,6 +29,7 @@ import re from psycopg2._psycopg import ProgrammingError, InterfaceError from psycopg2.extensions import ISQLQuote, adapt, register_adapter from psycopg2.extensions import new_type, new_array_type, register_type +from psycopg2.compat import string_types class Range(object): @@ -126,9 +127,13 @@ class Range(object): return True - def __nonzero__(self): + def __bool__(self): return self._bounds is not None + def __nonzero__(self): + # Python 2 compatibility + return type(self).__bool__(self) + def __eq__(self, other): if not isinstance(other, Range): return False @@ -296,7 +301,7 @@ class RangeCaster(object): # an implementation detail and is not documented. It is currently used # for the numeric ranges. self.adapter = None - if isinstance(pgrange, basestring): + if isinstance(pgrange, string_types): self.adapter = type(pgrange, (RangeAdapter,), {}) self.adapter.name = pgrange else: @@ -313,7 +318,7 @@ class RangeCaster(object): self.range = None try: - if isinstance(pyrange, basestring): + if isinstance(pyrange, string_types): self.range = type(pyrange, (Range,), {}) if issubclass(pyrange, Range) and pyrange is not Range: self.range = pyrange diff --git a/lib/compat.py b/lib/compat.py new file mode 100644 index 0000000..cfd5a88 --- /dev/null +++ b/lib/compat.py @@ -0,0 +1,10 @@ +import sys + +if sys.version_info[0] == 2: + # Python 2 + string_types = basestring, + text_type = unicode +else: + # Python 3 + string_types = str, + text_type = str diff --git a/lib/errorcodes.py b/lib/errorcodes.py index 24fcf25..b8742f5 100644 --- a/lib/errorcodes.py +++ b/lib/errorcodes.py @@ -40,7 +40,7 @@ def lookup(code, _cache={}): # Generate the lookup map at first usage. tmp = {} - for k, v in globals().iteritems(): + for k, v in globals().items(): if isinstance(v, str) and len(v) in (2, 5): tmp[v] = k diff --git a/lib/extensions.py b/lib/extensions.py index d15f76c..8644e41 100644 --- a/lib/extensions.py +++ b/lib/extensions.py @@ -163,7 +163,7 @@ def make_dsn(dsn=None, **kwargs): kwargs['dbname'] = kwargs.pop('database') # Drop the None arguments - kwargs = {k: v for (k, v) in kwargs.iteritems() if v is not None} + kwargs = {k: v for (k, v) in kwargs.items() if v is not None} if dsn is not None: tmp = parse_dsn(dsn) @@ -171,7 +171,7 @@ def make_dsn(dsn=None, **kwargs): kwargs = tmp dsn = " ".join(["%s=%s" % (k, _param_escape(str(v))) - for (k, v) in kwargs.iteritems()]) + for (k, v) in kwargs.items()]) # verify that the returned dsn is valid parse_dsn(dsn) @@ -216,7 +216,7 @@ del Range # When the encoding is set its name is cleaned up from - and _ and turned # uppercase, so an encoding not respecting these rules wouldn't be found in the # encodings keys and would raise an exception with the unicode typecaster -for k, v in encodings.items(): +for k, v in list(encodings.items()): k = k.replace('_', '').replace('-', '').upper() encodings[k] = v diff --git a/lib/extras.py b/lib/extras.py index 64467a8..1b0b2b6 100644 --- a/lib/extras.py +++ b/lib/extras.py @@ -318,14 +318,14 @@ class NamedTupleCursor(_cursor): nt = self.Record if nt is None: nt = self.Record = self._make_nt() - return map(nt._make, ts) + return list(map(nt._make, ts)) def fetchall(self): ts = super(NamedTupleCursor, self).fetchall() nt = self.Record if nt is None: nt = self.Record = self._make_nt() - return map(nt._make, ts) + return list(map(nt._make, ts)) def __iter__(self): try: @@ -566,7 +566,7 @@ class ReplicationCursor(_replicationCursor): "cannot specify output plugin options for physical replication") command += " (" - for k, v in options.iteritems(): + for k, v in options.items(): if not command.endswith('('): command += ", " command += "%s %s" % (quote_ident(k, self), _A(str(v))) @@ -762,7 +762,7 @@ class HstoreAdapter(object): adapt = _ext.adapt rv = [] - for k, v in self.wrapped.iteritems(): + for k, v in self.wrapped.items(): k = adapt(k) k.prepare(self.conn) k = k.getquoted() @@ -784,9 +784,9 @@ class HstoreAdapter(object): if not self.wrapped: return b"''::hstore" - k = _ext.adapt(self.wrapped.keys()) + k = _ext.adapt(list(self.wrapped.keys())) k.prepare(self.conn) - v = _ext.adapt(self.wrapped.values()) + v = _ext.adapt(list(self.wrapped.values())) v.prepare(self.conn) return b"hstore(" + k.getquoted() + b", " + v.getquoted() + b")" @@ -1112,7 +1112,7 @@ def _paginate(seq, page_size): it = iter(seq) while 1: try: - for i in xrange(page_size): + for i in range(page_size): page.append(next(it)) yield page page = [] diff --git a/lib/pool.py b/lib/pool.py index a91c9cc..6c26f7d 100644 --- a/lib/pool.py +++ b/lib/pool.py @@ -209,8 +209,8 @@ class PersistentConnectionPool(AbstractConnectionPool): # we we'll need the thread module, to determine thread ids, so we # import it here and copy it in an instance variable - import thread as _thread # work around for 2to3 bug - see ticket #348 - self.__thread = _thread + import thread + self.__thread = thread def getconn(self): """Generate thread id and return a connection.""" @@ -27,6 +27,7 @@ import sys import string from psycopg2 import extensions as ext +from psycopg2.compat import string_types _formatter = string.Formatter() @@ -147,7 +148,7 @@ class Composed(Composable): "foo", "bar" """ - if isinstance(joiner, basestring): + if isinstance(joiner, string_types): joiner = SQL(joiner) elif not isinstance(joiner, SQL): raise TypeError( @@ -179,7 +180,7 @@ class SQL(Composable): select "foo", "bar" from "table" """ def __init__(self, string): - if not isinstance(string, basestring): + if not isinstance(string, string_types): raise TypeError("SQL values must be strings") super(SQL, self).__init__(string) @@ -308,7 +309,7 @@ class Identifier(Composable): """ def __init__(self, string): - if not isinstance(string, basestring): + if not isinstance(string, string_types): raise TypeError("SQL identifiers must be strings") super(Identifier, self).__init__(string) @@ -395,7 +396,7 @@ class Placeholder(Composable): """ def __init__(self, name=None): - if isinstance(name, basestring): + if isinstance(name, string_types): if ')' in name: raise ValueError("invalid name: %r" % name) |
