summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/__init__.py2
-rw-r--r--lib/sqlalchemy/connectors/mxodbc.py2
-rw-r--r--lib/sqlalchemy/connectors/pyodbc.py32
-rw-r--r--lib/sqlalchemy/dialects/firebird/base.py4
-rw-r--r--lib/sqlalchemy/dialects/informix/base.py5
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py21
-rw-r--r--lib/sqlalchemy/dialects/mssql/information_schema.py5
-rw-r--r--lib/sqlalchemy/dialects/mssql/pyodbc.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py33
-rw-r--r--lib/sqlalchemy/dialects/mysql/cymysql.py10
-rw-r--r--lib/sqlalchemy/dialects/mysql/oursql.py19
-rw-r--r--lib/sqlalchemy/dialects/mysql/zxjdbc.py2
-rw-r--r--lib/sqlalchemy/dialects/oracle/base.py30
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py87
-rw-r--r--lib/sqlalchemy/dialects/oracle/zxjdbc.py4
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py58
-rw-r--r--lib/sqlalchemy/dialects/postgresql/hstore.py41
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2.py35
-rw-r--r--lib/sqlalchemy/dialects/sqlite/base.py4
-rw-r--r--lib/sqlalchemy/dialects/sqlite/pysqlite.py6
-rw-r--r--lib/sqlalchemy/dialects/sybase/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/sybase/base.py36
-rw-r--r--lib/sqlalchemy/engine/base.py38
-rw-r--r--lib/sqlalchemy/engine/ddl.py4
-rw-r--r--lib/sqlalchemy/engine/default.py55
-rw-r--r--lib/sqlalchemy/engine/reflection.py21
-rw-r--r--lib/sqlalchemy/engine/result.py38
-rw-r--r--lib/sqlalchemy/engine/strategies.py20
-rw-r--r--lib/sqlalchemy/engine/url.py13
-rw-r--r--lib/sqlalchemy/event.py12
-rw-r--r--lib/sqlalchemy/exc.py2
-rw-r--r--lib/sqlalchemy/ext/associationproxy.py57
-rw-r--r--lib/sqlalchemy/ext/declarative/base.py4
-rw-r--r--lib/sqlalchemy/ext/declarative/clsregistry.py6
-rw-r--r--lib/sqlalchemy/ext/orderinglist.py8
-rw-r--r--lib/sqlalchemy/ext/serializer.py19
-rw-r--r--lib/sqlalchemy/orm/__init__.py2
-rw-r--r--lib/sqlalchemy/orm/attributes.py9
-rw-r--r--lib/sqlalchemy/orm/collections.py68
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py2
-rw-r--r--lib/sqlalchemy/orm/evaluator.py18
-rw-r--r--lib/sqlalchemy/orm/identity.py41
-rw-r--r--lib/sqlalchemy/orm/instrumentation.py32
-rw-r--r--lib/sqlalchemy/orm/interfaces.py9
-rw-r--r--lib/sqlalchemy/orm/loading.py12
-rw-r--r--lib/sqlalchemy/orm/mapper.py25
-rw-r--r--lib/sqlalchemy/orm/persistence.py24
-rw-r--r--lib/sqlalchemy/orm/properties.py4
-rw-r--r--lib/sqlalchemy/orm/query.py177
-rw-r--r--lib/sqlalchemy/orm/session.py12
-rw-r--r--lib/sqlalchemy/orm/strategies.py64
-rw-r--r--lib/sqlalchemy/orm/unitofwork.py4
-rw-r--r--lib/sqlalchemy/orm/util.py47
-rw-r--r--lib/sqlalchemy/pool.py12
-rw-r--r--lib/sqlalchemy/processors.py6
-rw-r--r--lib/sqlalchemy/schema.py88
-rw-r--r--lib/sqlalchemy/sql/__init__.py2
-rw-r--r--lib/sqlalchemy/sql/compiler.py37
-rw-r--r--lib/sqlalchemy/sql/expression.py106
-rw-r--r--lib/sqlalchemy/sql/functions.py3
-rw-r--r--lib/sqlalchemy/sql/operators.py17
-rw-r--r--lib/sqlalchemy/sql/util.py14
-rw-r--r--lib/sqlalchemy/sql/visitors.py12
-rw-r--r--lib/sqlalchemy/testing/__init__.py2
-rw-r--r--lib/sqlalchemy/testing/assertions.py31
-rw-r--r--lib/sqlalchemy/testing/assertsql.py10
-rw-r--r--lib/sqlalchemy/testing/engines.py39
-rw-r--r--lib/sqlalchemy/testing/entities.py4
-rw-r--r--lib/sqlalchemy/testing/exclusions.py10
-rw-r--r--lib/sqlalchemy/testing/fixtures.py16
-rw-r--r--lib/sqlalchemy/testing/plugin/noseplugin.py16
-rw-r--r--lib/sqlalchemy/testing/profiling.py10
-rw-r--r--lib/sqlalchemy/testing/schema.py4
-rw-r--r--lib/sqlalchemy/testing/suite/test_ddl.py2
-rw-r--r--lib/sqlalchemy/testing/suite/test_reflection.py4
-rw-r--r--lib/sqlalchemy/testing/suite/test_types.py21
-rw-r--r--lib/sqlalchemy/testing/util.py18
-rw-r--r--lib/sqlalchemy/testing/warnings.py2
-rw-r--r--lib/sqlalchemy/types.py107
-rw-r--r--lib/sqlalchemy/util/__init__.py7
-rw-r--r--lib/sqlalchemy/util/_collections.py87
-rw-r--r--lib/sqlalchemy/util/compat.py204
-rw-r--r--lib/sqlalchemy/util/deprecations.py2
-rw-r--r--lib/sqlalchemy/util/langhelpers.py157
84 files changed, 1246 insertions, 1091 deletions
diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py
index 21e06f548..2c805e607 100644
--- a/lib/sqlalchemy/__init__.py
+++ b/lib/sqlalchemy/__init__.py
@@ -120,7 +120,7 @@ from .engine import create_engine, engine_from_config
__all__ = sorted(name for name, obj in locals().items()
if not (name.startswith('_') or _inspect.ismodule(obj)))
-__version__ = '0.8.2'
+__version__ = '0.9.0'
del _inspect, sys
diff --git a/lib/sqlalchemy/connectors/mxodbc.py b/lib/sqlalchemy/connectors/mxodbc.py
index db297c9ab..ebdcd2758 100644
--- a/lib/sqlalchemy/connectors/mxodbc.py
+++ b/lib/sqlalchemy/connectors/mxodbc.py
@@ -82,7 +82,7 @@ class MxODBCConnector(Connector):
category=errorclass,
stacklevel=2)
else:
- raise errorclass, errorvalue
+ raise errorclass(errorvalue)
return error_handler
def create_connect_args(self, url):
diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py
index f1a979286..6b4e3036d 100644
--- a/lib/sqlalchemy/connectors/pyodbc.py
+++ b/lib/sqlalchemy/connectors/pyodbc.py
@@ -5,20 +5,23 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from . import Connector
-from ..util import asbool
+from .. import util
+
import sys
import re
-import urllib
class PyODBCConnector(Connector):
driver = 'pyodbc'
supports_sane_multi_rowcount = False
- # PyODBC unicode is broken on UCS-4 builds
- supports_unicode = sys.maxunicode == 65535
- supports_unicode_statements = supports_unicode
+
+ if util.py2k:
+ # PyODBC unicode is broken on UCS-4 builds
+ supports_unicode = sys.maxunicode == 65535
+ supports_unicode_statements = supports_unicode
+
supports_native_decimal = True
default_paramstyle = 'named'
@@ -56,10 +59,10 @@ class PyODBCConnector(Connector):
connect_args = {}
for param in ('ansi', 'unicode_results', 'autocommit'):
if param in keys:
- connect_args[param] = asbool(keys.pop(param))
+ connect_args[param] = util.asbool(keys.pop(param))
if 'odbc_connect' in keys:
- connectors = [urllib.unquote_plus(keys.pop('odbc_connect'))]
+ connectors = [util.unquote_plus(keys.pop('odbc_connect'))]
else:
dsn_connection = 'dsn' in keys or \
('host' in keys and 'database' not in keys)
@@ -91,7 +94,7 @@ class PyODBCConnector(Connector):
connectors.append("AutoTranslate=%s" %
keys.pop("odbc_autotranslate"))
- connectors.extend(['%s=%s' % (k, v) for k, v in keys.iteritems()])
+ connectors.extend(['%s=%s' % (k, v) for k, v in keys.items()])
return [[";".join(connectors)], connect_args]
def is_disconnect(self, e, connection, cursor):
@@ -121,18 +124,19 @@ class PyODBCConnector(Connector):
self.freetds_driver_version = dbapi_con.getinfo(
pyodbc.SQL_DRIVER_VER)
- # the "Py2K only" part here is theoretical.
- # have not tried pyodbc + python3.1 yet.
- # Py2K
self.supports_unicode_statements = (
- not self.freetds and not self.easysoft)
+ not util.py2k or
+ (not self.freetds and not self.easysoft)
+ )
+
if self._user_supports_unicode_binds is not None:
self.supports_unicode_binds = self._user_supports_unicode_binds
- else:
+ elif util.py2k:
self.supports_unicode_binds = (
not self.freetds or self.freetds_driver_version >= '0.91'
) and not self.easysoft
- # end Py2K
+ else:
+ self.supports_unicode_binds = True
# run other initialization which asks for user name, etc.
super(PyODBCConnector, self).initialize(connection)
diff --git a/lib/sqlalchemy/dialects/firebird/base.py b/lib/sqlalchemy/dialects/firebird/base.py
index 95196f44c..bb60a591e 100644
--- a/lib/sqlalchemy/dialects/firebird/base.py
+++ b/lib/sqlalchemy/dialects/firebird/base.py
@@ -685,7 +685,7 @@ class FBDialect(default.DefaultDialect):
self.normalize_name(row['fname']))
fk['referred_columns'].append(
self.normalize_name(row['targetfname']))
- return fks.values()
+ return list(fks.values())
@reflection.cache
def get_indexes(self, connection, table_name, schema=None, **kw):
@@ -716,7 +716,7 @@ class FBDialect(default.DefaultDialect):
indexrec['column_names'].append(
self.normalize_name(row['field_name']))
- return indexes.values()
+ return list(indexes.values())
def do_execute(self, cursor, statement, parameters, context=None):
# kinterbase does not accept a None, but wants an empty list
diff --git a/lib/sqlalchemy/dialects/informix/base.py b/lib/sqlalchemy/dialects/informix/base.py
index 77361a5d0..e13ea8819 100644
--- a/lib/sqlalchemy/dialects/informix/base.py
+++ b/lib/sqlalchemy/dialects/informix/base.py
@@ -24,6 +24,7 @@ from sqlalchemy import sql, schema, exc, pool, util
from sqlalchemy.sql import compiler, text
from sqlalchemy.engine import default, reflection
from sqlalchemy import types as sqltypes
+from functools import reduce
RESERVED_WORDS = set(
["abs", "absolute", "access", "access_method", "acos", "active", "add",
@@ -298,7 +299,7 @@ class InfoDDLCompiler(compiler.DDLCompiler):
def get_column_default_string(self, column):
if (isinstance(column.server_default, schema.DefaultClause) and
- isinstance(column.server_default.arg, basestring)):
+ isinstance(column.server_default.arg, util.string_types)):
if isinstance(column.type, (sqltypes.Integer, sqltypes.Numeric)):
return self.sql_compiler.process(text(column.server_default.arg))
@@ -506,7 +507,7 @@ class InformixDialect(default.DefaultDialect):
if remote_column not in remote_cols:
remote_cols.append(remote_column)
- return fkeys.values()
+ return list(fkeys.values())
@reflection.cache
def get_pk_constraint(self, connection, table_name, schema=None, **kw):
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index fc952f4b5..3c329fe5e 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -295,7 +295,7 @@ class _MSDate(sqltypes.Date):
def process(value):
if isinstance(value, datetime.datetime):
return value.date()
- elif isinstance(value, basestring):
+ elif isinstance(value, util.string_types):
return datetime.date(*[
int(x or 0)
for x in self._reg.match(value).groups()
@@ -328,7 +328,7 @@ class TIME(sqltypes.TIME):
def process(value):
if isinstance(value, datetime.datetime):
return value.time()
- elif isinstance(value, basestring):
+ elif isinstance(value, util.string_types):
return datetime.time(*[
int(x or 0)
for x in self._reg.match(value).groups()])
@@ -1008,7 +1008,7 @@ class MSDDLCompiler(compiler.DDLCompiler):
# handle other included columns
if index.kwargs.get("mssql_include"):
inclusions = [index.table.c[col]
- if isinstance(col, basestring) else col
+ if isinstance(col, util.string_types) else col
for col in index.kwargs["mssql_include"]]
text += " INCLUDE (%s)" \
@@ -1109,7 +1109,7 @@ class MSDialect(default.DefaultDialect):
query_timeout=None,
use_scope_identity=True,
max_identifier_length=None,
- schema_name=u"dbo", **opts):
+ schema_name="dbo", **opts):
self.query_timeout = int(query_timeout or 0)
self.schema_name = schema_name
@@ -1129,7 +1129,7 @@ class MSDialect(default.DefaultDialect):
def initialize(self, connection):
super(MSDialect, self).initialize(connection)
- if self.server_version_info[0] not in range(8, 17):
+ if self.server_version_info[0] not in list(range(8, 17)):
# FreeTDS with version 4.2 seems to report here
# a number like "95.10.255". Don't know what
# that is. So emit warning.
@@ -1156,7 +1156,7 @@ class MSDialect(default.DefaultDialect):
try:
default_schema_name = connection.scalar(query, name=user_name)
if default_schema_name is not None:
- return unicode(default_schema_name)
+ return util.text_type(default_schema_name)
except:
pass
return self.schema_name
@@ -1172,6 +1172,7 @@ class MSDialect(default.DefaultDialect):
columns = ischema.columns
whereclause = self._unicode_cast(columns.c.table_name) == tablename
+
if owner:
whereclause = sql.and_(whereclause,
columns.c.table_schema == owner)
@@ -1194,7 +1195,7 @@ class MSDialect(default.DefaultDialect):
s = sql.select([tables.c.table_name],
sql.and_(
tables.c.table_schema == owner,
- tables.c.table_type == u'BASE TABLE'
+ tables.c.table_type == 'BASE TABLE'
),
order_by=[tables.c.table_name]
)
@@ -1208,7 +1209,7 @@ class MSDialect(default.DefaultDialect):
s = sql.select([tables.c.table_name],
sql.and_(
tables.c.table_schema == owner,
- tables.c.table_type == u'VIEW'
+ tables.c.table_type == 'VIEW'
),
order_by=[tables.c.table_name]
)
@@ -1273,7 +1274,7 @@ class MSDialect(default.DefaultDialect):
if row['index_id'] in indexes:
indexes[row['index_id']]['column_names'].append(row['name'])
- return indexes.values()
+ return list(indexes.values())
@reflection.cache
@_db_plus_owner
@@ -1480,4 +1481,4 @@ class MSDialect(default.DefaultDialect):
local_cols.append(scol)
remote_cols.append(rcol)
- return fkeys.values()
+ return list(fkeys.values())
diff --git a/lib/sqlalchemy/dialects/mssql/information_schema.py b/lib/sqlalchemy/dialects/mssql/information_schema.py
index 80e59d323..a7628f213 100644
--- a/lib/sqlalchemy/dialects/mssql/information_schema.py
+++ b/lib/sqlalchemy/dialects/mssql/information_schema.py
@@ -9,6 +9,7 @@
from ... import Table, MetaData, Column
from ...types import String, Unicode, Integer, TypeDecorator
from ... import cast
+from ... import util
ischema = MetaData()
@@ -17,10 +18,8 @@ class CoerceUnicode(TypeDecorator):
impl = Unicode
def process_bind_param(self, value, dialect):
- # Py2K
- if isinstance(value, str):
+ if util.py2k and isinstance(value, util.binary_type):
value = value.decode(dialect.encoding)
- # end Py2K
return value
def bind_expression(self, bindvalue):
diff --git a/lib/sqlalchemy/dialects/mssql/pyodbc.py b/lib/sqlalchemy/dialects/mssql/pyodbc.py
index beb6066f5..5a359d179 100644
--- a/lib/sqlalchemy/dialects/mssql/pyodbc.py
+++ b/lib/sqlalchemy/dialects/mssql/pyodbc.py
@@ -219,7 +219,7 @@ class MSExecutionContext_pyodbc(MSExecutionContext):
# without closing it (FreeTDS particularly)
row = self.cursor.fetchall()[0]
break
- except self.dialect.dbapi.Error, e:
+ except self.dialect.dbapi.Error as e:
# no way around this - nextset() consumes the previous set
# so we need to just keep flipping
self.cursor.nextset()
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py
index 076fa2517..ad4650f6d 100644
--- a/lib/sqlalchemy/dialects/mysql/base.py
+++ b/lib/sqlalchemy/dialects/mysql/base.py
@@ -640,7 +640,7 @@ class BIT(sqltypes.TypeEngine):
def process(value):
if value is not None:
- v = 0L
+ v = 0
for i in map(ord, value):
v = v << 8 | i
return v
@@ -1139,14 +1139,10 @@ class SET(_StringType):
# No ',' quoting issues- commas aren't allowed in SET values
# The bad news:
# Plenty of driver inconsistencies here.
- if isinstance(value, util.set_types):
+ if isinstance(value, set):
# ..some versions convert '' to an empty set
if not value:
value.add('')
- # ..some return sets.Set, even for pythons
- # that have __builtin__.set
- if not isinstance(value, set):
- value = set(value)
return value
# ...and some versions return strings
if value is not None:
@@ -1159,7 +1155,7 @@ class SET(_StringType):
super_convert = super(SET, self).bind_processor(dialect)
def process(value):
- if value is None or isinstance(value, (int, long, basestring)):
+ if value is None or isinstance(value, util.int_types + util.string_types):
pass
else:
if None in value:
@@ -1340,7 +1336,7 @@ class MySQLCompiler(compiler.SQLCompiler):
of a SELECT.
"""
- if isinstance(select._distinct, basestring):
+ if isinstance(select._distinct, util.string_types):
return select._distinct.upper() + " "
elif select._distinct:
return "DISTINCT "
@@ -1429,7 +1425,7 @@ class MySQLDDLCompiler(compiler.DDLCompiler):
MySQLDDLCompiler, self).create_table_constraints(table)
engine_key = '%s_engine' % self.dialect.name
- is_innodb = table.kwargs.has_key(engine_key) and \
+ is_innodb = engine_key in table.kwargs and \
table.kwargs[engine_key].lower() == 'innodb'
auto_inc_column = table._autoincrement_column
@@ -2034,7 +2030,7 @@ class MySQLDialect(default.DefaultDialect):
have = rs.fetchone() is not None
rs.close()
return have
- except exc.DBAPIError, e:
+ except exc.DBAPIError as e:
if self._extract_error_code(e.orig) == 1146:
return False
raise
@@ -2317,7 +2313,7 @@ class MySQLDialect(default.DefaultDialect):
rp = None
try:
rp = connection.execute(st)
- except exc.DBAPIError, e:
+ except exc.DBAPIError as e:
if self._extract_error_code(e.orig) == 1146:
raise exc.NoSuchTableError(full_name)
else:
@@ -2341,7 +2337,7 @@ class MySQLDialect(default.DefaultDialect):
try:
try:
rp = connection.execute(st)
- except exc.DBAPIError, e:
+ except exc.DBAPIError as e:
if self._extract_error_code(e.orig) == 1146:
raise exc.NoSuchTableError(full_name)
else:
@@ -2791,11 +2787,8 @@ class _DecodingRowProxy(object):
item = self.rowproxy[index]
if isinstance(item, _array):
item = item.tostring()
- # Py2K
- if self.charset and isinstance(item, str):
- # end Py2K
- # Py3K
- #if self.charset and isinstance(item, bytes):
+
+ if self.charset and isinstance(item, util.binary_type):
return item.decode(self.charset)
else:
return item
@@ -2804,11 +2797,7 @@ class _DecodingRowProxy(object):
item = getattr(self.rowproxy, attr)
if isinstance(item, _array):
item = item.tostring()
- # Py2K
- if self.charset and isinstance(item, str):
- # end Py2K
- # Py3K
- #if self.charset and isinstance(item, bytes):
+ if self.charset and isinstance(item, util.binary_type):
return item.decode(self.charset)
else:
return item
diff --git a/lib/sqlalchemy/dialects/mysql/cymysql.py b/lib/sqlalchemy/dialects/mysql/cymysql.py
index 0806f63b4..deb2de449 100644
--- a/lib/sqlalchemy/dialects/mysql/cymysql.py
+++ b/lib/sqlalchemy/dialects/mysql/cymysql.py
@@ -25,15 +25,9 @@ class _cymysqlBIT(BIT):
def process(value):
if value is not None:
- # Py2K
- v = 0L
- for i in map(ord, value):
+ v = 0
+ for i in util.iterbytes(value):
v = v << 8 | i
- # end Py2K
- # Py3K
- #v = 0
- #for i in value:
- # v = v << 8 | i
return v
return value
return process
diff --git a/lib/sqlalchemy/dialects/mysql/oursql.py b/lib/sqlalchemy/dialects/mysql/oursql.py
index db24adf03..77370f91d 100644
--- a/lib/sqlalchemy/dialects/mysql/oursql.py
+++ b/lib/sqlalchemy/dialects/mysql/oursql.py
@@ -55,10 +55,10 @@ class MySQLExecutionContext_oursql(MySQLExecutionContext):
class MySQLDialect_oursql(MySQLDialect):
driver = 'oursql'
-# Py2K
- supports_unicode_binds = True
- supports_unicode_statements = True
-# end Py2K
+
+ if util.py2k:
+ supports_unicode_binds = True
+ supports_unicode_statements = True
supports_native_decimal = True
@@ -90,12 +90,11 @@ class MySQLDialect_oursql(MySQLDialect):
connection.cursor().execute('BEGIN', plain_query=True)
def _xa_query(self, connection, query, xid):
-# Py2K
- arg = connection.connection._escape_string(xid)
-# end Py2K
-# Py3K
-# charset = self._connection_charset
-# arg = connection.connection._escape_string(xid.encode(charset)).decode(charset)
+ if util.py2k:
+ arg = connection.connection._escape_string(xid)
+ else:
+ charset = self._connection_charset
+ arg = connection.connection._escape_string(xid.encode(charset)).decode(charset)
arg = "'%s'" % arg
connection.execution_options(_oursql_plain_query=True).execute(query % arg)
diff --git a/lib/sqlalchemy/dialects/mysql/zxjdbc.py b/lib/sqlalchemy/dialects/mysql/zxjdbc.py
index ea01da21c..20f2e7359 100644
--- a/lib/sqlalchemy/dialects/mysql/zxjdbc.py
+++ b/lib/sqlalchemy/dialects/mysql/zxjdbc.py
@@ -37,7 +37,7 @@ class _ZxJDBCBit(BIT):
return value
if isinstance(value, bool):
return int(value)
- v = 0L
+ v = 0
for i in value:
v = v << 8 | (i & 0xff)
value = v
diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py
index 831ba5f1b..6b6c32ae0 100644
--- a/lib/sqlalchemy/dialects/oracle/base.py
+++ b/lib/sqlalchemy/dialects/oracle/base.py
@@ -654,14 +654,14 @@ class OracleDDLCompiler(compiler.DDLCompiler):
class OracleIdentifierPreparer(compiler.IdentifierPreparer):
reserved_words = set([x.lower() for x in RESERVED_WORDS])
- illegal_initial_characters = set(xrange(0, 10)).union(["_", "$"])
+ illegal_initial_characters = set(range(0, 10)).union(["_", "$"])
def _bindparam_requires_quotes(self, value):
"""Return True if the given identifier requires quoting."""
lc_value = value.lower()
return (lc_value in self.reserved_words
or value[0] in self.illegal_initial_characters
- or not self.legal_characters.match(unicode(value))
+ or not self.legal_characters.match(util.text_type(value))
)
def format_savepoint(self, savepoint):
@@ -765,10 +765,9 @@ class OracleDialect(default.DefaultDialect):
def normalize_name(self, name):
if name is None:
return None
- # Py2K
- if isinstance(name, str):
- name = name.decode(self.encoding)
- # end Py2K
+ if util.py2k:
+ if isinstance(name, str):
+ name = name.decode(self.encoding)
if name.upper() == name and \
not self.identifier_preparer._requires_quotes(name.lower()):
return name.lower()
@@ -780,16 +779,15 @@ class OracleDialect(default.DefaultDialect):
return None
elif name.lower() == name and not self.identifier_preparer._requires_quotes(name.lower()):
name = name.upper()
- # Py2K
- if not self.supports_unicode_binds:
- name = name.encode(self.encoding)
- else:
- name = unicode(name)
- # end Py2K
+ if util.py2k:
+ if not self.supports_unicode_binds:
+ name = name.encode(self.encoding)
+ else:
+ name = unicode(name)
return name
def _get_default_schema_name(self, connection):
- return self.normalize_name(connection.execute(u'SELECT USER FROM DUAL').scalar())
+ return self.normalize_name(connection.execute('SELECT USER FROM DUAL').scalar())
def _resolve_synonym(self, connection, desired_owner=None, desired_synonym=None, desired_table=None):
"""search for a local synonym matching the given desired owner/name.
@@ -1167,7 +1165,7 @@ class OracleDialect(default.DefaultDialect):
local_cols.append(local_column)
remote_cols.append(remote_column)
- return fkeys.values()
+ return list(fkeys.values())
@reflection.cache
def get_view_definition(self, connection, view_name, schema=None,
@@ -1187,7 +1185,9 @@ class OracleDialect(default.DefaultDialect):
rp = connection.execute(sql.text(text), **params).scalar()
if rp:
- return rp.decode(self.encoding)
+ if util.py2k:
+ rp = rp.decode(self.encoding)
+ return rp
else:
return None
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index b8f7439f5..e013799db 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -268,20 +268,17 @@ class _LOBMixin(object):
class _NativeUnicodeMixin(object):
- # Py3K
- #pass
- # Py2K
- def bind_processor(self, dialect):
- if dialect._cx_oracle_with_unicode:
- def process(value):
- if value is None:
- return value
- else:
- return unicode(value)
- return process
- else:
- return super(_NativeUnicodeMixin, self).bind_processor(dialect)
- # end Py2K
+ if util.py2k:
+ def bind_processor(self, dialect):
+ if dialect._cx_oracle_with_unicode:
+ def process(value):
+ if value is None:
+ return value
+ else:
+ return unicode(value)
+ return process
+ else:
+ return super(_NativeUnicodeMixin, self).bind_processor(dialect)
# we apply a connection output handler that returns
# unicode in all cases, so the "native_unicode" flag
@@ -493,11 +490,11 @@ class OracleExecutionContext_cx_oracle_with_unicode(OracleExecutionContext_cx_or
"""
def __init__(self, *arg, **kw):
OracleExecutionContext_cx_oracle.__init__(self, *arg, **kw)
- self.statement = unicode(self.statement)
+ self.statement = util.text_type(self.statement)
def _execute_scalar(self, stmt):
return super(OracleExecutionContext_cx_oracle_with_unicode, self).\
- _execute_scalar(unicode(stmt))
+ _execute_scalar(util.text_type(stmt))
class ReturningResultProxy(_result.FullyBufferedResultProxy):
@@ -607,19 +604,23 @@ class OracleDialect_cx_oracle(OracleDialect):
self.supports_unicode_statements = True
self.supports_unicode_binds = True
self._cx_oracle_with_unicode = True
- # Py2K
- # There's really no reason to run with WITH_UNICODE under Python 2.x.
- # Give the user a hint.
- util.warn("cx_Oracle is compiled under Python 2.xx using the "
- "WITH_UNICODE flag. Consider recompiling cx_Oracle without "
- "this flag, which is in no way necessary for full support of Unicode. "
- "Otherwise, all string-holding bind parameters must "
- "be explicitly typed using SQLAlchemy's String type or one of its subtypes,"
- "or otherwise be passed as Python unicode. Plain Python strings "
- "passed as bind parameters will be silently corrupted by cx_Oracle."
- )
- self.execution_ctx_cls = OracleExecutionContext_cx_oracle_with_unicode
- # end Py2K
+
+ if util.py2k:
+ # There's really no reason to run with WITH_UNICODE under Python 2.x.
+ # Give the user a hint.
+ util.warn(
+ "cx_Oracle is compiled under Python 2.xx using the "
+ "WITH_UNICODE flag. Consider recompiling cx_Oracle "
+ "without this flag, which is in no way necessary for full "
+ "support of Unicode. Otherwise, all string-holding bind "
+ "parameters must be explicitly typed using SQLAlchemy's "
+ "String type or one of its subtypes,"
+ "or otherwise be passed as Python unicode. "
+ "Plain Python strings passed as bind parameters will be "
+ "silently corrupted by cx_Oracle."
+ )
+ self.execution_ctx_cls = \
+ OracleExecutionContext_cx_oracle_with_unicode
else:
self._cx_oracle_with_unicode = False
@@ -731,7 +732,7 @@ class OracleDialect_cx_oracle(OracleDialect):
arraysize=cursor.arraysize)
# allow all strings to come back natively as Unicode
elif defaultType in (cx_Oracle.STRING, cx_Oracle.FIXED_CHAR):
- return cursor.var(unicode, size, cursor.arraysize)
+ return cursor.var(util.text_type, size, cursor.arraysize)
def on_connect(conn):
conn.outputtypehandler = output_type_handler
@@ -766,20 +767,19 @@ class OracleDialect_cx_oracle(OracleDialect):
twophase=self.allow_twophase,
)
- # Py2K
- if self._cx_oracle_with_unicode:
- for k, v in opts.items():
- if isinstance(v, str):
- opts[k] = unicode(v)
- else:
- for k, v in opts.items():
- if isinstance(v, unicode):
- opts[k] = str(v)
- # end Py2K
+ if util.py2k:
+ if self._cx_oracle_with_unicode:
+ for k, v in opts.items():
+ if isinstance(v, str):
+ opts[k] = unicode(v)
+ else:
+ for k, v in opts.items():
+ if isinstance(v, unicode):
+ opts[k] = str(v)
if 'mode' in url.query:
opts['mode'] = url.query['mode']
- if isinstance(opts['mode'], basestring):
+ if isinstance(opts['mode'], util.string_types):
mode = opts['mode'].upper()
if mode == 'SYSDBA':
opts['mode'] = self.dbapi.SYSDBA
@@ -819,6 +819,11 @@ class OracleDialect_cx_oracle(OracleDialect):
id = random.randint(0, 2 ** 128)
return (0x1234, "%032x" % id, "%032x" % 9)
+ def do_executemany(self, cursor, statement, parameters, context=None):
+ if isinstance(parameters, tuple):
+ parameters = list(parameters)
+ cursor.executemany(statement, parameters)
+
def do_begin_twophase(self, connection, xid):
connection.connection.begin(*xid)
diff --git a/lib/sqlalchemy/dialects/oracle/zxjdbc.py b/lib/sqlalchemy/dialects/oracle/zxjdbc.py
index d74f21aca..ad53b89a1 100644
--- a/lib/sqlalchemy/dialects/oracle/zxjdbc.py
+++ b/lib/sqlalchemy/dialects/oracle/zxjdbc.py
@@ -95,8 +95,8 @@ class OracleExecutionContext_zxjdbc(OracleExecutionContext):
try:
try:
rrs = self.statement.__statement__.getReturnResultSet()
- rrs.next()
- except SQLException, sqle:
+ next(rrs)
+ except SQLException as sqle:
msg = '%s [SQLCode: %d]' % (sqle.getMessage(), sqle.getErrorCode())
if sqle.getSQLState() is not None:
msg += ' [SQLState: %s]' % sqle.getSQLState()
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index 1acdb57b9..00d0acc2c 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -188,7 +188,6 @@ underlying CREATE INDEX command, so it *must* be a valid index type for your
version of PostgreSQL.
"""
-
import re
from ... import sql, schema, exc, util
@@ -333,7 +332,7 @@ class UUID(sqltypes.TypeEngine):
if self.as_uuid:
def process(value):
if value is not None:
- value = str(value)
+ value = util.text_type(value)
return value
return process
else:
@@ -1419,7 +1418,7 @@ class PGDialect(default.DefaultDialect):
query,
bindparams=[
sql.bindparam(
- 'schema', unicode(schema.lower()),
+ 'schema', util.text_type(schema.lower()),
type_=sqltypes.Unicode)]
)
)
@@ -1435,7 +1434,7 @@ class PGDialect(default.DefaultDialect):
"n.oid=c.relnamespace where n.nspname=current_schema() and "
"relname=:name",
bindparams=[
- sql.bindparam('name', unicode(table_name),
+ sql.bindparam('name', util.text_type(table_name),
type_=sqltypes.Unicode)]
)
)
@@ -1447,9 +1446,9 @@ class PGDialect(default.DefaultDialect):
"relname=:name",
bindparams=[
sql.bindparam('name',
- unicode(table_name), type_=sqltypes.Unicode),
+ util.text_type(table_name), type_=sqltypes.Unicode),
sql.bindparam('schema',
- unicode(schema), type_=sqltypes.Unicode)]
+ util.text_type(schema), type_=sqltypes.Unicode)]
)
)
return bool(cursor.first())
@@ -1463,7 +1462,7 @@ class PGDialect(default.DefaultDialect):
"n.nspname=current_schema() "
"and relname=:name",
bindparams=[
- sql.bindparam('name', unicode(sequence_name),
+ sql.bindparam('name', util.text_type(sequence_name),
type_=sqltypes.Unicode)
]
)
@@ -1475,10 +1474,10 @@ class PGDialect(default.DefaultDialect):
"n.oid=c.relnamespace where relkind='S' and "
"n.nspname=:schema and relname=:name",
bindparams=[
- sql.bindparam('name', unicode(sequence_name),
+ sql.bindparam('name', util.text_type(sequence_name),
type_=sqltypes.Unicode),
sql.bindparam('schema',
- unicode(schema), type_=sqltypes.Unicode)
+ util.text_type(schema), type_=sqltypes.Unicode)
]
)
)
@@ -1488,9 +1487,9 @@ class PGDialect(default.DefaultDialect):
def has_type(self, connection, type_name, schema=None):
bindparams = [
sql.bindparam('typname',
- unicode(type_name), type_=sqltypes.Unicode),
+ util.text_type(type_name), type_=sqltypes.Unicode),
sql.bindparam('nspname',
- unicode(schema), type_=sqltypes.Unicode),
+ util.text_type(schema), type_=sqltypes.Unicode),
]
if schema is not None:
query = """
@@ -1546,9 +1545,9 @@ class PGDialect(default.DefaultDialect):
""" % schema_where_clause
# Since we're binding to unicode, table_name and schema_name must be
# unicode.
- table_name = unicode(table_name)
+ table_name = util.text_type(table_name)
if schema is not None:
- schema = unicode(schema)
+ schema = util.text_type(schema)
s = sql.text(query, bindparams=[
sql.bindparam('table_name', type_=sqltypes.Unicode),
sql.bindparam('schema', type_=sqltypes.Unicode)
@@ -1570,13 +1569,13 @@ class PGDialect(default.DefaultDialect):
"""
rp = connection.execute(s)
# what about system tables?
- # Py3K
- #schema_names = [row[0] for row in rp \
- # if not row[0].startswith('pg_')]
- # Py2K
- schema_names = [row[0].decode(self.encoding) for row in rp \
+
+ if util.py2k:
+ schema_names = [row[0].decode(self.encoding) for row in rp \
+ if not row[0].startswith('pg_')]
+ else:
+ schema_names = [row[0] for row in rp \
if not row[0].startswith('pg_')]
- # end Py2K
return schema_names
@reflection.cache
@@ -1587,7 +1586,7 @@ class PGDialect(default.DefaultDialect):
current_schema = self.default_schema_name
result = connection.execute(
- sql.text(u"SELECT relname FROM pg_class c "
+ sql.text("SELECT relname FROM pg_class c "
"WHERE relkind = 'r' "
"AND '%s' = (select nspname from pg_namespace n "
"where n.oid = c.relnamespace) " %
@@ -1610,12 +1609,12 @@ class PGDialect(default.DefaultDialect):
AND '%(schema)s' = (select nspname from pg_namespace n
where n.oid = c.relnamespace)
""" % dict(schema=current_schema)
- # Py3K
- #view_names = [row[0] for row in connection.execute(s)]
- # Py2K
- view_names = [row[0].decode(self.encoding)
+
+ if util.py2k:
+ view_names = [row[0].decode(self.encoding)
for row in connection.execute(s)]
- # end Py2K
+ else:
+ view_names = [row[0] for row in connection.execute(s)]
return view_names
@reflection.cache
@@ -1632,11 +1631,10 @@ class PGDialect(default.DefaultDialect):
rp = connection.execute(sql.text(s),
view_name=view_name, schema=current_schema)
if rp:
- # Py3K
- #view_def = rp.scalar()
- # Py2K
- view_def = rp.scalar().decode(self.encoding)
- # end Py2K
+ if util.py2k:
+ view_def = rp.scalar().decode(self.encoding)
+ else:
+ view_def = rp.scalar()
return view_def
@reflection.cache
diff --git a/lib/sqlalchemy/dialects/postgresql/hstore.py b/lib/sqlalchemy/dialects/postgresql/hstore.py
index e555a1afd..d7368ff42 100644
--- a/lib/sqlalchemy/dialects/postgresql/hstore.py
+++ b/lib/sqlalchemy/dialects/postgresql/hstore.py
@@ -10,6 +10,7 @@ from .base import ARRAY, ischema_names
from ... import types as sqltypes
from ...sql import functions as sqlfunc
from ...sql.operators import custom_op
+from ... import util
__all__ = ('HSTORE', 'hstore')
@@ -96,14 +97,14 @@ def _serialize_hstore(val):
def esc(s, position):
if position == 'value' and s is None:
return 'NULL'
- elif isinstance(s, basestring):
+ elif isinstance(s, util.string_types):
return '"%s"' % s.replace('"', r'\"')
else:
raise ValueError("%r in %s position is not a string." %
(s, position))
return ', '.join('%s=>%s' % (esc(k, 'key'), esc(v, 'value'))
- for k, v in val.iteritems())
+ for k, v in val.items())
class HSTORE(sqltypes.Concatenable, sqltypes.TypeEngine):
@@ -260,19 +261,35 @@ class HSTORE(sqltypes.Concatenable, sqltypes.TypeEngine):
_adapt_expression(self, op, other_comparator)
def bind_processor(self, dialect):
- def process(value):
- if isinstance(value, dict):
- return _serialize_hstore(value)
- else:
- return value
+ if util.py2k:
+ encoding = dialect.encoding
+ def process(value):
+ if isinstance(value, dict):
+ return _serialize_hstore(value).encode(encoding)
+ else:
+ return value
+ else:
+ def process(value):
+ if isinstance(value, dict):
+ return _serialize_hstore(value)
+ else:
+ return value
return process
def result_processor(self, dialect, coltype):
- def process(value):
- if value is not None:
- return _parse_hstore(value)
- else:
- return value
+ if util.py2k:
+ encoding = dialect.encoding
+ def process(value):
+ if value is not None:
+ return _parse_hstore(value.decode(encoding))
+ else:
+ return value
+ else:
+ def process(value):
+ if value is not None:
+ return _parse_hstore(value)
+ else:
+ return value
return process
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index 805fc72af..fcc1946ff 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -143,6 +143,7 @@ effect for other DBAPIs.
"""
from __future__ import absolute_import
+
import re
import logging
@@ -190,22 +191,20 @@ class _PGNumeric(sqltypes.Numeric):
class _PGEnum(ENUM):
def __init__(self, *arg, **kw):
super(_PGEnum, self).__init__(*arg, **kw)
- # Py2K
- if self.convert_unicode:
- self.convert_unicode = "force"
- # end Py2K
+ if util.py2k:
+ if self.convert_unicode:
+ self.convert_unicode = "force"
class _PGArray(ARRAY):
def __init__(self, *arg, **kw):
super(_PGArray, self).__init__(*arg, **kw)
- # Py2K
- # FIXME: this check won't work for setups that
- # have convert_unicode only on their create_engine().
- if isinstance(self.item_type, sqltypes.String) and \
- self.item_type.convert_unicode:
- self.item_type.convert_unicode = "force"
- # end Py2K
+ if util.py2k:
+ # FIXME: this check won't work for setups that
+ # have convert_unicode only on their create_engine().
+ if isinstance(self.item_type, sqltypes.String) and \
+ self.item_type.convert_unicode:
+ self.item_type.convert_unicode = "force"
class _PGHStore(HSTORE):
@@ -294,9 +293,9 @@ class PGIdentifierPreparer_psycopg2(PGIdentifierPreparer):
class PGDialect_psycopg2(PGDialect):
driver = 'psycopg2'
- # Py2K
- supports_unicode_statements = False
- # end Py2K
+ if util.py2k:
+ supports_unicode_statements = False
+
default_paramstyle = 'pyformat'
supports_sane_multi_rowcount = False
execution_ctx_cls = PGExecutionContext_psycopg2
@@ -393,7 +392,13 @@ class PGDialect_psycopg2(PGDialect):
hstore_oids = self._hstore_oids(conn)
if hstore_oids is not None:
oid, array_oid = hstore_oids
- extras.register_hstore(conn, oid=oid, array_oid=array_oid)
+ if util.py2k:
+ extras.register_hstore(conn, oid=oid,
+ array_oid=array_oid,
+ unicode=True)
+ else:
+ extras.register_hstore(conn, oid=oid,
+ array_oid=array_oid)
fns.append(on_connect)
if fns:
diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py
index f21a81d0c..1ca8f4e64 100644
--- a/lib/sqlalchemy/dialects/sqlite/base.py
+++ b/lib/sqlalchemy/dialects/sqlite/base.py
@@ -508,7 +508,7 @@ class SQLiteDDLCompiler(compiler.DDLCompiler):
def visit_foreign_key_constraint(self, constraint):
- local_table = constraint._elements.values()[0].parent.table
+ local_table = list(constraint._elements.values())[0].parent.table
remote_table = list(constraint._elements.values())[0].column.table
if local_table.schema != remote_table.schema:
@@ -812,7 +812,7 @@ class SQLiteDialect(default.DefaultDialect):
coltype = sqltypes.NullType()
if default is not None:
- default = unicode(default)
+ default = util.text_type(default)
return {
'name': name,
diff --git a/lib/sqlalchemy/dialects/sqlite/pysqlite.py b/lib/sqlalchemy/dialects/sqlite/pysqlite.py
index d827607ba..ad0dd5292 100644
--- a/lib/sqlalchemy/dialects/sqlite/pysqlite.py
+++ b/lib/sqlalchemy/dialects/sqlite/pysqlite.py
@@ -267,8 +267,8 @@ class SQLiteDialect_pysqlite(SQLiteDialect):
}
)
- # Py3K
- #description_encoding = None
+ if not util.py2k:
+ description_encoding = None
driver = 'pysqlite'
@@ -288,7 +288,7 @@ class SQLiteDialect_pysqlite(SQLiteDialect):
def dbapi(cls):
try:
from pysqlite2 import dbapi2 as sqlite
- except ImportError, e:
+ except ImportError as e:
try:
from sqlite3 import dbapi2 as sqlite # try 2.5+ stdlib name.
except ImportError:
diff --git a/lib/sqlalchemy/dialects/sybase/__init__.py b/lib/sqlalchemy/dialects/sybase/__init__.py
index 7d504e54e..f61352ceb 100644
--- a/lib/sqlalchemy/dialects/sybase/__init__.py
+++ b/lib/sqlalchemy/dialects/sybase/__init__.py
@@ -9,7 +9,7 @@ from sqlalchemy.dialects.sybase import base, pysybase, pyodbc
# default dialect
base.dialect = pyodbc.dialect
-from base import CHAR, VARCHAR, TIME, NCHAR, NVARCHAR,\
+from .base import CHAR, VARCHAR, TIME, NCHAR, NVARCHAR,\
TEXT, DATE, DATETIME, FLOAT, NUMERIC,\
BIGINT, INT, INTEGER, SMALLINT, BINARY,\
VARBINARY, UNITEXT, UNICHAR, UNIVARCHAR,\
diff --git a/lib/sqlalchemy/dialects/sybase/base.py b/lib/sqlalchemy/dialects/sybase/base.py
index a9e5c5fda..6770ed8e7 100644
--- a/lib/sqlalchemy/dialects/sybase/base.py
+++ b/lib/sqlalchemy/dialects/sybase/base.py
@@ -475,12 +475,12 @@ class SybaseDialect(default.DefaultDialect):
AND o.type in ('U', 'V')
""")
- # Py2K
- if isinstance(schema, unicode):
- schema = schema.encode("ascii")
- if isinstance(table_name, unicode):
- table_name = table_name.encode("ascii")
- # end Py2K
+# start Py2K
+# if isinstance(schema, unicode):
+# schema = schema.encode("ascii")
+# if isinstance(table_name, unicode):
+# table_name = table_name.encode("ascii")
+# end Py2K
result = connection.execute(TABLEID_SQL,
schema_name=schema,
table_name=table_name)
@@ -759,10 +759,10 @@ class SybaseDialect(default.DefaultDialect):
AND o.type = 'U'
""")
- # Py2K
- if isinstance(schema, unicode):
- schema = schema.encode("ascii")
- # end Py2K
+# start Py2K
+# if isinstance(schema, unicode):
+# schema = schema.encode("ascii")
+# end Py2K
tables = connection.execute(TABLE_SQL, schema_name=schema)
return [t["name"] for t in tables]
@@ -779,10 +779,10 @@ class SybaseDialect(default.DefaultDialect):
AND o.type = 'V'
""")
- # Py2K
- if isinstance(view_name, unicode):
- view_name = view_name.encode("ascii")
- # end Py2K
+# start Py2K
+# if isinstance(view_name, unicode):
+# view_name = view_name.encode("ascii")
+# end Py2K
view = connection.execute(VIEW_DEF_SQL, view_name=view_name)
return view.scalar()
@@ -799,10 +799,10 @@ class SybaseDialect(default.DefaultDialect):
AND o.type = 'V'
""")
- # Py2K
- if isinstance(schema, unicode):
- schema = schema.encode("ascii")
- # end Py2K
+# start Py2K
+# if isinstance(schema, unicode):
+# schema = schema.encode("ascii")
+# end Py2K
views = connection.execute(VIEW_SQL, schema_name=schema)
return [v["name"] for v in views]
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index b4c9b1e1c..2d9f3af94 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -3,13 +3,13 @@
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-
+from __future__ import with_statement
"""Defines :class:`.Connection` and :class:`.Engine`.
"""
-from __future__ import with_statement
+
import sys
from .. import exc, schema, util, log, interfaces
from ..sql import expression, util as sql_util
@@ -460,7 +460,7 @@ class Connection(Connectable):
try:
self.engine.dialect.do_begin(self.connection)
- except Exception, e:
+ except Exception as e:
self._handle_dbapi_exception(e, None, None, None, None)
def _rollback_impl(self):
@@ -473,7 +473,7 @@ class Connection(Connectable):
try:
self.engine.dialect.do_rollback(self.connection)
self.__transaction = None
- except Exception, e:
+ except Exception as e:
self._handle_dbapi_exception(e, None, None, None, None)
else:
self.__transaction = None
@@ -487,7 +487,7 @@ class Connection(Connectable):
try:
self.engine.dialect.do_commit(self.connection)
self.__transaction = None
- except Exception, e:
+ except Exception as e:
self._handle_dbapi_exception(e, None, None, None, None)
def _savepoint_impl(self, name=None):
@@ -688,7 +688,7 @@ class Connection(Connectable):
dialect = self.dialect
ctx = dialect.execution_ctx_cls._init_default(
dialect, self, conn)
- except Exception, e:
+ except Exception as e:
self._handle_dbapi_exception(e, None, None, None, None)
ret = ctx._exec_default(default, None)
@@ -734,6 +734,8 @@ class Connection(Connectable):
distilled_params = _distill_params(multiparams, params)
if distilled_params:
+ # note this is usually dict but we support RowProxy
+ # as well; but dict.keys() as an iterator is OK
keys = distilled_params[0].keys()
else:
keys = []
@@ -822,7 +824,7 @@ class Connection(Connectable):
conn = self._revalidate_connection()
context = constructor(dialect, self, conn, *args)
- except Exception, e:
+ except Exception as e:
self._handle_dbapi_exception(e,
str(statement), parameters,
None, None)
@@ -865,7 +867,7 @@ class Connection(Connectable):
statement,
parameters,
context)
- except Exception, e:
+ except Exception as e:
self._handle_dbapi_exception(
e,
statement,
@@ -939,7 +941,7 @@ class Connection(Connectable):
cursor,
statement,
parameters)
- except Exception, e:
+ except Exception as e:
self._handle_dbapi_exception(
e,
statement,
@@ -954,17 +956,11 @@ class Connection(Connectable):
"""
try:
cursor.close()
- except Exception, e:
- try:
- ex_text = str(e)
- except TypeError:
- ex_text = repr(e)
- if not self.closed:
- self.connection._logger.warn(
- "Error closing cursor: %s", ex_text)
-
- if isinstance(e, (SystemExit, KeyboardInterrupt)):
- raise
+ except (SystemExit, KeyboardInterrupt):
+ raise
+ except Exception:
+ self.connection._logger.error(
+ "Error closing cursor", exc_info=True)
_reentrant_error = False
_is_disconnect = False
@@ -1045,7 +1041,7 @@ class Connection(Connectable):
Compiled: _execute_compiled,
schema.SchemaItem: _execute_default,
schema.DDLElement: _execute_ddl,
- basestring: _execute_text
+ util.string_types[0]: _execute_text
}
def default_schema_name(self):
diff --git a/lib/sqlalchemy/engine/ddl.py b/lib/sqlalchemy/engine/ddl.py
index c61a9d59c..6daa9be6b 100644
--- a/lib/sqlalchemy/engine/ddl.py
+++ b/lib/sqlalchemy/engine/ddl.py
@@ -52,7 +52,7 @@ class SchemaGenerator(DDLBase):
if self.tables is not None:
tables = self.tables
else:
- tables = metadata.tables.values()
+ tables = list(metadata.tables.values())
collection = [t for t in sql_util.sort_tables(tables)
if self._can_create_table(t)]
seq_coll = [s for s in metadata._sequences.values()
@@ -120,7 +120,7 @@ class SchemaDropper(DDLBase):
if self.tables is not None:
tables = self.tables
else:
- tables = metadata.tables.values()
+ tables = list(metadata.tables.values())
collection = [
t
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index dc45e12b1..91869ab75 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -59,17 +59,16 @@ class DefaultDialect(interfaces.Dialect):
# *not* the FLOAT type however.
supports_native_decimal = False
- # Py3K
- #supports_unicode_statements = True
- #supports_unicode_binds = True
- #returns_unicode_strings = True
- #description_encoding = None
- # Py2K
- supports_unicode_statements = False
- supports_unicode_binds = False
- returns_unicode_strings = False
- description_encoding = 'use_encoding'
- # end Py2K
+ if util.py3k:
+ supports_unicode_statements = True
+ supports_unicode_binds = True
+ returns_unicode_strings = True
+ description_encoding = None
+ else:
+ supports_unicode_statements = False
+ supports_unicode_binds = False
+ returns_unicode_strings = False
+ description_encoding = 'use_encoding'
name = 'default'
@@ -203,14 +202,10 @@ class DefaultDialect(interfaces.Dialect):
return None
def _check_unicode_returns(self, connection):
- # Py2K
- if self.supports_unicode_statements:
- cast_to = unicode
+ if util.py2k and not self.supports_unicode_statements:
+ cast_to = util.binary_type
else:
- cast_to = str
- # end Py2K
- # Py3K
- #cast_to = str
+ cast_to = util.text_type
def check_unicode(formatstr, type_):
cursor = connection.connection.cursor()
@@ -219,8 +214,8 @@ class DefaultDialect(interfaces.Dialect):
cursor.execute(
cast_to(
expression.select(
- [expression.cast(
- expression.literal_column(
+ [expression.cast(
+ expression.literal_column(
"'test %s returns'" % formatstr),
type_)
]).compile(dialect=self)
@@ -228,8 +223,8 @@ class DefaultDialect(interfaces.Dialect):
)
row = cursor.fetchone()
- return isinstance(row[0], unicode)
- except self.dbapi.Error, de:
+ return isinstance(row[0], util.text_type)
+ except self.dbapi.Error as de:
util.warn("Exception attempting to "
"detect unicode returns: %r" % de)
return False
@@ -375,10 +370,10 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
self.execution_options.update(connection._execution_options)
if not dialect.supports_unicode_statements:
- self.unicode_statement = unicode(compiled)
+ self.unicode_statement = util.text_type(compiled)
self.statement = dialect._encoder(self.unicode_statement)[0]
else:
- self.statement = self.unicode_statement = unicode(compiled)
+ self.statement = self.unicode_statement = util.text_type(compiled)
self.cursor = self.create_cursor()
self.compiled_parameters = []
@@ -416,7 +411,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
self.result_map = compiled.result_map
- self.unicode_statement = unicode(compiled)
+ self.unicode_statement = util.text_type(compiled)
if not dialect.supports_unicode_statements:
self.statement = self.unicode_statement.encode(
self.dialect.encoding)
@@ -521,7 +516,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
self.executemany = len(parameters) > 1
if not dialect.supports_unicode_statements and \
- isinstance(statement, unicode):
+ isinstance(statement, util.text_type):
self.unicode_statement = statement
self.statement = dialect._encoder(statement)[0]
else:
@@ -575,8 +570,8 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
"""
conn = self.root_connection
- if isinstance(stmt, unicode) and \
- not self.dialect.supports_unicode_statements:
+ if isinstance(stmt, util.text_type) and \
+ not self.dialect.supports_unicode_statements:
stmt = self.dialect._encoder(stmt)[0]
if self.dialect.positional:
@@ -736,7 +731,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
inputsizes.append(dbtype)
try:
self.cursor.setinputsizes(*inputsizes)
- except Exception, e:
+ except Exception as e:
self.root_connection._handle_dbapi_exception(
e, None, None, None, self)
else:
@@ -754,7 +749,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
inputsizes[key] = dbtype
try:
self.cursor.setinputsizes(**inputsizes)
- except Exception, e:
+ except Exception as e:
self.root_connection._handle_dbapi_exception(
e, None, None, None, self)
diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py
index 90f21db09..cf2caf679 100644
--- a/lib/sqlalchemy/engine/reflection.py
+++ b/lib/sqlalchemy/engine/reflection.py
@@ -41,8 +41,12 @@ def cache(fn, self, con, *args, **kw):
return fn(self, con, *args, **kw)
key = (
fn.__name__,
- tuple(a for a in args if isinstance(a, basestring)),
- tuple((k, v) for k, v in kw.iteritems() if isinstance(v, (basestring, int, float)))
+ tuple(a for a in args if isinstance(a, util.string_types)),
+ tuple((k, v) for k, v in kw.items() if
+ isinstance(v,
+ util.string_types + util.int_types + (float, )
+ )
+ )
)
ret = info_cache.get(key)
if ret is None:
@@ -381,16 +385,15 @@ class Inspector(object):
# table.kwargs will need to be passed to each reflection method. Make
# sure keywords are strings.
tblkw = table.kwargs.copy()
- for (k, v) in tblkw.items():
+ for (k, v) in list(tblkw.items()):
del tblkw[k]
tblkw[str(k)] = v
- # Py2K
- if isinstance(schema, str):
- schema = schema.decode(dialect.encoding)
- if isinstance(table_name, str):
- table_name = table_name.decode(dialect.encoding)
- # end Py2K
+ if util.py2k:
+ if isinstance(schema, str):
+ schema = schema.decode(dialect.encoding)
+ if isinstance(table_name, str):
+ table_name = table_name.decode(dialect.encoding)
# columns
found_table = False
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index 88930081e..65ce3b742 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -8,7 +8,7 @@
and :class:`.RowProxy."""
-from itertools import izip
+
from .. import exc, types, util
from ..sql import expression
import collections
@@ -55,7 +55,7 @@ except ImportError:
return list(self)
def __iter__(self):
- for processor, value in izip(self._processors, self._row):
+ for processor, value in zip(self._processors, self._row):
if processor is None:
yield value
else:
@@ -72,7 +72,7 @@ except ImportError:
except TypeError:
if isinstance(key, slice):
l = []
- for processor, value in izip(self._processors[key],
+ for processor, value in zip(self._processors[key],
self._row[key]):
if processor is None:
l.append(value)
@@ -93,7 +93,7 @@ except ImportError:
def __getattr__(self, name):
try:
return self[name]
- except KeyError, e:
+ except KeyError as e:
raise AttributeError(e.args[0])
@@ -142,7 +142,7 @@ class RowProxy(BaseRowProxy):
def items(self):
"""Return a list of tuples, each tuple containing a key/value pair."""
# TODO: no coverage here
- return [(key, self[key]) for key in self.iterkeys()]
+ return [(key, self[key]) for key in self.keys()]
def keys(self):
"""Return the list of keys as strings represented by this RowProxy."""
@@ -274,7 +274,7 @@ class ResultMetaData(object):
def _key_fallback(self, key, raiseerr=True):
map = self._keymap
result = None
- if isinstance(key, basestring):
+ if isinstance(key, util.string_types):
result = map.get(key if self.case_sensitive else key.lower())
# fallback for targeting a ColumnElement to a textual expression
# this is a rare use case which only occurs when matching text()
@@ -328,8 +328,8 @@ class ResultMetaData(object):
return {
'_pickled_keymap': dict(
(key, index)
- for key, (processor, obj, index) in self._keymap.iteritems()
- if isinstance(key, (basestring, int))
+ for key, (processor, obj, index) in self._keymap.items()
+ if isinstance(key, util.string_types + util.int_types)
),
'keys': self.keys,
"case_sensitive": self.case_sensitive,
@@ -338,9 +338,9 @@ class ResultMetaData(object):
def __setstate__(self, state):
# the row has been processed at pickling time so we don't need any
# processor anymore
- self._processors = [None for _ in xrange(len(state['keys']))]
+ self._processors = [None for _ in range(len(state['keys']))]
self._keymap = keymap = {}
- for key, index in state['_pickled_keymap'].iteritems():
+ for key, index in state['_pickled_keymap'].items():
# not preserving "obj" here, unfortunately our
# proxy comparison fails with the unpickle
keymap[key] = (None, None, index)
@@ -440,7 +440,7 @@ class ResultProxy(object):
"""
try:
return self.context.rowcount
- except Exception, e:
+ except Exception as e:
self.connection._handle_dbapi_exception(
e, None, None, self.cursor, self.context)
@@ -462,7 +462,7 @@ class ResultProxy(object):
"""
try:
return self._saved_cursor.lastrowid
- except Exception, e:
+ except Exception as e:
self.connection._handle_dbapi_exception(
e, None, None,
self._saved_cursor, self.context)
@@ -746,7 +746,7 @@ class ResultProxy(object):
l = self.process_rows(self._fetchall_impl())
self.close()
return l
- except Exception, e:
+ except Exception as e:
self.connection._handle_dbapi_exception(
e, None, None,
self.cursor, self.context)
@@ -765,7 +765,7 @@ class ResultProxy(object):
if len(l) == 0:
self.close()
return l
- except Exception, e:
+ except Exception as e:
self.connection._handle_dbapi_exception(
e, None, None,
self.cursor, self.context)
@@ -784,7 +784,7 @@ class ResultProxy(object):
else:
self.close()
return None
- except Exception, e:
+ except Exception as e:
self.connection._handle_dbapi_exception(
e, None, None,
self.cursor, self.context)
@@ -800,7 +800,7 @@ class ResultProxy(object):
try:
row = self._fetchone_impl()
- except Exception, e:
+ except Exception as e:
self.connection._handle_dbapi_exception(
e, None, None,
self.cursor, self.context)
@@ -966,9 +966,9 @@ class BufferedColumnResultProxy(ResultProxy):
# constructed.
metadata._orig_processors = metadata._processors
# replace the all type processors by None processors.
- metadata._processors = [None for _ in xrange(len(metadata.keys))]
+ metadata._processors = [None for _ in range(len(metadata.keys))]
keymap = {}
- for k, (func, obj, index) in metadata._keymap.iteritems():
+ for k, (func, obj, index) in metadata._keymap.items():
keymap[k] = (None, obj, index)
self._metadata._keymap = keymap
@@ -989,7 +989,7 @@ class BufferedColumnResultProxy(ResultProxy):
if size is None:
return self.fetchall()
l = []
- for i in xrange(size):
+ for i in range(size):
row = self.fetchone()
if row is None:
break
diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py
index 4c81df8f0..c65986ca2 100644
--- a/lib/sqlalchemy/engine/strategies.py
+++ b/lib/sqlalchemy/engine/strategies.py
@@ -78,20 +78,14 @@ class DefaultEngineStrategy(EngineStrategy):
def connect():
try:
return dialect.connect(*cargs, **cparams)
- except Exception, e:
+ except Exception as e:
invalidated = dialect.is_disconnect(e, None, None)
- # Py3K
- #raise exc.DBAPIError.instance(None, None,
- # e, dialect.dbapi.Error,
- # connection_invalidated=invalidated
- #) from e
- # Py2K
- import sys
- raise exc.DBAPIError.instance(
- None, None, e, dialect.dbapi.Error,
- connection_invalidated=invalidated
- ), None, sys.exc_info()[2]
- # end Py2K
+ util.raise_from_cause(
+ exc.DBAPIError.instance(None, None,
+ e, dialect.dbapi.Error,
+ connection_invalidated=invalidated
+ )
+ )
creator = kwargs.pop('creator', connect)
diff --git a/lib/sqlalchemy/engine/url.py b/lib/sqlalchemy/engine/url.py
index c4931b48c..ed5729eea 100644
--- a/lib/sqlalchemy/engine/url.py
+++ b/lib/sqlalchemy/engine/url.py
@@ -14,7 +14,6 @@ be used directly and is also accepted directly by ``create_engine()``.
"""
import re
-import urllib
from .. import exc, util
from . import Dialect
@@ -67,7 +66,7 @@ class URL(object):
if self.username is not None:
s += self.username
if self.password is not None:
- s += ':' + urllib.quote_plus(self.password)
+ s += ':' + util.quote_plus(self.password)
s += "@"
if self.host is not None:
s += self.host
@@ -76,7 +75,7 @@ class URL(object):
if self.database is not None:
s += '/' + self.database
if self.query:
- keys = self.query.keys()
+ keys = list(self.query)
keys.sort()
s += '?' + "&".join("%s=%s" % (k, self.query[k]) for k in keys)
return s
@@ -150,7 +149,7 @@ def make_url(name_or_url):
existing URL object is passed, just returns the object.
"""
- if isinstance(name_or_url, basestring):
+ if isinstance(name_or_url, util.string_types):
return _parse_rfc1738_args(name_or_url)
else:
return name_or_url
@@ -177,17 +176,15 @@ def _parse_rfc1738_args(name):
tokens = components['database'].split('?', 2)
components['database'] = tokens[0]
query = (len(tokens) > 1 and dict(util.parse_qsl(tokens[1]))) or None
- # Py2K
- if query is not None:
+ if util.py2k and query is not None:
query = dict((k.encode('ascii'), query[k]) for k in query)
- # end Py2K
else:
query = None
components['query'] = query
if components['password'] is not None:
components['password'] = \
- urllib.unquote_plus(components['password'])
+ util.unquote_plus(components['password'])
name = components.pop('name')
return URL(name, **components)
diff --git a/lib/sqlalchemy/event.py b/lib/sqlalchemy/event.py
index f28f19ee9..bfd027ead 100644
--- a/lib/sqlalchemy/event.py
+++ b/lib/sqlalchemy/event.py
@@ -200,12 +200,9 @@ def _remove_dispatcher(cls):
if not _registrars[k]:
del _registrars[k]
-
-class Events(object):
+class Events(util.with_metaclass(_EventMeta, object)):
"""Define event listening functions for a particular target type."""
- __metaclass__ = _EventMeta
-
@classmethod
def _accept_with(cls, target):
# Mapper, ClassManager, Session override this to
@@ -377,9 +374,11 @@ class _EmptyListener(object):
def __iter__(self):
return iter(self.parent_listeners)
- def __nonzero__(self):
+ def __bool__(self):
return bool(self.parent_listeners)
+ __nonzero__ = __bool__
+
class _CompoundListener(object):
_exec_once = False
@@ -414,9 +413,10 @@ class _CompoundListener(object):
def __iter__(self):
return chain(self.parent_listeners, self.listeners)
- def __nonzero__(self):
+ def __bool__(self):
return bool(self.listeners or self.parent_listeners)
+ __nonzero__ = __bool__
class _ListenerCollection(_CompoundListener):
"""Instance-level attributes on instances of :class:`._Dispatch`.
diff --git a/lib/sqlalchemy/exc.py b/lib/sqlalchemy/exc.py
index 0ce5393be..f5dc1119d 100644
--- a/lib/sqlalchemy/exc.py
+++ b/lib/sqlalchemy/exc.py
@@ -285,7 +285,7 @@ class DBAPIError(StatementError):
text = str(orig)
except (KeyboardInterrupt, SystemExit):
raise
- except Exception, e:
+ except Exception as e:
text = 'Error in str() of DB-API-generated exception: ' + str(e)
StatementError.__init__(
self,
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py
index 252efcb42..0482a9205 100644
--- a/lib/sqlalchemy/ext/associationproxy.py
+++ b/lib/sqlalchemy/ext/associationproxy.py
@@ -475,9 +475,11 @@ class _AssociationCollection(object):
def __len__(self):
return len(self.col)
- def __nonzero__(self):
+ def __bool__(self):
return bool(self.col)
+ __nonzero__ = __bool__
+
def __getstate__(self):
return {'parent': self.parent, 'lazy_collection': self.lazy_collection}
@@ -514,7 +516,7 @@ class _AssociationList(_AssociationCollection):
stop = index.stop
step = index.step or 1
- rng = range(index.start or 0, stop, step)
+ rng = list(range(index.start or 0, stop, step))
if step == 1:
for i in rng:
del self[index.start]
@@ -569,7 +571,7 @@ class _AssociationList(_AssociationCollection):
def count(self, value):
return sum([1 for _ in
- itertools.ifilter(lambda v: v == value, iter(self))])
+ util.itertools_filter(lambda v: v == value, iter(self))])
def extend(self, values):
for v in values:
@@ -668,8 +670,8 @@ class _AssociationList(_AssociationCollection):
def __hash__(self):
raise TypeError("%s objects are unhashable" % type(self).__name__)
- for func_name, func in locals().items():
- if (util.callable(func) and func.func_name == func_name and
+ for func_name, func in list(locals().items()):
+ if (util.callable(func) and func.__name__ == func_name and
not func.__doc__ and hasattr(list, func_name)):
func.__doc__ = getattr(list, func_name).__doc__
del func_name, func
@@ -711,7 +713,7 @@ class _AssociationDict(_AssociationCollection):
return key in self.col
def __iter__(self):
- return self.col.iterkeys()
+ return iter(self.col.keys())
def clear(self):
self.col.clear()
@@ -756,24 +758,27 @@ class _AssociationDict(_AssociationCollection):
def keys(self):
return self.col.keys()
- def iterkeys(self):
- return self.col.iterkeys()
+ if util.py2k:
+ def iteritems(self):
+ return ((key, self._get(self.col[key])) for key in self.col)
- def values(self):
- return [self._get(member) for member in self.col.values()]
+ def itervalues(self):
+ return (self._get(self.col[key]) for key in self.col)
- def itervalues(self):
- for key in self.col:
- yield self._get(self.col[key])
- raise StopIteration
+ def iterkeys(self):
+ return self.col.iterkeys()
- def items(self):
- return [(k, self._get(self.col[k])) for k in self]
+ def values(self):
+ return [self._get(member) for member in self.col.values()]
- def iteritems(self):
- for key in self.col:
- yield (key, self._get(self.col[key]))
- raise StopIteration
+ def items(self):
+ return [(k, self._get(self.col[k])) for k in self]
+ else:
+ def items(self):
+ return ((key, self._get(self.col[key])) for key in self.col)
+
+ def values(self):
+ return (self._get(self.col[key]) for key in self.col)
def pop(self, key, default=_NotProvided):
if default is _NotProvided:
@@ -816,8 +821,8 @@ class _AssociationDict(_AssociationCollection):
def __hash__(self):
raise TypeError("%s objects are unhashable" % type(self).__name__)
- for func_name, func in locals().items():
- if (util.callable(func) and func.func_name == func_name and
+ for func_name, func in list(locals().items()):
+ if (util.callable(func) and func.__name__ == func_name and
not func.__doc__ and hasattr(dict, func_name)):
func.__doc__ = getattr(dict, func_name).__doc__
del func_name, func
@@ -838,12 +843,14 @@ class _AssociationSet(_AssociationCollection):
def __len__(self):
return len(self.col)
- def __nonzero__(self):
+ def __bool__(self):
if self.col:
return True
else:
return False
+ __nonzero__ = __bool__
+
def __contains__(self, value):
for member in self.col:
# testlib.pragma exempt:__eq__
@@ -1014,8 +1021,8 @@ class _AssociationSet(_AssociationCollection):
def __hash__(self):
raise TypeError("%s objects are unhashable" % type(self).__name__)
- for func_name, func in locals().items():
- if (util.callable(func) and func.func_name == func_name and
+ for func_name, func in list(locals().items()):
+ if (util.callable(func) and func.__name__ == func_name and
not func.__doc__ and hasattr(set, func_name)):
func.__doc__ = getattr(set, func_name).__doc__
del func_name, func
diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py
index ee2f0134a..5a2b88db4 100644
--- a/lib/sqlalchemy/ext/declarative/base.py
+++ b/lib/sqlalchemy/ext/declarative/base.py
@@ -173,7 +173,7 @@ def _as_declarative(cls, classname, dict_):
# extract columns from the class dict
declared_columns = set()
- for key, c in our_stuff.iteritems():
+ for key, c in list(our_stuff.items()):
if isinstance(c, (ColumnProperty, CompositeProperty)):
for col in c.columns:
if isinstance(col, Column) and \
@@ -354,7 +354,7 @@ class _MapperConfig(object):
# in which case the mapper makes this combination).
# See if the superclass has a similar column property.
# If so, join them together.
- for k, col in properties.items():
+ for k, col in list(properties.items()):
if not isinstance(col, expression.ColumnElement):
continue
if k in inherited_mapper._props:
diff --git a/lib/sqlalchemy/ext/declarative/clsregistry.py b/lib/sqlalchemy/ext/declarative/clsregistry.py
index 89975716d..95aba93fa 100644
--- a/lib/sqlalchemy/ext/declarative/clsregistry.py
+++ b/lib/sqlalchemy/ext/declarative/clsregistry.py
@@ -255,7 +255,7 @@ def _resolver(cls, prop):
return x.cls
else:
return x
- except NameError, n:
+ except NameError as n:
raise exc.InvalidRequestError(
"When initializing mapper %s, expression %r failed to "
"locate a name (%r). If this is a class name, consider "
@@ -275,14 +275,14 @@ def _deferred_relationship(cls, prop):
for attr in ('argument', 'order_by', 'primaryjoin', 'secondaryjoin',
'secondary', '_user_defined_foreign_keys', 'remote_side'):
v = getattr(prop, attr)
- if isinstance(v, basestring):
+ if isinstance(v, str):
setattr(prop, attr, resolve_arg(v))
if prop.backref and isinstance(prop.backref, tuple):
key, kwargs = prop.backref
for attr in ('primaryjoin', 'secondaryjoin', 'secondary',
'foreign_keys', 'remote_side', 'order_by'):
- if attr in kwargs and isinstance(kwargs[attr], basestring):
+ if attr in kwargs and isinstance(kwargs[attr], str):
kwargs[attr] = resolve_arg(kwargs[attr])
return prop
diff --git a/lib/sqlalchemy/ext/orderinglist.py b/lib/sqlalchemy/ext/orderinglist.py
index ffdd971a0..24d405e39 100644
--- a/lib/sqlalchemy/ext/orderinglist.py
+++ b/lib/sqlalchemy/ext/orderinglist.py
@@ -324,7 +324,7 @@ class OrderingList(list):
if stop < 0:
stop += len(self)
- for i in xrange(start, stop, step):
+ for i in range(start, stop, step):
self.__setitem__(i, entity[i])
else:
self._order_entity(index, entity, True)
@@ -334,7 +334,6 @@ class OrderingList(list):
super(OrderingList, self).__delitem__(index)
self._reorder()
- # Py2K
def __setslice__(self, start, end, values):
super(OrderingList, self).__setslice__(start, end, values)
self._reorder()
@@ -342,13 +341,12 @@ class OrderingList(list):
def __delslice__(self, start, end):
super(OrderingList, self).__delslice__(start, end)
self._reorder()
- # end Py2K
def __reduce__(self):
return _reconstitute, (self.__class__, self.__dict__, list(self))
- for func_name, func in locals().items():
- if (util.callable(func) and func.func_name == func_name and
+ for func_name, func in list(locals().items()):
+ if (util.callable(func) and func.__name__ == func_name and
not func.__doc__ and hasattr(list, func_name)):
func.__doc__ = getattr(list, func_name).__doc__
del func_name, func
diff --git a/lib/sqlalchemy/ext/serializer.py b/lib/sqlalchemy/ext/serializer.py
index 5a3fb5937..8abd1fdf3 100644
--- a/lib/sqlalchemy/ext/serializer.py
+++ b/lib/sqlalchemy/ext/serializer.py
@@ -58,24 +58,9 @@ from ..orm.interfaces import MapperProperty
from ..orm.attributes import QueryableAttribute
from .. import Table, Column
from ..engine import Engine
-from ..util import pickle
+from ..util import pickle, byte_buffer, b64encode, b64decode
import re
-import base64
-# Py3K
-#from io import BytesIO as byte_buffer
-# Py2K
-from cStringIO import StringIO as byte_buffer
-# end Py2K
-
-# Py3K
-#def b64encode(x):
-# return base64.b64encode(x).decode('ascii')
-#def b64decode(x):
-# return base64.b64decode(x.encode('ascii'))
-# Py2K
-b64encode = base64.b64encode
-b64decode = base64.b64decode
-# end Py2K
+
__all__ = ['Serializer', 'Deserializer', 'dumps', 'loads']
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 35315d5d1..1173d5d09 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -1661,7 +1661,7 @@ def contains_eager(*keys, **kwargs):
alias = kwargs.pop('alias', None)
if kwargs:
raise exc.ArgumentError(
- 'Invalid kwargs for contains_eager: %r' % kwargs.keys())
+ 'Invalid kwargs for contains_eager: %r' % list(kwargs.keys()))
return strategies.EagerLazyOption(keys, lazy='joined',
propagate_to_loaders=False, chained=True), \
strategies.LoadEagerFromAliasOption(keys, alias=alias, chained=True)
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 3eda127fd..bfba695b8 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -386,8 +386,8 @@ def create_proxied_attribute(descriptor):
return getattr(self.comparator, attribute)
except AttributeError:
raise AttributeError(
- 'Neither %r object nor %r object associated with %s '
- 'has an attribute %r' % (
+ 'Neither %r object nor %r object associated with %s '
+ 'has an attribute %r' % (
type(descriptor).__name__,
type(self.comparator).__name__,
self,
@@ -866,7 +866,7 @@ class CollectionAttributeImpl(AttributeImpl):
self.collection_factory = typecallable
def __copy(self, item):
- return [y for y in list(collections.collection_adapter(item))]
+ return [y for y in collections.collection_adapter(item)]
def get_history(self, state, dict_, passive=PASSIVE_OFF):
current = self.get(state, dict_, passive=passive)
@@ -1214,8 +1214,9 @@ class History(History):
"""
- def __nonzero__(self):
+ def __bool__(self):
return self != HISTORY_BLANK
+ __nonzero__ = __bool__
def empty(self):
"""Return True if this :class:`.History` has no changes
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
index 5691acfff..03917d112 100644
--- a/lib/sqlalchemy/orm/collections.py
+++ b/lib/sqlalchemy/orm/collections.py
@@ -657,11 +657,10 @@ class CollectionAdapter(object):
if getattr(obj, '_sa_adapter', None) is not None:
return getattr(obj, '_sa_adapter')
elif setting_type == dict:
- # Py3K
- #return obj.values()
- # Py2K
- return getattr(obj, 'itervalues', getattr(obj, 'values'))()
- # end Py2K
+ if util.py3k:
+ return obj.values()
+ else:
+ return getattr(obj, 'itervalues', getattr(obj, 'values'))()
else:
return iter(obj)
@@ -705,16 +704,17 @@ class CollectionAdapter(object):
def __iter__(self):
"""Iterate over entities in the collection."""
- # Py3K requires iter() here
return iter(getattr(self._data(), '_sa_iterator')())
def __len__(self):
"""Count entities in the collection."""
return len(list(getattr(self._data(), '_sa_iterator')()))
- def __nonzero__(self):
+ def __bool__(self):
return True
+ __nonzero__ = __bool__
+
def fire_append_event(self, item, initiator=None):
"""Notify that a entity has entered the collection.
@@ -1094,14 +1094,14 @@ def _list_decorators():
stop += len(self)
if step == 1:
- for i in xrange(start, stop, step):
+ for i in range(start, stop, step):
if len(self) > start:
del self[start]
for i, item in enumerate(value):
self.insert(i + start, item)
else:
- rng = range(start, stop, step)
+ rng = list(range(start, stop, step))
if len(value) != len(rng):
raise ValueError(
"attempt to assign sequence of size %s to "
@@ -1128,24 +1128,23 @@ def _list_decorators():
_tidy(__delitem__)
return __delitem__
- # Py2K
- def __setslice__(fn):
- def __setslice__(self, start, end, values):
- for value in self[start:end]:
- __del(self, value)
- values = [__set(self, value) for value in values]
- fn(self, start, end, values)
- _tidy(__setslice__)
- return __setslice__
-
- def __delslice__(fn):
- def __delslice__(self, start, end):
- for value in self[start:end]:
- __del(self, value)
- fn(self, start, end)
- _tidy(__delslice__)
- return __delslice__
- # end Py2K
+ if util.py2k:
+ def __setslice__(fn):
+ def __setslice__(self, start, end, values):
+ for value in self[start:end]:
+ __del(self, value)
+ values = [__set(self, value) for value in values]
+ fn(self, start, end, values)
+ _tidy(__setslice__)
+ return __setslice__
+
+ def __delslice__(fn):
+ def __delslice__(self, start, end):
+ for value in self[start:end]:
+ __del(self, value)
+ fn(self, start, end)
+ _tidy(__delslice__)
+ return __delslice__
def extend(fn):
def extend(self, iterable):
@@ -1251,7 +1250,7 @@ def _dict_decorators():
def update(self, __other=Unspecified, **kw):
if __other is not Unspecified:
if hasattr(__other, 'keys'):
- for key in __other.keys():
+ for key in list(__other):
if (key not in self or
self[key] is not __other[key]):
self[key] = __other[key]
@@ -1270,11 +1269,7 @@ def _dict_decorators():
l.pop('Unspecified')
return l
-if util.py3k_warning:
- _set_binop_bases = (set, frozenset)
-else:
- import sets
- _set_binop_bases = (set, frozenset, sets.BaseSet)
+_set_binop_bases = (set, frozenset)
def _set_binops_check_strict(self, obj):
@@ -1467,11 +1462,8 @@ __interfaces = {
),
# decorators are required for dicts and object collections.
- # Py3K
- #dict: ({'iterator': 'values'}, _dict_decorators()),
- # Py2K
- dict: ({'iterator': 'itervalues'}, _dict_decorators()),
- # end Py2K
+ dict: ({'iterator': 'values'}, _dict_decorators()) if util.py3k
+ else ({'iterator': 'itervalues'}, _dict_decorators()),
}
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index 1969bd03b..86b445bb6 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -184,7 +184,7 @@ class CompositeProperty(DescriptorProperty):
def _init_props(self):
self.props = props = []
for attr in self.attrs:
- if isinstance(attr, basestring):
+ if isinstance(attr, str):
prop = self.parent.get_property(attr)
elif isinstance(attr, schema.Column):
prop = self.parent._columntoproperty[attr]
diff --git a/lib/sqlalchemy/orm/evaluator.py b/lib/sqlalchemy/orm/evaluator.py
index 0844e2f72..458eab7a1 100644
--- a/lib/sqlalchemy/orm/evaluator.py
+++ b/lib/sqlalchemy/orm/evaluator.py
@@ -13,9 +13,9 @@ class UnevaluatableError(Exception):
_straight_ops = set(getattr(operators, op)
for op in ('add', 'mul', 'sub',
- # Py2K
- 'div',
- # end Py2K
+# start Py2K
+# 'div',
+# end Py2K
'mod', 'truediv',
'lt', 'le', 'ne', 'gt', 'ge', 'eq'))
@@ -40,6 +40,12 @@ class EvaluatorCompiler(object):
def visit_null(self, clause):
return lambda obj: None
+ def visit_false(self, clause):
+ return lambda obj: False
+
+ def visit_true(self, clause):
+ return lambda obj: True
+
def visit_column(self, clause):
if 'parentmapper' in clause._annotations:
key = clause._annotations['parentmapper'].\
@@ -50,7 +56,7 @@ class EvaluatorCompiler(object):
return lambda obj: get_corresponding_attr(obj)
def visit_clauselist(self, clause):
- evaluators = map(self.process, clause.clauses)
+ evaluators = list(map(self.process, clause.clauses))
if clause.operator is operators.or_:
def evaluate(obj):
has_null = False
@@ -79,8 +85,8 @@ class EvaluatorCompiler(object):
return evaluate
def visit_binary(self, clause):
- eval_left, eval_right = map(self.process,
- [clause.left, clause.right])
+ eval_left, eval_right = list(map(self.process,
+ [clause.left, clause.right]))
operator = clause.operator
if operator is operators.is_:
def evaluate(obj):
diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py
index 01d34428e..d0234a1d3 100644
--- a/lib/sqlalchemy/orm/identity.py
+++ b/lib/sqlalchemy/orm/identity.py
@@ -6,7 +6,7 @@
import weakref
from . import attributes
-
+from .. import util
class IdentityMap(dict):
def __init__(self):
@@ -75,7 +75,7 @@ class WeakInstanceDict(IdentityMap):
state = dict.__getitem__(self, key)
o = state.obj()
if o is None:
- raise KeyError, key
+ raise KeyError(key)
return o
def __contains__(self, key):
@@ -152,30 +152,27 @@ class WeakInstanceDict(IdentityMap):
return result
- # Py3K
- #def items(self):
- # return iter(self._items())
- #
- #def values(self):
- # return iter(self._values())
- # Py2K
- items = _items
+ if util.py2k:
+ items = _items
+ values = _values
- def iteritems(self):
- return iter(self.items())
+ def iteritems(self):
+ return iter(self.items())
- values = _values
+ def itervalues(self):
+ return iter(self.values())
+ else:
+ def items(self):
+ return iter(self._items())
- def itervalues(self):
- return iter(self.values())
- # end Py2K
+ def values(self):
+ return iter(self._values())
def all_states(self):
- # Py3K
- # return list(dict.values(self))
- # Py2K
- return dict.values(self)
- # end Py2K
+ if util.py2k:
+ return dict.values(self)
+ else:
+ return list(dict.values(self))
def discard(self, state):
st = dict.get(self, state.key, None)
@@ -189,7 +186,7 @@ class WeakInstanceDict(IdentityMap):
class StrongInstanceDict(IdentityMap):
def all_states(self):
- return [attributes.instance_state(o) for o in self.itervalues()]
+ return [attributes.instance_state(o) for o in self.values()]
def contains_state(self, state):
return (
diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py
index 0e71494c4..f2d0df43f 100644
--- a/lib/sqlalchemy/orm/instrumentation.py
+++ b/lib/sqlalchemy/orm/instrumentation.py
@@ -279,7 +279,7 @@ class ClassManager(dict):
@property
def attributes(self):
- return self.itervalues()
+ return iter(self.values())
## InstanceState management
@@ -325,10 +325,12 @@ class ClassManager(dict):
"""TODO"""
return self.get_impl(key).hasparent(state, optimistic=optimistic)
- def __nonzero__(self):
+ def __bool__(self):
"""All ClassManagers are non-zero regardless of attribute state."""
return True
+ __nonzero__ = __bool__
+
def __repr__(self):
return '<%s of %r at %x>' % (
self.__class__.__name__, self.class_, id(self))
@@ -444,21 +446,23 @@ def __init__(%(apply_pos)s):
func_vars = util.format_argspec_init(original__init__, grouped=False)
func_text = func_body % func_vars
- # Py3K
- #func_defaults = getattr(original__init__, '__defaults__', None)
- #func_kw_defaults = getattr(original__init__, '__kwdefaults__', None)
- # Py2K
- func = getattr(original__init__, 'im_func', original__init__)
- func_defaults = getattr(func, 'func_defaults', None)
- # end Py2K
+# start Py3K
+ func_defaults = getattr(original__init__, '__defaults__', None)
+ func_kw_defaults = getattr(original__init__, '__kwdefaults__', None)
+# end Py3K
+# start Py2K
+# func = getattr(original__init__, 'im_func', original__init__)
+# func_defaults = getattr(func, 'func_defaults', None)
+# end Py2K
env = locals().copy()
- exec func_text in env
+ exec(func_text, env)
__init__ = env['__init__']
__init__.__doc__ = original__init__.__doc__
if func_defaults:
- __init__.func_defaults = func_defaults
- # Py3K
- #if func_kw_defaults:
- # __init__.__kwdefaults__ = func_kw_defaults
+ __init__.__defaults__ = func_defaults
+# start Py3K
+ if func_kw_defaults:
+ __init__.__kwdefaults__ = func_kw_defaults
+# end Py3K
return __init__
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index 70743624c..396f234c4 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -15,6 +15,7 @@ Other than the deprecated extensions, this module and the
classes within should be considered mostly private.
"""
+
from __future__ import absolute_import
from .. import exc as sa_exc, util, inspect
@@ -659,7 +660,7 @@ class PropertyOption(MapperOption):
tokens = deque(self.key)
while tokens:
token = tokens.popleft()
- if isinstance(token, basestring):
+ if isinstance(token, str):
# wildcard token
if token.endswith(':*'):
return [path.token(token)]
@@ -744,7 +745,7 @@ class PropertyOption(MapperOption):
ext_info.mapper, aliased=True,
_use_mapper_path=True)
ext_info = inspect(ac)
- path.set(query, "path_with_polymorphic", ext_info)
+ path.set(query._attributes, "path_with_polymorphic", ext_info)
else:
path_element = mapper = getattr(prop, 'mapper', None)
if mapper is None and tokens:
@@ -775,13 +776,13 @@ class StrategizedOption(PropertyOption):
if self.chained:
for path in paths:
path.set(
- query,
+ query._attributes,
"loaderstrategy",
strategy
)
else:
paths[-1].set(
- query,
+ query._attributes,
"loaderstrategy",
strategy
)
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index 5937197fd..e1f4d1b7c 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -11,7 +11,7 @@ the functions here are called primarily by Query, Mapper,
as well as some of the attribute loading strategies.
"""
-from __future__ import absolute_import
+
from .. import util
from . import attributes, exc as orm_exc, state as statelib
@@ -47,11 +47,11 @@ def instances(query, cursor, context):
query._entities[0].mapper.dispatch.append_result
(process, labels) = \
- zip(*[
+ list(zip(*[
query_entity.row_processor(query,
context, custom_rows)
for query_entity in query._entities
- ])
+ ]))
while True:
context.progress = {}
@@ -84,11 +84,11 @@ def instances(query, cursor, context):
context.progress.pop(context.refresh_state)
statelib.InstanceState._commit_all_states(
- context.progress.items(),
+ list(context.progress.items()),
session.identity_map
)
- for state, (dict_, attrs) in context.partials.iteritems():
+ for state, (dict_, attrs) in context.partials.items():
state._commit(dict_, attrs)
for row in rows:
@@ -507,7 +507,7 @@ def _populators(mapper, context, path, row, adapter,
pops = (new_populators, existing_populators, delayed_populators,
eager_populators)
- for prop in mapper._props.itervalues():
+ for prop in mapper._props.values():
for i, pop in enumerate(prop.create_row_processor(
context,
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index c08d91b57..285d338de 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -14,6 +14,7 @@ available in :class:`~sqlalchemy.orm.`.
"""
from __future__ import absolute_import
+
import types
import weakref
from itertools import chain
@@ -26,8 +27,8 @@ from . import instrumentation, attributes, \
from .interfaces import MapperProperty, _InspectionAttr, _MappedAttribute
from .util import _INSTRUMENTOR, _class_to_mapper, \
- _state_mapper, class_mapper, \
- PathRegistry
+ _state_mapper, class_mapper, \
+ PathRegistry
import sys
properties = util.importlater("sqlalchemy.orm", "properties")
descriptor_props = util.importlater("sqlalchemy.orm", "descriptor_props")
@@ -581,7 +582,7 @@ class Mapper(_InspectionAttr):
if with_polymorphic == '*':
self.with_polymorphic = ('*', None)
elif isinstance(with_polymorphic, (tuple, list)):
- if isinstance(with_polymorphic[0], (basestring, tuple, list)):
+ if isinstance(with_polymorphic[0], util.string_types + (tuple, list)):
self.with_polymorphic = with_polymorphic
else:
self.with_polymorphic = (with_polymorphic, None)
@@ -626,7 +627,7 @@ class Mapper(_InspectionAttr):
self.inherits._inheriting_mappers.add(self)
self.passive_updates = self.inherits.passive_updates
self._all_tables = self.inherits._all_tables
- for key, prop in mapper._props.iteritems():
+ for key, prop in mapper._props.items():
if key not in self._props and \
not self._should_exclude(key, key, local=False,
column=None):
@@ -866,12 +867,12 @@ class Mapper(_InspectionAttr):
# load custom properties
if self._init_properties:
- for key, prop in self._init_properties.iteritems():
+ for key, prop in self._init_properties.items():
self._configure_property(key, prop, False)
# pull properties from the inherited mapper if any.
if self.inherits:
- for key, prop in self.inherits._props.iteritems():
+ for key, prop in self.inherits._props.items():
if key not in self._props and \
not self._should_exclude(key, key, local=False,
column=None):
@@ -919,7 +920,7 @@ class Mapper(_InspectionAttr):
if self.polymorphic_on is not None:
setter = True
- if isinstance(self.polymorphic_on, basestring):
+ if isinstance(self.polymorphic_on, util.string_types):
# polymorphic_on specified as as string - link
# it to mapped ColumnProperty
try:
@@ -1235,7 +1236,7 @@ class Mapper(_InspectionAttr):
"""
self._log("_post_configure_properties() started")
- l = [(key, prop) for key, prop in self._props.iteritems()]
+ l = [(key, prop) for key, prop in self._props.items()]
for key, prop in l:
self._log("initialize prop %s", key)
@@ -1253,7 +1254,7 @@ class Mapper(_InspectionAttr):
using `add_property`.
"""
- for key, value in dict_of_properties.iteritems():
+ for key, value in dict_of_properties.items():
self.add_property(key, value)
def add_property(self, key, prop):
@@ -1350,7 +1351,7 @@ class Mapper(_InspectionAttr):
"""return an iterator of all MapperProperty objects."""
if _new_mappers:
configure_mappers()
- return self._props.itervalues()
+ return iter(self._props.values())
def _mappers_from_spec(self, spec, selectable):
"""given a with_polymorphic() argument, return the set of mappers it
@@ -1623,7 +1624,7 @@ class Mapper(_InspectionAttr):
if _new_mappers:
configure_mappers()
return util.ImmutableProperties(util.OrderedDict(
- (k, v) for k, v in self._props.iteritems()
+ (k, v) for k, v in self._props.items()
if isinstance(v, type_)
))
@@ -2040,7 +2041,7 @@ class Mapper(_InspectionAttr):
return fk.parent not in cols
return False
- sorted_ = sql_util.sort_tables(table_to_mapper.iterkeys(),
+ sorted_ = sql_util.sort_tables(table_to_mapper,
skip_fn=skip,
extra_dependencies=extra_dependencies)
diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py
index e225a7c83..a773786c4 100644
--- a/lib/sqlalchemy/orm/persistence.py
+++ b/lib/sqlalchemy/orm/persistence.py
@@ -19,6 +19,7 @@ from .. import sql, util, exc as sa_exc, schema
from . import attributes, sync, exc as orm_exc, evaluator
from .util import _state_mapper, state_str, _attr_as_key
from ..sql import expression
+from . import loading
def save_obj(base_mapper, states, uowtransaction, single=False):
@@ -45,7 +46,7 @@ def save_obj(base_mapper, states, uowtransaction, single=False):
cached_connections = _cached_connection_dict(base_mapper)
- for table, mapper in base_mapper._sorted_tables.iteritems():
+ for table, mapper in base_mapper._sorted_tables.items():
insert = _collect_insert_commands(base_mapper, uowtransaction,
table, states_to_insert)
@@ -77,7 +78,7 @@ def post_update(base_mapper, states, uowtransaction, post_update_cols):
base_mapper,
states, uowtransaction)
- for table, mapper in base_mapper._sorted_tables.iteritems():
+ for table, mapper in base_mapper._sorted_tables.items():
update = _collect_post_update_commands(base_mapper, uowtransaction,
table, states_to_update,
post_update_cols)
@@ -105,7 +106,7 @@ def delete_obj(base_mapper, states, uowtransaction):
table_to_mapper = base_mapper._sorted_tables
- for table in reversed(table_to_mapper.keys()):
+ for table in reversed(list(table_to_mapper.keys())):
delete = _collect_delete_commands(base_mapper, uowtransaction,
table, states_to_delete)
@@ -318,7 +319,7 @@ def _collect_update_commands(base_mapper, uowtransaction,
# history is only
# in a different table than the one
# where the version_id_col is.
- for prop in mapper._columntoproperty.itervalues():
+ for prop in mapper._columntoproperty.values():
history = attributes.get_state_history(
state, prop.key,
attributes.PASSIVE_NO_INITIALIZE)
@@ -526,7 +527,7 @@ def _emit_insert_statements(base_mapper, uowtransaction,
for (connection, pkeys, hasvalue, has_all_pks), \
records in groupby(insert,
lambda rec: (rec[4],
- rec[2].keys(),
+ list(rec[2].keys()),
bool(rec[5]),
rec[6])
):
@@ -612,7 +613,7 @@ def _emit_post_update_statements(base_mapper, uowtransaction,
# also group them into common (connection, cols) sets
# to support executemany().
for key, grouper in groupby(
- update, lambda rec: (rec[4], rec[2].keys())
+ update, lambda rec: (rec[4], list(rec[2].keys()))
):
connection = key[0]
multiparams = [params for state, state_dict,
@@ -646,7 +647,7 @@ def _emit_delete_statements(base_mapper, uowtransaction, cached_connections,
return table.delete(clause)
- for connection, del_objects in delete.iteritems():
+ for connection, del_objects in delete.items():
statement = base_mapper._memo(('delete', table), delete_stmt)
connection = cached_connections[connection]
@@ -699,7 +700,6 @@ def _finalize_insert_update_commands(base_mapper, uowtransaction,
# refresh whatever has been expired.
if base_mapper.eager_defaults and state.unloaded:
state.key = base_mapper._identity_key_from_state(state)
- from . import loading
loading.load_on_ident(
uowtransaction.session.query(base_mapper),
state.key, refresh_state=state,
@@ -803,7 +803,7 @@ class BulkUD(object):
raise sa_exc.ArgumentError(
"Valid strategies for session synchronization "
"are %s" % (", ".join(sorted(repr(x)
- for x in lookup.keys()))))
+ for x in lookup))))
else:
return klass(*arg)
@@ -868,7 +868,7 @@ class BulkEvaluate(BulkUD):
#TODO: detect when the where clause is a trivial primary key match
self.matched_objects = [
obj for (cls, pk), obj in
- query.session.identity_map.iteritems()
+ query.session.identity_map.items()
if issubclass(cls, target_cls) and
eval_condition(obj)]
@@ -951,7 +951,7 @@ class BulkUpdateEvaluate(BulkEvaluate, BulkUpdate):
def _additional_evaluators(self, evaluator_compiler):
self.value_evaluators = {}
- for key, value in self.values.iteritems():
+ for key, value in self.values.items():
key = _attr_as_key(key)
self.value_evaluators[key] = evaluator_compiler.process(
expression._literal_as_binds(value))
@@ -959,7 +959,7 @@ class BulkUpdateEvaluate(BulkEvaluate, BulkUpdate):
def _do_post_synchronize(self):
session = self.query.session
states = set()
- evaluated_keys = self.value_evaluators.keys()
+ evaluated_keys = list(self.value_evaluators.keys())
for obj in self.matched_objects:
state, dict_ = attributes.instance_state(obj),\
attributes.instance_dict(obj)
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 9f8721de9..8c0576527 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -27,7 +27,7 @@ from .interfaces import MANYTOMANY, MANYTOONE, ONETOMANY,\
mapperlib = util.importlater("sqlalchemy.orm", "mapperlib")
NoneType = type(None)
-from descriptor_props import CompositeProperty, SynonymProperty, \
+from .descriptor_props import CompositeProperty, SynonymProperty, \
ComparableProperty, ConcreteInheritedProperty
__all__ = ['ColumnProperty', 'CompositeProperty', 'SynonymProperty',
@@ -1204,7 +1204,7 @@ class RelationshipProperty(StrategizedProperty):
if not self.is_primary():
return
if self.backref is not None and not self.back_populates:
- if isinstance(self.backref, basestring):
+ if isinstance(self.backref, str):
backref_key, kwargs = self.backref, {}
else:
backref_key, kwargs = self.backref
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index c9f3a2699..beae7aba0 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -47,7 +47,7 @@ def _generative(*assertions):
def generate(fn, *args, **kw):
self = args[0]._clone()
for assertion in assertions:
- assertion(self, fn.func_name)
+ assertion(self, fn.__name__)
fn(self, *args[1:], **kw)
return self
return generate
@@ -162,15 +162,19 @@ class Query(object):
for m in m2.iterate_to_root():
self._polymorphic_adapters[m.local_table] = adapter
- def _set_select_from(self, *obj):
+ def _set_select_from(self, obj, set_base_alias):
fa = []
select_from_alias = None
+
for from_obj in obj:
info = inspect(from_obj)
if hasattr(info, 'mapper') and \
(info.is_mapper or info.is_aliased_class):
- self._select_from_entity = from_obj
+ if set_base_alias:
+ raise sa_exc.ArgumentError(
+ "A selectable (FromClause) instance is "
+ "expected when the base alias is being set.")
fa.append(info.selectable)
elif not info.is_selectable:
raise sa_exc.ArgumentError(
@@ -179,12 +183,14 @@ class Query(object):
else:
if isinstance(from_obj, expression.SelectBase):
from_obj = from_obj.alias()
- select_from_alias = from_obj
+ if set_base_alias:
+ select_from_alias = from_obj
fa.append(from_obj)
self._from_obj = tuple(fa)
- if len(self._from_obj) == 1 and \
+ if set_base_alias and \
+ len(self._from_obj) == 1 and \
isinstance(select_from_alias, expression.Alias):
equivs = self.__all_equivs()
self._from_obj_alias = sql_util.ColumnAdapter(
@@ -953,7 +959,7 @@ class Query(object):
'_prefixes',
):
self.__dict__.pop(attr, None)
- self._set_select_from(fromclause)
+ self._set_select_from([fromclause], True)
# this enables clause adaptation for non-ORM
# expressions.
@@ -981,11 +987,7 @@ class Query(object):
"""Return a scalar result corresponding to the given
column expression."""
try:
- # Py3K
- #return self.values(column).__next__()[0]
- # Py2K
- return self.values(column).next()[0]
- # end Py2K
+ return next(self.values(column))[0]
except StopIteration:
return None
@@ -1231,7 +1233,7 @@ class Query(object):
"""
clauses = [_entity_descriptor(self._joinpoint_zero(), key) == value
- for key, value in kwargs.iteritems()]
+ for key, value in kwargs.items()]
return self.filter(sql.and_(*clauses))
@_generative(_no_statement_condition, _no_limit_offset)
@@ -1296,7 +1298,7 @@ class Query(object):
"""
- if isinstance(criterion, basestring):
+ if isinstance(criterion, util.string_types):
criterion = sql.text(criterion)
if criterion is not None and \
@@ -1655,7 +1657,7 @@ class Query(object):
kwargs.pop('from_joinpoint', False)
if kwargs:
raise TypeError("unknown arguments: %s" %
- ','.join(kwargs.iterkeys()))
+ ','.join(kwargs.keys))
return self._join(props,
outerjoin=False, create_aliases=aliased,
from_joinpoint=from_joinpoint)
@@ -1671,7 +1673,7 @@ class Query(object):
kwargs.pop('from_joinpoint', False)
if kwargs:
raise TypeError("unknown arguments: %s" %
- ','.join(kwargs.iterkeys()))
+ ','.join(kwargs))
return self._join(props,
outerjoin=True, create_aliases=aliased,
from_joinpoint=from_joinpoint)
@@ -1701,7 +1703,7 @@ class Query(object):
if len(keys) == 2 and \
isinstance(keys[0], (expression.FromClause,
type, AliasedClass)) and \
- isinstance(keys[1], (basestring, expression.ClauseElement,
+ isinstance(keys[1], (str, expression.ClauseElement,
interfaces.PropComparator)):
# detect 2-arg form of join and
# convert to a tuple.
@@ -1721,14 +1723,14 @@ class Query(object):
# is a little bit of legacy behavior still at work here
# which means they might be in either order. may possibly
# lock this down to (right_entity, onclause) in 0.6.
- if isinstance(arg1, (interfaces.PropComparator, basestring)):
+ if isinstance(arg1, (interfaces.PropComparator, util.string_types)):
right_entity, onclause = arg2, arg1
else:
right_entity, onclause = arg1, arg2
left_entity = prop = None
- if isinstance(onclause, basestring):
+ if isinstance(onclause, util.string_types):
left_entity = self._joinpoint_zero()
descriptor = _entity_descriptor(left_entity, onclause)
@@ -1922,7 +1924,7 @@ class Query(object):
clause = orm_join(clause,
right,
onclause, isouter=outerjoin)
- except sa_exc.ArgumentError, ae:
+ except sa_exc.ArgumentError as ae:
raise sa_exc.InvalidRequestError(
"Could not find a FROM clause to join from. "
"Tried joining to %s, but got: %s" % (right, ae))
@@ -1947,7 +1949,7 @@ class Query(object):
try:
clause = orm_join(clause, right, onclause, isouter=outerjoin)
- except sa_exc.ArgumentError, ae:
+ except sa_exc.ArgumentError as ae:
raise sa_exc.InvalidRequestError(
"Could not find a FROM clause to join from. "
"Tried joining to %s, but got: %s" % (right, ae))
@@ -1974,21 +1976,134 @@ class Query(object):
def select_from(self, *from_obj):
"""Set the FROM clause of this :class:`.Query` explicitly.
- Sending a mapped class or entity here effectively replaces the
+ :meth:`.Query.select_from` is often used in conjunction with
+ :meth:`.Query.join` in order to control which entity is selected
+ from on the "left" side of the join.
+
+ The entity or selectable object here effectively replaces the
"left edge" of any calls to :meth:`~.Query.join`, when no
joinpoint is otherwise established - usually, the default "join
point" is the leftmost entity in the :class:`~.Query` object's
list of entities to be selected.
- Mapped entities or plain :class:`~.Table` or other selectables
- can be sent here which will form the default FROM clause.
+ A typical example::
+
+ q = session.query(Address).select_from(User).\\
+ join(User.addresses).\\
+ filter(User.name == 'ed')
+
+ Which produces SQL equivalent to::
+
+ SELECT address.* FROM user
+ JOIN address ON user.id=address.user_id
+ WHERE user.name = :name_1
+
+ :param \*from_obj: collection of one or more entities to apply
+ to the FROM clause. Entities can be mapped classes,
+ :class:`.AliasedClass` objects, :class:`.Mapper` objects
+ as well as core :class:`.FromClause` elements like subqueries.
+
+ .. versionchanged:: 0.9
+ This method no longer applies the given FROM object
+ to be the selectable from which matching entities
+ select from; the :meth:`.select_entity_from` method
+ now accomplishes this. See that method for a description
+ of this behavior.
+
+ .. seealso::
+
+ :meth:`~.Query.join`
+
+ :meth:`.Query.select_entity_from`
+
+ """
+
+ self._set_select_from(from_obj, False)
+
+ @_generative(_no_clauseelement_condition)
+ def select_entity_from(self, from_obj):
+ """Set the FROM clause of this :class:`.Query` to a
+ core selectable, applying it as a replacement FROM clause
+ for corresponding mapped entities.
+
+ This method is similar to the :meth:`.Query.select_from`
+ method, in that it sets the FROM clause of the query. However,
+ where :meth:`.Query.select_from` only affects what is placed
+ in the FROM, this method also applies the given selectable
+ to replace the FROM which the selected entities would normally
+ select from.
+
+ The given ``from_obj`` must be an instance of a :class:`.FromClause`,
+ e.g. a :func:`.select` or :class:`.Alias` construct.
+
+ An example would be a :class:`.Query` that selects ``User`` entities,
+ but uses :meth:`.Query.select_entity_from` to have the entities
+ selected from a :func:`.select` construct instead of the
+ base ``user`` table::
+
+ select_stmt = select([User]).where(User.id == 7)
+
+ q = session.query(User).\\
+ select_entity_from(select_stmt).\\
+ filter(User.name == 'ed')
+
+ The query generated will select ``User`` entities directly
+ from the given :func:`.select` construct, and will be::
+
+ SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name
+ FROM (SELECT "user".id AS id, "user".name AS name
+ FROM "user"
+ WHERE "user".id = :id_1) AS anon_1
+ WHERE anon_1.name = :name_1
+
+ Notice above that even the WHERE criterion was "adapted" such that
+ the ``anon_1`` subquery effectively replaces all references to the
+ ``user`` table, except for the one that it refers to internally.
+
+ Compare this to :meth:`.Query.select_from`, which as of
+ version 0.9, does not affect existing entities. The
+ statement below::
+
+ q = session.query(User).\\
+ select_from(select_stmt).\\
+ filter(User.name == 'ed')
+
+ Produces SQL where both the ``user`` table as well as the
+ ``select_stmt`` construct are present as separate elements
+ in the FROM clause. No "adaptation" of the ``user`` table
+ is applied::
+
+ SELECT "user".id AS user_id, "user".name AS user_name
+ FROM "user", (SELECT "user".id AS id, "user".name AS name
+ FROM "user"
+ WHERE "user".id = :id_1) AS anon_1
+ WHERE "user".name = :name_1
+
+ :meth:`.Query.select_entity_from` maintains an older
+ behavior of :meth:`.Query.select_from`. In modern usage,
+ similar results can also be achieved using :func:`.aliased`::
+
+ select_stmt = select([User]).where(User.id == 7)
+ user_from_select = aliased(User, select_stmt.alias())
+
+ q = session.query(user_from_select)
+
+ :param from_obj: a :class:`.FromClause` object that will replace
+ the FROM clause of this :class:`.Query`.
+
+ .. seealso::
+
+ :meth:`.Query.select_from`
- See the example in :meth:`~.Query.join` for a typical
- usage of :meth:`~.Query.select_from`.
+ .. versionadded:: 0.8
+ :meth:`.Query.select_entity_from` was added to specify
+ the specific behavior of entity replacement, however
+ the :meth:`.Query.select_from` maintains this behavior
+ as well until 0.9.
"""
- self._set_select_from(*from_obj)
+ self._set_select_from([from_obj], True)
def __getitem__(self, item):
if isinstance(item, slice):
@@ -2115,7 +2230,7 @@ class Query(object):
appropriate to the entity class represented by this ``Query``.
"""
- if isinstance(statement, basestring):
+ if isinstance(statement, util.string_types):
statement = sql.text(statement)
if not isinstance(statement,
@@ -2697,7 +2812,7 @@ class _QueryEntity(object):
def __new__(cls, *args, **kwargs):
if cls is _QueryEntity:
entity = args[1]
- if not isinstance(entity, basestring) and \
+ if not isinstance(entity, util.string_types) and \
_is_mapped_class(entity):
cls = _MapperEntity
else:
@@ -2905,7 +3020,7 @@ class _ColumnEntity(_QueryEntity):
self.expr = column
self.namespace = namespace
- if isinstance(column, basestring):
+ if isinstance(column, util.string_types):
column = sql.literal_column(column)
self._label_name = column.name
elif isinstance(column, (
@@ -3071,7 +3186,7 @@ class QueryContext(object):
self.create_eager_joins = []
self.propagate_options = set(o for o in query._with_options if
o.propagate_to_loaders)
- self.attributes = self._attributes = query._attributes.copy()
+ self.attributes = query._attributes.copy()
class AliasOption(interfaces.MapperOption):
@@ -3080,7 +3195,7 @@ class AliasOption(interfaces.MapperOption):
self.alias = alias
def process_query(self, query):
- if isinstance(self.alias, basestring):
+ if isinstance(self.alias, util.string_types):
alias = query._mapper_zero().mapped_table.alias(self.alias)
else:
alias = self.alias
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index ffb8a4e03..5a4486eef 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -5,7 +5,7 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""Provides the Session class and related utilities."""
-from __future__ import with_statement
+
import weakref
from .. import util, sql, engine, exc as sa_exc, event
@@ -328,7 +328,7 @@ class SessionTransaction(object):
subtransaction.commit()
if not self.session._flushing:
- for _flush_guard in xrange(100):
+ for _flush_guard in range(100):
if self.session._is_clean():
break
self.session.flush()
@@ -605,7 +605,7 @@ class Session(_SessionClassMethods):
SessionExtension._adapt_listener(self, ext)
if binds is not None:
- for mapperortable, bind in binds.iteritems():
+ for mapperortable, bind in binds.items():
if isinstance(mapperortable, (type, Mapper)):
self.bind_mapper(mapperortable, bind)
else:
@@ -1776,7 +1776,7 @@ class Session(_SessionClassMethods):
Session.
"""
- return iter(list(self._new.values()) + self.identity_map.values())
+ return iter(list(self._new.values()) + list(self.identity_map.values()))
def _contains_state(self, state):
return state in self._new or self.identity_map.contains_state(state)
@@ -2139,13 +2139,13 @@ class Session(_SessionClassMethods):
def deleted(self):
"The set of all instances marked as 'deleted' within this ``Session``"
- return util.IdentitySet(self._deleted.values())
+ return util.IdentitySet(list(self._deleted.values()))
@property
def new(self):
"The set of all instances marked as 'new' within this ``Session``."
- return util.IdentitySet(self._new.values())
+ return util.IdentitySet(list(self._new.values()))
class sessionmaker(_SessionClassMethods):
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 6660a39ef..cabfb35b9 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -359,7 +359,7 @@ class LazyLoader(AbstractRelationshipLoader):
)
if self.use_get:
- for col in self._equated_columns.keys():
+ for col in list(self._equated_columns):
if col in self.mapper._equivalent_columns:
for c in self.mapper._equivalent_columns[col]:
self._equated_columns[c] = self._equated_columns[col]
@@ -688,7 +688,8 @@ class SubqueryLoader(AbstractRelationshipLoader):
# build up a path indicating the path from the leftmost
# entity to the thing we're subquery loading.
- with_poly_info = path.get(context, "path_with_polymorphic", None)
+ with_poly_info = path.get(context.attributes,
+ "path_with_polymorphic", None)
if with_poly_info is not None:
effective_entity = with_poly_info.entity
else:
@@ -701,7 +702,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
# if not via query option, check for
# a cycle
- if not path.contains(context, "loaderstrategy"):
+ if not path.contains(context.attributes, "loaderstrategy"):
if self.join_depth:
if path.length / 2 > self.join_depth:
return
@@ -747,7 +748,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
# add new query to attributes to be picked up
# by create_row_processor
- path.set(context, "subquery", q)
+ path.set(context.attributes, "subquery", q)
def _get_leftmost(self, subq_path):
subq_path = subq_path.path
@@ -781,7 +782,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
# set a real "from" if not present, as this is more
# accurate than just going off of the column expression
if not q._from_obj and entity_mapper.isa(leftmost_mapper):
- q._set_select_from(entity_mapper)
+ q._set_select_from([entity_mapper], False)
# select from the identity columns of the outer
q._set_entities(q._adapt_col_list(leftmost_attr))
@@ -924,7 +925,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
path = path[self.parent_property]
- subq = path.get(context, 'subquery')
+ subq = path.get(context.attributes, 'subquery')
if subq is None:
return None, None, None
@@ -934,7 +935,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
# cache the loaded collections in the context
# so that inheriting mappers don't re-load when they
# call upon create_row_processor again
- collections = path.get(context, "collections")
+ collections = path.get(context.attributes, "collections")
if collections is None:
collections = dict(
(k, [v[0] for v in v])
@@ -942,7 +943,7 @@ class SubqueryLoader(AbstractRelationshipLoader):
subq,
lambda x: x[1:]
))
- path.set(context, 'collections', collections)
+ path.set(context.attributes, 'collections', collections)
if adapter:
local_cols = [adapter.columns[c] for c in local_cols]
@@ -1011,7 +1012,7 @@ class JoinedLoader(AbstractRelationshipLoader):
with_polymorphic = None
- user_defined_adapter = path.get(context,
+ user_defined_adapter = path.get(context.attributes,
"user_defined_eager_row_processor",
False)
if user_defined_adapter is not False:
@@ -1023,7 +1024,7 @@ class JoinedLoader(AbstractRelationshipLoader):
else:
# if not via query option, check for
# a cycle
- if not path.contains(context, "loaderstrategy"):
+ if not path.contains(context.attributes, "loaderstrategy"):
if self.join_depth:
if path.length / 2 > self.join_depth:
return
@@ -1037,7 +1038,7 @@ class JoinedLoader(AbstractRelationshipLoader):
)
with_poly_info = path.get(
- context,
+ context.attributes,
"path_with_polymorphic",
None
)
@@ -1065,11 +1066,11 @@ class JoinedLoader(AbstractRelationshipLoader):
adapter = entity._get_entity_clauses(context.query, context)
if adapter and user_defined_adapter:
user_defined_adapter = user_defined_adapter.wrap(adapter)
- path.set(context, "user_defined_eager_row_processor",
+ path.set(context.attributes, "user_defined_eager_row_processor",
user_defined_adapter)
elif adapter:
user_defined_adapter = adapter
- path.set(context, "user_defined_eager_row_processor",
+ path.set(context.attributes, "user_defined_eager_row_processor",
user_defined_adapter)
add_to_collection = context.primary_columns
@@ -1080,7 +1081,7 @@ class JoinedLoader(AbstractRelationshipLoader):
column_collection, parentmapper, allow_innerjoin
):
with_poly_info = path.get(
- context,
+ context.attributes,
"path_with_polymorphic",
None
)
@@ -1098,7 +1099,7 @@ class JoinedLoader(AbstractRelationshipLoader):
if self.parent_property.direction != interfaces.MANYTOONE:
context.multi_row_eager_loaders = True
- innerjoin = allow_innerjoin and path.get(context,
+ innerjoin = allow_innerjoin and path.get(context.attributes,
"eager_join_type",
self.parent_property.innerjoin)
if not innerjoin:
@@ -1113,7 +1114,7 @@ class JoinedLoader(AbstractRelationshipLoader):
)
add_to_collection = context.secondary_columns
- path.set(context, "eager_row_processor", clauses)
+ path.set(context.attributes, "eager_row_processor", clauses)
return clauses, adapter, add_to_collection, allow_innerjoin
@@ -1208,7 +1209,7 @@ class JoinedLoader(AbstractRelationshipLoader):
)
def _create_eager_adapter(self, context, row, adapter, path):
- user_defined_adapter = path.get(context,
+ user_defined_adapter = path.get(context.attributes,
"user_defined_eager_row_processor",
False)
if user_defined_adapter is not False:
@@ -1221,7 +1222,7 @@ class JoinedLoader(AbstractRelationshipLoader):
elif context.adapter:
decorator = context.adapter
else:
- decorator = path.get(context, "eager_row_processor")
+ decorator = path.get(context.attributes, "eager_row_processor")
if decorator is None:
return False
@@ -1332,7 +1333,7 @@ class EagerLazyOption(StrategizedOption):
def __init__(self, key, lazy=True, chained=False,
propagate_to_loaders=True
):
- if isinstance(key[0], basestring) and key[0] == '*':
+ if isinstance(key[0], str) and key[0] == '*':
if len(key) != 1:
raise sa_exc.ArgumentError(
"Wildcard identifier '*' must "
@@ -1374,9 +1375,9 @@ class EagerJoinOption(PropertyOption):
def process_query_property(self, query, paths):
if self.chained:
for path in paths:
- path.set(query, "eager_join_type", self.innerjoin)
+ path.set(query._attributes, "eager_join_type", self.innerjoin)
else:
- paths[-1].set(query, "eager_join_type", self.innerjoin)
+ paths[-1].set(query._attributes, "eager_join_type", self.innerjoin)
class LoadEagerFromAliasOption(PropertyOption):
@@ -1384,7 +1385,7 @@ class LoadEagerFromAliasOption(PropertyOption):
def __init__(self, key, alias=None, chained=False):
super(LoadEagerFromAliasOption, self).__init__(key)
if alias is not None:
- if not isinstance(alias, basestring):
+ if not isinstance(alias, str):
info = inspect(alias)
alias = info.selectable
self.alias = alias
@@ -1395,29 +1396,32 @@ class LoadEagerFromAliasOption(PropertyOption):
for path in paths[0:-1]:
(root_mapper, prop) = path.path[-2:]
adapter = query._polymorphic_adapters.get(prop.mapper, None)
- path.setdefault(query,
+ path.setdefault(query._attributes,
"user_defined_eager_row_processor",
adapter)
root_mapper, prop = paths[-1].path[-2:]
if self.alias is not None:
- if isinstance(self.alias, basestring):
+ if isinstance(self.alias, str):
self.alias = prop.target.alias(self.alias)
- paths[-1].set(query, "user_defined_eager_row_processor",
- sql_util.ColumnAdapter(self.alias,
+ paths[-1].set(query._attributes,
+ "user_defined_eager_row_processor",
+ sql_util.ColumnAdapter(self.alias,
equivalents=prop.mapper._equivalent_columns)
)
else:
- if paths[-1].contains(query, "path_with_polymorphic"):
- with_poly_info = paths[-1].get(query, "path_with_polymorphic")
+ if paths[-1].contains(query._attributes, "path_with_polymorphic"):
+ with_poly_info = paths[-1].get(query._attributes,
+ "path_with_polymorphic")
adapter = orm_util.ORMAdapter(
with_poly_info.entity,
equivalents=prop.mapper._equivalent_columns,
adapt_required=True)
else:
adapter = query._polymorphic_adapters.get(prop.mapper, None)
- paths[-1].set(query, "user_defined_eager_row_processor",
- adapter)
+ paths[-1].set(query._attributes,
+ "user_defined_eager_row_processor",
+ adapter)
def single_parent_validator(desc, prop):
diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py
index 1f5115c41..aa5f7836c 100644
--- a/lib/sqlalchemy/orm/unitofwork.py
+++ b/lib/sqlalchemy/orm/unitofwork.py
@@ -315,7 +315,7 @@ class UOWTransaction(object):
# see if the graph of mapper dependencies has cycles.
self.cycles = cycles = topological.find_cycles(
self.dependencies,
- self.postsort_actions.values())
+ list(self.postsort_actions.values()))
if cycles:
# if yes, break the per-mapper actions into
@@ -381,7 +381,7 @@ class UOWTransaction(object):
"""
states = set(self.states)
isdel = set(
- s for (s, (isdelete, listonly)) in self.states.iteritems()
+ s for (s, (isdelete, listonly)) in self.states.items()
if isdelete
)
other = states.difference(isdel)
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index 390e83538..bd8228f2c 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -120,7 +120,7 @@ def polymorphic_union(table_map, typecolname,
colnames = util.OrderedSet()
colnamemaps = {}
types = {}
- for key in table_map.keys():
+ for key in table_map:
table = table_map[key]
# mysql doesnt like selecting from a select;
@@ -146,7 +146,7 @@ def polymorphic_union(table_map, typecolname,
return sql.type_coerce(sql.null(), types[name]).label(name)
result = []
- for type, table in table_map.iteritems():
+ for type, table in table_map.items():
if typecolname is not None:
result.append(
sql.select([col(name, table) for name in colnames] +
@@ -203,7 +203,7 @@ def identity_key(*args, **kwargs):
"positional arguments, got %s" % len(args))
if kwargs:
raise sa_exc.ArgumentError("unknown keyword arguments: %s"
- % ", ".join(kwargs.keys()))
+ % ", ".join(kwargs))
mapper = class_mapper(class_)
if "ident" in locals():
return mapper.identity_key_from_primary_key(util.to_list(ident))
@@ -211,7 +211,7 @@ def identity_key(*args, **kwargs):
instance = kwargs.pop("instance")
if kwargs:
raise sa_exc.ArgumentError("unknown keyword arguments: %s"
- % ", ".join(kwargs.keys()))
+ % ", ".join(kwargs.keys))
mapper = object_mapper(instance)
return mapper.identity_key_from_instance(instance)
@@ -278,16 +278,16 @@ class PathRegistry(object):
return other is not None and \
self.path == other.path
- def set(self, reg, key, value):
- reg._attributes[(key, self.path)] = value
+ def set(self, attributes, key, value):
+ attributes[(key, self.path)] = value
- def setdefault(self, reg, key, value):
- reg._attributes.setdefault((key, self.path), value)
+ def setdefault(self, attributes, key, value):
+ attributes.setdefault((key, self.path), value)
- def get(self, reg, key, value=None):
+ def get(self, attributes, key, value=None):
key = (key, self.path)
- if key in reg._attributes:
- return reg._attributes[key]
+ if key in attributes:
+ return attributes[key]
else:
return value
@@ -300,7 +300,7 @@ class PathRegistry(object):
def pairs(self):
path = self.path
- for i in xrange(0, len(path), 2):
+ for i in range(0, len(path), 2):
yield path[i], path[i + 1]
def contains_mapper(self, mapper):
@@ -313,18 +313,18 @@ class PathRegistry(object):
else:
return False
- def contains(self, reg, key):
- return (key, self.path) in reg._attributes
+ def contains(self, attributes, key):
+ return (key, self.path) in attributes
def __reduce__(self):
return _unreduce_path, (self.serialize(), )
def serialize(self):
path = self.path
- return zip(
+ return list(zip(
[m.class_ for m in [path[i] for i in range(0, len(path), 2)]],
[path[i].key for i in range(1, len(path), 2)] + [None]
- )
+ ))
@classmethod
def deserialize(cls, path):
@@ -418,8 +418,9 @@ class EntityRegistry(PathRegistry, dict):
self.path = parent.path + (entity,)
- def __nonzero__(self):
+ def __bool__(self):
return True
+ __nonzero__ = __bool__
def __getitem__(self, entity):
if isinstance(entity, (int, slice)):
@@ -440,8 +441,8 @@ class EntityRegistry(PathRegistry, dict):
"""
path = dict.__getitem__(self, prop)
path_key = (key, path.path)
- if path_key in context._attributes:
- return context._attributes[path_key]
+ if path_key in context.attributes:
+ return context.attributes[path_key]
else:
return None
@@ -596,8 +597,8 @@ class AliasedClass(object):
return self.__adapt_prop(attr, key)
elif hasattr(attr, 'func_code'):
is_method = getattr(self.__target, key, None)
- if is_method and is_method.im_self is not None:
- return util.types.MethodType(attr.im_func, self, self)
+ if is_method and is_method.__self__ is not None:
+ return util.types.MethodType(attr.__func__, self, self)
else:
return None
elif hasattr(attr, '__get__'):
@@ -887,7 +888,7 @@ class _ORMJoin(expression.Join):
self._joined_from_info = right_info
- if isinstance(onclause, basestring):
+ if isinstance(onclause, util.string_types):
onclause = getattr(left_orm_info.entity, onclause)
if isinstance(onclause, attributes.QueryableAttribute):
@@ -1008,7 +1009,7 @@ def with_parent(instance, prop):
parent/child relationship.
"""
- if isinstance(prop, basestring):
+ if isinstance(prop, util.string_types):
mapper = object_mapper(instance)
prop = getattr(mapper.class_, prop).property
elif isinstance(prop, attributes.QueryableAttribute):
diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py
index 501b6d2a0..0470e9e48 100644
--- a/lib/sqlalchemy/pool.py
+++ b/lib/sqlalchemy/pool.py
@@ -57,7 +57,7 @@ def clear_managers():
All pools and connections are disposed.
"""
- for manager in proxies.itervalues():
+ for manager in proxies.values():
manager.close()
proxies.clear()
@@ -368,7 +368,7 @@ class _ConnectionRecord(object):
connection = self.__pool._creator()
self.__pool.logger.debug("Created new connection %r", connection)
return connection
- except Exception, e:
+ except Exception as e:
self.__pool.logger.debug("Error on connect(): %s", e)
raise
@@ -391,7 +391,7 @@ def _finalize_fairy(connection, connection_record, pool, ref, echo):
# Immediately close detached instances
if connection_record is None:
pool._close_connection(connection)
- except Exception, e:
+ except Exception as e:
if connection_record is not None:
connection_record.invalidate(e=e)
if isinstance(e, (SystemExit, KeyboardInterrupt)):
@@ -499,7 +499,7 @@ class _ConnectionFairy(object):
self._connection_record,
self)
return self
- except exc.DisconnectionError, e:
+ except exc.DisconnectionError as e:
self._pool.logger.info(
"Disconnection detected on checkout: %s", e)
self._connection_record.invalidate(e)
@@ -755,7 +755,7 @@ class QueuePool(Pool):
wait = self._max_overflow > -1 and \
self._overflow >= self._max_overflow
return self._pool.get(wait, self._timeout)
- except sqla_queue.SAAbort, aborted:
+ except sqla_queue.SAAbort as aborted:
return aborted.context._do_get()
except sqla_queue.Empty:
if self._max_overflow > -1 and \
@@ -1004,7 +1004,7 @@ class _DBProxy(object):
self._create_pool_mutex = threading.Lock()
def close(self):
- for key in self.pools.keys():
+ for key in list(self.pools):
del self.pools[key]
def __del__(self):
diff --git a/lib/sqlalchemy/processors.py b/lib/sqlalchemy/processors.py
index 9963ca9a3..bf95d146b 100644
--- a/lib/sqlalchemy/processors.py
+++ b/lib/sqlalchemy/processors.py
@@ -38,10 +38,10 @@ def str_to_datetime_processor_factory(regexp, type_):
"'%s'" % (type_.__name__, value))
if has_named_groups:
groups = m.groupdict(0)
- return type_(**dict(zip(groups.iterkeys(),
- map(int, groups.itervalues()))))
+ return type_(**dict(list(zip(iter(groups.keys()),
+ list(map(int, iter(groups.values())))))))
else:
- return type_(*map(int, m.groups(0)))
+ return type_(*list(map(int, m.groups(0))))
return process
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py
index f894e6c31..3a74cbd59 100644
--- a/lib/sqlalchemy/schema.py
+++ b/lib/sqlalchemy/schema.py
@@ -27,7 +27,7 @@ Since these objects are part of the SQL expression language, they are usable
as components in SQL expressions.
"""
-from __future__ import with_statement
+
import re
import inspect
from . import exc, util, dialects, event, events, inspection
@@ -679,7 +679,7 @@ class Table(SchemaItem, expression.TableClause):
# skip indexes that would be generated
# by the 'index' flag on Column
if len(index.columns) == 1 and \
- list(index.columns)[0].index:
+ list(index.columns)[0].index:
continue
Index(index.name,
unique=index.unique,
@@ -898,7 +898,7 @@ class Column(SchemaItem, expression.ColumnClause):
type_ = kwargs.pop('type_', None)
args = list(args)
if args:
- if isinstance(args[0], basestring):
+ if isinstance(args[0], util.string_types):
if name is not None:
raise exc.ArgumentError(
"May not pass name positionally and as a keyword.")
@@ -944,11 +944,7 @@ class Column(SchemaItem, expression.ColumnClause):
args.append(self.default)
else:
if getattr(self.type, '_warn_on_bytestring', False):
- # Py3K
- #if isinstance(self.default, bytes):
- # Py2K
- if isinstance(self.default, str):
- # end Py2K
+ if isinstance(self.default, util.binary_type):
util.warn("Unicode column received non-unicode "
"default value.")
args.append(ColumnDefault(self.default))
@@ -983,7 +979,7 @@ class Column(SchemaItem, expression.ColumnClause):
if kwargs:
raise exc.ArgumentError(
- "Unknown arguments passed to Column: " + repr(kwargs.keys()))
+ "Unknown arguments passed to Column: " + repr(list(kwargs)))
def __str__(self):
if self.name is None:
@@ -1048,7 +1044,7 @@ class Column(SchemaItem, expression.ColumnClause):
if self.key in table._columns:
col = table._columns.get(self.key)
if col is not self:
- for fk in list(col.foreign_keys):
+ for fk in col.foreign_keys:
table.foreign_keys.remove(fk)
if fk.constraint in table.constraints:
# this might have been removed
@@ -1069,7 +1065,7 @@ class Column(SchemaItem, expression.ColumnClause):
self.table = table
if self.index:
- if isinstance(self.index, basestring):
+ if isinstance(self.index, util.string_types):
raise exc.ArgumentError(
"The 'index' keyword argument on Column is boolean only. "
"To create indexes with a specific name, create an "
@@ -1077,7 +1073,7 @@ class Column(SchemaItem, expression.ColumnClause):
Index(expression._truncated_label('ix_%s' % self._label),
self, unique=self.unique)
elif self.unique:
- if isinstance(self.unique, basestring):
+ if isinstance(self.unique, util.string_types):
raise exc.ArgumentError(
"The 'unique' keyword argument on Column is boolean "
"only. To create unique constraints or indexes with a "
@@ -1153,23 +1149,15 @@ class Column(SchemaItem, expression.ColumnClause):
nullable=self.nullable,
quote=self.quote,
_proxies=[self], *fk)
- except TypeError, e:
- # Py3K
- #raise TypeError(
- # "Could not create a copy of this %r object. "
- # "Ensure the class includes a _constructor() "
- # "attribute or method which accepts the "
- # "standard Column constructor arguments, or "
- # "references the Column class itself." % self.__class__) from e
- # Py2K
- raise TypeError(
- "Could not create a copy of this %r object. "
- "Ensure the class includes a _constructor() "
- "attribute or method which accepts the "
- "standard Column constructor arguments, or "
- "references the Column class itself. "
- "Original error: %s" % (self.__class__, e))
- # end Py2K
+ except TypeError:
+ util.raise_from_cause(
+ TypeError(
+ "Could not create a copy of this %r object. "
+ "Ensure the class includes a _constructor() "
+ "attribute or method which accepts the "
+ "standard Column constructor arguments, or "
+ "references the Column class itself." % self.__class__)
+ )
c.table = selectable
selectable._columns.add(c)
@@ -1345,7 +1333,7 @@ class ForeignKey(SchemaItem):
if schema:
return schema + "." + self.column.table.name + \
"." + self.column.key
- elif isinstance(self._colspec, basestring):
+ elif isinstance(self._colspec, util.string_types):
return self._colspec
elif hasattr(self._colspec, '__clause_element__'):
_column = self._colspec.__clause_element__()
@@ -1390,7 +1378,7 @@ class ForeignKey(SchemaItem):
"""
# ForeignKey inits its remote column as late as possible, so tables
# can be defined without dependencies
- if isinstance(self._colspec, basestring):
+ if isinstance(self._colspec, util.string_types):
# locate the parent table this foreign key is attached to. we
# use the "original" column which our parent column represents
# (its a list of columns/other ColumnElements if the parent
@@ -1919,7 +1907,7 @@ class DefaultClause(FetchedValue):
has_argument = True
def __init__(self, arg, for_update=False, _reflected=False):
- util.assert_arg_type(arg, (basestring,
+ util.assert_arg_type(arg, (util.string_types[0],
expression.ClauseElement,
expression.TextClause), 'arg')
super(DefaultClause, self).__init__(for_update)
@@ -2029,7 +2017,7 @@ class ColumnCollectionMixin(object):
def _set_parent(self, table):
for col in self._pending_colargs:
- if isinstance(col, basestring):
+ if isinstance(col, util.string_types):
col = table.c[col]
self.columns.add(col)
@@ -2247,7 +2235,7 @@ class ForeignKeyConstraint(Constraint):
self._set_parent_with_dispatch(table)
elif columns and \
isinstance(columns[0], Column) and \
- columns[0].table is not None:
+ columns[0].table is not None:
self._set_parent_with_dispatch(columns[0].table)
@property
@@ -2256,19 +2244,19 @@ class ForeignKeyConstraint(Constraint):
@property
def columns(self):
- return self._elements.keys()
+ return list(self._elements)
@property
def elements(self):
- return self._elements.values()
+ return list(self._elements.values())
def _set_parent(self, table):
super(ForeignKeyConstraint, self)._set_parent(table)
- for col, fk in self._elements.iteritems():
+ for col, fk in self._elements.items():
# string-specified column names now get
# resolved to Column objects
- if isinstance(col, basestring):
+ if isinstance(col, util.string_types):
try:
col = table.c[col]
except KeyError:
@@ -2278,7 +2266,7 @@ class ForeignKeyConstraint(Constraint):
"named '%s' is present." % (table.description, col))
if not hasattr(fk, 'parent') or \
- fk.parent is not col:
+ fk.parent is not col:
fk._set_parent_with_dispatch(col)
if self.use_alter:
@@ -2569,7 +2557,7 @@ class MetaData(SchemaItem):
return 'MetaData(bind=%r)' % self.bind
def __contains__(self, table_or_key):
- if not isinstance(table_or_key, basestring):
+ if not isinstance(table_or_key, util.string_types):
table_or_key = table_or_key.key
return table_or_key in self.tables
@@ -2629,7 +2617,7 @@ class MetaData(SchemaItem):
def _bind_to(self, bind):
"""Bind this MetaData to an Engine, Connection, string or URL."""
- if isinstance(bind, (basestring, url.URL)):
+ if isinstance(bind, util.string_types + (url.URL, )):
from sqlalchemy import create_engine
self._bind = create_engine(bind)
else:
@@ -2662,7 +2650,7 @@ class MetaData(SchemaItem):
:meth:`.Inspector.sorted_tables`
"""
- return sqlutil.sort_tables(self.tables.itervalues())
+ return sqlutil.sort_tables(self.tables.values())
def reflect(self, bind=None, schema=None, views=False, only=None):
"""Load all available table definitions from the database.
@@ -2723,7 +2711,7 @@ class MetaData(SchemaItem):
bind.dialect.get_view_names(conn, schema)
)
- current = set(self.tables.iterkeys())
+ current = set(self.tables)
if only is None:
load = [name for name in available if name not in current]
@@ -2845,7 +2833,7 @@ class ThreadLocalMetaData(MetaData):
def _bind_to(self, bind):
"""Bind to a Connectable in the caller's thread."""
- if isinstance(bind, (basestring, url.URL)):
+ if isinstance(bind, util.string_types + (url.URL, )):
try:
self.context._engine = self.__engines[bind]
except KeyError:
@@ -2870,7 +2858,7 @@ class ThreadLocalMetaData(MetaData):
def dispose(self):
"""Dispose all bound engines, in all thread contexts."""
- for e in self.__engines.itervalues():
+ for e in self.__engines.values():
if hasattr(e, 'dispose'):
e.dispose()
@@ -3075,7 +3063,7 @@ class DDLElement(expression.Executable, _DDLCompiles):
not self._should_execute_deprecated(None, target, bind, **kw):
return False
- if isinstance(self.dialect, basestring):
+ if isinstance(self.dialect, util.string_types):
if self.dialect != bind.engine.name:
return False
elif isinstance(self.dialect, (tuple, list, set)):
@@ -3090,7 +3078,7 @@ class DDLElement(expression.Executable, _DDLCompiles):
def _should_execute_deprecated(self, event, target, bind, **kw):
if self.on is None:
return True
- elif isinstance(self.on, basestring):
+ elif isinstance(self.on, util.string_types):
return self.on == bind.engine.name
elif isinstance(self.on, (tuple, list, set)):
return bind.engine.name in self.on
@@ -3105,7 +3093,7 @@ class DDLElement(expression.Executable, _DDLCompiles):
def _check_ddl_on(self, on):
if (on is not None and
- (not isinstance(on, (basestring, tuple, list, set)) and
+ (not isinstance(on, util.string_types + (tuple, list, set)) and
not util.callable(on))):
raise exc.ArgumentError(
"Expected the name of a database dialect, a tuple "
@@ -3230,7 +3218,7 @@ class DDL(DDLElement):
"""
- if not isinstance(statement, basestring):
+ if not isinstance(statement, util.string_types):
raise exc.ArgumentError(
"Expected a string or unicode SQL statement, got '%r'" %
statement)
@@ -3262,7 +3250,7 @@ def _to_schema_column(element):
def _to_schema_column_or_string(element):
if hasattr(element, '__clause_element__'):
element = element.__clause_element__()
- if not isinstance(element, (basestring, expression.ColumnElement)):
+ if not isinstance(element, util.string_types + (expression.ColumnElement, )):
msg = "Element %r is not a string name or column element"
raise exc.ArgumentError(msg % element)
return element
diff --git a/lib/sqlalchemy/sql/__init__.py b/lib/sqlalchemy/sql/__init__.py
index 1b81a18c5..9700f26a0 100644
--- a/lib/sqlalchemy/sql/__init__.py
+++ b/lib/sqlalchemy/sql/__init__.py
@@ -64,5 +64,5 @@ from .expression import (
from .visitors import ClauseVisitor
-__tmp = locals().keys()
+__tmp = list(locals().keys())
__all__ = sorted([i for i in __tmp if not i.startswith('__')])
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 5dd7ec564..d475f54ac 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -51,7 +51,7 @@ RESERVED_WORDS = set([
'using', 'verbose', 'when', 'where'])
LEGAL_CHARACTERS = re.compile(r'^[A-Z0-9_$]+$', re.I)
-ILLEGAL_INITIAL_CHARACTERS = set([str(x) for x in xrange(0, 10)]).union(['$'])
+ILLEGAL_INITIAL_CHARACTERS = set([str(x) for x in range(0, 10)]).union(['$'])
BIND_PARAMS = re.compile(r'(?<![:\w\$\x5c]):([\w\$]+)(?![:\w\$])', re.UNICODE)
BIND_PARAMS_ESC = re.compile(r'\x5c(:[\w\$]+)(?![:\w\$])', re.UNICODE)
@@ -83,9 +83,7 @@ OPERATORS = {
operators.add: ' + ',
operators.mul: ' * ',
operators.sub: ' - ',
- # Py2K
operators.div: ' / ',
- # end Py2K
operators.mod: ' % ',
operators.truediv: ' / ',
operators.neg: '-',
@@ -334,7 +332,7 @@ class SQLCompiler(engine.Compiled):
if params:
pd = {}
- for bindparam, name in self.bind_names.iteritems():
+ for bindparam, name in self.bind_names.items():
if bindparam.key in params:
pd[name] = params[bindparam.key]
elif name in params:
@@ -488,7 +486,7 @@ class SQLCompiler(engine.Compiled):
def visit_textclause(self, textclause, **kwargs):
if textclause.typemap is not None:
- for colname, type_ in textclause.typemap.iteritems():
+ for colname, type_ in textclause.typemap.items():
self.result_map[colname
if self.dialect.case_sensitive
else colname.lower()] = \
@@ -862,12 +860,12 @@ class SQLCompiler(engine.Compiled):
of the DBAPI.
"""
- if isinstance(value, basestring):
+ if isinstance(value, util.string_types):
value = value.replace("'", "''")
return "'%s'" % value
elif value is None:
return "NULL"
- elif isinstance(value, (float, int, long)):
+ elif isinstance(value, (float, ) + util.int_types):
return repr(value)
elif isinstance(value, decimal.Decimal):
return str(value)
@@ -1172,7 +1170,7 @@ class SQLCompiler(engine.Compiled):
self, ashint=True)
})
for (from_, dialect), hinttext in
- select._hints.iteritems()
+ select._hints.items()
if dialect in ('*', self.dialect.name)
])
hint_text = self.get_select_hint_text(byfrom)
@@ -1570,7 +1568,7 @@ class SQLCompiler(engine.Compiled):
values = []
if stmt_parameters is not None:
- for k, v in stmt_parameters.iteritems():
+ for k, v in stmt_parameters.items():
colkey = sql._column_as_key(k)
if colkey is not None:
parameters.setdefault(colkey, v)
@@ -1910,22 +1908,13 @@ class DDLCompiler(engine.Compiled):
and not first_pk)
if column.primary_key:
first_pk = True
- except exc.CompileError, ce:
- # Py3K
- #raise exc.CompileError("(in table '%s', column '%s'): %s"
- # % (
- # table.description,
- # column.name,
- # ce.args[0]
- # )) from ce
- # Py2K
- raise exc.CompileError("(in table '%s', column '%s'): %s"
- % (
+ except exc.CompileError as ce:
+ util.raise_from_cause(
+ exc.CompileError(util.u("(in table '%s', column '%s'): %s") % (
table.description,
column.name,
ce.args[0]
- )), None, sys.exc_info()[2]
- # end Py2K
+ )))
const = self.create_table_constraints(table)
if const:
@@ -2078,7 +2067,7 @@ class DDLCompiler(engine.Compiled):
def get_column_default_string(self, column):
if isinstance(column.server_default, schema.DefaultClause):
- if isinstance(column.server_default.arg, basestring):
+ if isinstance(column.server_default.arg, util.string_types):
return "'%s'" % column.server_default.arg
else:
return self.sql_compiler.process(column.server_default.arg)
@@ -2397,7 +2386,7 @@ class IdentifierPreparer(object):
lc_value = value.lower()
return (lc_value in self.reserved_words
or value[0] in self.illegal_initial_characters
- or not self.legal_characters.match(unicode(value))
+ or not self.legal_characters.match(util.text_type(value))
or (lc_value != value))
def quote_schema(self, schema, force):
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 402e52272..6dc134d98 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -26,7 +26,7 @@ to stay the same in future releases.
"""
-
+from __future__ import unicode_literals
import itertools
import re
from operator import attrgetter
@@ -1375,7 +1375,7 @@ func = _FunctionGenerator()
modifier = _FunctionGenerator(group=False)
-class _truncated_label(unicode):
+class _truncated_label(util.text_type):
"""A unicode subclass used to identify symbolic "
"names that may require truncation."""
@@ -1395,13 +1395,13 @@ class _anonymous_label(_truncated_label):
def __add__(self, other):
return _anonymous_label(
- unicode(self) +
- unicode(other))
+ util.text_type(self) +
+ util.text_type(other))
def __radd__(self, other):
return _anonymous_label(
- unicode(other) +
- unicode(self))
+ util.text_type(other) +
+ util.text_type(self))
def apply_map(self, map_):
return self % map_
@@ -1422,7 +1422,7 @@ def _as_truncated(value):
def _string_or_unprintable(element):
- if isinstance(element, basestring):
+ if isinstance(element, util.string_types):
return element
else:
try:
@@ -1486,7 +1486,7 @@ def _labeled(element):
def _column_as_key(element):
- if isinstance(element, basestring):
+ if isinstance(element, util.string_types):
return element
if hasattr(element, '__clause_element__'):
element = element.__clause_element__()
@@ -1508,8 +1508,8 @@ def _literal_as_text(element):
return element
elif hasattr(element, '__clause_element__'):
return element.__clause_element__()
- elif isinstance(element, basestring):
- return TextClause(unicode(element))
+ elif isinstance(element, util.string_types):
+ return TextClause(util.text_type(element))
elif isinstance(element, (util.NoneType, bool)):
return _const_expr(element)
else:
@@ -1583,8 +1583,8 @@ def _interpret_as_column_or_from(element):
def _interpret_as_from(element):
insp = inspection.inspect(element, raiseerr=False)
if insp is None:
- if isinstance(element, basestring):
- return TextClause(unicode(element))
+ if isinstance(element, util.string_types):
+ return TextClause(util.text_type(element))
elif hasattr(insp, "selectable"):
return insp.selectable
raise exc.ArgumentError("FROM expression expected")
@@ -1717,17 +1717,6 @@ class ClauseElement(Visitable):
d.pop('_is_clone_of', None)
return d
- if util.jython:
- def __hash__(self):
- """Return a distinct hash code.
-
- ClauseElements may have special equality comparisons which
- makes us rely on them having unique hash codes for use in
- hash-based collections. Stock __hash__ doesn't guarantee
- unique values on platforms with moving GCs.
- """
- return id(self)
-
def _annotate(self, values):
"""return a copy of this ClauseElement with annotations
updated by the given dictionary.
@@ -1916,11 +1905,10 @@ class ClauseElement(Visitable):
return dialect.statement_compiler(dialect, self, **kw)
def __str__(self):
- # Py3K
- #return unicode(self.compile())
- # Py2K
- return unicode(self.compile()).encode('ascii', 'backslashreplace')
- # end Py2K
+ if util.py3k:
+ return str(self.compile())
+ else:
+ return unicode(self.compile()).encode('ascii', 'backslashreplace')
def __and__(self, other):
return and_(self, other)
@@ -1931,9 +1919,11 @@ class ClauseElement(Visitable):
def __invert__(self):
return self._negate()
- def __nonzero__(self):
+ def __bool__(self):
raise TypeError("Boolean value of this clause is not defined")
+ __nonzero__ = __bool__
+
def _negate(self):
if hasattr(self, 'negation_clause'):
return self.negation_clause
@@ -2205,7 +2195,7 @@ class _DefaultColumnComparator(operators.ColumnOperators):
def _check_literal(self, expr, operator, other):
if isinstance(other, (ColumnElement, TextClause)):
if isinstance(other, BindParameter) and \
- isinstance(other.type, sqltypes.NullType):
+ isinstance(other.type, sqltypes.NullType):
# TODO: perhaps we should not mutate the incoming
# bindparam() here and instead make a copy of it.
# this might be the only place that we're mutating
@@ -2525,7 +2515,7 @@ class ColumnCollection(util.OrderedProperties):
return and_(*l)
def __contains__(self, other):
- if not isinstance(other, basestring):
+ if not isinstance(other, util.string_types):
raise exc.ArgumentError("__contains__ requires a string argument")
return util.OrderedProperties.__contains__(self, other)
@@ -3117,7 +3107,6 @@ class Executable(Generative):
def execute(self, *multiparams, **params):
"""Compile and execute this :class:`.Executable`."""
-
e = self.bind
if e is None:
label = getattr(self, 'description', self.__class__.__name__)
@@ -3186,13 +3175,13 @@ class TextClause(Executable, ClauseElement):
_hide_froms = []
def __init__(
- self,
- text='',
- bind=None,
- bindparams=None,
- typemap=None,
- autocommit=None,
- ):
+ self,
+ text='',
+ bind=None,
+ bindparams=None,
+ typemap=None,
+ autocommit=None):
+
self._bind = bind
self.bindparams = {}
self.typemap = typemap
@@ -3202,9 +3191,9 @@ class TextClause(Executable, ClauseElement):
'e)')
self._execution_options = \
self._execution_options.union(
- {'autocommit': autocommit})
+ {'autocommit': autocommit})
if typemap is not None:
- for key in typemap.keys():
+ for key in typemap:
typemap[key] = sqltypes.to_instance(typemap[key])
def repl(m):
@@ -3241,7 +3230,7 @@ class TextClause(Executable, ClauseElement):
for b in self.bindparams.values())
def get_children(self, **kwargs):
- return self.bindparams.values()
+ return list(self.bindparams.values())
class Null(ColumnElement):
@@ -3759,7 +3748,7 @@ class BinaryExpression(ColumnElement):
negate=None, modifiers=None):
# allow compatibility with libraries that
# refer to BinaryExpression directly and pass strings
- if isinstance(operator, basestring):
+ if isinstance(operator, util.string_types):
operator = operators.custom_op(operator)
self._orig = (left, right)
self.left = _literal_as_text(left).self_group(against=operator)
@@ -3773,12 +3762,14 @@ class BinaryExpression(ColumnElement):
else:
self.modifiers = modifiers
- def __nonzero__(self):
+ def __bool__(self):
if self.operator in (operator.eq, operator.ne):
return self.operator(hash(self._orig[0]), hash(self._orig[1]))
else:
raise TypeError("Boolean value of this clause is not defined")
+ __nonzero__ = __bool__
+
@property
def is_comparison(self):
return operators.is_comparison(self.operator)
@@ -4066,11 +4057,10 @@ class Alias(FromClause):
@property
def description(self):
- # Py3K
- #return self.name
- # Py2K
- return self.name.encode('ascii', 'backslashreplace')
- # end Py2K
+ if util.py3k:
+ return self.name
+ else:
+ return self.name.encode('ascii', 'backslashreplace')
def as_scalar(self):
try:
@@ -4484,11 +4474,10 @@ class ColumnClause(Immutable, ColumnElement):
@util.memoized_property
def description(self):
- # Py3K
- #return self.name
- # Py2K
- return self.name.encode('ascii', 'backslashreplace')
- # end Py2K
+ if util.py3k:
+ return self.name
+ else:
+ return self.name.encode('ascii', 'backslashreplace')
@_memoized_property
def _key_label(self):
@@ -4615,11 +4604,10 @@ class TableClause(Immutable, FromClause):
@util.memoized_property
def description(self):
- # Py3K
- #return self.name
- # Py2K
- return self.name.encode('ascii', 'backslashreplace')
- # end Py2K
+ if util.py3k:
+ return self.name
+ else:
+ return self.name.encode('ascii', 'backslashreplace')
def append_column(self, c):
self._columns[c.key] = c
diff --git a/lib/sqlalchemy/sql/functions.py b/lib/sqlalchemy/sql/functions.py
index c1c07dfb6..5e2d0792c 100644
--- a/lib/sqlalchemy/sql/functions.py
+++ b/lib/sqlalchemy/sql/functions.py
@@ -41,7 +41,7 @@ class _GenericMeta(VisitableType):
super(_GenericMeta, cls).__init__(clsname, bases, clsdict)
-class GenericFunction(Function):
+class GenericFunction(util.with_metaclass(_GenericMeta, Function)):
"""Define a 'generic' function.
A generic function is a pre-established :class:`.Function`
@@ -112,7 +112,6 @@ class GenericFunction(Function):
name is still recognized for backwards-compatibility.
"""
- __metaclass__ = _GenericMeta
coerce_arguments = True
diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py
index a7e6af116..4afb3db48 100644
--- a/lib/sqlalchemy/sql/operators.py
+++ b/lib/sqlalchemy/sql/operators.py
@@ -9,16 +9,19 @@
"""Defines operators used in SQL expressions."""
+from .. import util
+
+
from operator import (
and_, or_, inv, add, mul, sub, mod, truediv, lt, le, ne, gt, ge, eq, neg,
getitem, lshift, rshift
)
-# Py2K
-from operator import (div,)
-# end Py2K
+if util.py2k:
+ from operator import div
+else:
+ div = truediv
-from ..util import symbol
class Operators(object):
@@ -781,17 +784,15 @@ parenthesize (a op b).
"""
-_smallest = symbol('_smallest', canonical=-100)
-_largest = symbol('_largest', canonical=100)
+_smallest = util.symbol('_smallest', canonical=-100)
+_largest = util.symbol('_largest', canonical=100)
_PRECEDENCE = {
from_: 15,
getitem: 15,
mul: 8,
truediv: 8,
- # Py2K
div: 8,
- # end Py2K
mod: 8,
neg: 8,
add: 7,
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index 4aa2d7496..91740dc16 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -232,7 +232,7 @@ def bind_values(clause):
def _quote_ddl_expr(element):
- if isinstance(element, basestring):
+ if isinstance(element, util.string_types):
element = element.replace("'", "''")
return "'%s'" % element
else:
@@ -349,7 +349,7 @@ def join_condition(a, b, ignore_nonexistent_tables=False,
continue
try:
col = fk.get_referent(left)
- except exc.NoReferenceError, nrte:
+ except exc.NoReferenceError as nrte:
if nrte.table_name == left.name:
raise
else:
@@ -367,7 +367,7 @@ def join_condition(a, b, ignore_nonexistent_tables=False,
continue
try:
col = fk.get_referent(b)
- except exc.NoReferenceError, nrte:
+ except exc.NoReferenceError as nrte:
if nrte.table_name == b.name:
raise
else:
@@ -518,15 +518,15 @@ class AnnotatedColumnElement(Annotated):
# so that the resulting objects are pickleable.
annotated_classes = {}
-for cls in expression.__dict__.values() + [schema.Column, schema.Table]:
+for cls in list(expression.__dict__.values()) + [schema.Column, schema.Table]:
if isinstance(cls, type) and issubclass(cls, expression.ClauseElement):
if issubclass(cls, expression.ColumnElement):
annotation_cls = "AnnotatedColumnElement"
else:
annotation_cls = "Annotated"
- exec "class Annotated%s(%s, cls):\n" \
- " pass" % (cls.__name__, annotation_cls) in locals()
- exec "annotated_classes[cls] = Annotated%s" % (cls.__name__,)
+ exec("class Annotated%s(%s, cls):\n" \
+ " pass" % (cls.__name__, annotation_cls), locals())
+ exec("annotated_classes[cls] = Annotated%s" % (cls.__name__,))
def _deep_annotate(element, annotations, exclude=None):
diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py
index f1dbb9e32..62f46ab64 100644
--- a/lib/sqlalchemy/sql/visitors.py
+++ b/lib/sqlalchemy/sql/visitors.py
@@ -49,11 +49,9 @@ class VisitableType(type):
Classes having no __visit_name__ attribute will remain unaffected.
"""
def __init__(cls, clsname, bases, clsdict):
- if cls.__name__ == 'Visitable' or not hasattr(cls, '__visit_name__'):
- super(VisitableType, cls).__init__(clsname, bases, clsdict)
- return
-
- _generate_dispatch(cls)
+ if clsname != 'Visitable' and \
+ hasattr(cls, '__visit_name__'):
+ _generate_dispatch(cls)
super(VisitableType, cls).__init__(clsname, bases, clsdict)
@@ -87,14 +85,12 @@ def _generate_dispatch(cls):
cls._compiler_dispatch = _compiler_dispatch
-class Visitable(object):
+class Visitable(util.with_metaclass(VisitableType, object)):
"""Base class for visitable objects, applies the
``VisitableType`` metaclass.
"""
- __metaclass__ = VisitableType
-
class ClauseVisitor(object):
"""Base class for visitor objects which can traverse using
diff --git a/lib/sqlalchemy/testing/__init__.py b/lib/sqlalchemy/testing/__init__.py
index e571a5045..d5522213d 100644
--- a/lib/sqlalchemy/testing/__init__.py
+++ b/lib/sqlalchemy/testing/__init__.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+
from .warnings import testing_warn, assert_warnings, resetwarnings
diff --git a/lib/sqlalchemy/testing/assertions.py b/lib/sqlalchemy/testing/assertions.py
index ebd10b130..c04153961 100644
--- a/lib/sqlalchemy/testing/assertions.py
+++ b/lib/sqlalchemy/testing/assertions.py
@@ -63,7 +63,7 @@ def emits_warning_on(db, *warnings):
@decorator
def decorate(fn, *args, **kw):
- if isinstance(db, basestring):
+ if isinstance(db, util.string_types):
if not spec(config.db):
return fn(*args, **kw)
else:
@@ -171,9 +171,9 @@ def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
try:
callable_(*args, **kwargs)
assert False, "Callable did not raise an exception"
- except except_cls, e:
- assert re.search(msg, unicode(e), re.UNICODE), u"%r !~ %s" % (msg, e)
- print unicode(e).encode('utf-8')
+ except except_cls as e:
+ assert re.search(msg, util.text_type(e), re.UNICODE), "%r !~ %s" % (msg, e)
+ print(util.text_type(e).encode('utf-8'))
class AssertsCompiledSQL(object):
@@ -190,12 +190,12 @@ class AssertsCompiledSQL(object):
dialect = default.DefaultDialect()
elif dialect is None:
dialect = config.db.dialect
- elif isinstance(dialect, basestring):
+ elif isinstance(dialect, util.string_types):
dialect = create_engine("%s://" % dialect).dialect
kw = {}
if params is not None:
- kw['column_keys'] = params.keys()
+ kw['column_keys'] = list(params)
if isinstance(clause, orm.Query):
context = clause._compile_context()
@@ -205,12 +205,13 @@ class AssertsCompiledSQL(object):
c = clause.compile(dialect=dialect, **kw)
param_str = repr(getattr(c, 'params', {}))
- # Py3K
- #param_str = param_str.encode('utf-8').decode('ascii', 'ignore')
- print "\nSQL String:\n" + str(c) + param_str
+ if util.py3k:
+ param_str = param_str.encode('utf-8').decode('ascii', 'ignore')
- cc = re.sub(r'[\n\t]', '', str(c))
+ print("\nSQL String:\n" + util.text_type(c) + param_str)
+
+ cc = re.sub(r'[\n\t]', '', util.text_type(c))
eq_(cc, result, "%r != %r on dialect %r" % (cc, result, dialect))
@@ -262,7 +263,7 @@ class ComparesTables(object):
class AssertsExecutionResults(object):
def assert_result(self, result, class_, *objects):
result = list(result)
- print repr(result)
+ print(repr(result))
self.assert_list(result, class_, objects)
def assert_list(self, result, class_, list):
@@ -275,7 +276,7 @@ class AssertsExecutionResults(object):
def assert_row(self, class_, rowobj, desc):
self.assert_(rowobj.__class__ is class_,
"item class is not " + repr(class_))
- for key, value in desc.iteritems():
+ for key, value in desc.items():
if isinstance(value, tuple):
if isinstance(value[1], list):
self.assert_list(getattr(rowobj, key), value[0], value[1])
@@ -300,7 +301,7 @@ class AssertsExecutionResults(object):
found = util.IdentitySet(result)
expected = set([immutabledict(e) for e in expected])
- for wrong in itertools.ifilterfalse(lambda o: type(o) == cls, found):
+ for wrong in util.itertools_filterfalse(lambda o: type(o) == cls, found):
fail('Unexpected type "%s", expected "%s"' % (
type(wrong).__name__, cls.__name__))
@@ -311,7 +312,7 @@ class AssertsExecutionResults(object):
NOVALUE = object()
def _compare_item(obj, spec):
- for key, value in spec.iteritems():
+ for key, value in spec.items():
if isinstance(value, tuple):
try:
self.assert_unordered_result(
@@ -352,7 +353,7 @@ class AssertsExecutionResults(object):
for rule in rules:
if isinstance(rule, dict):
newrule = assertsql.AllOf(*[
- assertsql.ExactSQL(k, v) for k, v in rule.iteritems()
+ assertsql.ExactSQL(k, v) for k, v in rule.items()
])
else:
newrule = assertsql.ExactSQL(*rule)
diff --git a/lib/sqlalchemy/testing/assertsql.py b/lib/sqlalchemy/testing/assertsql.py
index 0e250f356..a6b63b2c3 100644
--- a/lib/sqlalchemy/testing/assertsql.py
+++ b/lib/sqlalchemy/testing/assertsql.py
@@ -127,7 +127,7 @@ class RegexSQL(SQLMatchRule):
# do a positive compare only
for param, received in zip(params, _received_parameters):
- for k, v in param.iteritems():
+ for k, v in param.items():
if k not in received or received[k] != v:
equivalent = False
break
@@ -180,7 +180,7 @@ class CompiledSQL(SQLMatchRule):
all_received = list(_received_parameters)
while params:
param = dict(params.pop(0))
- for k, v in context.compiled.params.iteritems():
+ for k, v in context.compiled.params.items():
param.setdefault(k, v)
if param not in _received_parameters:
equivalent = False
@@ -195,9 +195,9 @@ class CompiledSQL(SQLMatchRule):
all_received = []
self._result = equivalent
if not self._result:
- print 'Testing for compiled statement %r partial params '\
+ print('Testing for compiled statement %r partial params '\
'%r, received %r with params %r' % (self.statement,
- all_params, _received_statement, all_received)
+ all_params, _received_statement, all_received))
self._errmsg = \
'Testing for compiled statement %r partial params %r, '\
'received %r with params %r' % (self.statement,
@@ -262,7 +262,7 @@ def _process_engine_statement(query, context):
# oracle+zxjdbc passes a PyStatement when returning into
- query = unicode(query)
+ query = str(query)
if context.engine.name == 'mssql' \
and query.endswith('; select scope_identity()'):
query = query[:-25]
diff --git a/lib/sqlalchemy/testing/engines.py b/lib/sqlalchemy/testing/engines.py
index 26f561016..efc0103f2 100644
--- a/lib/sqlalchemy/testing/engines.py
+++ b/lib/sqlalchemy/testing/engines.py
@@ -8,7 +8,7 @@ from .util import decorator
from .. import event, pool
import re
import warnings
-
+from .. import util
class ConnectionKiller(object):
@@ -31,18 +31,18 @@ class ConnectionKiller(object):
fn()
except (SystemExit, KeyboardInterrupt):
raise
- except Exception, e:
+ except Exception as e:
warnings.warn(
"testing_reaper couldn't "
"rollback/close connection: %s" % e)
def rollback_all(self):
- for rec in self.proxy_refs.keys():
+ for rec in list(self.proxy_refs):
if rec is not None and rec.is_valid:
self._safe(rec.rollback)
def close_all(self):
- for rec in self.proxy_refs.keys():
+ for rec in list(self.proxy_refs):
if rec is not None:
self._safe(rec._close)
@@ -66,7 +66,7 @@ class ConnectionKiller(object):
self.conns = set()
- for rec in self.testing_engines.keys():
+ for rec in list(self.testing_engines):
if rec is not config.db:
rec.dispose()
@@ -75,7 +75,7 @@ class ConnectionKiller(object):
for conn in self.conns:
self._safe(conn.close)
self.conns = set()
- for rec in self.testing_engines.keys():
+ for rec in list(self.testing_engines):
rec.dispose()
def assert_all_closed(self):
@@ -160,7 +160,7 @@ class ReconnectFixture(object):
fn()
except (SystemExit, KeyboardInterrupt):
raise
- except Exception, e:
+ except Exception as e:
warnings.warn(
"ReconnectFixture couldn't "
"close connection: %s" % e)
@@ -353,23 +353,22 @@ class ReplayableSession(object):
Callable = object()
NoAttribute = object()
- # Py3K
- #Natives = set([getattr(types, t)
- # for t in dir(types) if not t.startswith('_')]). \
- # union([type(t) if not isinstance(t, type)
- # else t for t in __builtins__.values()]).\
- # difference([getattr(types, t)
- # for t in ('FunctionType', 'BuiltinFunctionType',
- # 'MethodType', 'BuiltinMethodType',
- # 'LambdaType', )])
- # Py2K
- Natives = set([getattr(types, t)
- for t in dir(types) if not t.startswith('_')]). \
+ if util.py2k:
+ Natives = set([getattr(types, t)
+ for t in dir(types) if not t.startswith('_')]).\
difference([getattr(types, t)
for t in ('FunctionType', 'BuiltinFunctionType',
'MethodType', 'BuiltinMethodType',
'LambdaType', 'UnboundMethodType',)])
- # end Py2K
+ else:
+ Natives = set([getattr(types, t)
+ for t in dir(types) if not t.startswith('_')]).\
+ union([type(t) if not isinstance(t, type)
+ else t for t in __builtins__.values()]).\
+ difference([getattr(types, t)
+ for t in ('FunctionType', 'BuiltinFunctionType',
+ 'MethodType', 'BuiltinMethodType',
+ 'LambdaType', )])
def __init__(self):
self.buffer = deque()
diff --git a/lib/sqlalchemy/testing/entities.py b/lib/sqlalchemy/testing/entities.py
index 5c5e69154..c0dd58650 100644
--- a/lib/sqlalchemy/testing/entities.py
+++ b/lib/sqlalchemy/testing/entities.py
@@ -7,7 +7,7 @@ _repr_stack = set()
class BasicEntity(object):
def __init__(self, **kw):
- for key, value in kw.iteritems():
+ for key, value in kw.items():
setattr(self, key, value)
def __repr__(self):
@@ -67,7 +67,7 @@ class ComparableEntity(BasicEntity):
a = self
b = other
- for attr in a.__dict__.keys():
+ for attr in list(a.__dict__):
if attr.startswith('_'):
continue
value = getattr(a, attr)
diff --git a/lib/sqlalchemy/testing/exclusions.py b/lib/sqlalchemy/testing/exclusions.py
index 2c0679e1d..f580f3fde 100644
--- a/lib/sqlalchemy/testing/exclusions.py
+++ b/lib/sqlalchemy/testing/exclusions.py
@@ -1,4 +1,4 @@
-from __future__ import with_statement
+
import operator
from nose import SkipTest
@@ -23,10 +23,10 @@ class skip_if(object):
def fail_if(self, name='block'):
try:
yield
- except Exception, ex:
+ except Exception as ex:
if self.predicate():
- print ("%s failed as expected (%s): %s " % (
- name, self.predicate, str(ex)))
+ print(("%s failed as expected (%s): %s " % (
+ name, self.predicate, str(ex))))
else:
raise
else:
@@ -92,7 +92,7 @@ class Predicate(object):
return OrPredicate([cls.as_predicate(pred) for pred in predicate])
elif isinstance(predicate, tuple):
return SpecPredicate(*predicate)
- elif isinstance(predicate, basestring):
+ elif isinstance(predicate, util.string_types):
return SpecPredicate(predicate, None, None)
elif util.callable(predicate):
return LambdaPredicate(predicate)
diff --git a/lib/sqlalchemy/testing/fixtures.py b/lib/sqlalchemy/testing/fixtures.py
index 5c587cb2f..daa779ae3 100644
--- a/lib/sqlalchemy/testing/fixtures.py
+++ b/lib/sqlalchemy/testing/fixtures.py
@@ -1,6 +1,7 @@
from . import config
from . import assertions, schema
from .util import adict
+from .. import util
from .engines import drop_all_tables
from .entities import BasicEntity, ComparableEntity
import sys
@@ -125,9 +126,10 @@ class TablesTest(TestBase):
for table in reversed(self.metadata.sorted_tables):
try:
table.delete().execute().close()
- except sa.exc.DBAPIError, ex:
- print >> sys.stderr, "Error emptying table %s: %r" % (
- table, ex)
+ except sa.exc.DBAPIError as ex:
+ util.print_(
+ ("Error emptying table %s: %r" % (table, ex)),
+ file=sys.stderr)
def setup(self):
self._setup_each_tables()
@@ -187,10 +189,10 @@ class TablesTest(TestBase):
def _load_fixtures(cls):
"""Insert rows as represented by the fixtures() method."""
headers, rows = {}, {}
- for table, data in cls.fixtures().iteritems():
+ for table, data in cls.fixtures().items():
if len(data) < 2:
continue
- if isinstance(table, basestring):
+ if isinstance(table, util.string_types):
table = cls.tables[table]
headers[table] = data[0]
rows[table] = data[1:]
@@ -284,8 +286,8 @@ class MappedTest(_ORMTest, TablesTest, assertions.AssertsExecutionResults):
cls_registry[classname] = cls
return type.__init__(cls, classname, bases, dict_)
- class _Base(object):
- __metaclass__ = FindFixture
+ class _Base(util.with_metaclass(FindFixture, object)):
+ pass
class Basic(BasicEntity, _Base):
pass
diff --git a/lib/sqlalchemy/testing/plugin/noseplugin.py b/lib/sqlalchemy/testing/plugin/noseplugin.py
index 5bd7ff3cd..b3cd3a4e3 100644
--- a/lib/sqlalchemy/testing/plugin/noseplugin.py
+++ b/lib/sqlalchemy/testing/plugin/noseplugin.py
@@ -9,14 +9,20 @@ When third party libraries use this plugin, it can be imported
normally as "from sqlalchemy.testing.plugin import noseplugin".
"""
+
from __future__ import absolute_import
import os
-import ConfigParser
+import sys
+py3k = sys.version_info >= (3, 0)
+
+if py3k:
+ import configparser
+else:
+ import ConfigParser as configparser
from nose.plugins import Plugin
from nose import SkipTest
-import time
import sys
import re
@@ -55,9 +61,9 @@ def _log(option, opt_str, value, parser):
def _list_dbs(*args):
- print "Available --db options (use --dburi to override)"
+ print("Available --db options (use --dburi to override)")
for macro in sorted(file_config.options('db')):
- print "%20s\t%s" % (macro, file_config.get('db', macro))
+ print("%20s\t%s" % (macro, file_config.get('db', macro)))
sys.exit(0)
@@ -318,7 +324,7 @@ class NoseSQLAlchemy(Plugin):
opt("--write-profiles", action="store_true", dest="write_profiles", default=False,
help="Write/update profiling data.")
global file_config
- file_config = ConfigParser.ConfigParser()
+ file_config = configparser.ConfigParser()
file_config.read(['setup.cfg', 'test.cfg'])
def configure(self, options, conf):
diff --git a/lib/sqlalchemy/testing/profiling.py b/lib/sqlalchemy/testing/profiling.py
index 19a9731be..bda44d80c 100644
--- a/lib/sqlalchemy/testing/profiling.py
+++ b/lib/sqlalchemy/testing/profiling.py
@@ -60,9 +60,9 @@ def profiled(target=None, **target_opts):
if report:
sort_ = target_opts.get('sort', profile_config['sort'])
limit = target_opts.get('limit', profile_config['limit'])
- print ("Profile report for target '%s' (%s)" % (
+ print(("Profile report for target '%s' (%s)" % (
target, filename)
- )
+ ))
stats = load_stats()
stats.sort_stats(*sort_)
@@ -198,7 +198,7 @@ class ProfileStatsFile(object):
profile_f.close()
def _write(self):
- print("Writing profile file %s" % self.fname)
+ print(("Writing profile file %s" % self.fname))
profile_f = open(self.fname, "w")
profile_f.write(self._header())
for test_key in sorted(self.data):
@@ -253,11 +253,11 @@ def function_call_count(variance=0.05):
else:
line_no, expected_count = expected
- print("Pstats calls: %d Expected %s" % (
+ print(("Pstats calls: %d Expected %s" % (
callcount,
expected_count
)
- )
+ ))
stats.print_stats()
#stats.print_callers()
diff --git a/lib/sqlalchemy/testing/schema.py b/lib/sqlalchemy/testing/schema.py
index 325d74f1e..025bbaabe 100644
--- a/lib/sqlalchemy/testing/schema.py
+++ b/lib/sqlalchemy/testing/schema.py
@@ -11,7 +11,7 @@ table_options = {}
def Table(*args, **kw):
"""A schema.Table wrapper/hook for dialect-specific tweaks."""
- test_opts = dict([(k, kw.pop(k)) for k in kw.keys()
+ test_opts = dict([(k, kw.pop(k)) for k in list(kw)
if k.startswith('test_')])
kw.update(table_options)
@@ -58,7 +58,7 @@ def Table(*args, **kw):
def Column(*args, **kw):
"""A schema.Column wrapper/hook for dialect-specific tweaks."""
- test_opts = dict([(k, kw.pop(k)) for k in kw.keys()
+ test_opts = dict([(k, kw.pop(k)) for k in list(kw)
if k.startswith('test_')])
if not config.requirements.foreign_key_ddl.enabled:
diff --git a/lib/sqlalchemy/testing/suite/test_ddl.py b/lib/sqlalchemy/testing/suite/test_ddl.py
index fc1c19362..28251b807 100644
--- a/lib/sqlalchemy/testing/suite/test_ddl.py
+++ b/lib/sqlalchemy/testing/suite/test_ddl.py
@@ -1,4 +1,4 @@
-from __future__ import with_statement
+
from .. import fixtures, config, util
from ..config import requirements
diff --git a/lib/sqlalchemy/testing/suite/test_reflection.py b/lib/sqlalchemy/testing/suite/test_reflection.py
index 7cae48572..ff76bd2cd 100644
--- a/lib/sqlalchemy/testing/suite/test_reflection.py
+++ b/lib/sqlalchemy/testing/suite/test_reflection.py
@@ -1,4 +1,4 @@
-from __future__ import with_statement
+
import sqlalchemy as sa
from sqlalchemy import exc as sa_exc
@@ -386,7 +386,7 @@ class ComponentReflectionTest(fixtures.TablesTest):
self.tables.email_addresses, self.tables.dingalings
insp = inspect(meta.bind)
oid = insp.get_table_oid(table_name, schema)
- self.assert_(isinstance(oid, (int, long)))
+ self.assert_(isinstance(oid, int))
def test_get_table_oid(self):
self._test_get_table_oid('users')
diff --git a/lib/sqlalchemy/testing/suite/test_types.py b/lib/sqlalchemy/testing/suite/test_types.py
index 0716b1b91..0d8bfdc0f 100644
--- a/lib/sqlalchemy/testing/suite/test_types.py
+++ b/lib/sqlalchemy/testing/suite/test_types.py
@@ -10,14 +10,15 @@ from ..schema import Table, Column
from ... import testing
import decimal
import datetime
-
+from ...util import u
+from ... import util
class _UnicodeFixture(object):
__requires__ = 'unicode_data',
- data = u"Alors vous imaginez ma surprise, au lever du jour, "\
- u"quand une drôle de petite voix m’a réveillé. Elle "\
- u"disait: « S’il vous plaît… dessine-moi un mouton! »"
+ data = u("Alors vous imaginez ma surprise, au lever du jour, "\
+ "quand une drôle de petite voix m’a réveillé. Elle "\
+ "disait: « S’il vous plaît… dessine-moi un mouton! »")
@classmethod
def define_tables(cls, metadata):
@@ -47,7 +48,7 @@ class _UnicodeFixture(object):
row,
(self.data, )
)
- assert isinstance(row[0], unicode)
+ assert isinstance(row[0], util.text_type)
def test_round_trip_executemany(self):
unicode_table = self.tables.unicode_table
@@ -58,7 +59,7 @@ class _UnicodeFixture(object):
{
'unicode_data': self.data,
}
- for i in xrange(3)
+ for i in range(3)
]
)
@@ -69,22 +70,22 @@ class _UnicodeFixture(object):
).fetchall()
eq_(
rows,
- [(self.data, ) for i in xrange(3)]
+ [(self.data, ) for i in range(3)]
)
for row in rows:
- assert isinstance(row[0], unicode)
+ assert isinstance(row[0], util.text_type)
def _test_empty_strings(self):
unicode_table = self.tables.unicode_table
config.db.execute(
unicode_table.insert(),
- {"unicode_data": u''}
+ {"unicode_data": u('')}
)
row = config.db.execute(
select([unicode_table.c.unicode_data])
).first()
- eq_(row, (u'',))
+ eq_(row, (u(''),))
class UnicodeVarcharTest(_UnicodeFixture, fixtures.TablesTest):
diff --git a/lib/sqlalchemy/testing/util.py b/lib/sqlalchemy/testing/util.py
index d9ff14eaf..5facd2f06 100644
--- a/lib/sqlalchemy/testing/util.py
+++ b/lib/sqlalchemy/testing/util.py
@@ -32,13 +32,13 @@ else:
def picklers():
picklers = set()
- # Py2K
- try:
- import cPickle
- picklers.add(cPickle)
- except ImportError:
- pass
- # end Py2K
+# start Py2K
+# try:
+# import cPickle
+# picklers.add(cPickle)
+# except ImportError:
+# pass
+# end Py2K
import pickle
picklers.add(pickle)
@@ -130,8 +130,8 @@ def function_named(fn, name):
try:
fn.__name__ = name
except TypeError:
- fn = types.FunctionType(fn.func_code, fn.func_globals, name,
- fn.func_defaults, fn.func_closure)
+ fn = types.FunctionType(fn.__code__, fn.__globals__, name,
+ fn.__defaults__, fn.__closure__)
return fn
diff --git a/lib/sqlalchemy/testing/warnings.py b/lib/sqlalchemy/testing/warnings.py
index 41f3dbfed..6193acd88 100644
--- a/lib/sqlalchemy/testing/warnings.py
+++ b/lib/sqlalchemy/testing/warnings.py
@@ -10,7 +10,7 @@ def testing_warn(msg, stacklevel=3):
filename = "sqlalchemy.testing.warnings"
lineno = 1
- if isinstance(msg, basestring):
+ if isinstance(msg, util.string_types):
warnings.warn_explicit(msg, sa_exc.SAWarning, filename, lineno)
else:
warnings.warn_explicit(msg, filename, lineno)
diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py
index 46cf9e2a1..bfff05362 100644
--- a/lib/sqlalchemy/types.py
+++ b/lib/sqlalchemy/types.py
@@ -156,8 +156,8 @@ class TypeEngine(AbstractType):
"""
- return self.__class__.column_expression.func_code \
- is not TypeEngine.column_expression.func_code
+ return self.__class__.column_expression.__code__ \
+ is not TypeEngine.column_expression.__code__
def bind_expression(self, bindvalue):
""""Given a bind value (i.e. a :class:`.BindParameter` instance),
@@ -194,8 +194,8 @@ class TypeEngine(AbstractType):
"""
- return self.__class__.bind_expression.func_code \
- is not TypeEngine.bind_expression.func_code
+ return self.__class__.bind_expression.__code__ \
+ is not TypeEngine.bind_expression.__code__
def compare_values(self, x, y):
"""Compare two values for equality."""
@@ -392,12 +392,11 @@ class TypeEngine(AbstractType):
return default.DefaultDialect()
def __str__(self):
- # Py3K
- #return unicode(self.compile())
- # Py2K
- return unicode(self.compile()).\
+ if util.py2k:
+ return unicode(self.compile()).\
encode('ascii', 'backslashreplace')
- # end Py2K
+ else:
+ return str(self.compile())
def __init__(self, *args, **kwargs):
"""Support implementations that were passing arguments"""
@@ -723,8 +722,8 @@ class TypeDecorator(TypeEngine):
"""
- return self.__class__.process_bind_param.func_code \
- is not TypeDecorator.process_bind_param.func_code
+ return self.__class__.process_bind_param.__code__ \
+ is not TypeDecorator.process_bind_param.__code__
def bind_processor(self, dialect):
"""Provide a bound value processing function for the
@@ -769,8 +768,8 @@ class TypeDecorator(TypeEngine):
exception throw.
"""
- return self.__class__.process_result_value.func_code \
- is not TypeDecorator.process_result_value.func_code
+ return self.__class__.process_result_value.__code__ \
+ is not TypeDecorator.process_result_value.__code__
def result_processor(self, dialect, coltype):
"""Provide a result value processing function for the given
@@ -1114,11 +1113,7 @@ class String(Concatenable, TypeEngine):
self.convert_unicode != 'force':
if self._warn_on_bytestring:
def process(value):
- # Py3K
- #if isinstance(value, bytes):
- # Py2K
- if isinstance(value, str):
- # end Py2K
+ if isinstance(value, util.binary_type):
util.warn("Unicode type received non-unicode bind "
"param value.")
return value
@@ -1130,7 +1125,7 @@ class String(Concatenable, TypeEngine):
warn_on_bytestring = self._warn_on_bytestring
def process(value):
- if isinstance(value, unicode):
+ if isinstance(value, util.text_type):
return encoder(value, self.unicode_error)[0]
elif warn_on_bytestring and value is not None:
util.warn("Unicode type received non-unicode bind "
@@ -1156,7 +1151,7 @@ class String(Concatenable, TypeEngine):
# habits. since we will be getting back unicode
# in most cases, we check for it (decode will fail).
def process(value):
- if isinstance(value, unicode):
+ if isinstance(value, util.text_type):
return value
else:
return to_unicode(value)
@@ -1171,7 +1166,7 @@ class String(Concatenable, TypeEngine):
@property
def python_type(self):
if self.convert_unicode:
- return unicode
+ return util.text_type
else:
return str
@@ -1318,12 +1313,10 @@ class Integer(_DateAffinity, TypeEngine):
Integer: self.__class__,
Numeric: Numeric,
},
- # Py2K
operators.div: {
Integer: self.__class__,
Numeric: Numeric,
},
- # end Py2K
operators.truediv: {
Integer: self.__class__,
Numeric: Numeric,
@@ -1488,12 +1481,10 @@ class Numeric(_DateAffinity, TypeEngine):
Numeric: self.__class__,
Integer: self.__class__,
},
- # Py2K
operators.div: {
Numeric: self.__class__,
Integer: self.__class__,
},
- # end Py2K
operators.truediv: {
Numeric: self.__class__,
Integer: self.__class__,
@@ -1558,11 +1549,9 @@ class Float(Numeric):
Interval: Interval,
Numeric: self.__class__,
},
- # Py2K
operators.div: {
Numeric: self.__class__,
},
- # end Py2K
operators.truediv: {
Numeric: self.__class__,
},
@@ -1693,11 +1682,7 @@ class _Binary(TypeEngine):
@property
def python_type(self):
- # Py3K
- #return bytes
- # Py2K
- return str
- # end Py2K
+ return util.binary_type
# Python 3 - sqlite3 doesn't need the `Binary` conversion
# here, though pg8000 does to indicate "bytea"
@@ -1715,32 +1700,31 @@ class _Binary(TypeEngine):
# Python 3 has native bytes() type
# both sqlite3 and pg8000 seem to return it,
# psycopg2 as of 2.5 returns 'memoryview'
- # Py3K
- #def result_processor(self, dialect, coltype):
- # def process(value):
- # if value is not None:
- # value = bytes(value)
- # return value
- # return process
- # Py2K
- def result_processor(self, dialect, coltype):
- if util.jython:
+ if util.py2k:
+ def result_processor(self, dialect, coltype):
+ if util.jython:
+ def process(value):
+ if value is not None:
+ if isinstance(value, array.array):
+ return value.tostring()
+ return str(value)
+ else:
+ return None
+ else:
+ process = processors.to_str
+ return process
+ else:
+ def result_processor(self, dialect, coltype):
def process(value):
if value is not None:
- if isinstance(value, array.array):
- return value.tostring()
- return str(value)
- else:
- return None
- else:
- process = processors.to_str
- return process
- # end Py2K
+ value = bytes(value)
+ return value
+ return process
def coerce_compared_value(self, op, value):
"""See :meth:`.TypeEngine.coerce_compared_value` for a description."""
- if isinstance(value, basestring):
+ if isinstance(value, util.string_types):
return self
else:
return super(_Binary, self).coerce_compared_value(op, value)
@@ -1997,7 +1981,7 @@ class Enum(String, SchemaType):
convert_unicode = kw.pop('convert_unicode', None)
if convert_unicode is None:
for e in enums:
- if isinstance(e, unicode):
+ if isinstance(e, util.text_type):
convert_unicode = True
break
else:
@@ -2296,11 +2280,9 @@ class Interval(_DateAffinity, TypeDecorator):
operators.truediv: {
Numeric: self.__class__
},
- # Py2K
operators.div: {
Numeric: self.__class__
}
- # end Py2K
}
@property
@@ -2450,12 +2432,6 @@ BOOLEANTYPE = Boolean()
STRINGTYPE = String()
_type_map = {
- str: String(),
- # Py3K
- #bytes: LargeBinary(),
- # Py2K
- unicode: Unicode(),
- # end Py2K
int: Integer(),
float: Numeric(),
bool: BOOLEANTYPE,
@@ -2466,3 +2442,12 @@ _type_map = {
dt.timedelta: Interval(),
NoneType: NULLTYPE
}
+
+if util.py3k:
+ _type_map[bytes] = LargeBinary()
+ _type_map[str] = Unicode()
+else:
+ _type_map[unicode] = Unicode()
+ _type_map[str] = String()
+
+
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py
index 3fa06c793..687abb39a 100644
--- a/lib/sqlalchemy/util/__init__.py
+++ b/lib/sqlalchemy/util/__init__.py
@@ -5,9 +5,12 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from .compat import callable, cmp, reduce, \
- threading, py3k, py3k_warning, jython, pypy, cpython, win32, set_types, \
+ threading, py3k, py2k, jython, pypy, cpython, win32, \
pickle, dottedgetter, parse_qsl, namedtuple, next, WeakSet, reraise, \
- raise_from_cause
+ raise_from_cause, text_type, string_types, int_types, binary_type, \
+ quote_plus, with_metaclass, print_, itertools_filterfalse, u, ue, b,\
+ unquote_plus, b64decode, b64encode, byte_buffer, itertools_filter,\
+ StringIO
from ._collections import KeyedTuple, ImmutableContainer, immutabledict, \
Properties, OrderedProperties, ImmutableProperties, OrderedDict, \
diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py
index 8e61275e7..86a90828a 100644
--- a/lib/sqlalchemy/util/_collections.py
+++ b/lib/sqlalchemy/util/_collections.py
@@ -9,7 +9,8 @@
import itertools
import weakref
import operator
-from .compat import threading
+from .compat import threading, itertools_filterfalse
+from . import py2k
EMPTY_SET = frozenset()
@@ -142,7 +143,7 @@ class Properties(object):
return len(self._data)
def __iter__(self):
- return self._data.itervalues()
+ return iter(list(self._data.values()))
def __add__(self, other):
return list(self) + list(other)
@@ -189,13 +190,13 @@ class Properties(object):
return default
def keys(self):
- return self._data.keys()
+ return list(self._data)
def values(self):
- return self._data.values()
+ return list(self._data.values())
def items(self):
- return self._data.items()
+ return list(self._data.items())
def has_key(self, key):
return key in self._data
@@ -260,23 +261,55 @@ class OrderedDict(dict):
def __iter__(self):
return iter(self._list)
- def values(self):
- return [self[key] for key in self._list]
- def itervalues(self):
- return iter([self[key] for key in self._list])
+ if py2k:
+ def values(self):
+ return [self[key] for key in self._list]
- def keys(self):
- return list(self._list)
+ def keys(self):
+ return self._list
- def iterkeys(self):
- return iter(self.keys())
+ def itervalues(self):
+ return iter([self[key] for key in self._list])
- def items(self):
- return [(key, self[key]) for key in self.keys()]
+ def iterkeys(self):
+ return iter(self)
+
+ def iteritems(self):
+ return iter(self.items())
+
+ def items(self):
+ return [(key, self[key]) for key in self._list]
+ else:
+ def values(self):
+ #return (self[key] for key in self)
+ return (self[key] for key in self._list)
+
+ def keys(self):
+ #return iter(self)
+ return iter(self._list)
+
+ def items(self):
+ #return ((key, self[key]) for key in self)
+ return ((key, self[key]) for key in self._list)
+
+ _debug_iter = False
+ if _debug_iter:
+ # normally disabled to reduce function call
+ # overhead
+ def __iter__(self):
+ len_ = len(self._list)
+ for item in self._list:
+ yield item
+ assert len_ == len(self._list), \
+ "Dictionary changed size during iteration"
+ def values(self):
+ return (self[key] for key in self)
+ def keys(self):
+ return iter(self)
+ def items(self):
+ return ((key, self[key]) for key in self)
- def iteritems(self):
- return iter(self.items())
def __setitem__(self, key, object):
if key not in self:
@@ -470,8 +503,8 @@ class IdentitySet(object):
if len(self) > len(other):
return False
- for m in itertools.ifilterfalse(other._members.__contains__,
- self._members.iterkeys()):
+ for m in itertools_filterfalse(other._members.__contains__,
+ iter(self._members.keys())):
return False
return True
@@ -491,8 +524,8 @@ class IdentitySet(object):
if len(self) < len(other):
return False
- for m in itertools.ifilterfalse(self._members.__contains__,
- other._members.iterkeys()):
+ for m in itertools_filterfalse(self._members.__contains__,
+ iter(other._members.keys())):
return False
return True
@@ -582,7 +615,7 @@ class IdentitySet(object):
return result
def _member_id_tuples(self):
- return ((id(v), v) for v in self._members.itervalues())
+ return ((id(v), v) for v in self._members.values())
def __xor__(self, other):
if not isinstance(other, IdentitySet):
@@ -599,7 +632,7 @@ class IdentitySet(object):
return self
def copy(self):
- return type(self)(self._members.itervalues())
+ return type(self)(iter(self._members.values()))
__copy__ = copy
@@ -607,13 +640,13 @@ class IdentitySet(object):
return len(self._members)
def __iter__(self):
- return self._members.itervalues()
+ return iter(self._members.values())
def __hash__(self):
raise TypeError('set objects are unhashable')
def __repr__(self):
- return '%s(%r)' % (type(self).__name__, self._members.values())
+ return '%s(%r)' % (type(self).__name__, list(self._members.values()))
class WeakSequence(object):
@@ -623,7 +656,7 @@ class WeakSequence(object):
)
def __iter__(self):
- return self._storage.itervalues()
+ return iter(self._storage.values())
def __getitem__(self, index):
try:
@@ -754,7 +787,7 @@ def flatten_iterator(x):
"""
for elem in x:
- if not isinstance(elem, basestring) and hasattr(elem, '__iter__'):
+ if not isinstance(elem, str) and hasattr(elem, '__iter__'):
for y in flatten_iterator(elem):
yield y
else:
diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py
index 033a87cc7..fea22873c 100644
--- a/lib/sqlalchemy/util/compat.py
+++ b/lib/sqlalchemy/util/compat.py
@@ -14,39 +14,17 @@ except ImportError:
import dummy_threading as threading
py32 = sys.version_info >= (3, 2)
-py3k_warning = getattr(sys, 'py3kwarning', False) or sys.version_info >= (3, 0)
py3k = sys.version_info >= (3, 0)
+py2k = sys.version_info < (3, 0)
jython = sys.platform.startswith('java')
pypy = hasattr(sys, 'pypy_version_info')
win32 = sys.platform.startswith('win')
cpython = not pypy and not jython # TODO: something better for this ?
-if py3k_warning:
- set_types = set
-elif sys.version_info < (2, 6):
- import sets
- set_types = set, sets.Set
-else:
- # 2.6 deprecates sets.Set, but we still need to be able to detect them
- # in user code and as return values from DB-APIs
- ignore = ('ignore', None, DeprecationWarning, None, 0)
- import warnings
- try:
- warnings.filters.insert(0, ignore)
- except Exception:
- import sets
- else:
- import sets
- warnings.filters.remove(ignore)
- set_types = set, sets.Set
+next = next
-if sys.version_info < (2, 6):
- def next(iter):
- return iter.next()
-else:
- next = next
-if py3k_warning:
+if py3k:
import pickle
else:
try:
@@ -54,44 +32,114 @@ else:
except ImportError:
import pickle
-if sys.version_info < (2, 6):
- # emits a nasty deprecation warning
- # in newer pythons
- from cgi import parse_qsl
-else:
- from urlparse import parse_qsl
+if py3k:
+ import builtins
+
+ from inspect import getfullargspec as inspect_getfullargspec
+ from urllib.parse import quote_plus, unquote_plus, parse_qsl
+ import configparser
+ from io import StringIO
+
+ from io import BytesIO as byte_buffer
+
+
+ string_types = str,
+ binary_type = bytes
+ text_type = str
+ int_types = int,
+ iterbytes = iter
+
+ def u(s):
+ return s
-# Py3K
-#from inspect import getfullargspec as inspect_getfullargspec
-# Py2K
-from inspect import getargspec as inspect_getfullargspec
-# end Py2K
+ def ue(s):
+ return s
-if py3k_warning:
- # they're bringing it back in 3.2. brilliant !
- def callable(fn):
- return hasattr(fn, '__call__')
+ def b(s):
+ return s.encode("latin-1")
+
+ if py32:
+ callable = callable
+ else:
+ def callable(fn):
+ return hasattr(fn, '__call__')
def cmp(a, b):
return (a > b) - (a < b)
from functools import reduce
+
+ print_ = getattr(builtins, "print")
+
+ import_ = getattr(builtins, '__import__')
+
+ import itertools
+ itertools_filterfalse = itertools.filterfalse
+ itertools_filter = filter
+ itertools_imap = map
+
+ import base64
+ def b64encode(x):
+ return base64.b64encode(x).decode('ascii')
+ def b64decode(x):
+ return base64.b64decode(x.encode('ascii'))
+
else:
+ from inspect import getargspec as inspect_getfullargspec
+ from urllib import quote_plus, unquote_plus
+ from urlparse import parse_qsl
+ import ConfigParser as configparser
+ from StringIO import StringIO
+ from cStringIO import StringIO as byte_buffer
+
+ string_types = basestring,
+ binary_type = str
+ text_type = unicode
+ int_types = int, long
+ def iterbytes(buf):
+ return (ord(byte) for byte in buf)
+
+ def u(s):
+ # this differs from what six does, which doesn't support non-ASCII
+ # strings - we only use u() with
+ # literal source strings, and all our source files with non-ascii
+ # in them (all are tests) are utf-8 encoded.
+ return unicode(s, "utf-8")
+
+ def ue(s):
+ return unicode(s, "unicode_escape")
+
+ def b(s):
+ return s
+
+ def import_(*args):
+ if len(args) == 4:
+ args = args[0:3] + ([str(arg) for arg in args[3]],)
+ return __import__(*args)
+
callable = callable
cmp = cmp
reduce = reduce
-try:
- from collections import namedtuple
-except ImportError:
- def namedtuple(typename, fieldnames):
- def __new__(cls, *values):
- tup = tuple.__new__(cls, values)
- for i, fname in enumerate(fieldnames):
- setattr(tup, fname, tup[i])
- return tup
- tuptype = type(typename, (tuple, ), {'__new__': __new__})
- return tuptype
+ import base64
+ b64encode = base64.b64encode
+ b64decode = base64.b64decode
+
+ def print_(*args, **kwargs):
+ fp = kwargs.pop("file", sys.stdout)
+ if fp is None:
+ return
+ for arg in enumerate(args):
+ if not isinstance(arg, basestring):
+ arg = str(arg)
+ fp.write(arg)
+
+ import itertools
+ itertools_filterfalse = itertools.ifilterfalse
+ itertools_filter = itertools.ifilter
+ itertools_imap = itertools.imap
+
+
try:
from weakref import WeakSet
@@ -121,24 +169,8 @@ if win32 or jython:
else:
time_func = time.time
-
-if sys.version_info >= (2, 6):
- from operator import attrgetter as dottedgetter
-else:
- def dottedgetter(attr):
- def g(obj):
- for name in attr.split("."):
- obj = getattr(obj, name)
- return obj
- return g
-
-# Adapted from six.py
-if py3k:
- def b(s):
- return s.encode("latin-1")
-else:
- def b(s):
- return s
+from collections import namedtuple
+from operator import attrgetter as dottedgetter
if py3k:
@@ -149,19 +181,49 @@ if py3k:
raise value.with_traceback(tb)
raise value
- def raise_from_cause(exception, exc_info):
+ def raise_from_cause(exception, exc_info=None):
+ if exc_info is None:
+ exc_info = sys.exc_info()
exc_type, exc_value, exc_tb = exc_info
reraise(type(exception), exception, tb=exc_tb, cause=exc_value)
else:
exec("def reraise(tp, value, tb=None, cause=None):\n"
" raise tp, value, tb\n")
- def raise_from_cause(exception, exc_info):
+ def raise_from_cause(exception, exc_info=None):
# not as nice as that of Py3K, but at least preserves
# the code line where the issue occurred
+ if exc_info is None:
+ exc_info = sys.exc_info()
exc_type, exc_value, exc_tb = exc_info
reraise(type(exception), exception, tb=exc_tb)
+if py3k:
+ exec_ = getattr(builtins, 'exec')
+else:
+ def exec_(func_text, globals_, lcl=None):
+ if lcl is None:
+ exec('exec func_text in globals_')
+ else:
+ exec('exec func_text in globals_, lcl')
+
+
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass.
+
+ Drops the middle class upon creation.
+
+ Source: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/
+
+ """
+ class metaclass(meta):
+ __call__ = type.__call__
+ __init__ = type.__init__
+ def __new__(cls, name, this_bases, d):
+ if this_bases is None:
+ return type.__new__(cls, name, (), d)
+ return meta(name, bases, d)
+ return metaclass('temporary_class', None, {})
diff --git a/lib/sqlalchemy/util/deprecations.py b/lib/sqlalchemy/util/deprecations.py
index 34be4fbf8..e0dc168db 100644
--- a/lib/sqlalchemy/util/deprecations.py
+++ b/lib/sqlalchemy/util/deprecations.py
@@ -10,7 +10,7 @@ functionality."""
from .. import exc
import warnings
import re
-from langhelpers import decorator
+from .langhelpers import decorator
def warn_deprecated(msg, stacklevel=3):
diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py
index d82aefdea..b0ff5b073 100644
--- a/lib/sqlalchemy/util/langhelpers.py
+++ b/lib/sqlalchemy/util/langhelpers.py
@@ -15,16 +15,14 @@ import re
import sys
import types
import warnings
-from .compat import set_types, threading, \
- callable, inspect_getfullargspec
from functools import update_wrapper
from .. import exc
import hashlib
from . import compat
def md5_hex(x):
- # Py3K
- #x = x.encode('utf-8')
+ if compat.py3k:
+ x = x.encode('utf-8')
m = hashlib.md5()
m.update(x)
return m.hexdigest()
@@ -77,8 +75,8 @@ def _unique_symbols(used, *bases):
used = set(used)
for base in bases:
pool = itertools.chain((base,),
- itertools.imap(lambda i: base + str(i),
- xrange(1000)))
+ compat.itertools_imap(lambda i: base + str(i),
+ range(1000)))
for sym in pool:
if sym not in used:
used.add(sym)
@@ -94,8 +92,8 @@ def decorator(target):
def decorate(fn):
if not inspect.isfunction(fn):
raise Exception("not a decoratable function")
- spec = inspect_getfullargspec(fn)
- names = tuple(spec[0]) + spec[1:3] + (fn.func_name,)
+ spec = compat.inspect_getfullargspec(fn)
+ names = tuple(spec[0]) + spec[1:3] + (fn.__name__,)
targ_name, fn_name = _unique_symbols(names, 'target', 'fn')
metadata = dict(target=targ_name, fn=fn_name)
@@ -104,7 +102,7 @@ def decorator(target):
code = 'lambda %(args)s: %(target)s(%(fn)s, %(apply_kw)s)' % (
metadata)
decorated = eval(code, {targ_name: target, fn_name: fn})
- decorated.func_defaults = getattr(fn, 'im_func', fn).func_defaults
+ decorated.__defaults__ = getattr(fn, 'im_func', fn).__defaults__
return update_wrapper(decorated, fn)
return update_wrapper(decorate, target)
@@ -143,7 +141,7 @@ class PluginLoader(object):
def register(self, name, modulepath, objname):
def load():
- mod = __import__(modulepath)
+ mod = compat.import_(modulepath)
for token in modulepath.split(".")[1:]:
mod = getattr(mod, token)
return getattr(mod, objname)
@@ -169,7 +167,7 @@ def get_cls_kwargs(cls, _set=None):
ctr = cls.__dict__.get('__init__', False)
has_init = ctr and isinstance(ctr, types.FunctionType) and \
- isinstance(ctr.func_code, types.CodeType)
+ isinstance(ctr.__code__, types.CodeType)
if has_init:
names, has_kw = inspect_func_args(ctr)
@@ -192,7 +190,7 @@ try:
from inspect import CO_VARKEYWORDS
def inspect_func_args(fn):
- co = fn.func_code
+ co = fn.__code__
nargs = co.co_argcount
names = co.co_varnames
args = list(names[:nargs])
@@ -248,8 +246,8 @@ def format_argspec_plus(fn, grouped=True):
'apply_pos': '(self, a, b, c, **d)'}
"""
- if callable(fn):
- spec = inspect_getfullargspec(fn)
+ if compat.callable(fn):
+ spec = compat.inspect_getfullargspec(fn)
else:
# we accept an existing argspec...
spec = fn
@@ -261,22 +259,21 @@ def format_argspec_plus(fn, grouped=True):
else:
self_arg = None
- # Py3K
- #apply_pos = inspect.formatargspec(spec[0], spec[1],
- # spec[2], None, spec[4])
- #num_defaults = 0
- #if spec[3]:
- # num_defaults += len(spec[3])
- #if spec[4]:
- # num_defaults += len(spec[4])
- #name_args = spec[0] + spec[4]
- # Py2K
- apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2])
- num_defaults = 0
- if spec[3]:
- num_defaults += len(spec[3])
- name_args = spec[0]
- # end Py2K
+ if compat.py3k:
+ apply_pos = inspect.formatargspec(spec[0], spec[1],
+ spec[2], None, spec[4])
+ num_defaults = 0
+ if spec[3]:
+ num_defaults += len(spec[3])
+ if spec[4]:
+ num_defaults += len(spec[4])
+ name_args = spec[0] + spec[4]
+ else:
+ apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2])
+ num_defaults = 0
+ if spec[3]:
+ num_defaults += len(spec[3])
+ name_args = spec[0]
if num_defaults:
defaulted_vals = name_args[0 - num_defaults:]
@@ -339,8 +336,8 @@ def unbound_method_to_callable(func_or_cls):
"""
- if isinstance(func_or_cls, types.MethodType) and not func_or_cls.im_self:
- return func_or_cls.im_func
+ if isinstance(func_or_cls, types.MethodType) and not func_or_cls.__self__:
+ return func_or_cls.__func__
else:
return func_or_cls
@@ -397,7 +394,7 @@ class portable_instancemethod(object):
"""
def __init__(self, meth):
- self.target = meth.im_self
+ self.target = meth.__self__
self.name = meth.__name__
def __call__(self, *arg, **kw):
@@ -417,32 +414,33 @@ def class_hierarchy(cls):
will not be descended.
"""
- # Py2K
- if isinstance(cls, types.ClassType):
- return list()
- # end Py2K
+ if compat.py2k:
+ if isinstance(cls, types.ClassType):
+ return list()
+
hier = set([cls])
process = list(cls.__mro__)
while process:
c = process.pop()
- # Py2K
- if isinstance(c, types.ClassType):
- continue
- for b in (_ for _ in c.__bases__
- if _ not in hier and not isinstance(_, types.ClassType)):
- # end Py2K
- # Py3K
- #for b in (_ for _ in c.__bases__
- # if _ not in hier):
+ if compat.py2k:
+ if isinstance(c, types.ClassType):
+ continue
+ bases = (_ for _ in c.__bases__
+ if _ not in hier and not isinstance(_, types.ClassType))
+ else:
+ bases = (_ for _ in c.__bases__ if _ not in hier)
+
+ for b in bases:
process.append(b)
hier.add(b)
- # Py3K
- #if c.__module__ == 'builtins' or not hasattr(c, '__subclasses__'):
- # continue
- # Py2K
- if c.__module__ == '__builtin__' or not hasattr(c, '__subclasses__'):
- continue
- # end Py2K
+
+ if compat.py3k:
+ if c.__module__ == 'builtins' or not hasattr(c, '__subclasses__'):
+ continue
+ else:
+ if c.__module__ == '__builtin__' or not hasattr(c, '__subclasses__'):
+ continue
+
for s in [_ for _ in c.__subclasses__() if _ not in hier]:
process.append(s)
hier.add(s)
@@ -499,9 +497,9 @@ def monkeypatch_proxied_specials(into_cls, from_cls, skip=None, only=None,
"return %(name)s.%(method)s%(d_args)s" % locals())
env = from_instance is not None and {name: from_instance} or {}
- exec py in env
+ compat.exec_(py, env)
try:
- env[method].func_defaults = fn.func_defaults
+ env[method].__defaults__ = fn.__defaults__
except AttributeError:
pass
setattr(into_cls, method, env[method])
@@ -510,11 +508,7 @@ def monkeypatch_proxied_specials(into_cls, from_cls, skip=None, only=None,
def methods_equivalent(meth1, meth2):
"""Return True if the two methods are the same implementation."""
- # Py3K
- #return getattr(meth1, '__func__', meth1) is getattr(meth2, '__func__', meth2)
- # Py2K
- return getattr(meth1, 'im_func', meth1) is getattr(meth2, 'im_func', meth2)
- # end Py2K
+ return getattr(meth1, '__func__', meth1) is getattr(meth2, '__func__', meth2)
def as_interface(obj, cls=None, methods=None, required=None):
@@ -587,7 +581,7 @@ def as_interface(obj, cls=None, methods=None, required=None):
for method, impl in dictlike_iteritems(obj):
if method not in interface:
raise TypeError("%r: unknown in this interface" % method)
- if not callable(impl):
+ if not compat.callable(impl):
raise TypeError("%r=%r is not callable" % (method, impl))
setattr(AnonymousInterface, method, staticmethod(impl))
found.add(method)
@@ -728,11 +722,11 @@ class importlater(object):
def _resolve(self):
importlater._unresolved.discard(self)
if self._il_addtl:
- self._initial_import = __import__(
+ self._initial_import = compat.import_(
self._il_path, globals(), locals(),
[self._il_addtl])
else:
- self._initial_import = __import__(self._il_path)
+ self._initial_import = compat.import_(self._il_path)
def __getattr__(self, key):
if key == 'module':
@@ -751,7 +745,7 @@ class importlater(object):
# from paste.deploy.converters
def asbool(obj):
- if isinstance(obj, (str, unicode)):
+ if isinstance(obj, compat.string_types):
obj = obj.strip().lower()
if obj in ['true', 'yes', 'on', 'y', 't', '1']:
return True
@@ -811,14 +805,14 @@ def constructor_copy(obj, cls, **kw):
def counter():
"""Return a threadsafe counter function."""
- lock = threading.Lock()
- counter = itertools.count(1L)
+ lock = compat.threading.Lock()
+ counter = itertools.count(1)
# avoid the 2to3 "next" transformation...
def _next():
lock.acquire()
try:
- return counter.next()
+ return next(counter)
finally:
lock.release()
@@ -834,7 +828,7 @@ def duck_type_collection(specimen, default=None):
if hasattr(specimen, '__emulates__'):
# canonicalize set vs sets.Set to a standard: the builtin set
if (specimen.__emulates__ is not None and
- issubclass(specimen.__emulates__, set_types)):
+ issubclass(specimen.__emulates__, set)):
return set
else:
return specimen.__emulates__
@@ -842,7 +836,7 @@ def duck_type_collection(specimen, default=None):
isa = isinstance(specimen, type) and issubclass or isinstance
if isa(specimen, list):
return list
- elif isa(specimen, set_types):
+ elif isa(specimen, set):
return set
elif isa(specimen, dict):
return dict
@@ -874,15 +868,14 @@ def assert_arg_type(arg, argtype, name):
def dictlike_iteritems(dictlike):
"""Return a (key, value) iterator for almost any dict-like object."""
- # Py3K
- #if hasattr(dictlike, 'items'):
- # return dictlike.items()
- # Py2K
- if hasattr(dictlike, 'iteritems'):
- return dictlike.iteritems()
- elif hasattr(dictlike, 'items'):
- return iter(dictlike.items())
- # end Py2K
+ if compat.py3k:
+ if hasattr(dictlike, 'items'):
+ return list(dictlike.items())
+ else:
+ if hasattr(dictlike, 'iteritems'):
+ return dictlike.iteritems()
+ elif hasattr(dictlike, 'items'):
+ return iter(dictlike.items())
getter = getattr(dictlike, '__getitem__', getattr(dictlike, 'get', None))
if getter is None:
@@ -891,7 +884,7 @@ def dictlike_iteritems(dictlike):
if hasattr(dictlike, 'iterkeys'):
def iterator():
- for key in dictlike.iterkeys():
+ for key in dictlike.keys():
yield key, getter(key)
return iterator()
elif hasattr(dictlike, 'keys'):
@@ -935,7 +928,7 @@ class hybridmethod(object):
class _symbol(int):
def __new__(self, name, doc=None, canonical=None):
"""Construct a new named symbol."""
- assert isinstance(name, str)
+ assert isinstance(name, compat.string_types)
if canonical is None:
canonical = hash(name)
v = int.__new__(_symbol, canonical)
@@ -978,7 +971,7 @@ class symbol(object):
"""
symbols = {}
- _lock = threading.Lock()
+ _lock = compat.threading.Lock()
def __new__(cls, name, doc=None, canonical=None):
cls._lock.acquire()
@@ -1032,7 +1025,7 @@ def warn(msg, stacklevel=3):
be controlled.
"""
- if isinstance(msg, basestring):
+ if isinstance(msg, compat.string_types):
warnings.warn(msg, exc.SAWarning, stacklevel=stacklevel)
else:
warnings.warn(msg, stacklevel=stacklevel)