summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/__init__.py2
-rw-r--r--lib/sqlalchemy/cextension/processors.c2
-rw-r--r--lib/sqlalchemy/cextension/resultproxy.c2
-rw-r--r--lib/sqlalchemy/cextension/utils.c2
-rw-r--r--lib/sqlalchemy/connectors/__init__.py2
-rw-r--r--lib/sqlalchemy/connectors/mxodbc.py2
-rw-r--r--lib/sqlalchemy/connectors/pyodbc.py2
-rw-r--r--lib/sqlalchemy/connectors/zxJDBC.py2
-rw-r--r--lib/sqlalchemy/databases/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/firebird/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/firebird/base.py2
-rw-r--r--lib/sqlalchemy/dialects/firebird/fdb.py2
-rw-r--r--lib/sqlalchemy/dialects/firebird/kinterbasdb.py2
-rw-r--r--lib/sqlalchemy/dialects/mssql/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/mssql/adodbapi.py2
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py5
-rw-r--r--lib/sqlalchemy/dialects/mssql/information_schema.py2
-rw-r--r--lib/sqlalchemy/dialects/mssql/mxodbc.py2
-rw-r--r--lib/sqlalchemy/dialects/mssql/pymssql.py2
-rw-r--r--lib/sqlalchemy/dialects/mssql/pyodbc.py2
-rw-r--r--lib/sqlalchemy/dialects/mssql/zxjdbc.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py3
-rw-r--r--lib/sqlalchemy/dialects/mysql/cymysql.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/gaerdbms.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/mysqlconnector.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/mysqldb.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/oursql.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/pymysql.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/pyodbc.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/zxjdbc.py2
-rw-r--r--lib/sqlalchemy/dialects/oracle/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/oracle/base.py14
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py2
-rw-r--r--lib/sqlalchemy/dialects/oracle/zxjdbc.py2
-rw-r--r--lib/sqlalchemy/dialects/postgres.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py143
-rw-r--r--lib/sqlalchemy/dialects/postgresql/constraints.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/hstore.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/json.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/pg8000.py93
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/pypostgresql.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/ranges.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/zxjdbc.py2
-rw-r--r--lib/sqlalchemy/dialects/sqlite/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/sqlite/base.py40
-rw-r--r--lib/sqlalchemy/dialects/sqlite/pysqlcipher.py2
-rw-r--r--lib/sqlalchemy/dialects/sqlite/pysqlite.py2
-rw-r--r--lib/sqlalchemy/dialects/sybase/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/sybase/base.py2
-rw-r--r--lib/sqlalchemy/dialects/sybase/mxodbc.py2
-rw-r--r--lib/sqlalchemy/dialects/sybase/pyodbc.py2
-rw-r--r--lib/sqlalchemy/dialects/sybase/pysybase.py2
-rw-r--r--lib/sqlalchemy/engine/__init__.py2
-rw-r--r--lib/sqlalchemy/engine/base.py7
-rw-r--r--lib/sqlalchemy/engine/default.py10
-rw-r--r--lib/sqlalchemy/engine/interfaces.py2
-rw-r--r--lib/sqlalchemy/engine/reflection.py2
-rw-r--r--lib/sqlalchemy/engine/result.py224
-rw-r--r--lib/sqlalchemy/engine/strategies.py2
-rw-r--r--lib/sqlalchemy/engine/threadlocal.py2
-rw-r--r--lib/sqlalchemy/engine/url.py2
-rw-r--r--lib/sqlalchemy/engine/util.py2
-rw-r--r--lib/sqlalchemy/event/__init__.py2
-rw-r--r--lib/sqlalchemy/event/api.py2
-rw-r--r--lib/sqlalchemy/event/attr.py2
-rw-r--r--lib/sqlalchemy/event/base.py2
-rw-r--r--lib/sqlalchemy/event/legacy.py2
-rw-r--r--lib/sqlalchemy/event/registry.py2
-rw-r--r--lib/sqlalchemy/events.py2
-rw-r--r--lib/sqlalchemy/exc.py2
-rw-r--r--lib/sqlalchemy/ext/__init__.py2
-rw-r--r--lib/sqlalchemy/ext/associationproxy.py7
-rw-r--r--lib/sqlalchemy/ext/automap.py2
-rw-r--r--lib/sqlalchemy/ext/compiler.py2
-rw-r--r--lib/sqlalchemy/ext/declarative/__init__.py2
-rw-r--r--lib/sqlalchemy/ext/declarative/api.py2
-rw-r--r--lib/sqlalchemy/ext/declarative/base.py23
-rw-r--r--lib/sqlalchemy/ext/declarative/clsregistry.py2
-rw-r--r--lib/sqlalchemy/ext/horizontal_shard.py2
-rw-r--r--lib/sqlalchemy/ext/hybrid.py2
-rw-r--r--lib/sqlalchemy/ext/mutable.py2
-rw-r--r--lib/sqlalchemy/ext/orderinglist.py2
-rw-r--r--lib/sqlalchemy/ext/serializer.py2
-rw-r--r--lib/sqlalchemy/inspection.py2
-rw-r--r--lib/sqlalchemy/interfaces.py2
-rw-r--r--lib/sqlalchemy/log.py2
-rw-r--r--lib/sqlalchemy/orm/__init__.py2
-rw-r--r--lib/sqlalchemy/orm/attributes.py2
-rw-r--r--lib/sqlalchemy/orm/base.py2
-rw-r--r--lib/sqlalchemy/orm/collections.py6
-rw-r--r--lib/sqlalchemy/orm/dependency.py2
-rw-r--r--lib/sqlalchemy/orm/deprecated_interfaces.py2
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py2
-rw-r--r--lib/sqlalchemy/orm/dynamic.py2
-rw-r--r--lib/sqlalchemy/orm/evaluator.py2
-rw-r--r--lib/sqlalchemy/orm/events.py57
-rw-r--r--lib/sqlalchemy/orm/exc.py2
-rw-r--r--lib/sqlalchemy/orm/identity.py2
-rw-r--r--lib/sqlalchemy/orm/instrumentation.py2
-rw-r--r--lib/sqlalchemy/orm/interfaces.py2
-rw-r--r--lib/sqlalchemy/orm/loading.py2
-rw-r--r--lib/sqlalchemy/orm/mapper.py2
-rw-r--r--lib/sqlalchemy/orm/path_registry.py2
-rw-r--r--lib/sqlalchemy/orm/persistence.py2
-rw-r--r--lib/sqlalchemy/orm/properties.py2
-rw-r--r--lib/sqlalchemy/orm/query.py63
-rw-r--r--lib/sqlalchemy/orm/relationships.py2
-rw-r--r--lib/sqlalchemy/orm/scoping.py2
-rw-r--r--lib/sqlalchemy/orm/session.py16
-rw-r--r--lib/sqlalchemy/orm/state.py2
-rw-r--r--lib/sqlalchemy/orm/strategies.py4
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py2
-rw-r--r--lib/sqlalchemy/orm/sync.py2
-rw-r--r--lib/sqlalchemy/orm/unitofwork.py2
-rw-r--r--lib/sqlalchemy/orm/util.py2
-rw-r--r--lib/sqlalchemy/pool.py2
-rw-r--r--lib/sqlalchemy/processors.py2
-rw-r--r--lib/sqlalchemy/schema.py2
-rw-r--r--lib/sqlalchemy/sql/__init__.py2
-rw-r--r--lib/sqlalchemy/sql/annotation.py2
-rw-r--r--lib/sqlalchemy/sql/base.py2
-rw-r--r--lib/sqlalchemy/sql/compiler.py137
-rw-r--r--lib/sqlalchemy/sql/crud.py2
-rw-r--r--lib/sqlalchemy/sql/ddl.py44
-rw-r--r--lib/sqlalchemy/sql/default_comparator.py2
-rw-r--r--lib/sqlalchemy/sql/dml.py2
-rw-r--r--lib/sqlalchemy/sql/elements.py2
-rw-r--r--lib/sqlalchemy/sql/expression.py2
-rw-r--r--lib/sqlalchemy/sql/functions.py2
-rw-r--r--lib/sqlalchemy/sql/naming.py2
-rw-r--r--lib/sqlalchemy/sql/operators.py2
-rw-r--r--lib/sqlalchemy/sql/schema.py2
-rw-r--r--lib/sqlalchemy/sql/selectable.py36
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py28
-rw-r--r--lib/sqlalchemy/sql/type_api.py2
-rw-r--r--lib/sqlalchemy/sql/util.py2
-rw-r--r--lib/sqlalchemy/sql/visitors.py16
-rw-r--r--lib/sqlalchemy/testing/__init__.py2
-rw-r--r--lib/sqlalchemy/testing/assertions.py2
-rw-r--r--lib/sqlalchemy/testing/assertsql.py2
-rw-r--r--lib/sqlalchemy/testing/config.py2
-rw-r--r--lib/sqlalchemy/testing/engines.py2
-rw-r--r--lib/sqlalchemy/testing/entities.py2
-rw-r--r--lib/sqlalchemy/testing/exclusions.py2
-rw-r--r--lib/sqlalchemy/testing/fixtures.py2
-rw-r--r--lib/sqlalchemy/testing/mock.py2
-rw-r--r--lib/sqlalchemy/testing/pickleable.py2
-rw-r--r--lib/sqlalchemy/testing/plugin/noseplugin.py2
-rw-r--r--lib/sqlalchemy/testing/plugin/plugin_base.py2
-rw-r--r--lib/sqlalchemy/testing/profiling.py2
-rw-r--r--lib/sqlalchemy/testing/requirements.py2
-rw-r--r--lib/sqlalchemy/testing/runner.py2
-rw-r--r--lib/sqlalchemy/testing/schema.py2
-rw-r--r--lib/sqlalchemy/testing/util.py2
-rw-r--r--lib/sqlalchemy/testing/warnings.py2
-rw-r--r--lib/sqlalchemy/types.py2
-rw-r--r--lib/sqlalchemy/util/__init__.py2
-rw-r--r--lib/sqlalchemy/util/_collections.py91
-rw-r--r--lib/sqlalchemy/util/compat.py2
-rw-r--r--lib/sqlalchemy/util/deprecations.py2
-rw-r--r--lib/sqlalchemy/util/langhelpers.py2
-rw-r--r--lib/sqlalchemy/util/queue.py2
-rw-r--r--lib/sqlalchemy/util/topological.py2
167 files changed, 917 insertions, 440 deletions
diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py
index d184e1fbf..c3060b384 100644
--- a/lib/sqlalchemy/__init__.py
+++ b/lib/sqlalchemy/__init__.py
@@ -1,5 +1,5 @@
# sqlalchemy/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/cextension/processors.c b/lib/sqlalchemy/cextension/processors.c
index d56817763..59eb2648c 100644
--- a/lib/sqlalchemy/cextension/processors.c
+++ b/lib/sqlalchemy/cextension/processors.c
@@ -1,6 +1,6 @@
/*
processors.c
-Copyright (C) 2010-2014 the SQLAlchemy authors and contributors <see AUTHORS file>
+Copyright (C) 2010-2015 the SQLAlchemy authors and contributors <see AUTHORS file>
Copyright (C) 2010-2011 Gaetan de Menten gdementen@gmail.com
This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/cextension/resultproxy.c b/lib/sqlalchemy/cextension/resultproxy.c
index 218c7b807..ae2a059cf 100644
--- a/lib/sqlalchemy/cextension/resultproxy.c
+++ b/lib/sqlalchemy/cextension/resultproxy.c
@@ -1,6 +1,6 @@
/*
resultproxy.c
-Copyright (C) 2010-2014 the SQLAlchemy authors and contributors <see AUTHORS file>
+Copyright (C) 2010-2015 the SQLAlchemy authors and contributors <see AUTHORS file>
Copyright (C) 2010-2011 Gaetan de Menten gdementen@gmail.com
This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/cextension/utils.c b/lib/sqlalchemy/cextension/utils.c
index 377ba8a8d..6e00eb816 100644
--- a/lib/sqlalchemy/cextension/utils.c
+++ b/lib/sqlalchemy/cextension/utils.c
@@ -1,6 +1,6 @@
/*
utils.c
-Copyright (C) 2012-2014 the SQLAlchemy authors and contributors <see AUTHORS file>
+Copyright (C) 2012-2015 the SQLAlchemy authors and contributors <see AUTHORS file>
This module is part of SQLAlchemy and is released under
the MIT License: http://www.opensource.org/licenses/mit-license.php
diff --git a/lib/sqlalchemy/connectors/__init__.py b/lib/sqlalchemy/connectors/__init__.py
index 9253a21d5..5f65b9306 100644
--- a/lib/sqlalchemy/connectors/__init__.py
+++ b/lib/sqlalchemy/connectors/__init__.py
@@ -1,5 +1,5 @@
# connectors/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/connectors/mxodbc.py b/lib/sqlalchemy/connectors/mxodbc.py
index 851dc11e8..1bbf899c4 100644
--- a/lib/sqlalchemy/connectors/mxodbc.py
+++ b/lib/sqlalchemy/connectors/mxodbc.py
@@ -1,5 +1,5 @@
# connectors/mxodbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py
index 907e4d353..84bc92bee 100644
--- a/lib/sqlalchemy/connectors/pyodbc.py
+++ b/lib/sqlalchemy/connectors/pyodbc.py
@@ -1,5 +1,5 @@
# connectors/pyodbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/connectors/zxJDBC.py b/lib/sqlalchemy/connectors/zxJDBC.py
index c0af742fa..8219a06eb 100644
--- a/lib/sqlalchemy/connectors/zxJDBC.py
+++ b/lib/sqlalchemy/connectors/zxJDBC.py
@@ -1,5 +1,5 @@
# connectors/zxJDBC.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/databases/__init__.py b/lib/sqlalchemy/databases/__init__.py
index 356fbec59..321ff999b 100644
--- a/lib/sqlalchemy/databases/__init__.py
+++ b/lib/sqlalchemy/databases/__init__.py
@@ -1,5 +1,5 @@
# databases/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/__init__.py b/lib/sqlalchemy/dialects/__init__.py
index 74c48820d..d90a83809 100644
--- a/lib/sqlalchemy/dialects/__init__.py
+++ b/lib/sqlalchemy/dialects/__init__.py
@@ -1,5 +1,5 @@
# dialects/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/firebird/__init__.py b/lib/sqlalchemy/dialects/firebird/__init__.py
index 9e8a88245..b2fb57a63 100644
--- a/lib/sqlalchemy/dialects/firebird/__init__.py
+++ b/lib/sqlalchemy/dialects/firebird/__init__.py
@@ -1,5 +1,5 @@
# firebird/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/firebird/base.py b/lib/sqlalchemy/dialects/firebird/base.py
index 74e8abfc2..61d3646b1 100644
--- a/lib/sqlalchemy/dialects/firebird/base.py
+++ b/lib/sqlalchemy/dialects/firebird/base.py
@@ -1,5 +1,5 @@
# firebird/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/firebird/fdb.py b/lib/sqlalchemy/dialects/firebird/fdb.py
index ddffc80f5..0ab07498b 100644
--- a/lib/sqlalchemy/dialects/firebird/fdb.py
+++ b/lib/sqlalchemy/dialects/firebird/fdb.py
@@ -1,5 +1,5 @@
# firebird/fdb.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/firebird/kinterbasdb.py b/lib/sqlalchemy/dialects/firebird/kinterbasdb.py
index 6bd7887f7..7d1a834b8 100644
--- a/lib/sqlalchemy/dialects/firebird/kinterbasdb.py
+++ b/lib/sqlalchemy/dialects/firebird/kinterbasdb.py
@@ -1,5 +1,5 @@
# firebird/kinterbasdb.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mssql/__init__.py b/lib/sqlalchemy/dialects/mssql/__init__.py
index d0047765e..898b40cd5 100644
--- a/lib/sqlalchemy/dialects/mssql/__init__.py
+++ b/lib/sqlalchemy/dialects/mssql/__init__.py
@@ -1,5 +1,5 @@
# mssql/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mssql/adodbapi.py b/lib/sqlalchemy/dialects/mssql/adodbapi.py
index e9927f8ed..6e3f348fc 100644
--- a/lib/sqlalchemy/dialects/mssql/adodbapi.py
+++ b/lib/sqlalchemy/dialects/mssql/adodbapi.py
@@ -1,5 +1,5 @@
# mssql/adodbapi.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index 92d7e4ab3..ea0ed58a4 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -1,5 +1,5 @@
# mssql/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -1031,6 +1031,7 @@ class MSSQLCompiler(compiler.SQLCompiler):
_order_by_clauses = select._order_by_clause.clauses
limit_clause = select._limit_clause
offset_clause = select._offset_clause
+ kwargs['select_wraps_for'] = select
select = select._generate()
select._mssql_visit = True
select = select.column(
@@ -1048,7 +1049,7 @@ class MSSQLCompiler(compiler.SQLCompiler):
else:
limitselect.append_whereclause(
mssql_rn <= (limit_clause))
- return self.process(limitselect, iswrapper=True, **kwargs)
+ return self.process(limitselect, **kwargs)
else:
return compiler.SQLCompiler.visit_select(self, select, **kwargs)
diff --git a/lib/sqlalchemy/dialects/mssql/information_schema.py b/lib/sqlalchemy/dialects/mssql/information_schema.py
index 371a1edcc..a6faa7bca 100644
--- a/lib/sqlalchemy/dialects/mssql/information_schema.py
+++ b/lib/sqlalchemy/dialects/mssql/information_schema.py
@@ -1,5 +1,5 @@
# mssql/information_schema.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mssql/mxodbc.py b/lib/sqlalchemy/dialects/mssql/mxodbc.py
index ffe38d8dd..ac87c67a9 100644
--- a/lib/sqlalchemy/dialects/mssql/mxodbc.py
+++ b/lib/sqlalchemy/dialects/mssql/mxodbc.py
@@ -1,5 +1,5 @@
# mssql/mxodbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mssql/pymssql.py b/lib/sqlalchemy/dialects/mssql/pymssql.py
index b5a1bc566..2214d18d1 100644
--- a/lib/sqlalchemy/dialects/mssql/pymssql.py
+++ b/lib/sqlalchemy/dialects/mssql/pymssql.py
@@ -1,5 +1,5 @@
# mssql/pymssql.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mssql/pyodbc.py b/lib/sqlalchemy/dialects/mssql/pyodbc.py
index 445584d24..ad1e7ae37 100644
--- a/lib/sqlalchemy/dialects/mssql/pyodbc.py
+++ b/lib/sqlalchemy/dialects/mssql/pyodbc.py
@@ -1,5 +1,5 @@
# mssql/pyodbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mssql/zxjdbc.py b/lib/sqlalchemy/dialects/mssql/zxjdbc.py
index b23a010e7..2b8d3ff71 100644
--- a/lib/sqlalchemy/dialects/mssql/zxjdbc.py
+++ b/lib/sqlalchemy/dialects/mssql/zxjdbc.py
@@ -1,5 +1,5 @@
# mssql/zxjdbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/__init__.py b/lib/sqlalchemy/dialects/mysql/__init__.py
index 498603cf7..c1f78bd1d 100644
--- a/lib/sqlalchemy/dialects/mysql/__init__.py
+++ b/lib/sqlalchemy/dialects/mysql/__init__.py
@@ -1,5 +1,5 @@
# mysql/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py
index 0d2c36189..b8392bd4e 100644
--- a/lib/sqlalchemy/dialects/mysql/base.py
+++ b/lib/sqlalchemy/dialects/mysql/base.py
@@ -1,5 +1,5 @@
# mysql/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -1382,6 +1382,7 @@ class ENUM(sqltypes.Enum, _EnumeratedValues):
kw.pop('quote', None)
kw.pop('native_enum', None)
kw.pop('inherit_schema', None)
+ kw.pop('_create_events', None)
_StringType.__init__(self, length=length, **kw)
sqltypes.Enum.__init__(self, *values)
diff --git a/lib/sqlalchemy/dialects/mysql/cymysql.py b/lib/sqlalchemy/dialects/mysql/cymysql.py
index 51b63044e..6d8466ab1 100644
--- a/lib/sqlalchemy/dialects/mysql/cymysql.py
+++ b/lib/sqlalchemy/dialects/mysql/cymysql.py
@@ -1,5 +1,5 @@
# mysql/cymysql.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/gaerdbms.py b/lib/sqlalchemy/dialects/mysql/gaerdbms.py
index 284b51bde..bbb6a9868 100644
--- a/lib/sqlalchemy/dialects/mysql/gaerdbms.py
+++ b/lib/sqlalchemy/dialects/mysql/gaerdbms.py
@@ -1,5 +1,5 @@
# mysql/gaerdbms.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py
index 417e1ad6f..7a57705af 100644
--- a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py
+++ b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py
@@ -1,5 +1,5 @@
# mysql/mysqlconnector.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/mysqldb.py b/lib/sqlalchemy/dialects/mysql/mysqldb.py
index 929317467..0d125a245 100644
--- a/lib/sqlalchemy/dialects/mysql/mysqldb.py
+++ b/lib/sqlalchemy/dialects/mysql/mysqldb.py
@@ -1,5 +1,5 @@
# mysql/mysqldb.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/oursql.py b/lib/sqlalchemy/dialects/mysql/oursql.py
index fa127f3b0..ab6585abd 100644
--- a/lib/sqlalchemy/dialects/mysql/oursql.py
+++ b/lib/sqlalchemy/dialects/mysql/oursql.py
@@ -1,5 +1,5 @@
# mysql/oursql.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/pymysql.py b/lib/sqlalchemy/dialects/mysql/pymysql.py
index 8df2ba03f..ab7519d4c 100644
--- a/lib/sqlalchemy/dialects/mysql/pymysql.py
+++ b/lib/sqlalchemy/dialects/mysql/pymysql.py
@@ -1,5 +1,5 @@
# mysql/pymysql.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/pyodbc.py b/lib/sqlalchemy/dialects/mysql/pyodbc.py
index 58e8b30fe..08b339299 100644
--- a/lib/sqlalchemy/dialects/mysql/pyodbc.py
+++ b/lib/sqlalchemy/dialects/mysql/pyodbc.py
@@ -1,5 +1,5 @@
# mysql/pyodbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/mysql/zxjdbc.py b/lib/sqlalchemy/dialects/mysql/zxjdbc.py
index 0cf92cd13..9db969160 100644
--- a/lib/sqlalchemy/dialects/mysql/zxjdbc.py
+++ b/lib/sqlalchemy/dialects/mysql/zxjdbc.py
@@ -1,5 +1,5 @@
# mysql/zxjdbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/oracle/__init__.py b/lib/sqlalchemy/dialects/oracle/__init__.py
index fd32f2235..b055b0b16 100644
--- a/lib/sqlalchemy/dialects/oracle/__init__.py
+++ b/lib/sqlalchemy/dialects/oracle/__init__.py
@@ -1,5 +1,5 @@
# oracle/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py
index b482c9069..f20c2f296 100644
--- a/lib/sqlalchemy/dialects/oracle/base.py
+++ b/lib/sqlalchemy/dialects/oracle/base.py
@@ -1,5 +1,5 @@
# oracle/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -665,8 +665,8 @@ class OracleCompiler(compiler.SQLCompiler):
else:
return sql.and_(*clauses)
- def visit_outer_join_column(self, vc):
- return self.process(vc.column) + "(+)"
+ def visit_outer_join_column(self, vc, **kw):
+ return self.process(vc.column, **kw) + "(+)"
def visit_sequence(self, seq):
return (self.dialect.identifier_preparer.format_sequence(seq) +
@@ -692,8 +692,9 @@ class OracleCompiler(compiler.SQLCompiler):
self.bindparam_string(self._truncate_bindparam(outparam)))
columns.append(
self.process(col_expr, within_columns_clause=False))
- self.result_map[outparam.key] = (
- outparam.key,
+
+ self._add_to_result_map(
+ outparam.key, outparam.key,
(column, getattr(column, 'name', None),
getattr(column, 'key', None)),
column.type
@@ -736,7 +737,7 @@ class OracleCompiler(compiler.SQLCompiler):
# Outer select and "ROWNUM as ora_rn" can be dropped if
# limit=0
- # TODO: use annotations instead of clone + attr set ?
+ kwargs['select_wraps_for'] = select
select = select._generate()
select._oracle_visit = True
@@ -793,7 +794,6 @@ class OracleCompiler(compiler.SQLCompiler):
offsetselect._for_update_arg = select._for_update_arg
select = offsetselect
- kwargs['iswrapper'] = getattr(select, '_is_wrapper', False)
return compiler.SQLCompiler.visit_select(self, select, **kwargs)
def limit_clause(self, select, **kw):
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index 6fc88da8e..4aed45c14 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -1,5 +1,5 @@
# oracle/cx_oracle.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/oracle/zxjdbc.py b/lib/sqlalchemy/dialects/oracle/zxjdbc.py
index 82c8e2f0f..3025212b6 100644
--- a/lib/sqlalchemy/dialects/oracle/zxjdbc.py
+++ b/lib/sqlalchemy/dialects/oracle/zxjdbc.py
@@ -1,5 +1,5 @@
# oracle/zxjdbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgres.py b/lib/sqlalchemy/dialects/postgres.py
index f813e0003..3335333e5 100644
--- a/lib/sqlalchemy/dialects/postgres.py
+++ b/lib/sqlalchemy/dialects/postgres.py
@@ -1,5 +1,5 @@
# dialects/postgres.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/__init__.py b/lib/sqlalchemy/dialects/postgresql/__init__.py
index 01a846314..98fe6f085 100644
--- a/lib/sqlalchemy/dialects/postgresql/__init__.py
+++ b/lib/sqlalchemy/dialects/postgresql/__init__.py
@@ -1,5 +1,5 @@
# postgresql/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index 1935d0cad..7529c6ed3 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -1,5 +1,5 @@
# postgresql/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -402,6 +402,24 @@ underlying CREATE INDEX command, so it *must* be a valid index type for your
version of PostgreSQL.
+.. _postgresql_index_concurrently:
+
+Indexes with CONCURRENTLY
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Postgresql index option CONCURRENTLY is supported by passing the
+flag ``postgresql_concurrently`` to the :class:`.Index` construct::
+
+ tbl = Table('testtbl', m, Column('data', Integer))
+
+ idx1 = Index('test_idx1', tbl.c.data, postgresql_concurrently=True)
+
+The above index construct will render SQL as::
+
+ CREATE INDEX CONCURRENTLY test_idx1 ON testtbl (data)
+
+.. versionadded:: 0.9.9
+
.. _postgresql_index_reflection:
Postgresql Index Reflection
@@ -477,6 +495,22 @@ dialect in conjunction with the :class:`.Table` construct:
`Postgresql CREATE TABLE options
<http://www.postgresql.org/docs/9.3/static/sql-createtable.html>`_
+ENUM Types
+----------
+
+Postgresql has an independently creatable TYPE structure which is used
+to implement an enumerated type. This approach introduces significant
+complexity on the SQLAlchemy side in terms of when this type should be
+CREATED and DROPPED. The type object is also an independently reflectable
+entity. The following sections should be consulted:
+
+* :class:`.postgresql.ENUM` - DDL and typing support for ENUM.
+
+* :meth:`.PGInspector.get_enums` - retrieve a listing of current ENUM types
+
+* :meth:`.postgresql.ENUM.create` , :meth:`.postgresql.ENUM.drop` - individual
+ CREATE and DROP commands for ENUM.
+
"""
from collections import defaultdict
import re
@@ -1081,21 +1115,76 @@ class ENUM(sqltypes.Enum):
"""Postgresql ENUM type.
This is a subclass of :class:`.types.Enum` which includes
- support for PG's ``CREATE TYPE``.
-
- :class:`~.postgresql.ENUM` is used automatically when
- using the :class:`.types.Enum` type on PG assuming
- the ``native_enum`` is left as ``True``. However, the
- :class:`~.postgresql.ENUM` class can also be instantiated
- directly in order to access some additional Postgresql-specific
- options, namely finer control over whether or not
- ``CREATE TYPE`` should be emitted.
-
- Note that both :class:`.types.Enum` as well as
- :class:`~.postgresql.ENUM` feature create/drop
- methods; the base :class:`.types.Enum` type ultimately
- delegates to the :meth:`~.postgresql.ENUM.create` and
- :meth:`~.postgresql.ENUM.drop` methods present here.
+ support for PG's ``CREATE TYPE`` and ``DROP TYPE``.
+
+ When the builtin type :class:`.types.Enum` is used and the
+ :paramref:`.Enum.native_enum` flag is left at its default of
+ True, the Postgresql backend will use a :class:`.postgresql.ENUM`
+ type as the implementation, so the special create/drop rules
+ will be used.
+
+ The create/drop behavior of ENUM is necessarily intricate, due to the
+ awkward relationship the ENUM type has in relationship to the
+ parent table, in that it may be "owned" by just a single table, or
+ may be shared among many tables.
+
+ When using :class:`.types.Enum` or :class:`.postgresql.ENUM`
+ in an "inline" fashion, the ``CREATE TYPE`` and ``DROP TYPE`` is emitted
+ corresponding to when the :meth:`.Table.create` and :meth:`.Table.drop`
+ methods are called::
+
+ table = Table('sometable', metadata,
+ Column('some_enum', ENUM('a', 'b', 'c', name='myenum'))
+ )
+
+ table.create(engine) # will emit CREATE ENUM and CREATE TABLE
+ table.drop(engine) # will emit DROP TABLE and DROP ENUM
+
+ To use a common enumerated type between multiple tables, the best
+ practice is to declare the :class:`.types.Enum` or
+ :class:`.postgresql.ENUM` independently, and associate it with the
+ :class:`.MetaData` object itself::
+
+ my_enum = ENUM('a', 'b', 'c', name='myenum', metadata=metadata)
+
+ t1 = Table('sometable_one', metadata,
+ Column('some_enum', myenum)
+ )
+
+ t2 = Table('sometable_two', metadata,
+ Column('some_enum', myenum)
+ )
+
+ When this pattern is used, care must still be taken at the level
+ of individual table creates. Emitting CREATE TABLE without also
+ specifying ``checkfirst=True`` will still cause issues::
+
+ t1.create(engine) # will fail: no such type 'myenum'
+
+ If we specify ``checkfirst=True``, the individual table-level create
+ operation will check for the ``ENUM`` and create if not exists::
+
+ # will check if enum exists, and emit CREATE TYPE if not
+ t1.create(engine, checkfirst=True)
+
+ When using a metadata-level ENUM type, the type will always be created
+ and dropped if either the metadata-wide create/drop is called::
+
+ metadata.create_all(engine) # will emit CREATE TYPE
+ metadata.drop_all(engine) # will emit DROP TYPE
+
+ The type can also be created and dropped directly::
+
+ my_enum.create(engine)
+ my_enum.drop(engine)
+
+ .. versionchanged:: 1.0.0 The Postgresql :class:`.postgresql.ENUM` type
+ now behaves more strictly with regards to CREATE/DROP. A metadata-level
+ ENUM type will only be created and dropped at the metadata level,
+ not the table level, with the exception of
+ ``table.create(checkfirst=True)``.
+ The ``table.drop()`` call will now emit a DROP TYPE for a table-level
+ enumerated type.
"""
@@ -1201,9 +1290,18 @@ class ENUM(sqltypes.Enum):
return False
def _on_table_create(self, target, bind, checkfirst, **kw):
- if not self._check_for_name_in_memos(checkfirst, kw):
+ if checkfirst or (
+ not self.metadata and
+ not kw.get('_is_metadata_operation', False)) and \
+ not self._check_for_name_in_memos(checkfirst, kw):
self.create(bind=bind, checkfirst=checkfirst)
+ def _on_table_drop(self, target, bind, checkfirst, **kw):
+ if not self.metadata and \
+ not kw.get('_is_metadata_operation', False) and \
+ not self._check_for_name_in_memos(checkfirst, kw):
+ self.drop(bind=bind, checkfirst=checkfirst)
+
def _on_metadata_create(self, target, bind, checkfirst, **kw):
if not self._check_for_name_in_memos(checkfirst, kw):
self.create(bind=bind, checkfirst=checkfirst)
@@ -1459,7 +1557,13 @@ class PGDDLCompiler(compiler.DDLCompiler):
text = "CREATE "
if index.unique:
text += "UNIQUE "
- text += "INDEX %s ON %s " % (
+ text += "INDEX "
+
+ concurrently = index.dialect_options['postgresql']['concurrently']
+ if concurrently:
+ text += "CONCURRENTLY "
+
+ text += "%s ON %s " % (
self._prepared_index_name(index,
include_schema=False),
preparer.format_table(index.table)
@@ -1812,7 +1916,8 @@ class PGDialect(default.DefaultDialect):
(schema.Index, {
"using": False,
"where": None,
- "ops": {}
+ "ops": {},
+ "concurrently": False,
}),
(schema.Table, {
"ignore_search_path": False,
diff --git a/lib/sqlalchemy/dialects/postgresql/constraints.py b/lib/sqlalchemy/dialects/postgresql/constraints.py
index e8ebc75dd..0371daf3d 100644
--- a/lib/sqlalchemy/dialects/postgresql/constraints.py
+++ b/lib/sqlalchemy/dialects/postgresql/constraints.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2013-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/hstore.py b/lib/sqlalchemy/dialects/postgresql/hstore.py
index 9601edc41..9f369cb5b 100644
--- a/lib/sqlalchemy/dialects/postgresql/hstore.py
+++ b/lib/sqlalchemy/dialects/postgresql/hstore.py
@@ -1,5 +1,5 @@
# postgresql/hstore.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/json.py b/lib/sqlalchemy/dialects/postgresql/json.py
index f38c4a56a..13ebc4afe 100644
--- a/lib/sqlalchemy/dialects/postgresql/json.py
+++ b/lib/sqlalchemy/dialects/postgresql/json.py
@@ -1,5 +1,5 @@
# postgresql/json.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/pg8000.py b/lib/sqlalchemy/dialects/postgresql/pg8000.py
index 4ccc90208..c71f689a3 100644
--- a/lib/sqlalchemy/dialects/postgresql/pg8000.py
+++ b/lib/sqlalchemy/dialects/postgresql/pg8000.py
@@ -1,5 +1,5 @@
# postgresql/pg8000.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors <see AUTHORS
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors <see AUTHORS
# file>
#
# This module is part of SQLAlchemy and is released under
@@ -13,17 +13,30 @@
postgresql+pg8000://user:password@host:port/dbname[?key=value&key=value...]
:url: https://pythonhosted.org/pg8000/
+
+.. _pg8000_unicode:
+
Unicode
-------
-When communicating with the server, pg8000 **always uses the server-side
-character set**. SQLAlchemy has no ability to modify what character set
-pg8000 chooses to use, and additionally SQLAlchemy does no unicode conversion
-of any kind with the pg8000 backend. The origin of the client encoding setting
-is ultimately the CLIENT_ENCODING setting in postgresql.conf.
+pg8000 will encode / decode string values between it and the server using the
+PostgreSQL ``client_encoding`` parameter; by default this is the value in
+the ``postgresql.conf`` file, which often defaults to ``SQL_ASCII``.
+Typically, this can be changed to ``utf-8``, as a more useful default::
+
+ #client_encoding = sql_ascii # actually, defaults to database
+ # encoding
+ client_encoding = utf8
+
+The ``client_encoding`` can be overriden for a session by executing the SQL:
+
+SET CLIENT_ENCODING TO 'utf8';
+
+SQLAlchemy will execute this SQL on all new connections based on the value
+passed to :func:`.create_engine` using the ``client_encoding`` parameter::
-It is not necessary, though is also harmless, to pass the "encoding" parameter
-to :func:`.create_engine` when using pg8000.
+ engine = create_engine(
+ "postgresql+pg8000://user:pass@host/dbname", client_encoding='utf8')
.. _pg8000_isolation_level:
@@ -58,6 +71,8 @@ from ... import types as sqltypes
from .base import (
PGDialect, PGCompiler, PGIdentifierPreparer, PGExecutionContext,
_DECIMAL_TYPES, _FLOAT_TYPES, _INT_TYPES)
+import re
+from sqlalchemy.dialects.postgresql.json import JSON
class _PGNumeric(sqltypes.Numeric):
@@ -88,6 +103,15 @@ class _PGNumericNoBind(_PGNumeric):
return None
+class _PGJSON(JSON):
+
+ def result_processor(self, dialect, coltype):
+ if dialect._dbapi_version > (1, 10, 1):
+ return None # Has native JSON
+ else:
+ return super(_PGJSON, self).result_processor(dialect, coltype)
+
+
class PGExecutionContext_pg8000(PGExecutionContext):
pass
@@ -129,20 +153,29 @@ class PGDialect_pg8000(PGDialect):
PGDialect.colspecs,
{
sqltypes.Numeric: _PGNumericNoBind,
- sqltypes.Float: _PGNumeric
+ sqltypes.Float: _PGNumeric,
+ JSON: _PGJSON,
}
)
+ def __init__(self, client_encoding=None, **kwargs):
+ PGDialect.__init__(self, **kwargs)
+ self.client_encoding = client_encoding
+
def initialize(self, connection):
- if self.dbapi and hasattr(self.dbapi, '__version__'):
- self._dbapi_version = tuple([
- int(x) for x in
- self.dbapi.__version__.split(".")])
- else:
- self._dbapi_version = (99, 99, 99)
self.supports_sane_multi_rowcount = self._dbapi_version >= (1, 9, 14)
super(PGDialect_pg8000, self).initialize(connection)
+ @util.memoized_property
+ def _dbapi_version(self):
+ if self.dbapi and hasattr(self.dbapi, '__version__'):
+ return tuple(
+ [
+ int(x) for x in re.findall(
+ r'(\d+)(?:[-\.]?|$)', self.dbapi.__version__)])
+ else:
+ return (99, 99, 99)
+
@classmethod
def dbapi(cls):
return __import__('pg8000')
@@ -181,6 +214,16 @@ class PGDialect_pg8000(PGDialect):
(level, self.name, ", ".join(self._isolation_lookup))
)
+ def set_client_encoding(self, connection, client_encoding):
+ # adjust for ConnectionFairy possibly being present
+ if hasattr(connection, 'connection'):
+ connection = connection.connection
+
+ cursor = connection.cursor()
+ cursor.execute("SET CLIENT_ENCODING TO '" + client_encoding + "'")
+ cursor.execute("COMMIT")
+ cursor.close()
+
def do_begin_twophase(self, connection, xid):
connection.connection.tpc_begin((0, xid, ''))
@@ -198,4 +241,24 @@ class PGDialect_pg8000(PGDialect):
def do_recover_twophase(self, connection):
return [row[1] for row in connection.connection.tpc_recover()]
+ def on_connect(self):
+ fns = []
+ if self.client_encoding is not None:
+ def on_connect(conn):
+ self.set_client_encoding(conn, self.client_encoding)
+ fns.append(on_connect)
+
+ if self.isolation_level is not None:
+ def on_connect(conn):
+ self.set_isolation_level(conn, self.isolation_level)
+ fns.append(on_connect)
+
+ if len(fns) > 0:
+ def on_connect(conn):
+ for fn in fns:
+ fn(conn)
+ return on_connect
+ else:
+ return None
+
dialect = PGDialect_pg8000
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index 4f1e04f20..46228ac15 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -1,5 +1,5 @@
# postgresql/psycopg2.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/pypostgresql.py b/lib/sqlalchemy/dialects/postgresql/pypostgresql.py
index 3ebd0135f..00c67d170 100644
--- a/lib/sqlalchemy/dialects/postgresql/pypostgresql.py
+++ b/lib/sqlalchemy/dialects/postgresql/pypostgresql.py
@@ -1,5 +1,5 @@
# postgresql/pypostgresql.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/ranges.py b/lib/sqlalchemy/dialects/postgresql/ranges.py
index 28f80d000..59c35c871 100644
--- a/lib/sqlalchemy/dialects/postgresql/ranges.py
+++ b/lib/sqlalchemy/dialects/postgresql/ranges.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2013-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/postgresql/zxjdbc.py b/lib/sqlalchemy/dialects/postgresql/zxjdbc.py
index 00b428f84..1b542152c 100644
--- a/lib/sqlalchemy/dialects/postgresql/zxjdbc.py
+++ b/lib/sqlalchemy/dialects/postgresql/zxjdbc.py
@@ -1,5 +1,5 @@
# postgresql/zxjdbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/sqlite/__init__.py b/lib/sqlalchemy/dialects/sqlite/__init__.py
index a53d53e9d..608630a25 100644
--- a/lib/sqlalchemy/dialects/sqlite/__init__.py
+++ b/lib/sqlalchemy/dialects/sqlite/__init__.py
@@ -1,5 +1,5 @@
# sqlite/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py
index 1ed89bacb..0f32395e5 100644
--- a/lib/sqlalchemy/dialects/sqlite/base.py
+++ b/lib/sqlalchemy/dialects/sqlite/base.py
@@ -1,5 +1,5 @@
# sqlite/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -272,6 +272,26 @@ lookup is used instead:
.. versionadded:: 0.9.3 Support for SQLite type affinity rules when reflecting
columns.
+
+.. _sqlite_partial_index:
+
+Partial Indexes
+---------------
+
+A partial index, e.g. one which uses a WHERE clause, can be specified
+with the DDL system using the argument ``sqlite_where``::
+
+ tbl = Table('testtbl', m, Column('data', Integer))
+ idx = Index('test_idx1', tbl.c.data,
+ sqlite_where=and_(tbl.c.data > 5, tbl.c.data < 10))
+
+The index will be rendered at create time as::
+
+ CREATE INDEX test_idx1 ON testtbl (data)
+ WHERE data > 5 AND data < 10
+
+.. versionadded:: 0.9.9
+
"""
import datetime
@@ -714,9 +734,20 @@ class SQLiteDDLCompiler(compiler.DDLCompiler):
return preparer.format_table(table, use_schema=False)
def visit_create_index(self, create):
- return super(SQLiteDDLCompiler, self).visit_create_index(
+ index = create.element
+
+ text = super(SQLiteDDLCompiler, self).visit_create_index(
create, include_table_schema=False)
+ whereclause = index.dialect_options["sqlite"]["where"]
+ if whereclause is not None:
+ where_compiled = self.sql_compiler.process(
+ whereclause, include_table=False,
+ literal_binds=True)
+ text += " WHERE " + where_compiled
+
+ return text
+
class SQLiteTypeCompiler(compiler.GenericTypeCompiler):
def visit_large_binary(self, type_, **kw):
@@ -823,7 +854,10 @@ class SQLiteDialect(default.DefaultDialect):
construct_arguments = [
(sa_schema.Table, {
"autoincrement": False
- })
+ }),
+ (sa_schema.Index, {
+ "where": None,
+ }),
]
_broken_fk_pragma_quotes = False
diff --git a/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py b/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py
index 3c55a1de7..9166e36bc 100644
--- a/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py
+++ b/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py
@@ -1,5 +1,5 @@
# sqlite/pysqlcipher.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/sqlite/pysqlite.py b/lib/sqlalchemy/dialects/sqlite/pysqlite.py
index 62c19d145..e1c443477 100644
--- a/lib/sqlalchemy/dialects/sqlite/pysqlite.py
+++ b/lib/sqlalchemy/dialects/sqlite/pysqlite.py
@@ -1,5 +1,5 @@
# sqlite/pysqlite.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/sybase/__init__.py b/lib/sqlalchemy/dialects/sybase/__init__.py
index eb313592b..0c55de1d6 100644
--- a/lib/sqlalchemy/dialects/sybase/__init__.py
+++ b/lib/sqlalchemy/dialects/sybase/__init__.py
@@ -1,5 +1,5 @@
# sybase/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/sybase/base.py b/lib/sqlalchemy/dialects/sybase/base.py
index 369420358..34d896347 100644
--- a/lib/sqlalchemy/dialects/sybase/base.py
+++ b/lib/sqlalchemy/dialects/sybase/base.py
@@ -1,5 +1,5 @@
# sybase/base.py
-# Copyright (C) 2010-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2010-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
# get_select_precolumns(), limit_clause() implementation
# copyright (C) 2007 Fisch Asset Management
diff --git a/lib/sqlalchemy/dialects/sybase/mxodbc.py b/lib/sqlalchemy/dialects/sybase/mxodbc.py
index 373bea05d..240b634d4 100644
--- a/lib/sqlalchemy/dialects/sybase/mxodbc.py
+++ b/lib/sqlalchemy/dialects/sybase/mxodbc.py
@@ -1,5 +1,5 @@
# sybase/mxodbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/sybase/pyodbc.py b/lib/sqlalchemy/dialects/sybase/pyodbc.py
index cb76d1379..168997074 100644
--- a/lib/sqlalchemy/dialects/sybase/pyodbc.py
+++ b/lib/sqlalchemy/dialects/sybase/pyodbc.py
@@ -1,5 +1,5 @@
# sybase/pyodbc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/dialects/sybase/pysybase.py b/lib/sqlalchemy/dialects/sybase/pysybase.py
index 6843eb480..a30739444 100644
--- a/lib/sqlalchemy/dialects/sybase/pysybase.py
+++ b/lib/sqlalchemy/dialects/sybase/pysybase.py
@@ -1,5 +1,5 @@
# sybase/pysybase.py
-# Copyright (C) 2010-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2010-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/engine/__init__.py b/lib/sqlalchemy/engine/__init__.py
index 7a14cdfb5..0678dd201 100644
--- a/lib/sqlalchemy/engine/__init__.py
+++ b/lib/sqlalchemy/engine/__init__.py
@@ -1,5 +1,5 @@
# engine/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 305fa4620..6be446313 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -1,5 +1,5 @@
# engine/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -991,9 +991,8 @@ class Connection(Connectable):
dialect = self.dialect
if 'compiled_cache' in self._execution_options:
key = dialect, elem, tuple(sorted(keys)), len(distilled_params) > 1
- if key in self._execution_options['compiled_cache']:
- compiled_sql = self._execution_options['compiled_cache'][key]
- else:
+ compiled_sql = self._execution_options['compiled_cache'].get(key)
+ if compiled_sql is None:
compiled_sql = elem.compile(
dialect=dialect, column_keys=keys,
inline=len(distilled_params) > 1)
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 17d2e2531..b46acb650 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -1,5 +1,5 @@
# engine/default.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -461,9 +461,9 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
is_crud = False
isddl = False
executemany = False
- result_map = None
compiled = None
statement = None
+ result_column_struct = None
_is_implicit_returning = False
_is_explicit_returning = False
@@ -522,10 +522,8 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
self.execution_options = compiled.statement._execution_options.union(
connection._execution_options)
- # compiled clauseelement. process bind params, process table defaults,
- # track collections used by ResultProxy to target and process results
-
- self.result_map = compiled.result_map
+ self.result_column_struct = (
+ compiled._result_columns, compiled._ordered_columns)
self.unicode_statement = util.text_type(compiled)
if not dialect.supports_unicode_statements:
diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py
index 5f0d74328..da8fa81eb 100644
--- a/lib/sqlalchemy/engine/interfaces.py
+++ b/lib/sqlalchemy/engine/interfaces.py
@@ -1,5 +1,5 @@
# engine/interfaces.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py
index 6e102aad6..59eed51ec 100644
--- a/lib/sqlalchemy/engine/reflection.py
+++ b/lib/sqlalchemy/engine/reflection.py
@@ -1,5 +1,5 @@
# engine/reflection.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index 3995942ef..3c31ae1ea 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -1,5 +1,5 @@
# engine/result.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -187,86 +187,162 @@ class ResultMetaData(object):
context."""
def __init__(self, parent, metadata):
- self._processors = processors = []
-
- # We do not strictly need to store the processor in the key mapping,
- # though it is faster in the Python version (probably because of the
- # saved attribute lookup self._processors)
- self._keymap = keymap = {}
- self.keys = []
context = parent.context
dialect = context.dialect
typemap = dialect.dbapi_type_map
translate_colname = context._translate_colname
- self.case_sensitive = dialect.case_sensitive
-
- # high precedence key values.
- primary_keymap = {}
-
- for i, rec in enumerate(metadata):
- colname = rec[0]
- coltype = rec[1]
-
- if dialect.description_encoding:
- colname = dialect._description_decoder(colname)
+ self.case_sensitive = case_sensitive = dialect.case_sensitive
+ if context.result_column_struct:
+ result_columns, cols_are_ordered = context.result_column_struct
+ num_ctx_cols = len(result_columns)
+ else:
+ num_ctx_cols = None
+
+ if num_ctx_cols and \
+ cols_are_ordered and \
+ num_ctx_cols == len(metadata):
+ # case 1 - SQL expression statement, number of columns
+ # in result matches number of cols in compiled. This is the
+ # vast majority case for SQL expression constructs. In this
+ # case we don't bother trying to parse or match up to
+ # the colnames in the result description.
+ raw = [
+ (
+ idx,
+ key,
+ name.lower() if not case_sensitive else name,
+ context.get_result_processor(
+ type_, key, metadata[idx][1]
+ ),
+ obj,
+ None
+ ) for idx, (key, name, obj, type_)
+ in enumerate(result_columns)
+ ]
+ self.keys = [
+ elem[1] for elem in result_columns
+ ]
+ else:
+ # case 2 - raw string, or number of columns in result does
+ # not match number of cols in compiled. The raw string case
+ # is very common. The latter can happen
+ # when text() is used with only a partial typemap, or
+ # in the extremely unlikely cases where the compiled construct
+ # has a single element with multiple col expressions in it
+ # (e.g. has commas embedded) or there's some kind of statement
+ # that is adding extra columns.
+ # In all these cases we fall back to the "named" approach
+ # that SQLAlchemy has used up through 0.9.
+
+ if num_ctx_cols:
+ result_map = self._create_result_map(result_columns)
+
+ raw = []
+ self.keys = []
+ untranslated = None
+ for idx, rec in enumerate(metadata):
+ colname = rec[0]
+ coltype = rec[1]
+
+ if dialect.description_encoding:
+ colname = dialect._description_decoder(colname)
+
+ if translate_colname:
+ colname, untranslated = translate_colname(colname)
+
+ if dialect.requires_name_normalize:
+ colname = dialect.normalize_name(colname)
+
+ self.keys.append(colname)
+ if not case_sensitive:
+ colname = colname.lower()
+
+ if num_ctx_cols:
+ try:
+ ctx_rec = result_map[colname]
+ except KeyError:
+ mapped_type = typemap.get(coltype, sqltypes.NULLTYPE)
+ obj = None
+ else:
+ obj = ctx_rec[1]
+ mapped_type = ctx_rec[2]
+ else:
+ mapped_type = typemap.get(coltype, sqltypes.NULLTYPE)
+ obj = None
+ processor = context.get_result_processor(
+ mapped_type, colname, coltype)
+
+ raw.append(
+ (idx, colname, colname, processor, obj, untranslated)
+ )
+
+ # keymap indexes by integer index...
+ self._keymap = dict([
+ (elem[0], (elem[3], elem[4], elem[0]))
+ for elem in raw
+ ])
+
+ # processors in key order for certain per-row
+ # views like __iter__ and slices
+ self._processors = [elem[3] for elem in raw]
+
+ if num_ctx_cols:
+ # keymap by primary string...
+ by_key = dict([
+ (elem[2], (elem[3], elem[4], elem[0]))
+ for elem in raw
+ ])
+
+ # if by-primary-string dictionary smaller (or bigger?!) than
+ # number of columns, assume we have dupes, rewrite
+ # dupe records with "None" for index which results in
+ # ambiguous column exception when accessed.
+ if len(by_key) != num_ctx_cols:
+ seen = set()
+ for rec in raw:
+ key = rec[1]
+ if key in seen:
+ by_key[key] = (None, by_key[key][1], None)
+ seen.add(key)
+
+ # update keymap with secondary "object"-based keys
+ self._keymap.update([
+ (obj_elem, by_key[elem[2]])
+ for elem in raw if elem[4]
+ for obj_elem in elem[4]
+ ])
+
+ # update keymap with primary string names taking
+ # precedence
+ self._keymap.update(by_key)
+ else:
+ self._keymap.update([
+ (elem[2], (elem[3], elem[4], elem[0]))
+ for elem in raw
+ ])
+ # update keymap with "translated" names (sqlite-only thing)
if translate_colname:
- colname, untranslated = translate_colname(colname)
-
- if dialect.requires_name_normalize:
- colname = dialect.normalize_name(colname)
-
- if context.result_map:
- try:
- name, obj, type_ = context.result_map[
- colname if self.case_sensitive else colname.lower()]
- except KeyError:
- name, obj, type_ = \
- colname, None, typemap.get(coltype, sqltypes.NULLTYPE)
+ self._keymap.update([
+ (elem[5], self._keymap[elem[2]])
+ for elem in raw if elem[5]
+ ])
+
+ @classmethod
+ def _create_result_map(cls, result_columns):
+ d = {}
+ for elem in result_columns:
+ key, rec = elem[0], elem[1:]
+ if key in d:
+ # conflicting keyname, just double up the list
+ # of objects. this will cause an "ambiguous name"
+ # error if an attempt is made by the result set to
+ # access.
+ e_name, e_obj, e_type = d[key]
+ d[key] = e_name, e_obj + rec[1], e_type
else:
- name, obj, type_ = \
- colname, None, typemap.get(coltype, sqltypes.NULLTYPE)
-
- processor = context.get_result_processor(type_, colname, coltype)
-
- processors.append(processor)
- rec = (processor, obj, i)
-
- # indexes as keys. This is only needed for the Python version of
- # RowProxy (the C version uses a faster path for integer indexes).
- primary_keymap[i] = rec
-
- # populate primary keymap, looking for conflicts.
- if primary_keymap.setdefault(
- name if self.case_sensitive
- else name.lower(),
- rec) is not rec:
- # place a record that doesn't have the "index" - this
- # is interpreted later as an AmbiguousColumnError,
- # but only when actually accessed. Columns
- # colliding by name is not a problem if those names
- # aren't used; integer access is always
- # unambiguous.
- primary_keymap[name
- if self.case_sensitive
- else name.lower()] = rec = (None, obj, None)
-
- self.keys.append(colname)
- if obj:
- for o in obj:
- keymap[o] = rec
- # technically we should be doing this but we
- # are saving on callcounts by not doing so.
- # if keymap.setdefault(o, rec) is not rec:
- # keymap[o] = (None, obj, None)
-
- if translate_colname and \
- untranslated:
- keymap[untranslated] = rec
-
- # overwrite keymap values with those of the
- # high precedence keymap.
- keymap.update(primary_keymap)
+ d[key] = rec
+ return d
@util.pending_deprecation("0.8", "sqlite dialect uses "
"_translate_colname() now")
diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py
index fd665ad03..1fd105d67 100644
--- a/lib/sqlalchemy/engine/strategies.py
+++ b/lib/sqlalchemy/engine/strategies.py
@@ -1,5 +1,5 @@
# engine/strategies.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/engine/threadlocal.py b/lib/sqlalchemy/engine/threadlocal.py
index e64ab09f4..0d6e1c0f1 100644
--- a/lib/sqlalchemy/engine/threadlocal.py
+++ b/lib/sqlalchemy/engine/threadlocal.py
@@ -1,5 +1,5 @@
# engine/threadlocal.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/engine/url.py b/lib/sqlalchemy/engine/url.py
index 6544cfbf3..d045961dd 100644
--- a/lib/sqlalchemy/engine/url.py
+++ b/lib/sqlalchemy/engine/url.py
@@ -1,5 +1,5 @@
# engine/url.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/engine/util.py b/lib/sqlalchemy/engine/util.py
index d9eb1df10..3734c9960 100644
--- a/lib/sqlalchemy/engine/util.py
+++ b/lib/sqlalchemy/engine/util.py
@@ -1,5 +1,5 @@
# engine/util.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/event/__init__.py b/lib/sqlalchemy/event/__init__.py
index b93c0ef85..c9bdb9a0e 100644
--- a/lib/sqlalchemy/event/__init__.py
+++ b/lib/sqlalchemy/event/__init__.py
@@ -1,5 +1,5 @@
# event/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/event/api.py b/lib/sqlalchemy/event/api.py
index b3d79bcf4..86ef094d6 100644
--- a/lib/sqlalchemy/event/api.py
+++ b/lib/sqlalchemy/event/api.py
@@ -1,5 +1,5 @@
# event/api.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/event/attr.py b/lib/sqlalchemy/event/attr.py
index ed1dca644..a64c7d08d 100644
--- a/lib/sqlalchemy/event/attr.py
+++ b/lib/sqlalchemy/event/attr.py
@@ -1,5 +1,5 @@
# event/attr.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/event/base.py b/lib/sqlalchemy/event/base.py
index 2d5468886..1fe83eea2 100644
--- a/lib/sqlalchemy/event/base.py
+++ b/lib/sqlalchemy/event/base.py
@@ -1,5 +1,5 @@
# event/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/event/legacy.py b/lib/sqlalchemy/event/legacy.py
index 7513c7d4d..daa74226f 100644
--- a/lib/sqlalchemy/event/legacy.py
+++ b/lib/sqlalchemy/event/legacy.py
@@ -1,5 +1,5 @@
# event/legacy.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/event/registry.py b/lib/sqlalchemy/event/registry.py
index ebc0e6d18..a6eabb2ff 100644
--- a/lib/sqlalchemy/event/registry.py
+++ b/lib/sqlalchemy/event/registry.py
@@ -1,5 +1,5 @@
# event/registry.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/events.py b/lib/sqlalchemy/events.py
index 8600c20f5..22e066c88 100644
--- a/lib/sqlalchemy/events.py
+++ b/lib/sqlalchemy/events.py
@@ -1,5 +1,5 @@
# sqlalchemy/events.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/exc.py b/lib/sqlalchemy/exc.py
index d6355a212..c0d51382d 100644
--- a/lib/sqlalchemy/exc.py
+++ b/lib/sqlalchemy/exc.py
@@ -1,5 +1,5 @@
# sqlalchemy/exc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/__init__.py b/lib/sqlalchemy/ext/__init__.py
index 479a448e2..60a17c65e 100644
--- a/lib/sqlalchemy/ext/__init__.py
+++ b/lib/sqlalchemy/ext/__init__.py
@@ -1,5 +1,5 @@
# ext/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py
index bb08ce9ba..a74141973 100644
--- a/lib/sqlalchemy/ext/associationproxy.py
+++ b/lib/sqlalchemy/ext/associationproxy.py
@@ -1,5 +1,5 @@
# ext/associationproxy.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -527,7 +527,10 @@ class _AssociationList(_AssociationCollection):
return self.setter(object, value)
def __getitem__(self, index):
- return self._get(self.col[index])
+ if not isinstance(index, slice):
+ return self._get(self.col[index])
+ else:
+ return [self._get(member) for member in self.col[index]]
def __setitem__(self, index, value):
if not isinstance(index, slice):
diff --git a/lib/sqlalchemy/ext/automap.py b/lib/sqlalchemy/ext/automap.py
index c11795d37..ca550ded6 100644
--- a/lib/sqlalchemy/ext/automap.py
+++ b/lib/sqlalchemy/ext/automap.py
@@ -1,5 +1,5 @@
# ext/automap.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/compiler.py b/lib/sqlalchemy/ext/compiler.py
index 8d169aa57..9717e41c0 100644
--- a/lib/sqlalchemy/ext/compiler.py
+++ b/lib/sqlalchemy/ext/compiler.py
@@ -1,5 +1,5 @@
# ext/compiler.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/declarative/__init__.py b/lib/sqlalchemy/ext/declarative/__init__.py
index cbde6f9d2..ff306d60c 100644
--- a/lib/sqlalchemy/ext/declarative/__init__.py
+++ b/lib/sqlalchemy/ext/declarative/__init__.py
@@ -1,5 +1,5 @@
# ext/declarative/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/declarative/api.py b/lib/sqlalchemy/ext/declarative/api.py
index 66fe05fd0..048533b92 100644
--- a/lib/sqlalchemy/ext/declarative/api.py
+++ b/lib/sqlalchemy/ext/declarative/api.py
@@ -1,5 +1,5 @@
# ext/declarative/api.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py
index d19257366..7d4020b24 100644
--- a/lib/sqlalchemy/ext/declarative/base.py
+++ b/lib/sqlalchemy/ext/declarative/base.py
@@ -1,5 +1,5 @@
# ext/declarative/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -35,6 +35,21 @@ def _declared_mapping_info(cls):
return None
+def _resolve_for_abstract(cls):
+ if cls is object:
+ return None
+
+ if _get_immediate_cls_attr(cls, '__abstract__'):
+ for sup in cls.__bases__:
+ sup = _resolve_for_abstract(sup)
+ if sup is not None:
+ return sup
+ else:
+ return None
+ else:
+ return cls
+
+
def _get_immediate_cls_attr(cls, attrname):
"""return an attribute of the class that is either present directly
on the class, e.g. not on a superclass, or is from a superclass but
@@ -46,6 +61,9 @@ def _get_immediate_cls_attr(cls, attrname):
inherit from.
"""
+ if not issubclass(cls, object):
+ return None
+
for base in cls.__mro__:
_is_declarative_inherits = hasattr(base, '_decl_class_registry')
if attrname in base.__dict__:
@@ -389,6 +407,9 @@ class _MapperConfig(object):
table_args = self.table_args
declared_columns = self.declared_columns
for c in cls.__bases__:
+ c = _resolve_for_abstract(c)
+ if c is None:
+ continue
if _declared_mapping_info(c) is not None and \
not _get_immediate_cls_attr(
c, '_sa_decl_prepare_nocascade'):
diff --git a/lib/sqlalchemy/ext/declarative/clsregistry.py b/lib/sqlalchemy/ext/declarative/clsregistry.py
index d2a09d823..c3887d6cf 100644
--- a/lib/sqlalchemy/ext/declarative/clsregistry.py
+++ b/lib/sqlalchemy/ext/declarative/clsregistry.py
@@ -1,5 +1,5 @@
# ext/declarative/clsregistry.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/horizontal_shard.py b/lib/sqlalchemy/ext/horizontal_shard.py
index d311fb2d4..c9fb0b044 100644
--- a/lib/sqlalchemy/ext/horizontal_shard.py
+++ b/lib/sqlalchemy/ext/horizontal_shard.py
@@ -1,5 +1,5 @@
# ext/horizontal_shard.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/hybrid.py b/lib/sqlalchemy/ext/hybrid.py
index f72de6099..f94c2079e 100644
--- a/lib/sqlalchemy/ext/hybrid.py
+++ b/lib/sqlalchemy/ext/hybrid.py
@@ -1,5 +1,5 @@
# ext/hybrid.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/mutable.py b/lib/sqlalchemy/ext/mutable.py
index e49e9ea8b..24fc37a42 100644
--- a/lib/sqlalchemy/ext/mutable.py
+++ b/lib/sqlalchemy/ext/mutable.py
@@ -1,5 +1,5 @@
# ext/mutable.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/orderinglist.py b/lib/sqlalchemy/ext/orderinglist.py
index 61155731c..ac31c7cf7 100644
--- a/lib/sqlalchemy/ext/orderinglist.py
+++ b/lib/sqlalchemy/ext/orderinglist.py
@@ -1,5 +1,5 @@
# ext/orderinglist.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/ext/serializer.py b/lib/sqlalchemy/ext/serializer.py
index bf8d67d8e..555f3760b 100644
--- a/lib/sqlalchemy/ext/serializer.py
+++ b/lib/sqlalchemy/ext/serializer.py
@@ -1,5 +1,5 @@
# ext/serializer.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/inspection.py b/lib/sqlalchemy/inspection.py
index ab9f2ae38..a4738cc61 100644
--- a/lib/sqlalchemy/inspection.py
+++ b/lib/sqlalchemy/inspection.py
@@ -1,5 +1,5 @@
# sqlalchemy/inspect.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/interfaces.py b/lib/sqlalchemy/interfaces.py
index ae11d1930..717e99b5e 100644
--- a/lib/sqlalchemy/interfaces.py
+++ b/lib/sqlalchemy/interfaces.py
@@ -1,5 +1,5 @@
# sqlalchemy/interfaces.py
-# Copyright (C) 2007-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2007-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
# Copyright (C) 2007 Jason Kirtland jek@discorporate.us
#
diff --git a/lib/sqlalchemy/log.py b/lib/sqlalchemy/log.py
index b3c9ae024..c23412e38 100644
--- a/lib/sqlalchemy/log.py
+++ b/lib/sqlalchemy/log.py
@@ -1,5 +1,5 @@
# sqlalchemy/log.py
-# Copyright (C) 2006-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2006-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
# Includes alterations by Vinay Sajip vinay_sajip@yahoo.co.uk
#
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 741e79b9d..e02a271e3 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -1,5 +1,5 @@
# orm/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index a5af4e8ba..41803c8bf 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -1,5 +1,5 @@
# orm/attributes.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/base.py b/lib/sqlalchemy/orm/base.py
index fc4d3f350..c259878f0 100644
--- a/lib/sqlalchemy/orm/base.py
+++ b/lib/sqlalchemy/orm/base.py
@@ -1,5 +1,5 @@
# orm/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
index 356a8a3b9..4f988a8d4 100644
--- a/lib/sqlalchemy/orm/collections.py
+++ b/lib/sqlalchemy/orm/collections.py
@@ -1,5 +1,5 @@
# orm/collections.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -1507,8 +1507,8 @@ class MappedCollection(dict):
def __init__(self, keyfunc):
"""Create a new collection with keying provided by keyfunc.
- keyfunc may be any callable any callable that takes an object and
- returns an object for use as a dictionary key.
+ keyfunc may be any callable that takes an object and returns an object
+ for use as a dictionary key.
The keyfunc will be called every time the ORM needs to add a member by
value-only (such as when loading instances from the database) or
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py
index d10a38394..d8989939b 100644
--- a/lib/sqlalchemy/orm/dependency.py
+++ b/lib/sqlalchemy/orm/dependency.py
@@ -1,5 +1,5 @@
# orm/dependency.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/deprecated_interfaces.py b/lib/sqlalchemy/orm/deprecated_interfaces.py
index 275582323..bb6d185d4 100644
--- a/lib/sqlalchemy/orm/deprecated_interfaces.py
+++ b/lib/sqlalchemy/orm/deprecated_interfaces.py
@@ -1,5 +1,5 @@
# orm/deprecated_interfaces.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index e68ff1bea..17c2d28ce 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -1,5 +1,5 @@
# orm/descriptor_props.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py
index a4ccfe417..aedd863f8 100644
--- a/lib/sqlalchemy/orm/dynamic.py
+++ b/lib/sqlalchemy/orm/dynamic.py
@@ -1,5 +1,5 @@
# orm/dynamic.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/evaluator.py b/lib/sqlalchemy/orm/evaluator.py
index 2026e5d0a..1e828ff86 100644
--- a/lib/sqlalchemy/orm/evaluator.py
+++ b/lib/sqlalchemy/orm/evaluator.py
@@ -1,5 +1,5 @@
# orm/evaluator.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py
index 4d888a350..233cd66a6 100644
--- a/lib/sqlalchemy/orm/events.py
+++ b/lib/sqlalchemy/orm/events.py
@@ -1,5 +1,5 @@
# orm/events.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -17,7 +17,7 @@ from . import mapperlib, instrumentation
from .session import Session, sessionmaker
from .scoping import scoped_session
from .attributes import QueryableAttribute
-
+from .query import Query
class InstrumentationEvents(event.Events):
"""Events related to class instrumentation events.
@@ -1651,3 +1651,56 @@ class AttributeEvents(event.Events):
the :class:`.collection.linker` hook.
"""
+
+
+class QueryEvents(event.Events):
+ """Represent events within the construction of a :class:`.Query` object.
+
+ The events here are intended to be used with an as-yet-unreleased
+ inspection system for :class:`.Query`. Some very basic operations
+ are possible now, however the inspection system is intended to allow
+ complex query manipulations to be automated.
+
+ .. versionadded:: 1.0.0
+
+ """
+
+ _target_class_doc = "SomeQuery"
+ _dispatch_target = Query
+
+ def before_compile(self, query):
+ """Receive the :class:`.Query` object before it is composed into a
+ core :class:`.Select` object.
+
+ This event is intended to allow changes to the query given::
+
+ @event.listens_for(Query, "before_compile", retval=True)
+ def no_deleted(query):
+ for desc in query.column_descriptions:
+ if desc['type'] is User:
+ entity = desc['expr']
+ query = query.filter(entity.deleted == False)
+ return query
+
+ The event should normally be listened with the ``retval=True``
+ parameter set, so that the modified query may be returned.
+
+
+ """
+
+ @classmethod
+ def _listen(
+ cls, event_key, retval=False, **kw):
+ fn = event_key._listen_fn
+
+ if not retval:
+ def wrap(*arg, **kw):
+ if not retval:
+ query = arg[0]
+ fn(*arg, **kw)
+ return query
+ else:
+ return fn(*arg, **kw)
+ event_key = event_key.with_wrapper(wrap)
+
+ event_key.base_listen(**kw)
diff --git a/lib/sqlalchemy/orm/exc.py b/lib/sqlalchemy/orm/exc.py
index ff0ece411..e010a295d 100644
--- a/lib/sqlalchemy/orm/exc.py
+++ b/lib/sqlalchemy/orm/exc.py
@@ -1,5 +1,5 @@
# orm/exc.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py
index 769010950..46be2b719 100644
--- a/lib/sqlalchemy/orm/identity.py
+++ b/lib/sqlalchemy/orm/identity.py
@@ -1,5 +1,5 @@
# orm/identity.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py
index 78a573cfd..be2fe91c2 100644
--- a/lib/sqlalchemy/orm/instrumentation.py
+++ b/lib/sqlalchemy/orm/instrumentation.py
@@ -1,5 +1,5 @@
# orm/instrumentation.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index dc230d68b..6cc613baa 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -1,5 +1,5 @@
# orm/interfaces.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index 64c7e171c..50afaf601 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -1,5 +1,5 @@
# orm/loading.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index df67ff147..4554f78f9 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -1,5 +1,5 @@
# orm/mapper.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/path_registry.py b/lib/sqlalchemy/orm/path_registry.py
index ec80c70cc..9670a07fb 100644
--- a/lib/sqlalchemy/orm/path_registry.py
+++ b/lib/sqlalchemy/orm/path_registry.py
@@ -1,5 +1,5 @@
# orm/path_registry.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py
index c3b2d7bcb..c5df63dfd 100644
--- a/lib/sqlalchemy/orm/persistence.py
+++ b/lib/sqlalchemy/orm/persistence.py
@@ -1,5 +1,5 @@
# orm/persistence.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 09a6cf45d..5694f7255 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -1,5 +1,5 @@
# orm/properties.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 5a150d615..05349cf0b 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -1,5 +1,5 @@
# orm/query.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -100,7 +100,8 @@ class Query(object):
_with_options = ()
_with_hints = ()
_enable_single_crit = True
-
+ _orm_only_adapt = True
+ _orm_only_from_obj_alias = True
_current_path = _path_registry
def __init__(self, entities, session=None):
@@ -231,7 +232,8 @@ class Query(object):
adapters = []
# do we adapt all expression elements or only those
# tagged as 'ORM' constructs ?
- orm_only = getattr(self, '_orm_only_adapt', orm_only)
+ if not self._orm_only_adapt:
+ orm_only = False
if as_filter and self._filter_aliases:
for fa in self._filter_aliases._visitor_iterator:
@@ -248,7 +250,7 @@ class Query(object):
# to all SQL constructs.
adapters.append(
(
- getattr(self, '_orm_only_from_obj_alias', orm_only),
+ orm_only if self._orm_only_from_obj_alias else False,
self._from_obj_alias.replace
)
)
@@ -305,7 +307,7 @@ class Query(object):
ezero = self._mapper_zero()
if ezero is not None:
insp = inspect(ezero)
- if hasattr(insp, 'mapper'):
+ if not insp.is_clause_element:
return insp.mapper
return None
@@ -2558,18 +2560,21 @@ class Query(object):
'type':User,
'aliased':False,
'expr':User,
+ 'entity': User
},
{
'name':'id',
'type':Integer(),
'aliased':False,
'expr':User.id,
+ 'entity': User
},
{
'name':'user2',
'type':User,
'aliased':True,
- 'expr':user_alias
+ 'expr':user_alias,
+ 'entity': user_alias
}
]
@@ -2579,7 +2584,10 @@ class Query(object):
'name': ent._label_name,
'type': ent.type,
'aliased': getattr(ent, 'is_aliased_class', False),
- 'expr': ent.expr
+ 'expr': ent.expr,
+ 'entity':
+ ent.entity_zero.entity if ent.entity_zero is not None
+ else None
}
for ent in self._entities
]
@@ -2934,6 +2942,12 @@ class Query(object):
return update_op.rowcount
def _compile_context(self, labels=True):
+ if self.dispatch.before_compile:
+ for fn in self.dispatch.before_compile:
+ new_query = fn(self)
+ if new_query is not None:
+ self = new_query
+
context = QueryContext(self)
if context.statement is not None:
@@ -2954,10 +2968,8 @@ class Query(object):
# "load from explicit FROMs" mode,
# i.e. when select_from() or join() is used
context.froms = list(context.from_clause)
- else:
- # "load from discrete FROMs" mode,
- # i.e. when each _MappedEntity has its own FROM
- context.froms = context.froms
+ # else "load from discrete FROMs" mode,
+ # i.e. when each _MappedEntity has its own FROM
if self._enable_single_crit:
self._adjust_for_single_inheritance(context)
@@ -2977,6 +2989,7 @@ class Query(object):
context.statement = self._compound_eager_statement(context)
else:
context.statement = self._simple_statement(context)
+
return context
def _compound_eager_statement(self, context):
@@ -3344,6 +3357,12 @@ class Bundle(InspectionAttr):
"""If True, queries for a single Bundle will be returned as a single
entity, rather than an element within a keyed tuple."""
+ is_clause_element = False
+
+ is_mapper = False
+
+ is_aliased_class = False
+
def __init__(self, name, *exprs, **kw):
"""Construct a new :class:`.Bundle`.
@@ -3591,18 +3610,18 @@ class _ColumnEntity(_QueryEntity):
if 'parententity' in elem._annotations
]
- self.entities = util.unique_list(
+ self.entities = util.unique_list([
elem._annotations['parententity']
for elem in all_elements
if 'parententity' in elem._annotations
- )
+ ])
- self._from_entities = set(
+ self._from_entities = set([
elem._annotations['parententity']
for elem in all_elements
if 'parententity' in elem._annotations
and actual_froms.intersection(elem._from_objects)
- )
+ ])
if self.entities:
self.entity_zero = self.entities[0]
@@ -3647,12 +3666,11 @@ class _ColumnEntity(_QueryEntity):
return not _is_aliased_class(self.entity_zero) and \
entity.common_parent(self.entity_zero)
- def _resolve_expr_against_query_aliases(self, query, expr, context):
- return query._adapt_clause(expr, False, True)
-
def row_processor(self, query, context, result):
- column = self._resolve_expr_against_query_aliases(
- query, self.column, context)
+ if ('fetch_column', self) in context.attributes:
+ column = context.attributes[('fetch_column', self)]
+ else:
+ column = query._adapt_clause(self.column, False, True)
if context.adapter:
column = context.adapter.columns[column]
@@ -3661,11 +3679,12 @@ class _ColumnEntity(_QueryEntity):
return getter, self._label_name
def setup_context(self, query, context):
- column = self._resolve_expr_against_query_aliases(
- query, self.column, context)
+ column = query._adapt_clause(self.column, False, True)
context.froms += tuple(self.froms)
context.primary_columns.append(column)
+ context.attributes[('fetch_column', self)] = column
+
def __str__(self):
return str(self.column)
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index c4b466cb1..e36a644da 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -1,5 +1,5 @@
# orm/relationships.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/scoping.py b/lib/sqlalchemy/orm/scoping.py
index 71648d126..b3f2fa5db 100644
--- a/lib/sqlalchemy/orm/scoping.py
+++ b/lib/sqlalchemy/orm/scoping.py
@@ -1,5 +1,5 @@
# orm/scoping.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 6dc6d3755..bc9444040 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -1,5 +1,5 @@
# orm/session.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -1830,7 +1830,7 @@ class Session(_SessionClassMethods):
"function to send this object back to the transient state." %
state_str(state)
)
- self._before_attach(state)
+ self._before_attach(state, check_identity_map=False)
self._deleted.pop(state, None)
if discard_existing:
self.identity_map.replace(state)
@@ -1910,13 +1910,12 @@ class Session(_SessionClassMethods):
self._attach(state, include_before=True)
state._load_pending = True
- def _before_attach(self, state):
+ def _before_attach(self, state, check_identity_map=True):
if state.session_id != self.hash_key and \
self.dispatch.before_attach:
self.dispatch.before_attach(self, state.obj())
- def _attach(self, state, include_before=False):
- if state.key and \
+ if check_identity_map and state.key and \
state.key in self.identity_map and \
not self.identity_map.contains_state(state):
raise sa_exc.InvalidRequestError(
@@ -1932,10 +1931,11 @@ class Session(_SessionClassMethods):
"(this is '%s')" % (state_str(state),
state.session_id, self.hash_key))
+ def _attach(self, state, include_before=False):
+
if state.session_id != self.hash_key:
- if include_before and \
- self.dispatch.before_attach:
- self.dispatch.before_attach(self, state.obj())
+ if include_before:
+ self._before_attach(state)
state.session_id = self.hash_key
if state.modified and state._strong_obj is None:
state._strong_obj = state.obj()
diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py
index 7691c9826..6034e74de 100644
--- a/lib/sqlalchemy/orm/state.py
+++ b/lib/sqlalchemy/orm/state.py
@@ -1,5 +1,5 @@
# orm/state.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index ea2ca6912..0b2672d66 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -1,5 +1,5 @@
# orm/strategies.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -1249,7 +1249,7 @@ class JoinedLoader(AbstractRelationshipLoader):
anonymize_labels=True)
assert clauses.aliased_class is not None
- if self.parent_property.direction != interfaces.MANYTOONE:
+ if self.parent_property.uselist:
context.multi_row_eager_loaders = True
innerjoin = (
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 90e4e9661..cb7a5fef7 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/sync.py b/lib/sqlalchemy/orm/sync.py
index 671c7c067..e9a745cc0 100644
--- a/lib/sqlalchemy/orm/sync.py
+++ b/lib/sqlalchemy/orm/sync.py
@@ -1,5 +1,5 @@
# orm/sync.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py
index 05265b13f..1ef0d24ca 100644
--- a/lib/sqlalchemy/orm/unitofwork.py
+++ b/lib/sqlalchemy/orm/unitofwork.py
@@ -1,5 +1,5 @@
# orm/unitofwork.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index ee629b034..9787b0fb4 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -1,5 +1,5 @@
# orm/util.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py
index 25db5d5ba..ccb4f1e6a 100644
--- a/lib/sqlalchemy/pool.py
+++ b/lib/sqlalchemy/pool.py
@@ -1,5 +1,5 @@
# sqlalchemy/pool.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/processors.py b/lib/sqlalchemy/processors.py
index 3794b01f5..6575fad17 100644
--- a/lib/sqlalchemy/processors.py
+++ b/lib/sqlalchemy/processors.py
@@ -1,5 +1,5 @@
# sqlalchemy/processors.py
-# Copyright (C) 2010-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2010-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
# Copyright (C) 2010 Gaetan de Menten gdementen@gmail.com
#
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py
index 285ae579f..327498fc5 100644
--- a/lib/sqlalchemy/schema.py
+++ b/lib/sqlalchemy/schema.py
@@ -1,5 +1,5 @@
# schema.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/__init__.py b/lib/sqlalchemy/sql/__init__.py
index 351e08d0b..e8b70061d 100644
--- a/lib/sqlalchemy/sql/__init__.py
+++ b/lib/sqlalchemy/sql/__init__.py
@@ -1,5 +1,5 @@
# sql/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/annotation.py b/lib/sqlalchemy/sql/annotation.py
index 3df4257d4..8fec5039b 100644
--- a/lib/sqlalchemy/sql/annotation.py
+++ b/lib/sqlalchemy/sql/annotation.py
@@ -1,5 +1,5 @@
# sql/annotation.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py
index 0f6405309..eed079238 100644
--- a/lib/sqlalchemy/sql/base.py
+++ b/lib/sqlalchemy/sql/base.py
@@ -1,5 +1,5 @@
# sql/base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index f8f4d1dda..8e709a474 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -1,5 +1,5 @@
# sql/compiler.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -23,6 +23,7 @@ To generate user-defined SQL strings, see
"""
+import contextlib
import re
from . import schema, sqltypes, operators, functions, visitors, \
elements, selectable, crud
@@ -361,7 +362,12 @@ class SQLCompiler(Compiled):
# column/label name, ColumnElement object (if any) and
# TypeEngine. ResultProxy uses this for type processing and
# column targeting
- self.result_map = {}
+ self._result_columns = []
+
+ # if False, means we can't be sure the list of entries
+ # in _result_columns is actually the rendered order. This
+ # gets flipped when we use TextAsFrom, for example.
+ self._ordered_columns = True
# true if the paramstyle is positional
self.positional = dialect.positional
@@ -402,6 +408,26 @@ class SQLCompiler(Compiled):
if self.positional:
self.cte_positional = {}
+ @contextlib.contextmanager
+ def _nested_result(self):
+ """special API to support the use case of 'nested result sets'"""
+ result_columns, ordered_columns = (
+ self._result_columns, self._ordered_columns)
+ self._result_columns, self._ordered_columns = [], False
+
+ try:
+ if self.stack:
+ entry = self.stack[-1]
+ entry['need_result_map_for_nested'] = True
+ else:
+ entry = None
+ yield self._result_columns, self._ordered_columns
+ finally:
+ if entry:
+ entry.pop('need_result_map_for_nested')
+ self._result_columns, self._ordered_columns = (
+ result_columns, ordered_columns)
+
def _apply_numbered_params(self):
poscount = itertools.count(1)
self.string = re.sub(
@@ -480,6 +506,11 @@ class SQLCompiler(Compiled):
compiled object, for those values that are present."""
return self.construct_params(_check=False)
+ @util.dependencies("sqlalchemy.engine.result")
+ def _create_result_map(self, result):
+ """utility method used for unit tests only."""
+ return result.ResultMetaData._create_result_map(self._result_columns)
+
def default_from(self):
"""Called when a SELECT statement has no froms, and no FROM clause is
to be appended.
@@ -662,22 +693,22 @@ class SQLCompiler(Compiled):
self.post_process_text(textclause.text))
)
- def visit_text_as_from(self, taf, iswrapper=False,
- compound_index=0, force_result_map=False,
+ def visit_text_as_from(self, taf,
+ compound_index=None,
asfrom=False,
parens=True, **kw):
toplevel = not self.stack
entry = self._default_stack_entry if toplevel else self.stack[-1]
- populate_result_map = force_result_map or (
- compound_index == 0 and (
- toplevel or
- entry['iswrapper']
- )
- )
+ populate_result_map = toplevel or \
+ (
+ compound_index == 0 and entry.get(
+ 'need_result_map_for_compound', False)
+ ) or entry.get('need_result_map_for_nested', False)
if populate_result_map:
+ self._ordered_columns = False
for c in taf.column_args:
self.process(c, within_columns_clause=True,
add_to_result_map=self._add_to_result_map)
@@ -790,13 +821,16 @@ class SQLCompiler(Compiled):
parens=True, compound_index=0, **kwargs):
toplevel = not self.stack
entry = self._default_stack_entry if toplevel else self.stack[-1]
+ need_result_map = toplevel or \
+ (compound_index == 0
+ and entry.get('need_result_map_for_compound', False))
self.stack.append(
{
'correlate_froms': entry['correlate_froms'],
- 'iswrapper': toplevel,
'asfrom_froms': entry['asfrom_froms'],
- 'selectable': cs
+ 'selectable': cs,
+ 'need_result_map_for_compound': need_result_map
})
keyword = self.compound_keywords.get(cs.keyword)
@@ -818,8 +852,7 @@ class SQLCompiler(Compiled):
or cs._offset_clause is not None) and \
self.limit_clause(cs, **kwargs) or ""
- if self.ctes and \
- compound_index == 0 and toplevel:
+ if self.ctes and toplevel:
text = self._render_cte_clause() + text
self.stack.pop(-1)
@@ -1241,15 +1274,7 @@ class SQLCompiler(Compiled):
if not self.dialect.case_sensitive:
keyname = keyname.lower()
- if keyname in self.result_map:
- # conflicting keyname, just double up the list
- # of objects. this will cause an "ambiguous name"
- # error if an attempt is made by the result set to
- # access.
- e_name, e_obj, e_type = self.result_map[keyname]
- self.result_map[keyname] = e_name, e_obj + objects, e_type
- else:
- self.result_map[keyname] = name, objects, type_
+ self._result_columns.append((keyname, name, objects, type_))
def _label_select_column(self, select, column,
populate_result_map,
@@ -1439,12 +1464,13 @@ class SQLCompiler(Compiled):
(inner_col[c._key_label], c)
for c in select.inner_columns
)
- for key, (name, objs, typ) in list(self.result_map.items()):
- objs = tuple([d.get(col, col) for col in objs])
- self.result_map[key] = (name, objs, typ)
+
+ self._result_columns = [
+ (key, name, tuple([d.get(col, col) for col in objs]), typ)
+ for key, name, objs, typ in self._result_columns
+ ]
_default_stack_entry = util.immutabledict([
- ('iswrapper', False),
('correlate_froms', frozenset()),
('asfrom_froms', frozenset())
])
@@ -1472,10 +1498,10 @@ class SQLCompiler(Compiled):
return froms
def visit_select(self, select, asfrom=False, parens=True,
- iswrapper=False, fromhints=None,
+ fromhints=None,
compound_index=0,
- force_result_map=False,
nested_join_translation=False,
+ select_wraps_for=None,
**kwargs):
needs_nested_translation = \
@@ -1489,21 +1515,19 @@ class SQLCompiler(Compiled):
select)
text = self.visit_select(
transformed_select, asfrom=asfrom, parens=parens,
- iswrapper=iswrapper, fromhints=fromhints,
+ fromhints=fromhints,
compound_index=compound_index,
- force_result_map=force_result_map,
nested_join_translation=True, **kwargs
)
toplevel = not self.stack
entry = self._default_stack_entry if toplevel else self.stack[-1]
- populate_result_map = force_result_map or (
- compound_index == 0 and (
- toplevel or
- entry['iswrapper']
- )
- )
+ populate_result_map = toplevel or \
+ (
+ compound_index == 0 and entry.get(
+ 'need_result_map_for_compound', False)
+ ) or entry.get('need_result_map_for_nested', False)
if needs_nested_translation:
if populate_result_map:
@@ -1511,7 +1535,7 @@ class SQLCompiler(Compiled):
select, transformed_select)
return text
- froms = self._setup_select_stack(select, entry, asfrom, iswrapper)
+ froms = self._setup_select_stack(select, entry, asfrom)
column_clause_args = kwargs.copy()
column_clause_args.update({
@@ -1537,16 +1561,34 @@ class SQLCompiler(Compiled):
# the actual list of columns to print in the SELECT column list.
inner_columns = [
c for c in [
- self._label_select_column(select,
- column,
- populate_result_map, asfrom,
- column_clause_args,
- name=name)
+ self._label_select_column(
+ select,
+ column,
+ populate_result_map, asfrom,
+ column_clause_args,
+ name=name)
for name, column in select._columns_plus_names
]
if c is not None
]
+ if populate_result_map and select_wraps_for is not None:
+ # if this select is a compiler-generated wrapper,
+ # rewrite the targeted columns in the result map
+ wrapped_inner_columns = set(select_wraps_for.inner_columns)
+ translate = dict(
+ (outer, inner.pop()) for outer, inner in [
+ (
+ outer,
+ outer.proxy_set.intersection(wrapped_inner_columns))
+ for outer in select.inner_columns
+ ] if inner
+ )
+ self._result_columns = [
+ (key, name, tuple(translate.get(o, o) for o in obj), type_)
+ for key, name, obj, type_ in self._result_columns
+ ]
+
text = self._compose_select_body(
text, select, inner_columns, froms, byfrom, kwargs)
@@ -1559,8 +1601,7 @@ class SQLCompiler(Compiled):
if per_dialect:
text += " " + self.get_statement_hint_text(per_dialect)
- if self.ctes and \
- compound_index == 0 and toplevel:
+ if self.ctes and toplevel:
text = self._render_cte_clause() + text
if select._suffixes:
@@ -1587,7 +1628,7 @@ class SQLCompiler(Compiled):
hint_text = self.get_select_hint_text(byfrom)
return hint_text, byfrom
- def _setup_select_stack(self, select, entry, asfrom, iswrapper):
+ def _setup_select_stack(self, select, entry, asfrom):
correlate_froms = entry['correlate_froms']
asfrom_froms = entry['asfrom_froms']
@@ -1606,7 +1647,6 @@ class SQLCompiler(Compiled):
new_entry = {
'asfrom_froms': new_correlate_froms,
- 'iswrapper': iswrapper,
'correlate_froms': all_correlate_froms,
'selectable': select,
}
@@ -1749,7 +1789,6 @@ class SQLCompiler(Compiled):
def visit_insert(self, insert_stmt, **kw):
self.stack.append(
{'correlate_froms': set(),
- "iswrapper": False,
"asfrom_froms": set(),
"selectable": insert_stmt})
@@ -1873,7 +1912,6 @@ class SQLCompiler(Compiled):
def visit_update(self, update_stmt, **kw):
self.stack.append(
{'correlate_froms': set([update_stmt.table]),
- "iswrapper": False,
"asfrom_froms": set([update_stmt.table]),
"selectable": update_stmt})
@@ -1959,7 +1997,6 @@ class SQLCompiler(Compiled):
def visit_delete(self, delete_stmt, **kw):
self.stack.append({'correlate_froms': set([delete_stmt.table]),
- "iswrapper": False,
"asfrom_froms": set([delete_stmt.table]),
"selectable": delete_stmt})
self.isdelete = True
diff --git a/lib/sqlalchemy/sql/crud.py b/lib/sqlalchemy/sql/crud.py
index 2961f579f..2e39f6b36 100644
--- a/lib/sqlalchemy/sql/crud.py
+++ b/lib/sqlalchemy/sql/crud.py
@@ -1,5 +1,5 @@
# sql/crud.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/ddl.py b/lib/sqlalchemy/sql/ddl.py
index 7a1c7fef6..3834f25f4 100644
--- a/lib/sqlalchemy/sql/ddl.py
+++ b/lib/sqlalchemy/sql/ddl.py
@@ -1,5 +1,5 @@
# sql/ddl.py
-# Copyright (C) 2009-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2009-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -723,7 +723,8 @@ class SchemaGenerator(DDLBase):
if table is not None:
self.traverse_single(
table, create_ok=True,
- include_foreign_key_constraints=fkcs)
+ include_foreign_key_constraints=fkcs,
+ _is_metadata_operation=True)
else:
for fkc in fkcs:
self.traverse_single(fkc)
@@ -735,13 +736,16 @@ class SchemaGenerator(DDLBase):
def visit_table(
self, table, create_ok=False,
- include_foreign_key_constraints=None):
+ include_foreign_key_constraints=None,
+ _is_metadata_operation=False):
if not create_ok and not self._can_create_table(table):
return
- table.dispatch.before_create(table, self.connection,
- checkfirst=self.checkfirst,
- _ddl_runner=self)
+ table.dispatch.before_create(
+ table, self.connection,
+ checkfirst=self.checkfirst,
+ _ddl_runner=self,
+ _is_metadata_operation=_is_metadata_operation)
for column in table.columns:
if column.default is not None:
@@ -761,9 +765,11 @@ class SchemaGenerator(DDLBase):
for index in table.indexes:
self.traverse_single(index)
- table.dispatch.after_create(table, self.connection,
- checkfirst=self.checkfirst,
- _ddl_runner=self)
+ table.dispatch.after_create(
+ table, self.connection,
+ checkfirst=self.checkfirst,
+ _ddl_runner=self,
+ _is_metadata_operation=_is_metadata_operation)
def visit_foreign_key_constraint(self, constraint):
if not self.dialect.supports_alter:
@@ -837,7 +843,7 @@ class SchemaDropper(DDLBase):
for table, fkcs in collection:
if table is not None:
self.traverse_single(
- table, drop_ok=True)
+ table, drop_ok=True, _is_metadata_operation=True)
else:
for fkc in fkcs:
self.traverse_single(fkc)
@@ -870,13 +876,15 @@ class SchemaDropper(DDLBase):
def visit_index(self, index):
self.connection.execute(DropIndex(index))
- def visit_table(self, table, drop_ok=False):
+ def visit_table(self, table, drop_ok=False, _is_metadata_operation=False):
if not drop_ok and not self._can_drop_table(table):
return
- table.dispatch.before_drop(table, self.connection,
- checkfirst=self.checkfirst,
- _ddl_runner=self)
+ table.dispatch.before_drop(
+ table, self.connection,
+ checkfirst=self.checkfirst,
+ _ddl_runner=self,
+ _is_metadata_operation=_is_metadata_operation)
for column in table.columns:
if column.default is not None:
@@ -884,9 +892,11 @@ class SchemaDropper(DDLBase):
self.connection.execute(DropTable(table))
- table.dispatch.after_drop(table, self.connection,
- checkfirst=self.checkfirst,
- _ddl_runner=self)
+ table.dispatch.after_drop(
+ table, self.connection,
+ checkfirst=self.checkfirst,
+ _ddl_runner=self,
+ _is_metadata_operation=_is_metadata_operation)
def visit_foreign_key_constraint(self, constraint):
if not self.dialect.supports_alter:
diff --git a/lib/sqlalchemy/sql/default_comparator.py b/lib/sqlalchemy/sql/default_comparator.py
index bb9e53aae..e77ad765c 100644
--- a/lib/sqlalchemy/sql/default_comparator.py
+++ b/lib/sqlalchemy/sql/default_comparator.py
@@ -1,5 +1,5 @@
# sql/default_comparator.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/dml.py b/lib/sqlalchemy/sql/dml.py
index 38b3b8c44..6a4768fa1 100644
--- a/lib/sqlalchemy/sql/dml.py
+++ b/lib/sqlalchemy/sql/dml.py
@@ -1,5 +1,5 @@
# sql/dml.py
-# Copyright (C) 2009-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2009-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index fa4f14fb9..7d64c2c4a 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -1,5 +1,5 @@
# sql/elements.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 2218bd660..74b827d7e 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -1,5 +1,5 @@
# sql/expression.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/functions.py b/lib/sqlalchemy/sql/functions.py
index 9280c7d60..538a2c549 100644
--- a/lib/sqlalchemy/sql/functions.py
+++ b/lib/sqlalchemy/sql/functions.py
@@ -1,5 +1,5 @@
# sql/functions.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py
index 6508ed620..bc13835ed 100644
--- a/lib/sqlalchemy/sql/naming.py
+++ b/lib/sqlalchemy/sql/naming.py
@@ -1,5 +1,5 @@
# sqlalchemy/naming.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py
index f71cba913..3549fa10c 100644
--- a/lib/sqlalchemy/sql/operators.py
+++ b/lib/sqlalchemy/sql/operators.py
@@ -1,5 +1,5 @@
# sql/operators.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index fa48a16cc..2120e303b 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -1,5 +1,5 @@
# sql/schema.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index 87029ec2b..6520f08fc 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -1,5 +1,5 @@
# sql/selectable.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -43,9 +43,10 @@ def _interpret_as_from(element):
{"expr": util.ellipses_string(element)})
return TextClause(util.text_type(element))
- elif hasattr(insp, "selectable"):
+ try:
return insp.selectable
- raise exc.ArgumentError("FROM expression expected")
+ except AttributeError:
+ raise exc.ArgumentError("FROM expression expected")
def _interpret_as_select(element):
@@ -2484,21 +2485,20 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect):
seen = set()
translate = self._from_cloned
- def add(items):
- for item in items:
- if item is self:
- raise exc.InvalidRequestError(
- "select() construct refers to itself as a FROM")
- if translate and item in translate:
- item = translate[item]
- if not seen.intersection(item._cloned_set):
- froms.append(item)
- seen.update(item._cloned_set)
-
- add(_from_objects(*self._raw_columns))
- if self._whereclause is not None:
- add(_from_objects(self._whereclause))
- add(self._from_obj)
+ for item in itertools.chain(
+ _from_objects(*self._raw_columns),
+ _from_objects(self._whereclause)
+ if self._whereclause is not None else (),
+ self._from_obj
+ ):
+ if item is self:
+ raise exc.InvalidRequestError(
+ "select() construct refers to itself as a FROM")
+ if translate and item in translate:
+ item = translate[item]
+ if not seen.intersection(item._cloned_set):
+ froms.append(item)
+ seen.update(item._cloned_set)
return froms
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index bd1914da3..7e2e601e2 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -1,5 +1,5 @@
# sql/sqltypes.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -938,7 +938,7 @@ class SchemaType(SchemaEventTarget):
"""
def __init__(self, name=None, schema=None, metadata=None,
- inherit_schema=False, quote=None):
+ inherit_schema=False, quote=None, _create_events=True):
if name is not None:
self.name = quoted_name(name, quote)
else:
@@ -946,8 +946,9 @@ class SchemaType(SchemaEventTarget):
self.schema = schema
self.metadata = metadata
self.inherit_schema = inherit_schema
+ self._create_events = _create_events
- if self.metadata:
+ if _create_events and self.metadata:
event.listen(
self.metadata,
"before_create",
@@ -966,6 +967,9 @@ class SchemaType(SchemaEventTarget):
if self.inherit_schema:
self.schema = table.schema
+ if not self._create_events:
+ return
+
event.listen(
table,
"before_create",
@@ -992,17 +996,18 @@ class SchemaType(SchemaEventTarget):
)
def copy(self, **kw):
- return self.adapt(self.__class__)
+ return self.adapt(self.__class__, _create_events=True)
def adapt(self, impltype, **kw):
schema = kw.pop('schema', self.schema)
+ metadata = kw.pop('metadata', self.metadata)
+ _create_events = kw.pop('_create_events', False)
- # don't associate with self.metadata as the hosting type
- # is already associated with it, avoid creating event
- # listeners
return impltype(name=self.name,
schema=schema,
inherit_schema=self.inherit_schema,
+ metadata=metadata,
+ _create_events=_create_events,
**kw)
@property
@@ -1170,7 +1175,8 @@ class Enum(String, SchemaType):
def adapt(self, impltype, **kw):
schema = kw.pop('schema', self.schema)
- metadata = kw.pop('metadata', None)
+ metadata = kw.pop('metadata', self.metadata)
+ _create_events = kw.pop('_create_events', False)
if issubclass(impltype, Enum):
return impltype(name=self.name,
schema=schema,
@@ -1178,9 +1184,11 @@ class Enum(String, SchemaType):
convert_unicode=self.convert_unicode,
native_enum=self.native_enum,
inherit_schema=self.inherit_schema,
+ _create_events=_create_events,
*self.enums,
**kw)
else:
+ # TODO: why would we be here?
return super(Enum, self).adapt(impltype, **kw)
@@ -1276,7 +1284,8 @@ class Boolean(TypeEngine, SchemaType):
__visit_name__ = 'boolean'
- def __init__(self, create_constraint=True, name=None):
+ def __init__(
+ self, create_constraint=True, name=None, _create_events=True):
"""Construct a Boolean.
:param create_constraint: defaults to True. If the boolean
@@ -1289,6 +1298,7 @@ class Boolean(TypeEngine, SchemaType):
"""
self.create_constraint = create_constraint
self.name = name
+ self._create_events = _create_events
def _should_create_constraint(self, compiler):
return not compiler.dialect.supports_native_boolean
diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py
index 19398ae96..4660850bd 100644
--- a/lib/sqlalchemy/sql/type_api.py
+++ b/lib/sqlalchemy/sql/type_api.py
@@ -1,5 +1,5 @@
# sql/types_api.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index fbbe15da3..bec5b5824 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -1,5 +1,5 @@
# sql/util.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py
index d09b82148..0540ac5d3 100644
--- a/lib/sqlalchemy/sql/visitors.py
+++ b/lib/sqlalchemy/sql/visitors.py
@@ -1,5 +1,5 @@
# sql/visitors.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -213,12 +213,19 @@ def iterate(obj, opts):
traversal is configured to be breadth-first.
"""
+ # fasttrack for atomic elements like columns
+ children = obj.get_children(**opts)
+ if not children:
+ return [obj]
+
+ traversal = deque()
stack = deque([obj])
while stack:
t = stack.popleft()
- yield t
+ traversal.append(t)
for c in t.get_children(**opts):
stack.append(c)
+ return iter(traversal)
def iterate_depthfirst(obj, opts):
@@ -227,6 +234,11 @@ def iterate_depthfirst(obj, opts):
traversal is configured to be depth-first.
"""
+ # fasttrack for atomic elements like columns
+ children = obj.get_children(**opts)
+ if not children:
+ return [obj]
+
stack = deque([obj])
traversal = deque()
while stack:
diff --git a/lib/sqlalchemy/testing/__init__.py b/lib/sqlalchemy/testing/__init__.py
index 2375a13a9..bf83e9673 100644
--- a/lib/sqlalchemy/testing/__init__.py
+++ b/lib/sqlalchemy/testing/__init__.py
@@ -1,5 +1,5 @@
# testing/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/assertions.py b/lib/sqlalchemy/testing/assertions.py
index 91d0c6339..e5249c296 100644
--- a/lib/sqlalchemy/testing/assertions.py
+++ b/lib/sqlalchemy/testing/assertions.py
@@ -1,5 +1,5 @@
# testing/assertions.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/assertsql.py b/lib/sqlalchemy/testing/assertsql.py
index 5c746e8f1..a596d9743 100644
--- a/lib/sqlalchemy/testing/assertsql.py
+++ b/lib/sqlalchemy/testing/assertsql.py
@@ -1,5 +1,5 @@
# testing/assertsql.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/config.py b/lib/sqlalchemy/testing/config.py
index 6832eab74..d429c9f4e 100644
--- a/lib/sqlalchemy/testing/config.py
+++ b/lib/sqlalchemy/testing/config.py
@@ -1,5 +1,5 @@
# testing/config.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/engines.py b/lib/sqlalchemy/testing/engines.py
index 444a79b70..3a8303546 100644
--- a/lib/sqlalchemy/testing/engines.py
+++ b/lib/sqlalchemy/testing/engines.py
@@ -1,5 +1,5 @@
# testing/engines.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/entities.py b/lib/sqlalchemy/testing/entities.py
index 3e42955e6..65178ea5b 100644
--- a/lib/sqlalchemy/testing/entities.py
+++ b/lib/sqlalchemy/testing/entities.py
@@ -1,5 +1,5 @@
# testing/entities.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/exclusions.py b/lib/sqlalchemy/testing/exclusions.py
index 0aff43ae1..6aa4bf142 100644
--- a/lib/sqlalchemy/testing/exclusions.py
+++ b/lib/sqlalchemy/testing/exclusions.py
@@ -1,5 +1,5 @@
# testing/exclusions.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/fixtures.py b/lib/sqlalchemy/testing/fixtures.py
index 48d4d9c9b..7b421952f 100644
--- a/lib/sqlalchemy/testing/fixtures.py
+++ b/lib/sqlalchemy/testing/fixtures.py
@@ -1,5 +1,5 @@
# testing/fixtures.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/mock.py b/lib/sqlalchemy/testing/mock.py
index c6a4d4360..be83693cc 100644
--- a/lib/sqlalchemy/testing/mock.py
+++ b/lib/sqlalchemy/testing/mock.py
@@ -1,5 +1,5 @@
# testing/mock.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/pickleable.py b/lib/sqlalchemy/testing/pickleable.py
index 5a903aae7..7b696ad67 100644
--- a/lib/sqlalchemy/testing/pickleable.py
+++ b/lib/sqlalchemy/testing/pickleable.py
@@ -1,5 +1,5 @@
# testing/pickleable.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/plugin/noseplugin.py b/lib/sqlalchemy/testing/plugin/noseplugin.py
index 538087770..1ae6e28f5 100644
--- a/lib/sqlalchemy/testing/plugin/noseplugin.py
+++ b/lib/sqlalchemy/testing/plugin/noseplugin.py
@@ -1,5 +1,5 @@
# plugin/noseplugin.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/plugin/plugin_base.py b/lib/sqlalchemy/testing/plugin/plugin_base.py
index b0188aa5a..14cf1eb31 100644
--- a/lib/sqlalchemy/testing/plugin/plugin_base.py
+++ b/lib/sqlalchemy/testing/plugin/plugin_base.py
@@ -1,5 +1,5 @@
# plugin/plugin_base.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/profiling.py b/lib/sqlalchemy/testing/profiling.py
index 57308925e..65fe165cd 100644
--- a/lib/sqlalchemy/testing/profiling.py
+++ b/lib/sqlalchemy/testing/profiling.py
@@ -1,5 +1,5 @@
# testing/profiling.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py
index 5744431cb..32465c47d 100644
--- a/lib/sqlalchemy/testing/requirements.py
+++ b/lib/sqlalchemy/testing/requirements.py
@@ -1,5 +1,5 @@
# testing/requirements.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/runner.py b/lib/sqlalchemy/testing/runner.py
index 23d7a0a91..92a03061e 100644
--- a/lib/sqlalchemy/testing/runner.py
+++ b/lib/sqlalchemy/testing/runner.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# testing/runner.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/schema.py b/lib/sqlalchemy/testing/schema.py
index 9561b1f1e..93b52ad58 100644
--- a/lib/sqlalchemy/testing/schema.py
+++ b/lib/sqlalchemy/testing/schema.py
@@ -1,5 +1,5 @@
# testing/schema.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/util.py b/lib/sqlalchemy/testing/util.py
index 8230f923a..6d6fa094e 100644
--- a/lib/sqlalchemy/testing/util.py
+++ b/lib/sqlalchemy/testing/util.py
@@ -1,5 +1,5 @@
# testing/util.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/testing/warnings.py b/lib/sqlalchemy/testing/warnings.py
index 640f02a78..19b632d34 100644
--- a/lib/sqlalchemy/testing/warnings.py
+++ b/lib/sqlalchemy/testing/warnings.py
@@ -1,5 +1,5 @@
# testing/warnings.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py
index 1215bd790..9ab92e90b 100644
--- a/lib/sqlalchemy/types.py
+++ b/lib/sqlalchemy/types.py
@@ -1,5 +1,5 @@
# types.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py
index ceee18d86..d777d2e06 100644
--- a/lib/sqlalchemy/util/__init__.py
+++ b/lib/sqlalchemy/util/__init__.py
@@ -1,5 +1,5 @@
# util/__init__.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py
index a49848d08..4fb12d71b 100644
--- a/lib/sqlalchemy/util/_collections.py
+++ b/lib/sqlalchemy/util/_collections.py
@@ -1,5 +1,5 @@
# util/_collections.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -127,20 +127,6 @@ class _LW(AbstractKeyedTuple):
return d
-def lightweight_named_tuple(name, fields):
-
- tp_cls = type(name, (_LW,), {})
- for idx, field in enumerate(fields):
- if field is None:
- continue
- setattr(tp_cls, field, property(operator.itemgetter(idx)))
-
- tp_cls._real_fields = fields
- tp_cls._fields = tuple([f for f in fields if f is not None])
-
- return tp_cls
-
-
class ImmutableContainer(object):
def _immutable(self, *arg, **kw):
raise TypeError("%s object is immutable" % self.__class__.__name__)
@@ -372,7 +358,10 @@ class OrderedSet(set):
set.__init__(self)
self._list = []
if d is not None:
- self.update(d)
+ self._list = unique_list(d)
+ set.update(self, self._list)
+ else:
+ self._list = []
def add(self, element):
if element not in self:
@@ -747,6 +736,12 @@ ordered_column_set = OrderedSet
populate_column_dict = PopulateDict
+_getters = PopulateDict(operator.itemgetter)
+
+_property_getters = PopulateDict(
+ lambda idx: property(operator.itemgetter(idx)))
+
+
def unique_list(seq, hashfunc=None):
seen = {}
if not hashfunc:
@@ -849,17 +844,30 @@ class LRUCache(dict):
"""Dictionary with 'squishy' removal of least
recently used items.
+ Note that either get() or [] should be used here, but
+ generally its not safe to do an "in" check first as the dictionary
+ can change subsequent to that call.
+
"""
def __init__(self, capacity=100, threshold=.5):
self.capacity = capacity
self.threshold = threshold
self._counter = 0
+ self._mutex = threading.Lock()
def _inc_counter(self):
self._counter += 1
return self._counter
+ def get(self, key, default=None):
+ item = dict.get(self, key, default)
+ if item is not default:
+ item[2] = self._inc_counter()
+ return item[1]
+ else:
+ return default
+
def __getitem__(self, key):
item = dict.__getitem__(self, key)
item[2] = self._inc_counter()
@@ -885,18 +893,45 @@ class LRUCache(dict):
self._manage_size()
def _manage_size(self):
- while len(self) > self.capacity + self.capacity * self.threshold:
- by_counter = sorted(dict.values(self),
- key=operator.itemgetter(2),
- reverse=True)
- for item in by_counter[self.capacity:]:
- try:
- del self[item[0]]
- except KeyError:
- # if we couldn't find a key, most
- # likely some other thread broke in
- # on us. loop around and try again
- break
+ if not self._mutex.acquire(False):
+ return
+ try:
+ while len(self) > self.capacity + self.capacity * self.threshold:
+ by_counter = sorted(dict.values(self),
+ key=operator.itemgetter(2),
+ reverse=True)
+ for item in by_counter[self.capacity:]:
+ try:
+ del self[item[0]]
+ except KeyError:
+ # deleted elsewhere; skip
+ continue
+ finally:
+ self._mutex.release()
+
+
+_lw_tuples = LRUCache(100)
+
+
+def lightweight_named_tuple(name, fields):
+ hash_ = (name, ) + tuple(fields)
+ tp_cls = _lw_tuples.get(hash_)
+ if tp_cls:
+ return tp_cls
+
+ tp_cls = type(
+ name, (_LW,),
+ dict([
+ (field, _property_getters[idx])
+ for idx, field in enumerate(fields) if field is not None
+ ] + [('__slots__', ())])
+ )
+
+ tp_cls._real_fields = fields
+ tp_cls._fields = tuple([f for f in fields if f is not None])
+
+ _lw_tuples[hash_] = tp_cls
+ return tp_cls
class ScopedRegistry(object):
diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py
index 972fda667..5b6f691f1 100644
--- a/lib/sqlalchemy/util/compat.py
+++ b/lib/sqlalchemy/util/compat.py
@@ -1,5 +1,5 @@
# util/compat.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/util/deprecations.py b/lib/sqlalchemy/util/deprecations.py
index 124f304fc..4c7ea47e3 100644
--- a/lib/sqlalchemy/util/deprecations.py
+++ b/lib/sqlalchemy/util/deprecations.py
@@ -1,5 +1,5 @@
# util/deprecations.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py
index 5a938501a..6c52e41f8 100644
--- a/lib/sqlalchemy/util/langhelpers.py
+++ b/lib/sqlalchemy/util/langhelpers.py
@@ -1,5 +1,5 @@
# util/langhelpers.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/util/queue.py b/lib/sqlalchemy/util/queue.py
index 796c6a33e..29e00a434 100644
--- a/lib/sqlalchemy/util/queue.py
+++ b/lib/sqlalchemy/util/queue.py
@@ -1,5 +1,5 @@
# util/queue.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
diff --git a/lib/sqlalchemy/util/topological.py b/lib/sqlalchemy/util/topological.py
index 2bfcccc63..80735c4df 100644
--- a/lib/sqlalchemy/util/topological.py
+++ b/lib/sqlalchemy/util/topological.py
@@ -1,5 +1,5 @@
# util/topological.py
-# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under