summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py24
-rw-r--r--lib/sqlalchemy/dialects/mssql/information_schema.py6
-rw-r--r--lib/sqlalchemy/dialects/mysql/oursql.py2
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py47
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2.py16
-rw-r--r--lib/sqlalchemy/engine/__init__.py7
-rw-r--r--lib/sqlalchemy/engine/base.py42
-rw-r--r--lib/sqlalchemy/engine/default.py9
-rw-r--r--lib/sqlalchemy/engine/interfaces.py30
-rw-r--r--lib/sqlalchemy/engine/reflection.py20
-rw-r--r--lib/sqlalchemy/engine/result.py1
-rw-r--r--lib/sqlalchemy/engine/strategies.py3
-rw-r--r--lib/sqlalchemy/engine/threadlocal.py19
-rw-r--r--lib/sqlalchemy/event/base.py4
-rw-r--r--lib/sqlalchemy/event/registry.py6
-rw-r--r--lib/sqlalchemy/events.py13
-rw-r--r--lib/sqlalchemy/ext/horizontal_shard.py2
-rw-r--r--lib/sqlalchemy/interfaces.py48
-rw-r--r--lib/sqlalchemy/orm/attributes.py39
-rw-r--r--lib/sqlalchemy/orm/collections.py2
-rw-r--r--lib/sqlalchemy/orm/deprecated_interfaces.py28
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py26
-rw-r--r--lib/sqlalchemy/orm/mapper.py34
-rw-r--r--lib/sqlalchemy/orm/properties.py16
-rw-r--r--lib/sqlalchemy/orm/query.py12
-rw-r--r--lib/sqlalchemy/orm/relationships.py16
-rw-r--r--lib/sqlalchemy/orm/session.py87
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py45
-rw-r--r--lib/sqlalchemy/pool/base.py64
-rw-r--r--lib/sqlalchemy/pool/dbapi_proxy.py7
-rw-r--r--lib/sqlalchemy/pool/impl.py1
-rw-r--r--lib/sqlalchemy/sql/compiler.py58
-rw-r--r--lib/sqlalchemy/sql/ddl.py16
-rw-r--r--lib/sqlalchemy/sql/elements.py94
-rw-r--r--lib/sqlalchemy/sql/schema.py78
-rw-r--r--lib/sqlalchemy/sql/selectable.py60
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py131
-rw-r--r--lib/sqlalchemy/testing/engines.py3
-rw-r--r--lib/sqlalchemy/testing/suite/test_reflection.py14
-rw-r--r--lib/sqlalchemy/testing/suite/test_results.py2
-rw-r--r--lib/sqlalchemy/testing/suite/test_types.py10
-rw-r--r--lib/sqlalchemy/util/__init__.py2
-rw-r--r--lib/sqlalchemy/util/compat.py13
-rw-r--r--lib/sqlalchemy/util/deprecations.py153
44 files changed, 842 insertions, 468 deletions
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index d0f02bb23..5c446341c 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -2377,12 +2377,8 @@ class MSDialect(default.DefaultDialect):
"and ind.is_primary_key=0 and ind.type != 0"
)
.bindparams(
- sql.bindparam(
- "tabname", tablename, sqltypes.String(convert_unicode=True)
- ),
- sql.bindparam(
- "schname", owner, sqltypes.String(convert_unicode=True)
- ),
+ sql.bindparam("tabname", tablename, sqltypes.String()),
+ sql.bindparam("schname", owner, sqltypes.String()),
)
.columns(name=sqltypes.Unicode())
)
@@ -2406,12 +2402,8 @@ class MSDialect(default.DefaultDialect):
"and sch.name=:schname"
)
.bindparams(
- sql.bindparam(
- "tabname", tablename, sqltypes.String(convert_unicode=True)
- ),
- sql.bindparam(
- "schname", owner, sqltypes.String(convert_unicode=True)
- ),
+ sql.bindparam("tabname", tablename, sqltypes.String()),
+ sql.bindparam("schname", owner, sqltypes.String()),
)
.columns(name=sqltypes.Unicode())
)
@@ -2436,12 +2428,8 @@ class MSDialect(default.DefaultDialect):
"views.schema_id=sch.schema_id and "
"views.name=:viewname and sch.name=:schname"
).bindparams(
- sql.bindparam(
- "viewname", viewname, sqltypes.String(convert_unicode=True)
- ),
- sql.bindparam(
- "schname", owner, sqltypes.String(convert_unicode=True)
- ),
+ sql.bindparam("viewname", viewname, sqltypes.String()),
+ sql.bindparam("schname", owner, sqltypes.String()),
)
)
diff --git a/lib/sqlalchemy/dialects/mssql/information_schema.py b/lib/sqlalchemy/dialects/mssql/information_schema.py
index 88628e6a7..b72dbfe93 100644
--- a/lib/sqlalchemy/dialects/mssql/information_schema.py
+++ b/lib/sqlalchemy/dialects/mssql/information_schema.py
@@ -69,7 +69,7 @@ tables = Table(
Column("TABLE_CATALOG", CoerceUnicode, key="table_catalog"),
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
- Column("TABLE_TYPE", String(convert_unicode=True), key="table_type"),
+ Column("TABLE_TYPE", CoerceUnicode, key="table_type"),
schema="INFORMATION_SCHEMA",
)
@@ -98,9 +98,7 @@ constraints = Table(
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
- Column(
- "CONSTRAINT_TYPE", String(convert_unicode=True), key="constraint_type"
- ),
+ Column("CONSTRAINT_TYPE", CoerceUnicode, key="constraint_type"),
schema="INFORMATION_SCHEMA",
)
diff --git a/lib/sqlalchemy/dialects/mysql/oursql.py b/lib/sqlalchemy/dialects/mysql/oursql.py
index 165a8f4e2..80313a2fc 100644
--- a/lib/sqlalchemy/dialects/mysql/oursql.py
+++ b/lib/sqlalchemy/dialects/mysql/oursql.py
@@ -175,7 +175,7 @@ class MySQLDialect_oursql(MySQLDialect):
):
return MySQLDialect._show_create_table(
self,
- connection.contextual_connect(
+ connection._contextual_connect(
close_with_result=True
).execution_options(_oursql_plain_query=True),
table,
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index 1164c09f7..abeef39d2 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -736,6 +736,17 @@ class OracleDialect_cx_oracle(OracleDialect):
_cx_oracle_threaded = None
+ @util.deprecated_params(
+ threaded=(
+ "1.3",
+ "The 'threaded' parameter to the cx_oracle dialect "
+ "is deprecated as a dialect-level argument, and will be removed "
+ "in a future release. As of version 1.3, it defaults to False "
+ "rather than True. The 'threaded' option can be passed to "
+ "cx_Oracle directly in the URL query string passed to "
+ ":func:`.create_engine`.",
+ )
+ )
def __init__(
self,
auto_convert_lobs=True,
@@ -749,13 +760,6 @@ class OracleDialect_cx_oracle(OracleDialect):
OracleDialect.__init__(self, **kwargs)
self.arraysize = arraysize
if threaded is not None:
- util.warn_deprecated(
- "The 'threaded' parameter to the cx_oracle dialect "
- "itself is deprecated. The value now defaults to False in "
- "any case. To pass an explicit True value, use the "
- "create_engine connect_args dictionary or add ?threaded=true "
- "to the URL string."
- )
self._cx_oracle_threaded = threaded
self.auto_convert_lobs = auto_convert_lobs
self.coerce_to_unicode = coerce_to_unicode
@@ -811,23 +815,6 @@ class OracleDialect_cx_oracle(OracleDialect):
self._is_cx_oracle_6 = self.cx_oracle_ver >= (6,)
- def _pop_deprecated_kwargs(self, kwargs):
- auto_setinputsizes = kwargs.pop("auto_setinputsizes", None)
- exclude_setinputsizes = kwargs.pop("exclude_setinputsizes", None)
- if auto_setinputsizes or exclude_setinputsizes:
- util.warn_deprecated(
- "auto_setinputsizes and exclude_setinputsizes are deprecated. "
- "Modern cx_Oracle only requires that LOB types are part "
- "of this behavior, and these parameters no longer have any "
- "effect."
- )
- allow_twophase = kwargs.pop("allow_twophase", None)
- if allow_twophase is not None:
- util.warn.deprecated(
- "allow_twophase is deprecated. The cx_Oracle dialect no "
- "longer supports two-phase transaction mode."
- )
-
def _parse_cx_oracle_ver(self, version):
m = re.match(r"(\d+)\.(\d+)(?:\.(\d+))?", version)
if m:
@@ -982,6 +969,7 @@ class OracleDialect_cx_oracle(OracleDialect):
def create_connect_args(self, url):
opts = dict(url.query)
+ # deprecated in 1.3
for opt in ("use_ansi", "auto_convert_lobs"):
if opt in opts:
util.warn_deprecated(
@@ -1067,15 +1055,20 @@ class OracleDialect_cx_oracle(OracleDialect):
else:
return False
+ @util.deprecated(
+ "1.2",
+ "The create_xid() method of the cx_Oracle dialect is deprecated and "
+ "will be removed in a future release. "
+ "Two-phase transaction support is no longer functional "
+ "in SQLAlchemy's cx_Oracle dialect as of cx_Oracle 6.0b1, which no "
+ "longer supports the API that SQLAlchemy relied upon.",
+ )
def create_xid(self):
"""create a two-phase transaction ID.
this id will be passed to do_begin_twophase(), do_rollback_twophase(),
do_commit_twophase(). its format is unspecified.
- .. deprecated:: two-phase transaction support is no longer functional
- in SQLAlchemy's cx_Oracle dialect as of cx_Oracle 6.0b1
-
"""
id_ = random.randint(0, 2 ** 128)
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index 98e703fb5..8a15a8559 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -407,11 +407,17 @@ class _PGNumeric(sqltypes.Numeric):
class _PGEnum(ENUM):
def result_processor(self, dialect, coltype):
- if util.py2k and self.convert_unicode is True:
- # we can't easily use PG's extensions here because
- # the OID is on the fly, and we need to give it a python
- # function anyway - not really worth it.
- self.convert_unicode = "force_nocheck"
+ if util.py2k and self._expect_unicode is True:
+ # for py2k, if the enum type needs unicode data (which is set up as
+ # part of the Enum() constructor based on values passed as py2k
+ # unicode objects) we have to use our own converters since
+ # psycopg2's don't work, a rare exception to the "modern DBAPIs
+ # support unicode everywhere" theme of deprecating
+ # convert_unicode=True. Use the special "force_nocheck" directive
+ # which forces unicode conversion to happen on the Python side
+ # without an isinstance() check. in py3k psycopg2 does the right
+ # thing automatically.
+ self._expect_unicode = "force_nocheck"
return super(_PGEnum, self).result_processor(dialect, coltype)
diff --git a/lib/sqlalchemy/engine/__init__.py b/lib/sqlalchemy/engine/__init__.py
index 5f77d17a1..fbf346cec 100644
--- a/lib/sqlalchemy/engine/__init__.py
+++ b/lib/sqlalchemy/engine/__init__.py
@@ -147,6 +147,13 @@ def create_engine(*args, **kwargs):
columns to accommodate Python Unicode objects directly as though the
datatype were the :class:`.Unicode` type.
+ .. deprecated:: The :paramref:`.create_engine.convert_unicode` flag
+ and related Unicode conversion features are legacy Python 2
+ mechanisms which no longer have relevance under Python 3.
+ As all modern DBAPIs now support Python Unicode fully even
+ under Python 2, these flags will be removed in an upcoming
+ release.
+
.. note::
SQLAlchemy's unicode-conversion flags and features only apply
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index ebf8dd28a..64303f290 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -493,19 +493,7 @@ class Connection(Connectable):
return self._branch()
- def contextual_connect(self, **kwargs):
- """Returns a branched version of this :class:`.Connection`.
-
- The :meth:`.Connection.close` method on the returned
- :class:`.Connection` can be called and this
- :class:`.Connection` will remain open.
-
- This method provides usage symmetry with
- :meth:`.Engine.contextual_connect`, including for usage
- with context managers.
-
- """
-
+ def _contextual_connect(self, **kwargs):
return self._branch()
def invalidate(self, exception=None):
@@ -1993,13 +1981,13 @@ class Engine(Connectable, log.Identified):
self.dispatch.engine_disposed(self)
def _execute_default(self, default):
- with self.contextual_connect() as conn:
+ with self._contextual_connect() as conn:
return conn._execute_default(default, (), {})
@contextlib.contextmanager
def _optional_conn_ctx_manager(self, connection=None):
if connection is None:
- with self.contextual_connect() as conn:
+ with self._contextual_connect() as conn:
yield conn
else:
yield connection
@@ -2058,7 +2046,7 @@ class Engine(Connectable, log.Identified):
for a particular :class:`.Connection`.
"""
- conn = self.contextual_connect(close_with_result=close_with_result)
+ conn = self._contextual_connect(close_with_result=close_with_result)
try:
trans = conn.begin()
except:
@@ -2105,7 +2093,7 @@ class Engine(Connectable, log.Identified):
"""
- with self.contextual_connect() as conn:
+ with self._contextual_connect() as conn:
return conn.transaction(callable_, *args, **kwargs)
def run_callable(self, callable_, *args, **kwargs):
@@ -2121,7 +2109,7 @@ class Engine(Connectable, log.Identified):
which one is being dealt with.
"""
- with self.contextual_connect() as conn:
+ with self._contextual_connect() as conn:
return conn.run_callable(callable_, *args, **kwargs)
def execute(self, statement, *multiparams, **params):
@@ -2140,18 +2128,18 @@ class Engine(Connectable, log.Identified):
"""
- connection = self.contextual_connect(close_with_result=True)
+ connection = self._contextual_connect(close_with_result=True)
return connection.execute(statement, *multiparams, **params)
def scalar(self, statement, *multiparams, **params):
return self.execute(statement, *multiparams, **params).scalar()
def _execute_clauseelement(self, elem, multiparams=None, params=None):
- connection = self.contextual_connect(close_with_result=True)
+ connection = self._contextual_connect(close_with_result=True)
return connection._execute_clauseelement(elem, multiparams, params)
def _execute_compiled(self, compiled, multiparams, params):
- connection = self.contextual_connect(close_with_result=True)
+ connection = self._contextual_connect(close_with_result=True)
return connection._execute_compiled(compiled, multiparams, params)
def connect(self, **kwargs):
@@ -2170,6 +2158,13 @@ class Engine(Connectable, log.Identified):
return self._connection_cls(self, **kwargs)
+ @util.deprecated(
+ "1.3",
+ "The :meth:`.Engine.contextual_connect` method is deprecated. This "
+ "method is an artifact of the threadlocal engine strategy which is "
+ "also to be deprecated. For explicit connections from an "
+ ":class:`.Engine`, use the :meth:`.Engine.connect` method.",
+ )
def contextual_connect(self, close_with_result=False, **kwargs):
"""Return a :class:`.Connection` object which may be part of some
ongoing context.
@@ -2187,6 +2182,11 @@ class Engine(Connectable, log.Identified):
"""
+ return self._contextual_connect(
+ close_with_result=close_with_result, **kwargs
+ )
+
+ def _contextual_connect(self, close_with_result=False, **kwargs):
return self._connection_cls(
self,
self._wrap_pool_connect(self.pool.connect, None),
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 9c8069ff1..e54e99b75 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -184,6 +184,15 @@ class DefaultDialect(interfaces.Dialect):
"""
+ @util.deprecated_params(
+ convert_unicode=(
+ "1.3",
+ "The :paramref:`.create_engine.convert_unicode` parameter "
+ "and corresponding dialect-level parameters are deprecated, "
+ "and will be removed in a future release. Modern DBAPIs support "
+ "Python Unicode natively and this parameter is unnecessary.",
+ )
+ )
def __init__(
self,
convert_unicode=False,
diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py
index d4cd55b2f..d579e6fdb 100644
--- a/lib/sqlalchemy/engine/interfaces.py
+++ b/lib/sqlalchemy/engine/interfaces.py
@@ -251,15 +251,15 @@ class Dialect(object):
raise NotImplementedError()
+ @util.deprecated(
+ "0.8",
+ "The :meth:`.Dialect.get_primary_keys` method is deprecated and "
+ "will be removed in a future release. Please refer to the "
+ ":meth:`.Dialect.get_pk_constraint` method. ",
+ )
def get_primary_keys(self, connection, table_name, schema=None, **kw):
"""Return information about primary keys in `table_name`.
- .. deprecated:: 0.8
-
- The :meth:`.Dialect.get_primary_keys` method is deprecated and
- will be removed in a future release. Please refer to the
- :meth:`.Dialect.get_pk_constraint` method.
-
"""
raise NotImplementedError()
@@ -1117,7 +1117,15 @@ class Connectable(object):
"""
- def contextual_connect(self):
+ @util.deprecated(
+ "1.3",
+ "The :meth:`.Engine.contextual_connect` and "
+ ":meth:`.Connection.contextual_connect` methods are deprecated. This "
+ "method is an artifact of the threadlocal engine strategy which is "
+ "also to be deprecated. For explicit connections from an "
+ ":class:`.Engine`, use the :meth:`.Engine.connect` method.",
+ )
+ def contextual_connect(self, *arg, **kw):
"""Return a :class:`.Connection` object which may be part of an ongoing
context.
@@ -1128,6 +1136,9 @@ class Connectable(object):
"""
+ return self._contextual_connect(*arg, **kw)
+
+ def _contextual_connect(self):
raise NotImplementedError()
@util.deprecated(
@@ -1136,7 +1147,7 @@ class Connectable(object):
"removed in a future release. Please use the ``.create()`` method "
"on specific schema objects to emit DDL sequences, including "
":meth:`.Table.create`, :meth:`.Index.create`, and "
- ":meth:`.MetaData.create_all`."
+ ":meth:`.MetaData.create_all`.",
)
def create(self, entity, **kwargs):
"""Emit CREATE statements for the given schema entity.
@@ -1150,7 +1161,8 @@ class Connectable(object):
"removed in a future release. Please use the ``.drop()`` method "
"on specific schema objects to emit DDL sequences, including "
":meth:`.Table.drop`, :meth:`.Index.drop`, and "
- ":meth:`.MetaData.drop_all`.")
+ ":meth:`.MetaData.drop_all`.",
+ )
def drop(self, entity, **kwargs):
"""Emit DROP statements for the given schema entity.
"""
diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py
index 4e4ddab6d..14d647b9a 100644
--- a/lib/sqlalchemy/engine/reflection.py
+++ b/lib/sqlalchemy/engine/reflection.py
@@ -160,6 +160,16 @@ class Inspector(object):
)
return []
+ @util.deprecated_params(
+ order_by=(
+ "1.0",
+ "The :paramref:`get_table_names.order_by` parameter is deprecated "
+ "and will be removed in a future release. Please refer to "
+ ":meth:`.Inspector.get_sorted_table_and_fkc_names` for a "
+ "more comprehensive solution to resolving foreign key cycles "
+ "between tables.",
+ )
+ )
def get_table_names(self, schema=None, order_by=None):
"""Return all table names in referred to within a particular schema.
@@ -179,14 +189,6 @@ class Inspector(object):
resolve cycles, and will raise :class:`.CircularDependencyError`
if cycles exist.
- .. deprecated:: 1.0
-
- The :paramref:`get_table_names.order_by` parameter is deprecated
- and will be removed in a future release. Please refer to
- :meth:`.Inspector.get_sorted_table_and_fkc_names` for a
- more comprehensive solution to resolving foreign key cycles
- between tables.
-
.. seealso::
:meth:`.Inspector.get_sorted_table_and_fkc_names`
@@ -380,7 +382,7 @@ class Inspector(object):
"0.7",
"The :meth:`.Inspector.get_primary_keys` method is deprecated and "
"will be removed in a future release. Please refer to the "
- ":meth:`.Inspector.get_pk_constraint` method."
+ ":meth:`.Inspector.get_pk_constraint` method.",
)
def get_primary_keys(self, table_name, schema=None, **kw):
"""Return information about primary keys in `table_name`.
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index 55310d8b0..9255343e1 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -512,7 +512,6 @@ class ResultMetaData(object):
"smaller than number of columns requested (%d)"
% (num_ctx_cols, len(cursor_description))
)
-
seen = set()
for (
idx,
diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py
index 2ae48acbd..e367ef890 100644
--- a/lib/sqlalchemy/engine/strategies.py
+++ b/lib/sqlalchemy/engine/strategies.py
@@ -271,6 +271,9 @@ class MockEngineStrategy(EngineStrategy):
def contextual_connect(self, **kwargs):
return self
+ def connect(self, **kwargs):
+ return self
+
def execution_options(self, **kw):
return self
diff --git a/lib/sqlalchemy/engine/threadlocal.py b/lib/sqlalchemy/engine/threadlocal.py
index 01d6ecbb2..8e8663ccc 100644
--- a/lib/sqlalchemy/engine/threadlocal.py
+++ b/lib/sqlalchemy/engine/threadlocal.py
@@ -46,11 +46,22 @@ class TLEngine(base.Engine):
_tl_connection_cls = TLConnection
+ @util.deprecated(
+ "1.3",
+ "The 'threadlocal' engine strategy is deprecated, and will be "
+ "removed in a future release. The strategy is no longer relevant "
+ "to modern usage patterns (including that of the ORM "
+ ":class:`.Session` object) which make use of a :class:`.Connection` "
+ "object in order to invoke statements.",
+ )
def __init__(self, *args, **kwargs):
super(TLEngine, self).__init__(*args, **kwargs)
self._connections = util.threading.local()
def contextual_connect(self, **kw):
+ return self._contextual_connect(**kw)
+
+ def _contextual_connect(self, **kw):
if not hasattr(self._connections, "conn"):
connection = None
else:
@@ -72,7 +83,7 @@ class TLEngine(base.Engine):
if not hasattr(self._connections, "trans"):
self._connections.trans = []
self._connections.trans.append(
- self.contextual_connect().begin_twophase(xid=xid)
+ self._contextual_connect().begin_twophase(xid=xid)
)
return self
@@ -80,14 +91,14 @@ class TLEngine(base.Engine):
if not hasattr(self._connections, "trans"):
self._connections.trans = []
self._connections.trans.append(
- self.contextual_connect().begin_nested()
+ self._contextual_connect().begin_nested()
)
return self
def begin(self):
if not hasattr(self._connections, "trans"):
self._connections.trans = []
- self._connections.trans.append(self.contextual_connect().begin())
+ self._connections.trans.append(self._contextual_connect().begin())
return self
def __enter__(self):
@@ -139,7 +150,7 @@ class TLEngine(base.Engine):
def close(self):
if not self.closed:
- self.contextual_connect().close()
+ self._contextual_connect().close()
connection = self._connections.conn()
connection._force_close()
del self._connections.conn
diff --git a/lib/sqlalchemy/event/base.py b/lib/sqlalchemy/event/base.py
index aa5de7af0..9364714ab 100644
--- a/lib/sqlalchemy/event/base.py
+++ b/lib/sqlalchemy/event/base.py
@@ -275,6 +275,10 @@ class _JoinedDispatcher(object):
def _listen(self):
return self.parent._listen
+ @property
+ def _events(self):
+ return self.parent._events
+
class dispatcher(object):
"""Descriptor used by target classes to
diff --git a/lib/sqlalchemy/event/registry.py b/lib/sqlalchemy/event/registry.py
index 382e640eb..07b961c01 100644
--- a/lib/sqlalchemy/event/registry.py
+++ b/lib/sqlalchemy/event/registry.py
@@ -206,6 +206,12 @@ class _EventKey(object):
self = self.with_wrapper(adjusted_fn)
+ stub_function = getattr(
+ self.dispatch_target.dispatch._events, self.identifier
+ )
+ if hasattr(stub_function, "_sa_warn"):
+ stub_function._sa_warn()
+
if once:
self.with_wrapper(util.only_once(self._listen_fn)).listen(
*args, **kw
diff --git a/lib/sqlalchemy/events.py b/lib/sqlalchemy/events.py
index 5eb84a156..11d3402c5 100644
--- a/lib/sqlalchemy/events.py
+++ b/lib/sqlalchemy/events.py
@@ -9,6 +9,7 @@
from . import event
from . import exc
+from . import util
from .engine import Connectable
from .engine import Dialect
from .engine import Engine
@@ -749,6 +750,13 @@ class ConnectionEvents(event.Events):
"""
+ @util.deprecated(
+ "0.9",
+ "The :meth:`.ConnectionEvents.dbapi_error` "
+ "event is deprecated and will be removed in a future release. "
+ "Please refer to the :meth:`.ConnectionEvents.handle_error` "
+ "event.",
+ )
def dbapi_error(
self, conn, cursor, statement, parameters, context, exception
):
@@ -792,11 +800,6 @@ class ConnectionEvents(event.Events):
:param exception: The **unwrapped** exception emitted directly from the
DBAPI. The class here is specific to the DBAPI module in use.
- .. deprecated:: 0.9 - The :meth:`.ConnectionEvents.dbapi_error`
- event is deprecated and will be removed in a future release.
- Please refer to the :meth:`.ConnectionEvents.handle_error`
- event.
-
"""
def handle_error(self, exception_context):
diff --git a/lib/sqlalchemy/ext/horizontal_shard.py b/lib/sqlalchemy/ext/horizontal_shard.py
index 0628415ae..c263b1734 100644
--- a/lib/sqlalchemy/ext/horizontal_shard.py
+++ b/lib/sqlalchemy/ext/horizontal_shard.py
@@ -242,7 +242,7 @@ class ShardedSession(Session):
else:
return self.get_bind(
mapper, shard_id=shard_id, instance=instance
- ).contextual_connect(**kwargs)
+ )._contextual_connect(**kwargs)
def get_bind(
self, mapper, shard_id=None, instance=None, clause=None, **kw
diff --git a/lib/sqlalchemy/interfaces.py b/lib/sqlalchemy/interfaces.py
index 0caf85a23..374199143 100644
--- a/lib/sqlalchemy/interfaces.py
+++ b/lib/sqlalchemy/interfaces.py
@@ -86,10 +86,23 @@ class PoolListener(object):
"""
- listener = util.as_interface(
- listener,
- methods=("connect", "first_connect", "checkout", "checkin"),
- )
+ methods = ["connect", "first_connect", "checkout", "checkin"]
+ listener = util.as_interface(listener, methods=methods)
+
+ for meth in methods:
+ me_meth = getattr(PoolListener, meth)
+ ls_meth = getattr(listener, meth, None)
+
+ if ls_meth is not None and not util.methods_equivalent(
+ me_meth, ls_meth
+ ):
+ util.warn_deprecated(
+ "PoolListener.%s is deprecated. The "
+ "PoolListener class will be removed in a future "
+ "release. Please transition to the @event interface, "
+ "using @event.listens_for(Engine, '%s')." % (meth, meth)
+ )
+
if hasattr(listener, "connect"):
event.listen(self, "connect", listener.connect)
if hasattr(listener, "first_connect"):
@@ -195,6 +208,33 @@ class ConnectionProxy(object):
@classmethod
def _adapt_listener(cls, self, listener):
+
+ methods = [
+ "execute",
+ "cursor_execute",
+ "begin",
+ "rollback",
+ "commit",
+ "savepoint",
+ "rollback_savepoint",
+ "release_savepoint",
+ "begin_twophase",
+ "prepare_twophase",
+ "rollback_twophase",
+ "commit_twophase",
+ ]
+ for meth in methods:
+ me_meth = getattr(ConnectionProxy, meth)
+ ls_meth = getattr(listener, meth)
+
+ if not util.methods_equivalent(me_meth, ls_meth):
+ util.warn_deprecated(
+ "ConnectionProxy.%s is deprecated. The "
+ "ConnectionProxy class will be removed in a future "
+ "release. Please transition to the @event interface, "
+ "using @event.listens_for(Engine, '%s')." % (meth, meth)
+ )
+
def adapt_execute(conn, clauseelement, multiparams, params):
def execute_wrapper(clauseelement, *multiparams, **params):
return clauseelement, multiparams, params
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index c7c242501..cd81d759d 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -452,50 +452,57 @@ class AttributeImpl(object):
):
r"""Construct an AttributeImpl.
- \class_
- associated class
+ :param \class_: associated class
- key
- string name of the attribute
+ :param key: string name of the attribute
- \callable_
+ :param \callable_:
optional function which generates a callable based on a parent
instance, which produces the "default" values for a scalar or
collection attribute when it's first accessed, if not present
already.
- trackparent
+ :param trackparent:
if True, attempt to track if an instance has a parent attached
to it via this attribute.
- extension
+ :param extension:
a single or list of AttributeExtension object(s) which will
- receive set/delete/append/remove/etc. events. Deprecated.
+ receive set/delete/append/remove/etc. events.
The event package is now used.
- compare_function
+ .. deprecated:: 1.3
+
+ The :paramref:`.AttributeImpl.extension` parameter is deprecated
+ and will be removed in a future release, corresponding to the
+ "extension" parameter on the :class:`.MapperProprty` classes
+ like :func:`.column_property` and :func:`.relationship` The
+ events system is now used.
+
+ :param compare_function:
a function that compares two values which are normally
assignable to this attribute.
- active_history
+ :param active_history:
indicates that get_history() should always return the "old" value,
even if it means executing a lazy callable upon attribute change.
- parent_token
+ :param parent_token:
Usually references the MapperProperty, used as a key for
the hasparent() function to identify an "owning" attribute.
Allows multiple AttributeImpls to all match a single
owner attribute.
- expire_missing
+ :param expire_missing:
if False, don't add an "expiry" callable to this attribute
during state.expire_attributes(None), if no value is present
for this key.
- send_modified_events
+ :param send_modified_events:
if False, the InstanceState._modified_event method will have no
effect; this means the attribute will never show up as changed in a
history entry.
+
"""
self.class_ = class_
self.key = key
@@ -1841,9 +1848,9 @@ def init_collection(obj, key):
For an easier way to do the above, see
:func:`~sqlalchemy.orm.attributes.set_committed_value`.
- obj is an instrumented object instance. An InstanceState
- is accepted directly for backwards compatibility but
- this usage is deprecated.
+ :param obj: a mapped object
+
+ :param key: string attribute name where the collection is located.
"""
state = instance_state(obj)
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
index 1e561369f..b9297e15c 100644
--- a/lib/sqlalchemy/orm/collections.py
+++ b/lib/sqlalchemy/orm/collections.py
@@ -460,7 +460,7 @@ class collection(object):
@staticmethod
@util.deprecated(
"1.3",
- "The :meth:`.collection.converter` method is deprecated and will "
+ "The :meth:`.collection.converter` handler is deprecated and will "
"be removed in a future release. Please refer to the "
":class:`.AttributeEvents.bulk_replace` listener interface in "
"conjunction with the :func:`.event.listen` function.",
diff --git a/lib/sqlalchemy/orm/deprecated_interfaces.py b/lib/sqlalchemy/orm/deprecated_interfaces.py
index 50ef8448a..4069b43a5 100644
--- a/lib/sqlalchemy/orm/deprecated_interfaces.py
+++ b/lib/sqlalchemy/orm/deprecated_interfaces.py
@@ -87,6 +87,14 @@ class MapperExtension(object):
ls_meth = getattr(listener, meth)
if not util.methods_equivalent(me_meth, ls_meth):
+ util.warn_deprecated(
+ "MapperExtension.%s is deprecated. The "
+ "MapperExtension class will be removed in a future "
+ "release. Please transition to the @event interface, "
+ "using @event.listens_for(mapped_class, '%s')."
+ % (meth, meth)
+ )
+
if meth == "reconstruct_instance":
def go(ls_meth):
@@ -359,6 +367,13 @@ class SessionExtension(object):
ls_meth = getattr(listener, meth)
if not util.methods_equivalent(me_meth, ls_meth):
+ util.warn_deprecated(
+ "SessionExtension.%s is deprecated. The "
+ "SessionExtension class will be removed in a future "
+ "release. Please transition to the @event interface, "
+ "using @event.listens_for(Session, '%s')." % (meth, meth)
+ )
+
event.listen(self, meth, getattr(listener, meth))
def before_commit(self, session):
@@ -492,6 +507,19 @@ class AttributeExtension(object):
@classmethod
def _adapt_listener(cls, self, listener):
+ for meth in ["append", "remove", "set"]:
+ me_meth = getattr(AttributeExtension, meth)
+ ls_meth = getattr(listener, meth)
+
+ if not util.methods_equivalent(me_meth, ls_meth):
+ util.warn_deprecated(
+ "AttributeExtension.%s is deprecated. The "
+ "AttributeExtension class will be removed in a future "
+ "release. Please transition to the @event interface, "
+ "using @event.listens_for(Class.attribute, '%s')."
+ % (meth, meth)
+ )
+
event.listen(
self,
"append",
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index 45600928f..c1e5866b5 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -93,6 +93,15 @@ class CompositeProperty(DescriptorProperty):
"""
+ @util.deprecated_params(
+ extension=(
+ "0.7",
+ ":class:`.AttributeExtension` is deprecated in favor of the "
+ ":class:`.AttributeEvents` listener interface. The "
+ ":paramref:`.composite.extension` parameter will be "
+ "removed in a future release.",
+ )
+ )
def __init__(self, class_, *attrs, **kwargs):
r"""Return a composite column-based property for use with a Mapper.
@@ -141,13 +150,6 @@ class CompositeProperty(DescriptorProperty):
attribute listeners for the resulting descriptor placed on the
class.
- .. deprecated:: 0.7
-
- :class:`.AttributeExtension` is deprecated in favor of the
- :class:`.AttributeEvents` listener interface. The
- :paramref:`.composite.extension` parameter will be
- removed in a future release.
-
"""
super(CompositeProperty, self).__init__()
@@ -698,6 +700,12 @@ class SynonymProperty(DescriptorProperty):
@util.langhelpers.dependency_for("sqlalchemy.orm.properties", add_to_all=True)
+@util.deprecated_cls(
+ "0.7",
+ ":func:`.comparable_property` is deprecated and will be removed in a "
+ "future release. Please refer to the :mod:`~sqlalchemy.ext.hybrid` "
+ "extension.",
+)
class ComparableProperty(DescriptorProperty):
"""Instruments a Python property for use in query expressions."""
@@ -707,10 +715,6 @@ class ComparableProperty(DescriptorProperty):
"""Provides a method of applying a :class:`.PropComparator`
to any Python descriptor attribute.
- .. deprecated:: 0.7
- :func:`.comparable_property` is superseded by
- the :mod:`~sqlalchemy.ext.hybrid` extension. See the example
- at :ref:`hybrid_custom_comparators`.
Allows any Python descriptor to behave like a SQL-enabled
attribute when used at the class level in queries, allowing
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index a394ec06e..0c8ab0b10 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -104,6 +104,22 @@ class Mapper(InspectionAttr):
_new_mappers = False
_dispose_called = False
+ @util.deprecated_params(
+ extension=(
+ "0.7",
+ ":class:`.MapperExtension` is deprecated in favor of the "
+ ":class:`.MapperEvents` listener interface. The "
+ ":paramref:`.mapper.extension` parameter will be "
+ "removed in a future release.",
+ ),
+ order_by=(
+ "1.1",
+ "The :paramref:`.Mapper.order_by` parameter "
+ "is deprecated, and will be removed in a future release. "
+ "Use :meth:`.Query.order_by` to determine the ordering of a "
+ "result set.",
+ ),
+ )
def __init__(
self,
class_,
@@ -272,13 +288,6 @@ class Mapper(InspectionAttr):
list of :class:`.MapperExtension` instances which will be applied
to all operations by this :class:`.Mapper`.
- .. deprecated:: 0.7
-
- :class:`.MapperExtension` is deprecated in favor of the
- :class:`.MapperEvents` listener interface. The
- :paramref:`.mapper.extension` parameter will be
- removed in a future release.
-
:param include_properties: An inclusive list or set of string column
names to map.
@@ -339,11 +348,6 @@ class Mapper(InspectionAttr):
ordering for entities. By default mappers have no pre-defined
ordering.
- .. deprecated:: 1.1 The :paramref:`.Mapper.order_by` parameter
- is deprecated, and will be removed in a future release.
- Use :meth:`.Query.order_by` to determine the ordering of a
- result set.
-
:param passive_deletes: Indicates DELETE behavior of foreign key
columns when a joined-table inheritance entity is being deleted.
Defaults to ``False`` for a base mapper; for an inheriting mapper,
@@ -604,12 +608,6 @@ class Mapper(InspectionAttr):
if order_by is not False:
self.order_by = util.to_list(order_by)
- util.warn_deprecated(
- "Mapper.order_by is deprecated."
- "Use Query.order_by() in order to affect the ordering of ORM "
- "result sets."
- )
-
else:
self.order_by = order_by
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 328c9b1b4..530eadb6b 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -55,6 +55,15 @@ class ColumnProperty(StrategizedProperty):
"_deferred_column_loader",
)
+ @util.deprecated_params(
+ extension=(
+ "0.7",
+ ":class:`.AttributeExtension` is deprecated in favor of the "
+ ":class:`.AttributeEvents` listener interface. The "
+ ":paramref:`.column_property.extension` parameter will be "
+ "removed in a future release.",
+ )
+ )
def __init__(self, *columns, **kwargs):
r"""Provide a column-level property for use with a Mapper.
@@ -120,13 +129,6 @@ class ColumnProperty(StrategizedProperty):
which will be prepended to the list of attribute listeners for the
resulting descriptor placed on the class.
- .. deprecated:: 0.7
-
- :class:`.AttributeExtension` is deprecated in favor of the
- :class:`.AttributeEvents` listener interface. The
- :paramref:`.column_property.extension` parameter will be
- removed in a future release.
-
"""
super(ColumnProperty, self).__init__()
self._orig_columns = [expression._labeled(c) for c in columns]
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 387a72d0b..150347995 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -1569,16 +1569,16 @@ class Query(object):
self._execution_options = self._execution_options.union(kwargs)
@_generative()
+ @util.deprecated(
+ "0.9",
+ "The :meth:`.Query.with_lockmode` method is deprecated and will "
+ "be removed in a future release. Please refer to "
+ ":meth:`.Query.with_for_update`. ",
+ )
def with_lockmode(self, mode):
"""Return a new :class:`.Query` object with the specified "locking mode",
which essentially refers to the ``FOR UPDATE`` clause.
- .. deprecated:: 0.9
-
- The :meth:`.Query.with_lockmode` method is deprecated and will
- be removed in a future release. Please refer to
- :meth:`.Query.with_for_update`.
-
:param mode: a string representing the desired locking mode.
Valid values are:
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index af4d9a782..be2093fb9 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -105,6 +105,15 @@ class RelationshipProperty(StrategizedProperty):
_dependency_processor = None
+ @util.deprecated_params(
+ extension=(
+ "0.7",
+ ":class:`.AttributeExtension` is deprecated in favor of the "
+ ":class:`.AttributeEvents` listener interface. The "
+ ":paramref:`.relationship.extension` parameter will be "
+ "removed in a future release.",
+ )
+ )
def __init__(
self,
argument,
@@ -402,13 +411,6 @@ class RelationshipProperty(StrategizedProperty):
which will be prepended to the list of attribute listeners for
the resulting descriptor placed on the class.
- .. deprecated:: 0.7
-
- :class:`.AttributeExtension` is deprecated in favor of the
- :class:`.AttributeEvents` listener interface. The
- :paramref:`.relationship.extension` parameter will be
- removed in a future release.
-
:param foreign_keys:
a list of columns which are to be used as "foreign key"
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 5993e91b8..53f99b99d 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -427,7 +427,7 @@ class SessionTransaction(object):
"given Connection's Engine"
)
else:
- conn = bind.contextual_connect()
+ conn = bind._contextual_connect()
if execution_options:
conn = conn.execution_options(**execution_options)
@@ -642,6 +642,30 @@ class Session(_SessionClassMethods):
"scalar",
)
+ @util.deprecated_params(
+ weak_identity_map=(
+ "1.0",
+ "The :paramref:`.Session.weak_identity_map` parameter as well as "
+ "the strong-referencing identity map are deprecated, and will be "
+ "removed in a future release. For the use case where objects "
+ "present in a :class:`.Session` need to be automatically strong "
+ "referenced, see the recipe at "
+ ":ref:`session_referencing_behavior` for an event-based approach "
+ "to maintaining strong identity references. ",
+ ),
+ _enable_transaction_accounting=(
+ "0.7",
+ "The :paramref:`.Session._enable_transaction_accounting` "
+ "parameter is deprecated and will be removed in a future release.",
+ ),
+ extension=(
+ "0.7",
+ ":class:`.SessionExtension` is deprecated in favor of the "
+ ":class:`.SessionEvents` listener interface. The "
+ ":paramref:`.Session.extension` parameter will be "
+ "removed in a future release.",
+ ),
+ )
def __init__(
self,
bind=None,
@@ -650,12 +674,12 @@ class Session(_SessionClassMethods):
_enable_transaction_accounting=True,
autocommit=False,
twophase=False,
- weak_identity_map=True,
+ weak_identity_map=None,
binds=None,
extension=None,
enable_baked_queries=True,
info=None,
- query_cls=query.Query,
+ query_cls=None,
):
r"""Construct a new Session.
@@ -754,15 +778,10 @@ class Session(_SessionClassMethods):
.. versionadded:: 1.2
- :param _enable_transaction_accounting: Defaults to ``True``. A
+ :param _enable_transaction_accounting: A
legacy-only flag which when ``False`` disables *all* 0.5-style
object accounting on transaction boundaries.
- .. deprecated:: 0.7
-
- the :paramref:`.Session._enable_transaction_accounting`
- parameter will be removed in a future release.
-
:param expire_on_commit: Defaults to ``True``. When ``True``, all
instances will be fully expired after each :meth:`~.commit`,
so that all attribute/object access subsequent to a completed
@@ -773,13 +792,6 @@ class Session(_SessionClassMethods):
of such instances, which will receive pre- and post- commit and
flush events, as well as a post-rollback event.
- .. deprecated:: 0.7
-
- :class:`.SessionExtension` is deprecated in favor of the
- :class:`.SessionEvents` listener interface. The
- :paramref:`.Session.extension` parameter will be
- removed in a future release.
-
:param info: optional dictionary of arbitrary data to be associated
with this :class:`.Session`. Is available via the
:attr:`.Session.info` attribute. Note the dictionary is copied at
@@ -807,30 +819,14 @@ class Session(_SessionClassMethods):
strongly referenced until explicitly removed or the
:class:`.Session` is closed.
- .. deprecated:: 1.0
-
- The :paramref:`.Session.weak_identity_map` parameter as well as
- the strong-referencing identity map are deprecated, and will be
- removed in a future release. For the use case where objects
- present in a :class:`.Session` need to be automatically strong
- referenced, see the recipe at
- :ref:`session_referencing_behavior` for an event-based approach
- to maintaining strong identity references.
-
"""
- if weak_identity_map:
+ if weak_identity_map in (True, None):
self._identity_cls = identity.WeakInstanceDict
else:
- util.warn_deprecated(
- "weak_identity_map=False is deprecated. "
- "See the documentation on 'Session Referencing Behavior' "
- "for an event-based approach to maintaining strong identity "
- "references."
- )
-
self._identity_cls = identity.StrongInstanceDict
+
self.identity_map = self._identity_cls()
self._new = {} # InstanceState->object, strong refs object
@@ -846,8 +842,9 @@ class Session(_SessionClassMethods):
self.expire_on_commit = expire_on_commit
self.enable_baked_queries = enable_baked_queries
self._enable_transaction_accounting = _enable_transaction_accounting
+
self.twophase = twophase
- self._query_cls = query_cls
+ self._query_cls = query_cls if query_cls else query.Query
if info:
self.info.update(info)
@@ -1068,7 +1065,7 @@ class Session(_SessionClassMethods):
Alternatively, if this :class:`.Session` is configured with
``autocommit=True``, an ad-hoc :class:`.Connection` is returned
- using :meth:`.Engine.contextual_connect` on the underlying
+ using :meth:`.Engine.connect` on the underlying
:class:`.Engine`.
Ambiguity in multi-bind or unbound :class:`.Session` objects can be
@@ -1132,7 +1129,7 @@ class Session(_SessionClassMethods):
engine, execution_options
)
else:
- conn = engine.contextual_connect(**kw)
+ conn = engine._contextual_connect(**kw)
if execution_options:
conn = conn.execution_options(**execution_options)
return conn
@@ -2872,7 +2869,15 @@ class Session(_SessionClassMethods):
finally:
self._flushing = False
- def is_modified(self, instance, include_collections=True, passive=True):
+ @util.deprecated_params(
+ passive=(
+ "0.8",
+ "The :paramref:`.Session.is_modified.passive` flag is deprecated "
+ "and will be removed in a future release. The flag is no longer "
+ "used and is ignored.",
+ )
+ )
+ def is_modified(self, instance, include_collections=True, passive=None):
r"""Return ``True`` if the given instance has locally
modified attributes.
@@ -2921,11 +2926,7 @@ class Session(_SessionClassMethods):
way to detect only local-column based properties (i.e. scalar columns
or many-to-one foreign keys) that would result in an UPDATE for this
instance upon flush.
- :param passive:
-
- .. deprecated:: 0.8
- The ``passive`` flag is deprecated and will be removed
- in a future release. The flag is no longer used and is ignored.
+ :param passive: not used
"""
state = object_state(instance)
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index b3f52a2f7..6f9746daa 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -818,7 +818,6 @@ See :func:`.orm.%(name)s` for usage examples.
return self
def _add_unbound_all_fn(self, fn):
- self._unbound_all_fn = fn
fn.__doc__ = """Produce a standalone "all" option for :func:`.orm.%(name)s`.
.. deprecated:: 0.9
@@ -834,6 +833,15 @@ See :func:`.orm.%(name)s` for usage examples.
""" % {
"name": self.name
}
+ fn = util.deprecated(
+ "0.9",
+ "The :func:`.%(name)s_all` function is deprecated, and will be "
+ "removed in a future release. Please use method chaining with "
+ ":func:`.%(name)s` instead" % {"name": self.name},
+ add_deprecation_to_docstring=False,
+ )(fn)
+
+ self._unbound_all_fn = fn
return self
@@ -1307,8 +1315,8 @@ def defaultload(*keys):
@loader_option()
def defer(loadopt, key):
- r"""Indicate that the given column-oriented attribute should be deferred, e.g.
- not loaded until accessed.
+ r"""Indicate that the given column-oriented attribute should be deferred,
+ e.g. not loaded until accessed.
This function is part of the :class:`.Load` interface and supports
both method-chained and standalone operation.
@@ -1346,10 +1354,16 @@ def defer(loadopt, key):
:param key: Attribute to be deferred.
- :param \*addl_attrs: Deprecated; this option supports the old 0.8 style
+ :param \*addl_attrs: This option supports the old 0.8 style
of specifying a path as a series of attributes, which is now superseded
by the method-chained style.
+ .. deprecated:: 0.9 The \*addl_attrs on :func:`.orm.defer` is
+ deprecated and will be removed in a future release. Please
+ use method chaining in conjunction with defaultload() to
+ indicate a path.
+
+
.. seealso::
:ref:`deferred`
@@ -1364,6 +1378,12 @@ def defer(loadopt, key):
@defer._add_unbound_fn
def defer(key, *addl_attrs):
+ if addl_attrs:
+ util.warn_deprecated(
+ "The *addl_attrs on orm.defer is deprecated. Please use "
+ "method chaining in conjunction with defaultload() to "
+ "indicate a path."
+ )
return _UnboundLoad._from_keys(
_UnboundLoad.defer, (key,) + addl_attrs, False, {}
)
@@ -1389,12 +1409,21 @@ def undefer(loadopt, key):
session.query(MyClass, MyOtherClass).options(
Load(MyClass).undefer("*"))
+ # undefer a column on a related object
+ session.query(MyClass).options(
+ defaultload(MyClass.items).undefer('text'))
+
:param key: Attribute to be undeferred.
- :param \*addl_attrs: Deprecated; this option supports the old 0.8 style
+ :param \*addl_attrs: This option supports the old 0.8 style
of specifying a path as a series of attributes, which is now superseded
by the method-chained style.
+ .. deprecated:: 0.9 The \*addl_attrs on :func:`.orm.undefer` is
+ deprecated and will be removed in a future release. Please
+ use method chaining in conjunction with defaultload() to
+ indicate a path.
+
.. seealso::
:ref:`deferred`
@@ -1411,6 +1440,12 @@ def undefer(loadopt, key):
@undefer._add_unbound_fn
def undefer(key, *addl_attrs):
+ if addl_attrs:
+ util.warn_deprecated(
+ "The *addl_attrs on orm.undefer is deprecated. Please use "
+ "method chaining in conjunction with defaultload() to "
+ "indicate a path."
+ )
return _UnboundLoad._from_keys(
_UnboundLoad.undefer, (key,) + addl_attrs, False, {}
)
diff --git a/lib/sqlalchemy/pool/base.py b/lib/sqlalchemy/pool/base.py
index 15ac49561..40d97515e 100644
--- a/lib/sqlalchemy/pool/base.py
+++ b/lib/sqlalchemy/pool/base.py
@@ -60,6 +60,20 @@ class Pool(log.Identified):
_dialect = _ConnDialect()
+ @util.deprecated_params(
+ use_threadlocal=(
+ "1.3",
+ "The :paramref:`.Pool.use_threadlocal` parameter is "
+ "deprecated and will be removed in a future release.",
+ ),
+ listeners=(
+ "0.7",
+ ":class:`.PoolListener` is deprecated in favor of the "
+ ":class:`.PoolEvents` listener interface. The "
+ ":paramref:`.Pool.listeners` parameter will be removed in a "
+ "future release.",
+ ),
+ )
def __init__(
self,
creator,
@@ -99,35 +113,9 @@ class Pool(log.Identified):
:param use_threadlocal: If set to True, repeated calls to
:meth:`connect` within the same application thread will be
- guaranteed to return the same connection object, if one has
- already been retrieved from the pool and has not been
- returned yet. Offers a slight performance advantage at the
- cost of individual transactions by default. The
- :meth:`.Pool.unique_connection` method is provided to return
- a consistently unique connection to bypass this behavior
- when the flag is set.
-
- .. warning:: The :paramref:`.Pool.use_threadlocal` flag
- **does not affect the behavior** of :meth:`.Engine.connect`.
- :meth:`.Engine.connect` makes use of the
- :meth:`.Pool.unique_connection` method which **does not use thread
- local context**. To produce a :class:`.Connection` which refers
- to the :meth:`.Pool.connect` method, use
- :meth:`.Engine.contextual_connect`.
-
- Note that other SQLAlchemy connectivity systems such as
- :meth:`.Engine.execute` as well as the orm
- :class:`.Session` make use of
- :meth:`.Engine.contextual_connect` internally, so these functions
- are compatible with the :paramref:`.Pool.use_threadlocal` setting.
-
- .. seealso::
-
- :ref:`threadlocal_strategy` - contains detail on the
- "threadlocal" engine strategy, which provides a more comprehensive
- approach to "threadlocal" connectivity for the specific
- use case of using :class:`.Engine` and :class:`.Connection` objects
- directly.
+ guaranteed to return the same connection object that is already
+ checked out. This is a legacy use case and the flag has no
+ effect when using the pool with a :class:`.Engine` object.
:param reset_on_return: Determine steps to take on
connections as they are returned to the pool.
@@ -175,13 +163,6 @@ class Pool(log.Identified):
connections are created, checked out and checked in to the
pool.
- .. deprecated:: 0.7
-
- :class:`.PoolListener` is deprecated in favor of the
- :class:`.PoolEvents` listener interface. The
- :paramref:`.Pool.listeners` parameter will be removed in a
- future release.
-
:param dialect: a :class:`.Dialect` that will handle the job
of calling rollback(), close(), or commit() on DBAPI connections.
If omitted, a built-in "stub" dialect is used. Applications that
@@ -235,12 +216,6 @@ class Pool(log.Identified):
for fn, target in events:
event.listen(self, target, fn)
if listeners:
- util.warn_deprecated(
- "The 'listeners' argument to Pool and create_engine() is "
- "deprecated and will be removed in a future release. "
- "Please refer to the PoolEvents class in conjunction "
- "with event.listen()"
- )
for l in listeners:
self.add_listener(l)
@@ -290,9 +265,10 @@ class Pool(log.Identified):
)
@util.deprecated(
- "0.7", "The :meth:`.Pool.add_listener` method is deprecated and "
+ "0.7",
+ "The :meth:`.Pool.add_listener` method is deprecated and "
"will be removed in a future release. Please use the "
- ":class:`.PoolEvents` listener interface."
+ ":class:`.PoolEvents` listener interface.",
)
def add_listener(self, listener):
"""Add a :class:`.PoolListener`-like object to this pool.
diff --git a/lib/sqlalchemy/pool/dbapi_proxy.py b/lib/sqlalchemy/pool/dbapi_proxy.py
index 6049c8e28..d78d85d1f 100644
--- a/lib/sqlalchemy/pool/dbapi_proxy.py
+++ b/lib/sqlalchemy/pool/dbapi_proxy.py
@@ -16,12 +16,17 @@ today.
"""
from .impl import QueuePool
+from .. import util
from ..util import threading
-
proxies = {}
+@util.deprecated(
+ "1.3",
+ "The :func:`.pool.manage` function is deprecated, and will be "
+ "removed in a future release.",
+)
def manage(module, **params):
r"""Return a proxy for a DB-API module that automatically
pools connections.
diff --git a/lib/sqlalchemy/pool/impl.py b/lib/sqlalchemy/pool/impl.py
index ebbbfdb3d..768921423 100644
--- a/lib/sqlalchemy/pool/impl.py
+++ b/lib/sqlalchemy/pool/impl.py
@@ -283,7 +283,6 @@ class SingletonThreadPool(Pool):
"""
def __init__(self, creator, pool_size=5, **kw):
- kw["use_threadlocal"] = True
Pool.__init__(self, creator, **kw)
self._conn = threading.local()
self._all_conns = set()
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index a3184f270..b703c59f2 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -315,7 +315,7 @@ class Compiled(object):
"The :meth:`.Compiled.compile` method is deprecated and will be "
"removed in a future release. The :class:`.Compiled` object "
"now runs its compilation within the constructor, and this method "
- "does nothing."
+ "does nothing.",
)
def compile(self):
"""Produce the internal string representation of this element.
@@ -3442,6 +3442,7 @@ class IdentifierPreparer(object):
def quote_schema(self, schema, force=None):
"""Conditionally quote a schema name.
+
The name is quoted if it is a reserved word, contains quote-necessary
characters, or is an instance of :class:`.quoted_name` which includes
``quote`` set to ``True``.
@@ -3450,17 +3451,30 @@ class IdentifierPreparer(object):
quoting behavior for schema names.
:param schema: string schema name
- :param force: this parameter is no longer used.
+ :param force: unused
- .. deprecated:: 0.9
+ .. deprecated:: 0.9
- The :paramref:`.IdentifierPreparer.force` parameter is deprecated
- and will be removed in a future release. Quoting preference
- is now intrinsic to the string being quoted by making use of the
- :class:`.quoted_name` class.
+ The :paramref:`.IdentifierPreparer.quote_schema.force`
+ parameter is deprecated and will be removed in a future
+ release. This flag has no effect on the behavior of the
+ :meth:`.IdentifierPreparer.quote` method; please refer to
+ :class:`.quoted_name`.
"""
- return self.quote(schema, force)
+ if force is not None:
+ # not using the util.deprecated_params() decorator in this
+ # case because of the additional function call overhead on this
+ # very performance-critical spot.
+ util.warn_deprecated(
+ "The IdentifierPreparer.quote_schema.force parameter is "
+ "deprecated and will be removed in a future release. This "
+ "flag has no effect on the behavior of the "
+ "IdentifierPreparer.quote method; please refer to "
+ "quoted_name()."
+ )
+
+ return self.quote(schema)
def quote(self, ident, force=None):
"""Conditionally quote an identfier.
@@ -3473,16 +3487,28 @@ class IdentifierPreparer(object):
quoting behavior for identifier names.
:param ident: string identifier
- :param force: this parameter is no longer used.
+ :param force: unused
- .. deprecated:: 0.9
+ .. deprecated:: 0.9
- The :paramref:`.IdentifierPreparer.force` parameter is deprecated
- and will be removed in a future release. Quoting preference
- is now intrinsic to the string being quoted by making use of the
- :class:`.quoted_name` class.
+ The :paramref:`.IdentifierPreparer.quote.force`
+ parameter is deprecated and will be removed in a future
+ release. This flag has no effect on the behavior of the
+ :meth:`.IdentifierPreparer.quote` method; please refer to
+ :class:`.quoted_name`.
"""
+ if force is not None:
+ # not using the util.deprecated_params() decorator in this
+ # case because of the additional function call overhead on this
+ # very performance-critical spot.
+ util.warn_deprecated(
+ "The IdentifierPreparer.quote.force parameter is "
+ "deprecated and will be removed in a future release. This "
+ "flag has no effect on the behavior of the "
+ "IdentifierPreparer.quote method; please refer to "
+ "quoted_name()."
+ )
force = getattr(ident, "quote", None)
@@ -3580,10 +3606,10 @@ class IdentifierPreparer(object):
result = self.quote_schema(effective_schema) + "." + result
return result
- def format_schema(self, name, quote=None):
+ def format_schema(self, name):
"""Prepare a quoted schema name."""
- return self.quote(name, quote)
+ return self.quote(name)
def format_column(
self,
diff --git a/lib/sqlalchemy/sql/ddl.py b/lib/sqlalchemy/sql/ddl.py
index 3deb588ab..954f769ef 100644
--- a/lib/sqlalchemy/sql/ddl.py
+++ b/lib/sqlalchemy/sql/ddl.py
@@ -106,7 +106,7 @@ class DDLElement(Executable, _DDLCompiles):
"The :meth:`.DDLElement.execute_at` method is deprecated and will "
"be removed in a future release. Please use the :class:`.DDLEvents` "
"listener interface in conjunction with the "
- ":meth:`.DDLElement.execute_if` method."
+ ":meth:`.DDLElement.execute_if` method.",
)
def execute_at(self, event_name, target):
"""Link execution of this DDL to the DDL lifecycle of a SchemaItem.
@@ -317,6 +317,14 @@ class DDL(DDLElement):
__visit_name__ = "ddl"
+ @util.deprecated_params(
+ on=(
+ "0.7",
+ "The :paramref:`.DDL.on` parameter is deprecated and will be "
+ "removed in a future release. Please refer to "
+ ":meth:`.DDLElement.execute_if`.",
+ )
+ )
def __init__(self, statement, on=None, context=None, bind=None):
"""Create a DDL statement.
@@ -331,12 +339,6 @@ class DDL(DDLElement):
:param on:
- .. deprecated:: 0.7
-
- The :paramref:`.DDL.on` parameter is deprecated and will be
- removed in a future release. Please refer to
- :meth:`.DDLElement.execute_if`.
-
Optional filtering criteria. May be a string, tuple or a callable
predicate. If a string, it will be compared to the name of the
executing database dialect::
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index fae25cc2c..71f346f45 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -461,21 +461,27 @@ class ClauseElement(Visitable):
"ascii", "backslashreplace"
) # noqa
+ @util.deprecated(
+ "0.9",
+ "The :meth:`.ClauseElement.__and__` method is deprecated and will "
+ "be removed in a future release. Conjunctions should only be "
+ "used from a :class:`.ColumnElement` subclass, e.g. "
+ ":meth:`.ColumnElement.__and__`.",
+ )
def __and__(self, other):
"""'and' at the ClauseElement level.
-
- .. deprecated:: 0.9.5 - conjunctions are intended to be
- at the :class:`.ColumnElement`. level
-
"""
return and_(self, other)
+ @util.deprecated(
+ "0.9",
+ "The :meth:`.ClauseElement.__or__` method is deprecated and will "
+ "be removed in a future release. Conjunctions should only be "
+ "used from a :class:`.ColumnElement` subclass, e.g. "
+ ":meth:`.ColumnElement.__or__`.",
+ )
def __or__(self, other):
"""'or' at the ClauseElement level.
-
- .. deprecated:: 0.9.5 - conjunctions are intended to be
- at the :class:`.ColumnElement`. level
-
"""
return or_(self, other)
@@ -1280,6 +1286,10 @@ class TextClause(Executable, ClauseElement):
)
_is_implicitly_boolean = False
+ def __and__(self, other):
+ # support use in select.where(), query.filter()
+ return and_(self, other)
+
@property
def _select_iterable(self):
return (self,)
@@ -1311,6 +1321,28 @@ class TextClause(Executable, ClauseElement):
self.text = self._bind_params_regex.sub(repl, text)
@classmethod
+ @util.deprecated_params(
+ autocommit=(
+ "0.6",
+ "The :paramref:`.text.autocommit` parameter is deprecated and "
+ "will be removed in a future release. Please use the "
+ ":paramref:`.Connection.execution_options.autocommit` parameter "
+ "in conjunction with the :meth:`.Executable.execution_options` "
+ "method.",
+ ),
+ bindparams=(
+ "0.9",
+ "The :paramref:`.text.bindparams` parameter "
+ "is deprecated and will be removed in a future release. Please "
+ "refer to the :meth:`.TextClause.bindparams` method.",
+ ),
+ typemap=(
+ "0.9",
+ "The :paramref:`.text.typemap` parameter is "
+ "deprecated and will be removed in a future release. Please "
+ "refer to the :meth:`.TextClause.columns` method.",
+ ),
+ )
def _create_text(
self, text, bind=None, bindparams=None, typemap=None, autocommit=None
):
@@ -1389,15 +1421,8 @@ class TextClause(Executable, ClauseElement):
to specify bind parameters; they will be compiled to their
engine-specific format.
- :param autocommit:
-
- .. deprecated:: 0.6
-
- The :paramref:`.text.autocommit` flag is deprecated and
- will be removed in a future release. Please use the
- :paramref:`.Connection.execution_options.autocommit` parameter
- in conjunction with the :meth:`.Executable.execution_options`
- method.
+ :param autocommit: whether or not to set the "autocommit" execution
+ option for this :class:`.TextClause` object.
:param bind:
an optional connection or engine to be used for this text query.
@@ -1405,27 +1430,22 @@ class TextClause(Executable, ClauseElement):
:param bindparams:
A list of :func:`.bindparam` instances used to
provide information about parameters embedded in the statement.
+
E.g.::
stmt = text("SELECT * FROM table WHERE id=:id",
bindparams=[bindparam('id', value=5, type_=Integer)])
- .. deprecated:: 0.9 the :paramref:`.TextClause.bindparams` parameter
- is deprecated and will be removed in a future release. Please
- refer to the :meth:`.TextClause.bindparams` method.
-
:param typemap:
A dictionary mapping the names of columns represented in the columns
- clause of a ``SELECT`` statement to type objects, e.g.::
+ clause of a ``SELECT`` statement to type objects.
+
+ E.g.::
stmt = text("SELECT * FROM table",
typemap={'id': Integer, 'name': String},
)
- .. deprecated:: 0.9 The :paramref:`.TextClause.typemap` argument is
- deprecated and will be removed in a future release. Please
- refer to the :meth:`.TextClause.columns` method.
-
.. seealso::
:ref:`sqlexpression_text` - in the Core tutorial
@@ -1439,10 +1459,6 @@ class TextClause(Executable, ClauseElement):
if typemap:
stmt = stmt.columns(**typemap)
if autocommit is not None:
- util.warn_deprecated(
- "autocommit on text() is deprecated. "
- "Use .execution_options(autocommit=True)"
- )
stmt = stmt.execution_options(autocommit=autocommit)
return stmt
@@ -1511,12 +1527,6 @@ class TextClause(Executable, ClauseElement):
timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5)
)
-
- .. versionadded:: 0.9.0 The :meth:`.TextClause.bindparams` method
- supersedes the argument ``bindparams`` passed to
- :func:`~.expression.text`.
-
-
"""
self._bindparams = new_params = self._bindparams.copy()
@@ -1631,8 +1641,7 @@ class TextClause(Executable, ClauseElement):
.. versionadded:: 0.9.0 :func:`.text` can now be converted into a
fully featured "selectable" construct using the
- :meth:`.TextClause.columns` method. This method supersedes the
- ``typemap`` argument to :func:`.text`.
+ :meth:`.TextClause.columns` method.
"""
@@ -3364,13 +3373,16 @@ class Over(ColumnElement):
return lower, upper
@property
+ @util.deprecated(
+ "1.1",
+ "the :attr:`.Over.func` member of the :class:`.Over` "
+ "class is deprecated and will be removed in a future release. "
+ "Please refer to the :attr:`.Over.element` attribute.",
+ )
def func(self):
"""the element referred to by this :class:`.Over`
clause.
- .. deprecated:: 1.1 the :attr:`.Over.func` member of the :class:`.Over`
- class is deprecated and will be removed in a future release. Please
- refer to the :attr:`.Over.element` attribute.
"""
return self.element
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 43a2e5d0f..d9555b196 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -118,7 +118,8 @@ class SchemaItem(SchemaEventTarget, visitors.Visitable):
"The :attr:`.SchemaItem.quote` attribute is deprecated and will be "
"removed in a future release. Use the :attr:`.quoted_name.quote` "
"attribute on the ``name`` field of the target schema item to retrieve"
- "quoted status.")
+ "quoted status.",
+ )
def quote(self):
"""Return the value of the ``quote`` flag passed
to this schema object, for those schema items which
@@ -394,7 +395,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
name, specify the flag ``quote_schema=True`` to the constructor, or use
the :class:`.quoted_name` construct to specify the name.
- :param useexisting: Deprecated. Use :paramref:`.Table.extend_existing`.
+ :param useexisting: the same as :paramref:`.Table.extend_existing`.
:param comment: Optional string that will render an SQL comment on table
creation.
@@ -411,6 +412,14 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
__visit_name__ = "table"
+ @util.deprecated_params(
+ useexisting=(
+ "0.7",
+ "The :paramref:`.Table.useexisting` parameter is deprecated and "
+ "will be removed in a future release. Please use "
+ ":paramref:`.Table.extend_existing`.",
+ )
+ )
def __new__(cls, *args, **kw):
if not args:
# python3k pickle seems to call this
@@ -429,8 +438,6 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
keep_existing = kw.pop("keep_existing", False)
extend_existing = kw.pop("extend_existing", False)
if "useexisting" in kw:
- msg = "useexisting is deprecated. Use extend_existing."
- util.warn_deprecated(msg)
if extend_existing:
msg = "useexisting is synonymous with extend_existing."
raise exc.ArgumentError(msg)
@@ -475,7 +482,8 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
"The :meth:`.SchemaItem.quote` method is deprecated and will be "
"removed in a future release. Use the :attr:`.quoted_name.quote` "
"attribute on the ``schema`` field of the target schema item to "
- "retrieve quoted status.")
+ "retrieve quoted status.",
+ )
def quote_schema(self):
"""Return the value of the ``quote_schema`` flag passed
to this :class:`.Table`.
@@ -763,12 +771,15 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
constraint._set_parent_with_dispatch(self)
+ @util.deprecated(
+ "0.7",
+ "the :meth:`.Table.append_ddl_listener` method is deprecated and "
+ "will be removed in a future release. Please refer to "
+ ":class:`.DDLEvents`.",
+ )
def append_ddl_listener(self, event_name, listener):
"""Append a DDL event listener to this ``Table``.
- .. deprecated:: 0.7
- See :class:`.DDLEvents`.
-
"""
def adapt_listener(target, connection, **kw):
@@ -2579,22 +2590,15 @@ class DefaultClause(FetchedValue):
return "DefaultClause(%r, for_update=%r)" % (self.arg, self.for_update)
+@util.deprecated_cls(
+ "0.6",
+ ":class:`.PassiveDefault` is deprecated and will be removed in a "
+ "future release. Please refer to :class:`.DefaultClause`.",
+)
class PassiveDefault(DefaultClause):
"""A DDL-specified DEFAULT column value.
-
- .. deprecated:: 0.6
-
- The :class:`.PassiveDefault` class is deprecated and will be removed
- in a future release. Please use :class:`.DefaultClause`.
-
"""
- @util.deprecated(
- "0.6",
- ":class:`.PassiveDefault` is deprecated and will be removed in a "
- "future release. Use :class:`.DefaultClause`.",
- False,
- )
def __init__(self, *arg, **kw):
DefaultClause.__init__(self, *arg, **kw)
@@ -3711,13 +3715,21 @@ class MetaData(SchemaItem):
__visit_name__ = "metadata"
+ @util.deprecated_params(
+ reflect=(
+ "0.8",
+ "The :paramref:`.MetaData.reflect` flag is deprecated and will "
+ "be removed in a future release. Please use the "
+ ":meth:`.MetaData.reflect` method.",
+ )
+ )
def __init__(
self,
bind=None,
reflect=False,
schema=None,
quote_schema=None,
- naming_convention=DEFAULT_NAMING_CONVENTION,
+ naming_convention=None,
info=None,
):
"""Create a new MetaData object.
@@ -3731,12 +3743,6 @@ class MetaData(SchemaItem):
Optional, automatically load all tables from the bound database.
Defaults to False. ``bind`` is required when this option is set.
- .. deprecated:: 0.8
-
- The :paramref:`.MetaData.reflect` flag is deprecated and will
- be removed in a future release. Please use the
- :meth:`.MetaData.reflect` method.
-
:param schema:
The default schema to use for the :class:`.Table`,
:class:`.Sequence`, and potentially other objects associated with
@@ -3877,7 +3883,11 @@ class MetaData(SchemaItem):
"""
self.tables = util.immutabledict()
self.schema = quoted_name(schema, quote_schema)
- self.naming_convention = naming_convention
+ self.naming_convention = (
+ naming_convention
+ if naming_convention
+ else DEFAULT_NAMING_CONVENTION
+ )
if info:
self.info = info
self._schemas = set()
@@ -3886,10 +3896,6 @@ class MetaData(SchemaItem):
self.bind = bind
if reflect:
- util.warn_deprecated(
- "reflect=True is deprecate; please "
- "use the reflect() method."
- )
if not bind:
raise exc.ArgumentError(
"A bind must be supplied in conjunction "
@@ -4180,11 +4186,15 @@ class MetaData(SchemaItem):
except exc.UnreflectableTableError as uerr:
util.warn("Skipping table %s: %s" % (name, uerr))
+ @util.deprecated(
+ "0.7",
+ "the :meth:`.MetaData.append_ddl_listener` method is deprecated and "
+ "will be removed in a future release. Please refer to "
+ ":class:`.DDLEvents`.",
+ )
def append_ddl_listener(self, event_name, listener):
"""Append a DDL event listener to this ``MetaData``.
- .. deprecated:: 0.7
- See :class:`.DDLEvents`.
"""
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index 0b2155a68..f48fa6f57 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -391,7 +391,7 @@ class FromClause(Selectable):
message="The :meth:`.FromClause.count` method is deprecated, "
"and will be removed in a future release. Please use the "
":class:`.functions.count` function available from the "
- ":attr:`.func` namespace."
+ ":attr:`.func` namespace.",
)
@util.dependencies("sqlalchemy.sql.functions")
def count(self, functions, whereclause=None, **params):
@@ -973,6 +973,15 @@ class Join(FromClause):
return self._join_condition(left, right, a_subset=left_right)
@classmethod
+ @util.deprecated_params(
+ ignore_nonexistent_tables=(
+ "0.9",
+ "The :paramref:`.join_condition.ignore_nonexistent_tables` "
+ "parameter is deprecated and will be removed in a future "
+ "release. Tables outside of the two tables being handled "
+ "are no longer considered.",
+ )
+ )
def _join_condition(
cls,
a,
@@ -995,15 +1004,8 @@ class Join(FromClause):
between the two selectables. If there are multiple ways
to join, or no way to join, an error is raised.
- :param ignore_nonexistent_tables:
-
- .. deprecated:: 0.9
-
- The :paramref:`_join_condition.ignore_nonexistent_tables`
- parameter is deprecated and will be removed in a future
- release. Tables outside of the two tables being handled
- are no longer considered.
-
+ :param ignore_nonexistent_tables: unused - tables outside of the
+ two tables being handled are not considered.
:param a_subset: An optional expression that is a sub-component
of ``a``. An attempt will be made to join to just this sub-component
@@ -2026,7 +2028,7 @@ class SelectBase(HasCTE, Executable, FromClause):
"and will be removed in a future release. Please use the "
"the :paramref:`.Connection.execution_options.autocommit` "
"parameter in conjunction with the "
- ":meth:`.Executable.execution_options` method."
+ ":meth:`.Executable.execution_options` method.",
)
def autocommit(self):
"""return a new selectable with the 'autocommit' flag set to
@@ -2642,6 +2644,24 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect):
_memoized_property = SelectBase._memoized_property
_is_select = True
+ @util.deprecated_params(
+ autocommit=(
+ "0.6",
+ "The :paramref:`.select.autocommit` parameter is deprecated "
+ "and will be removed in a future release. Please refer to "
+ "the :paramref:`.Connection.execution_options.autocommit` "
+ "parameter in conjunction with the the "
+ ":meth:`.Executable.execution_options` method in order to "
+ "affect the autocommit behavior for a statement.",
+ ),
+ for_update=(
+ "0.9",
+ "The :paramref:`.select.for_update` parameter is deprecated and "
+ "will be removed in a future release. Please refer to the "
+ ":meth:`.Select.with_for_update` to specify the "
+ "structure of the ``FOR UPDATE`` clause.",
+ ),
+ )
def __init__(
self,
columns=None,
@@ -2712,16 +2732,7 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect):
:meth:`.Select.select_from` - full description of explicit
FROM clause specification.
- :param autocommit:
-
- .. deprecated:: 0.6
-
- The :paramref:`.select.autocommit` parameter is deprecated
- and will be removed in a future release. Please refer to
- the :paramref:`.Connection.execution_options.autocommit`
- parameter in conjunction with the the
- :meth:`.Executable.execution_options` method in order to
- affect the autocommit behavior for a statement.
+ :param autocommit: legacy autocommit parameter.
:param bind=None:
an :class:`~.Engine` or :class:`~.Connection` instance
@@ -2762,13 +2773,6 @@ class Select(HasPrefixes, HasSuffixes, GenerativeSelect):
when ``True``, applies ``FOR UPDATE`` to the end of the
resulting statement.
- .. deprecated:: 0.9
-
- The :paramref:`.select.for_update` parameter is deprecated and
- will be removed in a future release. Please refer to the
- :meth:`.Select.with_for_update` to specify the
- structure of the ``FOR UPDATE`` clause.
-
``for_update`` accepts various string values interpreted by
specific backends, including:
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index 1d97bf35c..8131be443 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -137,6 +137,22 @@ class String(Concatenable, TypeEngine):
__visit_name__ = "string"
+ @util.deprecated_params(
+ convert_unicode=(
+ "1.3",
+ "The :paramref:`.String.convert_unicode` parameter is deprecated "
+ "and will be removed in a future release. All modern DBAPIs "
+ "now support Python Unicode directly and this parameter is "
+ "unnecessary.",
+ ),
+ unicode_error=(
+ "1.3",
+ "The :paramref:`.String.unicode_errors` parameter is deprecated "
+ "and will be removed in a future release. This parameter is "
+ "unnecessary for modern Python DBAPIs and degrades performance "
+ "significantly.",
+ ),
+ )
def __init__(
self,
length=None,
@@ -144,6 +160,7 @@ class String(Concatenable, TypeEngine):
convert_unicode=False,
unicode_error=None,
_warn_on_bytestring=False,
+ _expect_unicode=False,
):
"""
Create a string-holding type.
@@ -207,15 +224,9 @@ class String(Concatenable, TypeEngine):
:param unicode_error: Optional, a method to use to handle Unicode
conversion errors. Behaves like the ``errors`` keyword argument to
- the standard library's ``string.decode()`` functions. This flag
- requires that :paramref:`.String.convert_unicode` is set to
- ``"force"`` - otherwise,
- SQLAlchemy is not guaranteed to handle the task of unicode
- conversion. Note that this flag adds significant performance
- overhead to row-fetching operations for backends that already
- return unicode objects natively (which most DBAPIs do). This
- flag should only be used as a last resort for reading
- strings from a column with varied or corrupted encodings.
+ the standard library's ``string.decode()`` functions, requires
+ that :paramref:`.String.convert_unicode` is set to
+ ``"force"``
"""
if unicode_error is not None and convert_unicode != "force":
@@ -225,8 +236,9 @@ class String(Concatenable, TypeEngine):
self.length = length
self.collation = collation
- self.convert_unicode = convert_unicode
- self.unicode_error = unicode_error
+ self._expect_unicode = convert_unicode or _expect_unicode
+ self._expect_unicode_error = unicode_error
+
self._warn_on_bytestring = _warn_on_bytestring
def literal_processor(self, dialect):
@@ -241,10 +253,10 @@ class String(Concatenable, TypeEngine):
return process
def bind_processor(self, dialect):
- if self.convert_unicode or dialect.convert_unicode:
+ if self._expect_unicode or dialect.convert_unicode:
if (
dialect.supports_unicode_binds
- and self.convert_unicode != "force"
+ and self._expect_unicode != "force"
):
if self._warn_on_bytestring:
@@ -266,7 +278,7 @@ class String(Concatenable, TypeEngine):
def process(value):
if isinstance(value, util.text_type):
- return encoder(value, self.unicode_error)[0]
+ return encoder(value, self._expect_unicode_error)[0]
elif warn_on_bytestring and value is not None:
util.warn_limited(
"Unicode type received non-unicode bind "
@@ -280,31 +292,31 @@ class String(Concatenable, TypeEngine):
return None
def result_processor(self, dialect, coltype):
- wants_unicode = self.convert_unicode or dialect.convert_unicode
+ wants_unicode = self._expect_unicode or dialect.convert_unicode
needs_convert = wants_unicode and (
dialect.returns_unicode_strings is not True
- or self.convert_unicode in ("force", "force_nocheck")
+ or self._expect_unicode in ("force", "force_nocheck")
)
needs_isinstance = (
needs_convert
and dialect.returns_unicode_strings
- and self.convert_unicode != "force_nocheck"
+ and self._expect_unicode != "force_nocheck"
)
if needs_convert:
if needs_isinstance:
return processors.to_conditional_unicode_processor_factory(
- dialect.encoding, self.unicode_error
+ dialect.encoding, self._expect_unicode_error
)
else:
return processors.to_unicode_processor_factory(
- dialect.encoding, self.unicode_error
+ dialect.encoding, self._expect_unicode_error
)
else:
return None
@property
def python_type(self):
- if self.convert_unicode:
+ if self._expect_unicode:
return util.text_type
else:
return str
@@ -312,6 +324,16 @@ class String(Concatenable, TypeEngine):
def get_dbapi_type(self, dbapi):
return dbapi.STRING
+ @classmethod
+ def _warn_deprecated_unicode(cls):
+ util.warn_deprecated(
+ "The convert_unicode on Engine and String as well as the "
+ "unicode_error flag on String are deprecated. All modern "
+ "DBAPIs now support Python Unicode natively under Python 2, and "
+ "under Python 3 all strings are inherently Unicode. These flags "
+ "will be removed in a future release."
+ )
+
class Text(String):
@@ -395,7 +417,7 @@ class Unicode(String):
defaults to ``True``.
"""
- kwargs.setdefault("convert_unicode", True)
+ kwargs.setdefault("_expect_unicode", True)
kwargs.setdefault("_warn_on_bytestring", True)
super(Unicode, self).__init__(length=length, **kwargs)
@@ -424,10 +446,13 @@ class UnicodeText(Text):
defaults to ``True``.
"""
- kwargs.setdefault("convert_unicode", True)
+ kwargs.setdefault("_expect_unicode", True)
kwargs.setdefault("_warn_on_bytestring", True)
super(UnicodeText, self).__init__(length=length, **kwargs)
+ def _warn_deprecated_unicode(self):
+ pass
+
class Integer(_LookupExpressionAdapter, TypeEngine):
@@ -697,11 +722,7 @@ class Float(Numeric):
scale = None
def __init__(
- self,
- precision=None,
- asdecimal=False,
- decimal_return_scale=None,
- **kwargs
+ self, precision=None, asdecimal=False, decimal_return_scale=None
):
r"""
Construct a Float.
@@ -724,25 +745,10 @@ class Float(Numeric):
.. versionadded:: 0.9.0
- :param \**kwargs:
-
- .. deprecated:: 0.9
-
- Additional keyword arguments are ignored by the base
- :class:`.Float` type, and keyword arguments will no longer
- be accepted in a future release. For database specific floats
- that support additional arguments, see that dialect's
- documentation for details, such as
- :class:`sqlalchemy.dialects.mysql.FLOAT`.
-
"""
self.precision = precision
self.asdecimal = asdecimal
self.decimal_return_scale = decimal_return_scale
- if kwargs:
- util.warn_deprecated(
- "Additional keyword arguments " "passed to Float ignored."
- )
def result_processor(self, dialect, coltype):
if self.asdecimal:
@@ -975,19 +981,13 @@ class LargeBinary(_Binary):
_Binary.__init__(self, length=length)
+@util.deprecated_cls(
+ "0.6",
+ "The :class:`.Binary` class is deprecated and will be removed "
+ "in a future relase. Please use :class:`.LargeBinary`.",
+)
class Binary(LargeBinary):
-
- """.. deprecated:: 0.6
-
- The :class:`.Binary` class is deprecated and will be removed
- in a future relase. Please use :class:`.LargeBinary`.
-
- """
-
def __init__(self, *arg, **kw):
- util.warn_deprecated(
- "The Binary type has been renamed to " "LargeBinary."
- )
LargeBinary.__init__(self, *arg, **kw)
@@ -1264,6 +1264,15 @@ class Enum(Emulated, String, SchemaType):
__visit_name__ = "enum"
+ @util.deprecated_params(
+ convert_unicode=(
+ "1.3",
+ "The :paramref:`.Enum.convert_unicode` parameter is deprecated "
+ "and will be removed in a future release. All modern DBAPIs "
+ "now support Python Unicode directly and this parameter is "
+ "unnecessary.",
+ )
+ )
def __init__(self, *enums, **kw):
r"""Construct an enum.
@@ -1376,11 +1385,15 @@ class Enum(Emulated, String, SchemaType):
if convert_unicode is None:
for e in self.enums:
+ # this is all py2k logic that can go away for py3k only,
+ # "expect unicode" will always be implicitly true
if isinstance(e, util.text_type):
- convert_unicode = True
+ _expect_unicode = True
break
else:
- convert_unicode = False
+ _expect_unicode = False
+ else:
+ _expect_unicode = convert_unicode
if self.enums:
length = max(len(x) for x in self.enums)
@@ -1389,7 +1402,7 @@ class Enum(Emulated, String, SchemaType):
self._valid_lookup[None] = self._object_lookup[None] = None
super(Enum, self).__init__(
- length=length, convert_unicode=convert_unicode
+ length=length, _expect_unicode=_expect_unicode
)
if self.enum_class:
@@ -1469,7 +1482,7 @@ class Enum(Emulated, String, SchemaType):
)
if op is operators.concat_op:
typ = String(
- self.type.length, convert_unicode=self.type.convert_unicode
+ self.type.length, _expect_unicode=self.type._expect_unicode
)
return op, typ
@@ -1491,7 +1504,7 @@ class Enum(Emulated, String, SchemaType):
)
def adapt_to_emulated(self, impltype, **kw):
- kw.setdefault("convert_unicode", self.convert_unicode)
+ kw.setdefault("_expect_unicode", self._expect_unicode)
kw.setdefault("validate_strings", self.validate_strings)
kw.setdefault("name", self.name)
kw.setdefault("schema", self.schema)
@@ -2205,7 +2218,7 @@ class JSON(Indexable, TypeEngine):
@util.memoized_property
def _str_impl(self):
- return String(convert_unicode=True)
+ return String(_expect_unicode=True)
def bind_processor(self, dialect):
string_process = self._str_impl.bind_processor(dialect)
diff --git a/lib/sqlalchemy/testing/engines.py b/lib/sqlalchemy/testing/engines.py
index 22faa2394..232eebeb3 100644
--- a/lib/sqlalchemy/testing/engines.py
+++ b/lib/sqlalchemy/testing/engines.py
@@ -12,6 +12,7 @@ import warnings
import weakref
from . import config
+from . import uses_deprecated
from .util import decorator
from .. import event
from .. import pool
@@ -74,6 +75,7 @@ class ConnectionKiller(object):
else:
self._stop_test_ctx_aggressive()
+ @uses_deprecated()
def _stop_test_ctx_minimal(self):
self.close_all()
@@ -83,6 +85,7 @@ class ConnectionKiller(object):
if rec is not config.db:
rec.dispose()
+ @uses_deprecated()
def _stop_test_ctx_aggressive(self):
self.close_all()
for conn, rec in list(self.conns):
diff --git a/lib/sqlalchemy/testing/suite/test_reflection.py b/lib/sqlalchemy/testing/suite/test_reflection.py
index aa04b6073..e8d75bafa 100644
--- a/lib/sqlalchemy/testing/suite/test_reflection.py
+++ b/lib/sqlalchemy/testing/suite/test_reflection.py
@@ -313,11 +313,15 @@ class ComponentReflectionTest(fixtures.TablesTest):
answer = ["email_addresses_v", "users_v"]
eq_(sorted(table_names), answer)
else:
- table_names = [
- t
- for t in insp.get_table_names(schema, order_by=order_by)
- if t not in _ignore_tables
- ]
+ if order_by:
+ tables = [
+ rec[0]
+ for rec in insp.get_sorted_table_and_fkc_names(schema)
+ if rec[0]
+ ]
+ else:
+ tables = insp.get_table_names(schema)
+ table_names = [t for t in tables if t not in _ignore_tables]
if order_by == "foreign_key":
answer = ["users", "email_addresses", "dingalings"]
diff --git a/lib/sqlalchemy/testing/suite/test_results.py b/lib/sqlalchemy/testing/suite/test_results.py
index aa98a5088..a07e45df2 100644
--- a/lib/sqlalchemy/testing/suite/test_results.py
+++ b/lib/sqlalchemy/testing/suite/test_results.py
@@ -320,7 +320,7 @@ class ServerSideCursorsTest(
def test_for_update_expr(self):
engine = self._fixture(True)
- s1 = select([1], for_update=True)
+ s1 = select([1]).with_for_update()
result = engine.execute(s1)
assert self._is_server_side(result.cursor)
diff --git a/lib/sqlalchemy/testing/suite/test_types.py b/lib/sqlalchemy/testing/suite/test_types.py
index 4791671f3..1e02c0e74 100644
--- a/lib/sqlalchemy/testing/suite/test_types.py
+++ b/lib/sqlalchemy/testing/suite/test_types.py
@@ -933,10 +933,7 @@ class JSONTest(_LiteralRoundTripFixture, fixtures.TablesTest):
)
eq_(
s.query(
- cast(
- self.tables.data_table.c.data,
- String(convert_unicode="force"),
- ),
+ cast(self.tables.data_table.c.data, String()),
cast(self.tables.data_table.c.nulldata, String),
)
.filter(self.tables.data_table.c.name == "d1")
@@ -945,10 +942,7 @@ class JSONTest(_LiteralRoundTripFixture, fixtures.TablesTest):
)
eq_(
s.query(
- cast(
- self.tables.data_table.c.data,
- String(convert_unicode="force"),
- ),
+ cast(self.tables.data_table.c.data, String()),
cast(self.tables.data_table.c.nulldata, String),
)
.filter(self.tables.data_table.c.name == "d2")
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py
index f812671d3..383c143c4 100644
--- a/lib/sqlalchemy/util/__init__.py
+++ b/lib/sqlalchemy/util/__init__.py
@@ -87,6 +87,8 @@ from .compat import win32 # noqa
from .compat import with_metaclass # noqa
from .compat import zip_longest # noqa
from .deprecations import deprecated # noqa
+from .deprecations import deprecated_cls # noqa
+from .deprecations import deprecated_params # noqa
from .deprecations import inject_docstring_text # noqa
from .deprecations import pending_deprecation # noqa
from .deprecations import warn_deprecated # noqa
diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py
index abd36d9b0..ff644cd36 100644
--- a/lib/sqlalchemy/util/compat.py
+++ b/lib/sqlalchemy/util/compat.py
@@ -44,6 +44,19 @@ FullArgSpec = collections.namedtuple(
],
)
+FullArgSpec = collections.namedtuple(
+ "FullArgSpec",
+ [
+ "args",
+ "varargs",
+ "varkw",
+ "defaults",
+ "kwonlyargs",
+ "kwonlydefaults",
+ "annotations",
+ ],
+)
+
try:
import threading
except ImportError:
diff --git a/lib/sqlalchemy/util/deprecations.py b/lib/sqlalchemy/util/deprecations.py
index e7b972deb..a43acc72e 100644
--- a/lib/sqlalchemy/util/deprecations.py
+++ b/lib/sqlalchemy/util/deprecations.py
@@ -12,6 +12,7 @@ import re
import textwrap
import warnings
+from . import compat
from .langhelpers import decorator
from .. import exc
@@ -24,6 +25,21 @@ def warn_pending_deprecation(msg, stacklevel=3):
warnings.warn(msg, exc.SAPendingDeprecationWarning, stacklevel=stacklevel)
+def deprecated_cls(version, message, constructor="__init__"):
+ header = ".. deprecated:: %s %s" % (version, (message or ""))
+
+ def decorate(cls):
+ return _decorate_cls_with_warning(
+ cls,
+ constructor,
+ exc.SADeprecationWarning,
+ message % dict(func=constructor),
+ header,
+ )
+
+ return decorate
+
+
def deprecated(version, message=None, add_deprecation_to_docstring=True):
"""Decorates a function and issues a deprecation warning on use.
@@ -60,6 +76,74 @@ def deprecated(version, message=None, add_deprecation_to_docstring=True):
return decorate
+def deprecated_params(**specs):
+ """Decorates a function to warn on use of certain parameters.
+
+ e.g. ::
+
+ @deprecated_params(
+ weak_identity_map=(
+ "0.7",
+ "the :paramref:`.Session.weak_identity_map parameter "
+ "is deprecated."
+ )
+
+ )
+
+ """
+
+ messages = {}
+ for param, (version, message) in specs.items():
+ messages[param] = _sanitize_restructured_text(message)
+
+ def decorate(fn):
+ spec = compat.inspect_getfullargspec(fn)
+ if spec.defaults is not None:
+ defaults = dict(
+ zip(
+ spec.args[(len(spec.args) - len(spec.defaults)) :],
+ spec.defaults,
+ )
+ )
+ check_defaults = set(defaults).intersection(messages)
+ check_kw = set(messages).difference(defaults)
+ else:
+ check_defaults = ()
+ check_kw = set(messages)
+
+ has_kw = spec.varkw is not None
+
+ @decorator
+ def warned(fn, *args, **kwargs):
+ for m in check_defaults:
+ if kwargs[m] != defaults[m]:
+ warnings.warn(
+ messages[m], exc.SADeprecationWarning, stacklevel=3
+ )
+ for m in check_kw:
+ if m in kwargs:
+ warnings.warn(
+ messages[m], exc.SADeprecationWarning, stacklevel=3
+ )
+
+ return fn(*args, **kwargs)
+
+ doc = fn.__doc__ is not None and fn.__doc__ or ""
+ if doc:
+ doc = inject_param_text(
+ doc,
+ {
+ param: ".. deprecated:: %s %s" % (version, (message or ""))
+ for param, (version, message) in specs.items()
+ },
+ )
+ decorated = warned(fn)
+ decorated.__doc__ = doc
+ return decorated
+
+ return decorate
+
+
def pending_deprecation(
version, message=None, add_deprecation_to_docstring=True
):
@@ -98,6 +182,14 @@ def pending_deprecation(
return decorate
+def deprecated_option_value(parameter_value, default_value, warning_text):
+ if parameter_value is None:
+ return default_value
+ else:
+ warn_deprecated(warning_text)
+ return parameter_value
+
+
def _sanitize_restructured_text(text):
def repl(m):
type_, name = m.group(1, 2)
@@ -108,6 +200,33 @@ def _sanitize_restructured_text(text):
return re.sub(r"\:(\w+)\:`~?\.?(.+?)`", repl, text)
+def _decorate_cls_with_warning(
+ cls, constructor, wtype, message, docstring_header=None
+):
+ doc = cls.__doc__ is not None and cls.__doc__ or ""
+ if docstring_header is not None:
+ docstring_header %= dict(func=constructor)
+
+ doc = inject_docstring_text(doc, docstring_header, 1)
+
+ if type(cls) is type:
+ clsdict = dict(cls.__dict__)
+ clsdict["__doc__"] = doc
+ cls = type(cls.__name__, cls.__bases__, clsdict)
+ constructor_fn = clsdict[constructor]
+ else:
+ cls.__doc__ = doc
+ constructor_fn = getattr(cls, constructor)
+
+ setattr(
+ cls,
+ constructor,
+ _decorate_with_warning(constructor_fn, wtype, message, None),
+ )
+
+ return cls
+
+
def _decorate_with_warning(func, wtype, message, docstring_header=None):
"""Wrap a function with a warnings.warn and augmented docstring."""
@@ -126,6 +245,7 @@ def _decorate_with_warning(func, wtype, message, docstring_header=None):
decorated = warned(func)
decorated.__doc__ = doc
+ decorated._sa_warn = lambda: warnings.warn(message, wtype, stacklevel=3)
return decorated
@@ -155,3 +275,36 @@ def inject_docstring_text(doctext, injecttext, pos):
lines = lines[0:inject_pos] + injectlines + lines[inject_pos:]
return "\n".join(lines)
+
+
+def inject_param_text(doctext, inject_params):
+ doclines = doctext.splitlines()
+ lines = []
+
+ to_inject = None
+ while doclines:
+ line = doclines.pop(0)
+ if to_inject is None:
+ m = re.match(r"(\s+):param (.+?):", line)
+ if m:
+ param = m.group(2)
+ if param in inject_params:
+ # default indent to that of :param: plus one
+ indent = " " * len(m.group(1)) + " "
+
+ # but if the next line has text, use that line's
+ # indentntation
+ if doclines:
+ m2 = re.match(r"(\s+)\S", doclines[0])
+ if m2:
+ indent = " " * len(m2.group(1))
+
+ to_inject = indent + inject_params[param]
+ elif not line.rstrip():
+ lines.append(line)
+ lines.append(to_inject)
+ lines.append("\n")
+ to_inject = None
+ lines.append(line)
+
+ return "\n".join(lines)