summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/__init__.py1
-rw-r--r--lib/sqlalchemy/dialects/__init__.py10
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py6
-rw-r--r--lib/sqlalchemy/dialects/mysql/__init__.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py8
-rw-r--r--lib/sqlalchemy/dialects/mysql/enumerated.py111
-rw-r--r--lib/sqlalchemy/dialects/mysql/gaerdbms.py102
-rw-r--r--lib/sqlalchemy/dialects/mysql/reflection.py17
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py4
-rw-r--r--lib/sqlalchemy/engine/base.py13
-rw-r--r--lib/sqlalchemy/engine/default.py11
-rw-r--r--lib/sqlalchemy/engine/events.py60
-rw-r--r--lib/sqlalchemy/engine/interfaces.py47
-rw-r--r--lib/sqlalchemy/engine/reflection.py19
-rw-r--r--lib/sqlalchemy/engine/result.py10
-rw-r--r--lib/sqlalchemy/exc.py9
-rw-r--r--lib/sqlalchemy/ext/declarative/__init__.py2
-rw-r--r--lib/sqlalchemy/ext/declarative/api.py26
-rw-r--r--lib/sqlalchemy/ext/declarative/base.py8
-rw-r--r--lib/sqlalchemy/orm/__init__.py18
-rw-r--r--lib/sqlalchemy/orm/attributes.py12
-rw-r--r--lib/sqlalchemy/orm/collections.py33
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py87
-rw-r--r--lib/sqlalchemy/orm/events.py8
-rw-r--r--lib/sqlalchemy/orm/identity.py126
-rw-r--r--lib/sqlalchemy/orm/mapper.py25
-rw-r--r--lib/sqlalchemy/orm/properties.py2
-rw-r--r--lib/sqlalchemy/orm/query.py17
-rw-r--r--lib/sqlalchemy/orm/session.py93
-rw-r--r--lib/sqlalchemy/orm/strategies.py3
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py11
-rw-r--r--lib/sqlalchemy/sql/coercions.py9
-rw-r--r--lib/sqlalchemy/sql/compiler.py20
-rw-r--r--lib/sqlalchemy/sql/elements.py85
-rw-r--r--lib/sqlalchemy/sql/schema.py10
-rw-r--r--lib/sqlalchemy/sql/selectable.py30
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py13
-rw-r--r--lib/sqlalchemy/sql/type_api.py19
-rw-r--r--lib/sqlalchemy/testing/assertions.py4
-rw-r--r--lib/sqlalchemy/testing/suite/test_reflection.py15
-rw-r--r--lib/sqlalchemy/types.py2
-rw-r--r--lib/sqlalchemy/util/deprecations.py69
42 files changed, 159 insertions, 1017 deletions
diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py
index f7b9214aa..e7f087599 100644
--- a/lib/sqlalchemy/__init__.py
+++ b/lib/sqlalchemy/__init__.py
@@ -82,7 +82,6 @@ from .types import ARRAY # noqa
from .types import BIGINT # noqa
from .types import BigInteger # noqa
from .types import BINARY # noqa
-from .types import Binary # noqa
from .types import BLOB # noqa
from .types import BOOLEAN # noqa
from .types import Boolean # noqa
diff --git a/lib/sqlalchemy/dialects/__init__.py b/lib/sqlalchemy/dialects/__init__.py
index 4407ab62d..9b46a4d0c 100644
--- a/lib/sqlalchemy/dialects/__init__.py
+++ b/lib/sqlalchemy/dialects/__init__.py
@@ -18,9 +18,6 @@ __all__ = (
from .. import util
-_translates = {"postgres": "postgresql"}
-
-
def _auto_fn(name):
"""default dialect importer.
@@ -34,13 +31,6 @@ def _auto_fn(name):
dialect = name
driver = "base"
- if dialect in _translates:
- translated = _translates[dialect]
- util.warn_deprecated(
- "The '%s' dialect name has been "
- "renamed to '%s'" % (dialect, translated)
- )
- dialect = translated
try:
module = __import__("sqlalchemy.dialects.%s" % (dialect,)).dialects
except ImportError:
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index 69e6834d2..a7086259b 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -2061,7 +2061,8 @@ class MSDDLCompiler(compiler.DDLCompiler):
"will correspond to an actual SQL Server "
"CREATE SEQUENCE in "
"a future release. Please use the mssql_identity_start "
- "and mssql_identity_increment parameters."
+ "and mssql_identity_increment parameters.",
+ version="1.3",
)
if column.default.start == 0:
start = 0
@@ -2225,7 +2226,8 @@ class MSIdentifierPreparer(compiler.IdentifierPreparer):
"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()."
+ "quoted_name().",
+ version="1.3",
)
dbname, owner = _schema_elements(schema)
diff --git a/lib/sqlalchemy/dialects/mysql/__init__.py b/lib/sqlalchemy/dialects/mysql/__init__.py
index f1f1cce37..683d43877 100644
--- a/lib/sqlalchemy/dialects/mysql/__init__.py
+++ b/lib/sqlalchemy/dialects/mysql/__init__.py
@@ -7,7 +7,6 @@
from . import base # noqa
from . import cymysql # noqa
-from . import gaerdbms # noqa
from . import mysqlconnector # noqa
from . import mysqldb # noqa
from . import oursql # noqa
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py
index 54a13b550..a075b4d6b 100644
--- a/lib/sqlalchemy/dialects/mysql/base.py
+++ b/lib/sqlalchemy/dialects/mysql/base.py
@@ -2141,14 +2141,10 @@ class MySQLTypeCompiler(compiler.GenericTypeCompiler):
)
def visit_ENUM(self, type_, **kw):
- return self._visit_enumerated_values(
- "ENUM", type_, type_._enumerated_values
- )
+ return self._visit_enumerated_values("ENUM", type_, type_.enums)
def visit_SET(self, type_, **kw):
- return self._visit_enumerated_values(
- "SET", type_, type_._enumerated_values
- )
+ return self._visit_enumerated_values("SET", type_, type_.values)
def visit_BOOLEAN(self, type_, **kw):
return "BOOL"
diff --git a/lib/sqlalchemy/dialects/mysql/enumerated.py b/lib/sqlalchemy/dialects/mysql/enumerated.py
index 536d03876..2bc25585e 100644
--- a/lib/sqlalchemy/dialects/mysql/enumerated.py
+++ b/lib/sqlalchemy/dialects/mysql/enumerated.py
@@ -12,53 +12,10 @@ from ... import exc
from ... import sql
from ... import util
from ...sql import sqltypes
+from ...sql.base import NO_ARG
-class _EnumeratedValues(_StringType):
- def _init_values(self, values, kw):
- self.quoting = kw.pop("quoting", "auto")
-
- if self.quoting == "auto" and len(values):
- # What quoting character are we using?
- q = None
- for e in values:
- if len(e) == 0:
- self.quoting = "unquoted"
- break
- elif q is None:
- q = e[0]
-
- if len(e) == 1 or e[0] != q or e[-1] != q:
- self.quoting = "unquoted"
- break
- else:
- self.quoting = "quoted"
-
- if self.quoting == "quoted":
- util.warn_deprecated(
- "Manually quoting %s value literals is deprecated. Supply "
- "unquoted values and use the quoting= option in cases of "
- "ambiguity." % self.__class__.__name__
- )
-
- values = self._strip_values(values)
-
- self._enumerated_values = values
- length = max([len(v) for v in values] + [0])
- return values, length
-
- @classmethod
- def _strip_values(cls, values):
- strip_values = []
- for a in values:
- if a[0:1] == '"' or a[0:1] == "'":
- # strip enclosing quotes and unquote interior
- a = a[1:-1].replace(a[0] * 2, a[0])
- strip_values.append(a)
- return strip_values
-
-
-class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _EnumeratedValues):
+class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _StringType):
"""MySQL ENUM type."""
__visit_name__ = "ENUM"
@@ -72,10 +29,10 @@ class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _EnumeratedValues):
Column('myenum', ENUM("foo", "bar", "baz"))
- :param enums: The range of valid values for this ENUM. Values will be
- quoted when generating the schema according to the quoting flag (see
- below). This object may also be a PEP-435-compliant enumerated
- type.
+ :param enums: The range of valid values for this ENUM. Values in
+ enums are not quoted, they will be escaped and surrounded by single
+ quotes when generating the schema. This object may also be a
+ PEP-435-compliant enumerated type.
.. versionadded: 1.1 added support for PEP-435-compliant enumerated
types.
@@ -102,22 +59,15 @@ class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _EnumeratedValues):
BINARY in schema. This does not affect the type of data stored,
only the collation of character data.
- :param quoting: Defaults to 'auto': automatically determine enum value
- quoting. If all enum values are surrounded by the same quoting
- character, then use 'quoted' mode. Otherwise, use 'unquoted' mode.
-
- 'quoted': values in enums are already quoted, they will be used
- directly when generating the schema - this usage is deprecated.
-
- 'unquoted': values in enums are not quoted, they will be escaped and
- surrounded by single quotes when generating the schema.
-
- Previous versions of this type always required manually quoted
- values to be supplied; future versions will always quote the string
- literals for you. This is a transitional option.
+ :param quoting: Not used. A warning will be raised if provided.
"""
-
+ if kw.pop("quoting", NO_ARG) is not NO_ARG:
+ util.warn_deprecated_20(
+ "The 'quoting' parameter to :class:`.mysql.ENUM` is deprecated"
+ " and will be removed in a future release. "
+ "This parameter now has no effect."
+ )
kw.pop("strict", None)
self._enum_init(enums, kw)
_StringType.__init__(self, length=self.length, **kw)
@@ -132,10 +82,6 @@ class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _EnumeratedValues):
kw.setdefault("values_callable", impl.values_callable)
return cls(**kw)
- def _setup_for_values(self, values, objects, kw):
- values, length = self._init_values(values, kw)
- return super(ENUM, self)._setup_for_values(values, objects, kw)
-
def _object_value_for_elem(self, elem):
# mysql sends back a blank string for any value that
# was persisted that was not in the enums; that is, it does no
@@ -152,7 +98,7 @@ class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _EnumeratedValues):
)
-class SET(_EnumeratedValues):
+class SET(_StringType):
"""MySQL SET type."""
__visit_name__ = "SET"
@@ -169,7 +115,9 @@ class SET(_EnumeratedValues):
set will be used to generate DDL for a table, or if the
:paramref:`.SET.retrieve_as_bitwise` flag is set to True.
- :param values: The range of valid values for this SET.
+ :param values: The range of valid values for this SET. The values
+ are not quoted, they will be escaped and surrounded by single
+ quotes when generating the schema.
:param convert_unicode: Same flag as that of
:paramref:`.String.convert_unicode`.
@@ -184,22 +132,6 @@ class SET(_EnumeratedValues):
:param binary: same as that of :paramref:`.VARCHAR.binary`.
- :param quoting: Defaults to 'auto': automatically determine set value
- quoting. If all values are surrounded by the same quoting
- character, then use 'quoted' mode. Otherwise, use 'unquoted' mode.
-
- 'quoted': values in enums are already quoted, they will be used
- directly when generating the schema - this usage is deprecated.
-
- 'unquoted': values in enums are not quoted, they will be escaped and
- surrounded by single quotes when generating the schema.
-
- Previous versions of this type always required manually quoted
- values to be supplied; future versions will always quote the string
- literals for you. This is a transitional option.
-
- .. versionadded:: 0.9.0
-
:param retrieve_as_bitwise: if True, the data for the set type will be
persisted and selected using an integer value, where a set is coerced
into a bitwise mask for persistence. MySQL allows this mode which
@@ -218,10 +150,16 @@ class SET(_EnumeratedValues):
.. versionadded:: 1.0.0
+ :param quoting: Not used. A warning will be raised if passed.
"""
+ if kw.pop("quoting", NO_ARG) is not NO_ARG:
+ util.warn_deprecated_20(
+ "The 'quoting' parameter to :class:`.mysql.SET` is deprecated"
+ " and will be removed in a future release. "
+ "This parameter now has no effect."
+ )
self.retrieve_as_bitwise = kw.pop("retrieve_as_bitwise", False)
- values, length = self._init_values(values, kw)
self.values = tuple(values)
if not self.retrieve_as_bitwise and "" in values:
raise exc.ArgumentError(
@@ -235,6 +173,7 @@ class SET(_EnumeratedValues):
self._bitmap.update(
(2 ** idx, value) for idx, value in enumerate(self.values)
)
+ length = max([len(v) for v in values] + [0])
kw.setdefault("length", length)
super(SET, self).__init__(**kw)
diff --git a/lib/sqlalchemy/dialects/mysql/gaerdbms.py b/lib/sqlalchemy/dialects/mysql/gaerdbms.py
deleted file mode 100644
index 0ba819d2d..000000000
--- a/lib/sqlalchemy/dialects/mysql/gaerdbms.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# mysql/gaerdbms.py
-# Copyright (C) 2005-2020 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
-r"""
-.. dialect:: mysql+gaerdbms
- :name: Google Cloud SQL
- :dbapi: rdbms
- :connectstring: mysql+gaerdbms:///<dbname>?instance=<instancename>
- :url: https://developers.google.com/appengine/docs/python/cloud-sql/developers-guide
-
- This dialect is based primarily on the :mod:`.mysql.mysqldb` dialect with
- minimal changes.
-
- .. deprecated:: 1.0 This dialect is **no longer necessary** for
- Google Cloud SQL; the MySQLdb dialect can be used directly.
- Cloud SQL now recommends creating connections via the
- mysql dialect using the URL format
-
- ``mysql+mysqldb://root@/<dbname>?unix_socket=/cloudsql/<projectid>:<instancename>``
-
-
-Pooling
--------
-
-Google App Engine connections appear to be randomly recycled,
-so the dialect does not pool connections. The :class:`.NullPool`
-implementation is installed within the :class:`.Engine` by
-default.
-
-""" # noqa
-
-import os
-import re
-
-from sqlalchemy.util import warn_deprecated
-from .mysqldb import MySQLDialect_mysqldb
-from ...pool import NullPool
-
-
-def _is_dev_environment():
- return os.environ.get("SERVER_SOFTWARE", "").startswith("Development/")
-
-
-class MySQLDialect_gaerdbms(MySQLDialect_mysqldb):
- @classmethod
- def dbapi(cls):
-
- warn_deprecated(
- "Google Cloud SQL now recommends creating connections via the "
- "MySQLdb dialect directly, using the URL format "
- "mysql+mysqldb://root@/<dbname>?unix_socket=/cloudsql/"
- "<projectid>:<instancename>"
- )
-
- # from django:
- # http://code.google.com/p/googleappengine/source/
- # browse/trunk/python/google/storage/speckle/
- # python/django/backend/base.py#118
- # see also [ticket:2649]
- # see also http://stackoverflow.com/q/14224679/34549
- from google.appengine.api import apiproxy_stub_map
-
- if _is_dev_environment():
- from google.appengine.api import rdbms_mysqldb
-
- return rdbms_mysqldb
- elif apiproxy_stub_map.apiproxy.GetStub("rdbms"):
- from google.storage.speckle.python.api import rdbms_apiproxy
-
- return rdbms_apiproxy
- else:
- from google.storage.speckle.python.api import rdbms_googleapi
-
- return rdbms_googleapi
-
- @classmethod
- def get_pool_class(cls, url):
- # Cloud SQL connections die at any moment
- return NullPool
-
- def create_connect_args(self, url):
- opts = url.translate_connect_args()
- if not _is_dev_environment():
- # 'dsn' and 'instance' are because we are skipping
- # the traditional google.api.rdbms wrapper
- opts["dsn"] = ""
- opts["instance"] = url.query["instance"]
- return [], opts
-
- def _extract_error_code(self, exception):
- match = re.compile(r"^(\d+)L?:|^\((\d+)L?,").match(str(exception))
- # The rdbms api will wrap then re-raise some types of errors
- # making this regex return no matches.
- code = match.group(1) or match.group(2) if match else None
- if code:
- return int(code)
-
-
-dialect = MySQLDialect_gaerdbms
diff --git a/lib/sqlalchemy/dialects/mysql/reflection.py b/lib/sqlalchemy/dialects/mysql/reflection.py
index 8aeb1dc96..5be6a010e 100644
--- a/lib/sqlalchemy/dialects/mysql/reflection.py
+++ b/lib/sqlalchemy/dialects/mysql/reflection.py
@@ -7,7 +7,7 @@
import re
-from .enumerated import _EnumeratedValues
+from .enumerated import ENUM
from .enumerated import SET
from .types import DATETIME
from .types import TIME
@@ -215,8 +215,8 @@ class MySQLTableDefinitionParser(object):
for kw in ("charset", "collate"):
if spec.get(kw, False):
type_kw[kw] = spec[kw]
- if issubclass(col_type, _EnumeratedValues):
- type_args = _EnumeratedValues._strip_values(type_args)
+ if issubclass(col_type, (ENUM, SET)):
+ type_args = _strip_values(type_args)
if issubclass(col_type, SET) and "" in type_args:
type_kw["retrieve_as_bitwise"] = True
@@ -545,3 +545,14 @@ def _re_compile(regex):
"""Compile a string to regex, I and UNICODE."""
return re.compile(regex, re.I | re.UNICODE)
+
+
+def _strip_values(values):
+ "Strip reflected values quotes"
+ strip_values = []
+ for a in values:
+ if a[0:1] == '"' or a[0:1] == "'":
+ # strip enclosing quotes and unquote interior
+ a = a[1:-1].replace(a[0] * 2, a[0])
+ strip_values.append(a)
+ return strip_values
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index 3a3bbad25..2ac5510d1 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -1003,12 +1003,12 @@ 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(
"cx_oracle dialect option %r should only be passed to "
- "create_engine directly, not within the URL string" % opt
+ "create_engine directly, not within the URL string" % opt,
+ version="1.3",
)
util.coerce_kw_type(opts, opt, bool)
setattr(self, opt, opts.pop(opt))
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 34a4f04a9..1a5562a9b 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -1449,9 +1449,6 @@ class Connection(Connectable):
):
exc_info = sys.exc_info()
- if context and context.exception is None:
- context.exception = e
-
is_exit_exception = not isinstance(e, Exception)
if not self._is_disconnect:
@@ -1465,9 +1462,6 @@ class Connection(Connectable):
)
) or (is_exit_exception and not self.closed)
- if context:
- context.is_disconnect = self._is_disconnect
-
invalidate_pool_on_disconnect = not is_exit_exception
if self._reentrant_error:
@@ -1519,13 +1513,6 @@ class Connection(Connectable):
) and not self._execution_options.get(
"skip_user_error_events", False
):
- # legacy dbapi_error event
- if should_wrap and context:
- self.dispatch.dbapi_error(
- self, cursor, statement, parameters, context, e
- )
-
- # new handle_error event
ctx = ExceptionContextImpl(
e,
sqlalchemy_exception,
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index a896dfc73..43ebce83a 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -451,17 +451,6 @@ class DefaultDialect(interfaces.Dialect):
"""
return sqltypes.adapt_type(typeobj, self.colspecs)
- def get_pk_constraint(self, conn, table_name, schema=None, **kw):
- """Compatibility method, adapts the result of get_primary_keys()
- for those dialects which don't implement get_pk_constraint().
-
- """
- return {
- "constrained_columns": self.get_primary_keys(
- conn, table_name, schema=schema, **kw
- )
- }
-
def has_index(self, connection, table_name, index_name, schema=None):
if not self.has_table(connection, table_name, schema=schema):
return False
diff --git a/lib/sqlalchemy/engine/events.py b/lib/sqlalchemy/engine/events.py
index 638048e6f..32292c826 100644
--- a/lib/sqlalchemy/engine/events.py
+++ b/lib/sqlalchemy/engine/events.py
@@ -11,7 +11,6 @@ from .interfaces import Connectable
from .interfaces import Dialect
from .. import event
from .. import exc
-from .. import util
class ConnectionEvents(event.Events):
@@ -42,10 +41,9 @@ class ConnectionEvents(event.Events):
log.info("Received statement: %s", statement)
When the methods are called with a `statement` parameter, such as in
- :meth:`.after_cursor_execute`, :meth:`.before_cursor_execute` and
- :meth:`.dbapi_error`, the statement is the exact SQL string that was
- prepared for transmission to the DBAPI ``cursor`` in the connection's
- :class:`.Dialect`.
+ :meth:`.after_cursor_execute` or :meth:`.before_cursor_execute`,
+ the statement is the exact SQL string that was prepared for transmission
+ to the DBAPI ``cursor`` in the connection's :class:`.Dialect`.
The :meth:`.before_execute` and :meth:`.before_cursor_execute`
events can also be established with the ``retval=True`` flag, which
@@ -245,58 +243,6 @@ 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
- ):
- """Intercept a raw DBAPI error.
-
- This event is called with the DBAPI exception instance
- received from the DBAPI itself, *before* SQLAlchemy wraps the
- exception with it's own exception wrappers, and before any
- other operations are performed on the DBAPI cursor; the
- existing transaction remains in effect as well as any state
- on the cursor.
-
- The use case here is to inject low-level exception handling
- into an :class:`.Engine`, typically for logging and
- debugging purposes.
-
- .. warning::
-
- Code should **not** modify
- any state or throw any exceptions here as this will
- interfere with SQLAlchemy's cleanup and error handling
- routines. For exception modification, please refer to the
- new :meth:`.ConnectionEvents.handle_error` event.
-
- Subsequent to this hook, SQLAlchemy may attempt any
- number of operations on the connection/cursor, including
- closing the cursor, rolling back of the transaction in the
- case of connectionless execution, and disposing of the entire
- connection pool if a "disconnect" was detected. The
- exception is then wrapped in a SQLAlchemy DBAPI exception
- wrapper and re-thrown.
-
- :param conn: :class:`.Connection` object
- :param cursor: DBAPI cursor object
- :param statement: string SQL statement, as passed to the DBAPI
- :param parameters: Dictionary, tuple, or list of parameters being
- passed to the ``execute()`` or ``executemany()`` method of the
- DBAPI ``cursor``. In some cases may be ``None``.
- :param context: :class:`.ExecutionContext` object in use. May
- be ``None``.
- :param exception: The **unwrapped** exception emitted directly from the
- DBAPI. The class here is specific to the DBAPI module in use.
-
- """
-
def handle_error(self, exception_context):
r"""Intercept all exceptions processed by the :class:`.Connection`.
diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py
index 84def853f..6cf4d7dbd 100644
--- a/lib/sqlalchemy/engine/interfaces.py
+++ b/lib/sqlalchemy/engine/interfaces.py
@@ -245,19 +245,6 @@ 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`.
-
- """
-
- raise NotImplementedError()
-
def get_pk_constraint(self, connection, table_name, schema=None, **kw):
"""Return information about the primary key constraint on
table_name`.
@@ -1094,40 +1081,6 @@ class ExecutionContext(object):
and updates.
"""
- exception = None
- """A DBAPI-level exception that was caught when this ExecutionContext
- attempted to execute a statement.
-
- This attribute is meaningful only within the
- :meth:`.ConnectionEvents.dbapi_error` event.
-
- .. versionadded:: 0.9.7
-
- .. seealso::
-
- :attr:`.ExecutionContext.is_disconnect`
-
- :meth:`.ConnectionEvents.dbapi_error`
-
- """
-
- is_disconnect = None
- """Boolean flag set to True or False when a DBAPI-level exception
- is caught when this ExecutionContext attempted to execute a statement.
-
- This attribute is meaningful only within the
- :meth:`.ConnectionEvents.dbapi_error` event.
-
- .. versionadded:: 0.9.7
-
- .. seealso::
-
- :attr:`.ExecutionContext.exception`
-
- :meth:`.ConnectionEvents.dbapi_error`
-
- """
-
def create_cursor(self):
"""Return a new cursor generated from this ExecutionContext's
connection.
diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py
index 8ef0d572f..85e671421 100644
--- a/lib/sqlalchemy/engine/reflection.py
+++ b/lib/sqlalchemy/engine/reflection.py
@@ -37,7 +37,6 @@ from .. import util
from ..sql import operators
from ..sql import schema as sa_schema
from ..sql.type_api import TypeEngine
-from ..util import deprecated
from ..util import topological
@@ -463,24 +462,6 @@ class Inspector(object):
col_def["type"] = coltype()
return col_defs
- @deprecated(
- "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.",
- )
- def get_primary_keys(self, table_name, schema=None, **kw):
- """Return information about primary keys in `table_name`.
-
- Given a string `table_name`, and an optional string `schema`, return
- primary key information as a list of column names.
- """
-
- with self._operation_context() as conn:
- return self.dialect.get_pk_constraint(
- conn, table_name, schema, info_cache=self.info_cache, **kw
- )["constrained_columns"]
-
def get_pk_constraint(self, table_name, schema=None, **kw):
"""Return information about primary key constraint on `table_name`.
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index 986edd617..ba998aff0 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -687,13 +687,13 @@ class LegacyCursorResultMetaData(CursorResultMetaData):
def _contains(self, value, row):
key = value
if key in self._keymap:
- util.warn_deprecated(
+ util.warn_deprecated_20(
"Using the 'in' operator to test for string or column "
"keys, or integer indexes, in a :class:`.Row` object is "
"deprecated and will "
"be removed in a future release. "
"Use the `Row._fields` or `Row._mapping` attribute, i.e. "
- "'key in row._fields'"
+ "'key in row._fields'",
)
return True
else:
@@ -743,7 +743,8 @@ class LegacyCursorResultMetaData(CursorResultMetaData):
"Retreiving row values using Column objects from a "
"row that was unpickled is deprecated; adequate "
"state cannot be pickled for this to be efficient. "
- "This usage will raise KeyError in a future release."
+ "This usage will raise KeyError in a future release.",
+ version="1.4",
)
else:
util.warn_deprecated(
@@ -751,7 +752,8 @@ class LegacyCursorResultMetaData(CursorResultMetaData):
"matching names as keys is deprecated, and will raise "
"KeyError in a future release; only Column "
"objects that are explicitly part of the statement "
- "object should be used."
+ "object should be used.",
+ version="1.4",
)
if result is None:
if raiseerr:
diff --git a/lib/sqlalchemy/exc.py b/lib/sqlalchemy/exc.py
index cc096ad03..a6da844dc 100644
--- a/lib/sqlalchemy/exc.py
+++ b/lib/sqlalchemy/exc.py
@@ -589,6 +589,9 @@ class NotSupportedError(DatabaseError):
class SADeprecationWarning(DeprecationWarning):
"""Issued for usage of deprecated APIs."""
+ deprecated_since = None
+ "Indicates the version that started raising this deprecation warning"
+
class RemovedIn20Warning(SADeprecationWarning):
"""Issued for usage of APIs specifically deprecated in SQLAlchemy 2.0.
@@ -599,6 +602,9 @@ class RemovedIn20Warning(SADeprecationWarning):
"""
+ deprecated_since = "1.4"
+ "Indicates the version that started raising this deprecation warning"
+
class SAPendingDeprecationWarning(PendingDeprecationWarning):
"""A similar warning as :class:`.SADeprecationWarning`, this warning
@@ -606,6 +612,9 @@ class SAPendingDeprecationWarning(PendingDeprecationWarning):
"""
+ deprecated_since = None
+ "Indicates the version that started raising this deprecation warning"
+
class SAWarning(RuntimeWarning):
"""Issued at runtime."""
diff --git a/lib/sqlalchemy/ext/declarative/__init__.py b/lib/sqlalchemy/ext/declarative/__init__.py
index d79dd1960..6dc4d23c8 100644
--- a/lib/sqlalchemy/ext/declarative/__init__.py
+++ b/lib/sqlalchemy/ext/declarative/__init__.py
@@ -7,7 +7,6 @@
from .api import AbstractConcreteBase
from .api import as_declarative
-from .api import comparable_using
from .api import ConcreteBase
from .api import declarative_base
from .api import DeclarativeMeta
@@ -22,7 +21,6 @@ __all__ = [
"declarative_base",
"synonym_for",
"has_inherited_table",
- "comparable_using",
"instrument_declarative",
"declared_attr",
"as_declarative",
diff --git a/lib/sqlalchemy/ext/declarative/api.py b/lib/sqlalchemy/ext/declarative/api.py
index ca7d3a022..b1574339d 100644
--- a/lib/sqlalchemy/ext/declarative/api.py
+++ b/lib/sqlalchemy/ext/declarative/api.py
@@ -20,7 +20,6 @@ from ... import exc
from ... import inspection
from ... import util
from ...orm import attributes
-from ...orm import comparable_property
from ...orm import exc as orm_exc
from ...orm import interfaces
from ...orm import relationships
@@ -122,31 +121,6 @@ def synonym_for(name, map_column=False):
return decorate
-def comparable_using(comparator_factory):
- """Decorator, allow a Python @property to be used in query criteria.
-
- This is a decorator front end to
- :func:`~sqlalchemy.orm.comparable_property` that passes
- through the comparator_factory and the function being decorated::
-
- @comparable_using(MyComparatorType)
- @property
- def prop(self):
- return 'special sauce'
-
- The regular ``comparable_property()`` is also usable directly in a
- declarative setting and may be convenient for read/write properties::
-
- prop = comparable_property(MyComparatorType)
-
- """
-
- def decorate(fn):
- return comparable_property(comparator_factory, fn)
-
- return decorate
-
-
class declared_attr(interfaces._MappedAttribute, property):
"""Mark a class-level method as representing the definition of
a mapped property or special declarative member name.
diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py
index 314e96cf1..9b72fe8ab 100644
--- a/lib/sqlalchemy/ext/declarative/base.py
+++ b/lib/sqlalchemy/ext/declarative/base.py
@@ -288,8 +288,7 @@ class _MapperConfig(object):
"on declarative mixin classes."
)
elif isinstance(obj, declarative_props):
- oldclassprop = isinstance(obj, util.classproperty)
- if not oldclassprop and obj._cascading:
+ if obj._cascading:
if name in dict_:
# unfortunately, while we can use the user-
# defined attribute here to allow a clean
@@ -309,11 +308,6 @@ class _MapperConfig(object):
] = ret = obj.__get__(obj, cls)
setattr(cls, name, ret)
else:
- if oldclassprop:
- util.warn_deprecated(
- "Use of sqlalchemy.util.classproperty on "
- "declarative classes is deprecated."
- )
# access attribute using normal class access
ret = getattr(cls, name)
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 83edb0ff5..d08b35a2e 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -16,7 +16,6 @@ documentation for an overview of how this module is used.
from . import exc # noqa
from . import mapper as mapperlib # noqa
from . import strategy_options
-from .descriptor_props import ComparableProperty # noqa
from .descriptor_props import CompositeProperty # noqa
from .descriptor_props import SynonymProperty # noqa
from .interfaces import EXT_CONTINUE # noqa
@@ -194,23 +193,6 @@ mapper = public_factory(Mapper, ".orm.mapper")
synonym = public_factory(SynonymProperty, ".orm.synonym")
-comparable_property = public_factory(
- ComparableProperty, ".orm.comparable_property"
-)
-
-
-@_sa_util.deprecated(
- "0.7",
- message=":func:`.compile_mappers` is deprecated and will be removed "
- "in a future release. Please use :func:`.configure_mappers`",
-)
-def compile_mappers():
- """Initialize the inter-mapper relationships of all mappers that have
- been defined.
-
- """
- configure_mappers()
-
def clear_mappers():
"""Remove all mappers from all classes.
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 5ca2858e9..2bacb25b0 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -1811,18 +1811,6 @@ def get_history(obj, key, passive=PASSIVE_OFF):
using loader callables if the value is not locally present.
"""
- if passive is True:
- util.warn_deprecated(
- "Passing True for 'passive' is deprecated. "
- "Use attributes.PASSIVE_NO_INITIALIZE"
- )
- passive = PASSIVE_NO_INITIALIZE
- elif passive is False:
- util.warn_deprecated(
- "Passing False for 'passive' is "
- "deprecated. Use attributes.PASSIVE_OFF"
- )
- passive = PASSIVE_OFF
return get_state_history(instance_state(obj), key, passive)
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
index cfafea0fc..9d68179e5 100644
--- a/lib/sqlalchemy/orm/collections.py
+++ b/lib/sqlalchemy/orm/collections.py
@@ -301,7 +301,7 @@ class collection(object):
The decorators fall into two groups: annotations and interception recipes.
- The annotating decorators (appender, remover, iterator, linker, converter,
+ The annotating decorators (appender, remover, iterator, converter,
internally_instrumented) indicate the method's purpose and take no
arguments. They are not written with parens::
@@ -430,36 +430,6 @@ class collection(object):
@staticmethod
@util.deprecated(
- "1.0",
- "The :meth:`.collection.linker` handler is deprecated and will "
- "be removed in a future release. Please refer to the "
- ":meth:`.AttributeEvents.init_collection` "
- "and :meth:`.AttributeEvents.dispose_collection` event handlers. ",
- )
- def linker(fn):
- """Tag the method as a "linked to attribute" event handler.
-
- This optional event handler will be called when the collection class
- is linked to or unlinked from the InstrumentedAttribute. It is
- invoked immediately after the '_sa_adapter' property is set on
- the instance. A single argument is passed: the collection adapter
- that has been linked, or None if unlinking.
-
-
- """
- fn._sa_instrument_role = "linker"
- return fn
-
- link = linker
- """Synonym for :meth:`.collection.linker`.
-
- .. deprecated:: 1.0 - :meth:`.collection.link` is deprecated and will be
- removed in a future release.
-
- """
-
- @staticmethod
- @util.deprecated(
"1.3",
"The :meth:`.collection.converter` handler is deprecated and will "
"be removed in a future release. Please refer to the "
@@ -946,7 +916,6 @@ def _locate_roles_and_methods(cls):
"appender",
"remover",
"iterator",
- "linker",
"converter",
)
roles.setdefault(role, name)
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index c2067c228..3bc009da8 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -705,90 +705,3 @@ class SynonymProperty(DescriptorProperty):
p._mapped_by_synonym = self.key
self.parent = parent
-
-
-@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."""
-
- def __init__(
- self, comparator_factory, descriptor=None, doc=None, info=None
- ):
- """Provides a method of applying a :class:`.PropComparator`
- to any Python descriptor attribute.
-
-
- Allows any Python descriptor to behave like a SQL-enabled
- attribute when used at the class level in queries, allowing
- redefinition of expression operator behavior.
-
- In the example below we redefine :meth:`.PropComparator.operate`
- to wrap both sides of an expression in ``func.lower()`` to produce
- case-insensitive comparison::
-
- from sqlalchemy.orm import comparable_property
- from sqlalchemy.orm.interfaces import PropComparator
- from sqlalchemy.sql import func
- from sqlalchemy import Integer, String, Column
- from sqlalchemy.ext.declarative import declarative_base
-
- class CaseInsensitiveComparator(PropComparator):
- def __clause_element__(self):
- return self.prop
-
- def operate(self, op, other):
- return op(
- func.lower(self.__clause_element__()),
- func.lower(other)
- )
-
- Base = declarative_base()
-
- class SearchWord(Base):
- __tablename__ = 'search_word'
- id = Column(Integer, primary_key=True)
- word = Column(String)
- word_insensitive = comparable_property(lambda prop, mapper:
- CaseInsensitiveComparator(
- mapper.c.word, mapper)
- )
-
-
- A mapping like the above allows the ``word_insensitive`` attribute
- to render an expression like::
-
- >>> print(SearchWord.word_insensitive == "Trucks")
- lower(search_word.word) = lower(:lower_1)
-
- :param comparator_factory:
- A PropComparator subclass or factory that defines operator behavior
- for this property.
-
- :param descriptor:
- Optional when used in a ``properties={}`` declaration. The Python
- descriptor or property to layer comparison behavior on top of.
-
- The like-named descriptor will be automatically retrieved from the
- mapped class if left blank in a ``properties`` declaration.
-
- :param info: Optional data dictionary which will be populated into the
- :attr:`.InspectionAttr.info` attribute of this object.
-
- .. versionadded:: 1.0.0
-
- """
- super(ComparableProperty, self).__init__()
- self.descriptor = descriptor
- self.comparator_factory = comparator_factory
- self.doc = doc or (descriptor and descriptor.__doc__) or None
- if info:
- self.info = info
- util.set_creation_order(self)
-
- def _comparator_factory(self, mapper):
- return self.comparator_factory(self, mapper)
diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py
index 64f09ea2f..a41ea49e8 100644
--- a/lib/sqlalchemy/orm/events.py
+++ b/lib/sqlalchemy/orm/events.py
@@ -2472,9 +2472,8 @@ class AttributeEvents(event.Events):
:param collection_adapter: the :class:`.CollectionAdapter` that will
mediate internal access to the collection.
- .. versionadded:: 1.0.0 the :meth:`.AttributeEvents.init_collection`
- and :meth:`.AttributeEvents.dispose_collection` events supersede
- the :class:`.orm.collection.linker` hook.
+ .. versionadded:: 1.0.0 :meth:`.AttributeEvents.init_collection`
+ and :meth:`.AttributeEvents.dispose_collection` events.
.. seealso::
@@ -2504,8 +2503,7 @@ class AttributeEvents(event.Events):
would be empty.
.. versionadded:: 1.0.0 the :meth:`.AttributeEvents.init_collection`
- and :meth:`.AttributeEvents.dispose_collection` events supersede
- the :class:`.collection.linker` hook.
+ and :meth:`.AttributeEvents.dispose_collection` events.
.. seealso::
diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py
index e8e39346e..e4795a92d 100644
--- a/lib/sqlalchemy/orm/identity.py
+++ b/lib/sqlalchemy/orm/identity.py
@@ -7,7 +7,6 @@
import weakref
-from . import attributes
from . import util as orm_util
from .. import exc as sa_exc
from .. import util
@@ -239,128 +238,3 @@ class WeakInstanceDict(IdentityMap):
if st is state:
self._dict.pop(state.key, None)
self._manage_removed_state(state)
-
- def prune(self):
- return 0
-
-
-class StrongInstanceDict(IdentityMap):
- """A 'strong-referencing' version of the identity map.
-
- .. deprecated 1.1::
- The strong
- reference identity map is legacy. See the
- recipe at :ref:`session_referencing_behavior` for
- an event-based approach to maintaining strong identity
- references.
-
-
- """
-
- if util.py2k:
-
- def itervalues(self):
- return self._dict.itervalues()
-
- def iteritems(self):
- return self._dict.iteritems()
-
- def __iter__(self):
- return iter(self.dict_)
-
- def __getitem__(self, key):
- return self._dict[key]
-
- def __contains__(self, key):
- return key in self._dict
-
- def get(self, key, default=None):
- return self._dict.get(key, default)
-
- def values(self):
- return self._dict.values()
-
- def items(self):
- return self._dict.items()
-
- def all_states(self):
- return [attributes.instance_state(o) for o in self.values()]
-
- def contains_state(self, state):
- return (
- state.key in self
- and attributes.instance_state(self[state.key]) is state
- )
-
- def replace(self, state):
- if state.key in self._dict:
- existing = self._dict[state.key]
- existing = attributes.instance_state(existing)
- if existing is not state:
- self._manage_removed_state(existing)
- else:
- return
- else:
- existing = None
-
- self._dict[state.key] = state.obj()
- self._manage_incoming_state(state)
- return existing
-
- def add(self, state):
- if state.key in self:
- if attributes.instance_state(self._dict[state.key]) is not state:
- raise sa_exc.InvalidRequestError(
- "Can't attach instance "
- "%s; another instance with key %s is already "
- "present in this session."
- % (orm_util.state_str(state), state.key)
- )
- return False
- else:
- self._dict[state.key] = state.obj()
- self._manage_incoming_state(state)
- return True
-
- def _add_unpresent(self, state, key):
- # inlined form of add() called by loading.py
- self._dict[key] = state.obj()
- state._instance_dict = self._wr
-
- def _fast_discard(self, state):
- # used by InstanceState for state being
- # GC'ed, inlines _managed_removed_state
- try:
- obj = self._dict[state.key]
- except KeyError:
- # catch gc removed the key after we just checked for it
- pass
- else:
- if attributes.instance_state(obj) is state:
- self._dict.pop(state.key, None)
-
- def discard(self, state):
- self.safe_discard(state)
-
- def safe_discard(self, state):
- if state.key in self._dict:
- obj = self._dict[state.key]
- st = attributes.instance_state(obj)
- if st is state:
- self._dict.pop(state.key, None)
- self._manage_removed_state(state)
-
- def prune(self):
- """prune unreferenced, non-dirty states."""
-
- ref_count = len(self)
- dirty = [s.obj() for s in self.all_states() if s.modified]
-
- # work around http://bugs.python.org/issue6149
- keepers = weakref.WeakValueDictionary()
- keepers.update(self)
-
- self._dict.clear()
- self._dict.update(keepers)
- self.modified = bool(dirty)
- return ref_count - len(self)
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index f4e20afdf..3e4c3a5d5 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -107,13 +107,6 @@ class Mapper(sql_base.HasCacheKey, InspectionAttr):
_dispose_called = False
@util.deprecated_params(
- 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.",
- ),
non_primary=(
"1.3",
"The :paramref:`.mapper.non_primary` parameter is deprecated, "
@@ -133,7 +126,6 @@ class Mapper(sql_base.HasCacheKey, InspectionAttr):
inherits=None,
inherit_condition=None,
inherit_foreign_keys=None,
- order_by=False,
always_refresh=False,
version_id_col=None,
version_id_generator=None,
@@ -341,11 +333,6 @@ class Mapper(sql_base.HasCacheKey, InspectionAttr):
:ref:`relationship_non_primary_mapper`
- :param order_by: A single :class:`.Column` or list of :class:`.Column`
- objects for which selection operations should use as the default
- ordering for entities. By default mappers have no pre-defined
- ordering.
-
: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,11 +591,6 @@ class Mapper(sql_base.HasCacheKey, InspectionAttr):
self._primary_key_argument = util.to_list(primary_key)
self.non_primary = non_primary
- if order_by is not False:
- self.order_by = util.to_list(order_by)
- else:
- self.order_by = order_by
-
self.always_refresh = always_refresh
if isinstance(version_id_col, MapperProperty):
@@ -1065,13 +1047,6 @@ class Mapper(sql_base.HasCacheKey, InspectionAttr):
)
)
- if (
- self.order_by is False
- and not self.concrete
- and self.inherits.order_by is not False
- ):
- self.order_by = self.inherits.order_by
-
self.polymorphic_map = self.inherits.polymorphic_map
self.batch = self.inherits.batch
self.inherits._inheriting_mappers.append(self)
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index aa9dd3274..05904d1a9 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -14,7 +14,6 @@ mapped attributes.
from __future__ import absolute_import
from . import attributes
-from .descriptor_props import ComparableProperty
from .descriptor_props import CompositeProperty
from .descriptor_props import ConcreteInheritedProperty
from .descriptor_props import SynonymProperty
@@ -30,7 +29,6 @@ from ..sql import roles
__all__ = [
"ColumnProperty",
- "ComparableProperty",
"CompositeProperty",
"ConcreteInheritedProperty",
"RelationshipProperty",
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index d001ab983..e131a4aa3 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -1765,10 +1765,7 @@ class Query(Generative):
the newly resulting ``Query``
All existing ORDER BY settings can be suppressed by
- passing ``None`` - this will suppress any ordering configured
- on the :func:`.mapper` object using the deprecated
- :paramref:`.mapper.order_by` parameter.
-
+ passing ``None``.
"""
if len(criterion) == 1:
@@ -3439,7 +3436,8 @@ class Query(Generative):
"Using the Query.instances() method without a context "
"is deprecated and will be disallowed in a future release. "
"Please make use of :meth:`.Query.from_statement` "
- "for linking ORM results to arbitrary select constructs."
+ "for linking ORM results to arbitrary select constructs.",
+ version="1.4",
)
context = QueryContext(self)
@@ -4256,15 +4254,6 @@ class _MapperEntity(_QueryEntity):
# if self._adapted_selectable is None:
context.froms += (self.selectable,)
- if context.order_by is False and self.mapper.order_by:
- context.order_by = self.mapper.order_by
-
- # apply adaptation to the mapper's order_by if needed.
- if adapter:
- context.order_by = adapter.adapt_list(
- util.to_list(context.order_by)
- )
-
loading._setup_entity_query(
context,
self.mapper,
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index aa55fab58..98fa819b1 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -234,8 +234,7 @@ class SessionTransaction(object):
"transaction is in progress"
)
- if self.session._enable_transaction_accounting:
- self._take_snapshot(autobegin=autobegin)
+ self._take_snapshot(autobegin=autobegin)
self.session.dispatch.after_transaction_create(self.session, self)
@@ -514,8 +513,7 @@ class SessionTransaction(object):
self._state = COMMITTED
self.session.dispatch.after_commit(self.session)
- if self.session._enable_transaction_accounting:
- self._remove_snapshot()
+ self._remove_snapshot()
self.close()
return self._parent
@@ -543,10 +541,9 @@ class SessionTransaction(object):
rollback_err = sys.exc_info()
finally:
transaction._state = DEACTIVE
- if self.session._enable_transaction_accounting:
- transaction._restore_snapshot(
- dirty_only=transaction.nested
- )
+ transaction._restore_snapshot(
+ dirty_only=transaction.nested
+ )
boundary = transaction
break
else:
@@ -554,11 +551,7 @@ class SessionTransaction(object):
sess = self.session
- if (
- not rollback_err
- and sess._enable_transaction_accounting
- and not sess._is_clean()
- ):
+ if not rollback_err and not sess._is_clean():
# if items were added, deleted, or mutated
# here, we need to re-restore the snapshot
@@ -654,32 +647,13 @@ 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.",
- ),
- )
def __init__(
self,
bind=None,
autoflush=True,
expire_on_commit=True,
- _enable_transaction_accounting=True,
autocommit=False,
twophase=False,
- weak_identity_map=None,
binds=None,
enable_baked_queries=True,
info=None,
@@ -782,10 +756,6 @@ class Session(_SessionClassMethods):
.. versionadded:: 1.2
- :param _enable_transaction_accounting: A
- legacy-only flag which when ``False`` disables *all* 0.5-style
- object accounting on transaction boundaries.
-
: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
@@ -813,20 +783,8 @@ class Session(_SessionClassMethods):
called. This allows each database to roll back the entire
transaction, before each transaction is committed.
- :param weak_identity_map: Defaults to ``True`` - when set to
- ``False``, objects placed in the :class:`.Session` will be
- strongly referenced until explicitly removed or the
- :class:`.Session` is closed.
-
-
"""
-
- if weak_identity_map in (True, None):
- self._identity_cls = identity.WeakInstanceDict
- else:
- self._identity_cls = identity.StrongInstanceDict
-
- self.identity_map = self._identity_cls()
+ self.identity_map = identity.WeakInstanceDict()
self._new = {} # InstanceState->object, strong refs object
self._deleted = {} # same
@@ -840,7 +798,6 @@ class Session(_SessionClassMethods):
self.autocommit = autocommit
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 if query_cls else query.Query
@@ -1353,7 +1310,7 @@ class Session(_SessionClassMethods):
"""
all_states = self.identity_map.all_states() + list(self._new)
- self.identity_map = self._identity_cls()
+ self.identity_map = identity.WeakInstanceDict()
self._new = {}
self._deleted = {}
@@ -1841,25 +1798,6 @@ class Session(_SessionClassMethods):
self._new.pop(state)
state._detach(self)
- @util.deprecated(
- "0.7",
- "The :meth:`.Session.prune` method is deprecated along with "
- ":paramref:`.Session.weak_identity_map`. This method will be "
- "removed in a future release.",
- )
- def prune(self):
- """Remove unreferenced instances cached in the identity map.
-
- Note that this method is only meaningful if "weak_identity_map" is set
- to False. The default weak identity map is self-pruning.
-
- Removes any object in this Session's identity map that is not
- referenced in user code, modified, new or scheduled for deletion.
- Returns the number of objects pruned.
-
- """
- return self.identity_map.prune()
-
def expunge(self, instance):
"""Remove the `instance` from this ``Session``.
@@ -1981,7 +1919,7 @@ class Session(_SessionClassMethods):
self._new.pop(state)
def _register_altered(self, states):
- if self._enable_transaction_accounting and self._transaction:
+ if self._transaction:
for state in states:
if state in self._new:
self._transaction._new[state] = True
@@ -1991,7 +1929,7 @@ class Session(_SessionClassMethods):
def _remove_newly_deleted(self, states):
persistent_to_deleted = self.dispatch.persistent_to_deleted or None
for state in states:
- if self._enable_transaction_accounting and self._transaction:
+ if self._transaction:
self._transaction._deleted[state] = True
if persistent_to_deleted is not None:
@@ -2981,15 +2919,7 @@ class Session(_SessionClassMethods):
finally:
self._flushing = False
- @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):
+ def is_modified(self, instance, include_collections=True):
r"""Return ``True`` if the given instance has locally
modified attributes.
@@ -3038,7 +2968,6 @@ 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: not used
"""
state = object_state(instance)
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 696741216..bb08d31ea 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -1228,9 +1228,6 @@ class SubqueryLoader(PostLoader):
q._distinct = True
break
- if q._order_by is False:
- q._order_by = leftmost_mapper.order_by
-
# don't need ORDER BY if no limit/offset
if q._limit is None and q._offset is None:
q._order_by = None
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 1fa5bf245..1fe51514e 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -1010,6 +1010,8 @@ See :func:`.orm.%(name)s` for usage examples.
"name": self.name
}
fn = util.deprecated(
+ # This is used by `baked_lazyload_all` was only deprecated in
+ # version 1.2 so this must stick around until that is removed
"0.9",
"The :func:`.%(name)s_all` function is deprecated, and will be "
"removed in a future release. Please use method chaining with "
@@ -1092,7 +1094,8 @@ def contains_eager(loadopt, attr, alias=None):
"Passing a string name for the 'alias' argument to "
"'contains_eager()` is deprecated, and will not work in a "
"future release. Please use a sqlalchemy.alias() or "
- "sqlalchemy.orm.aliased() construct."
+ "sqlalchemy.orm.aliased() construct.",
+ version="1.4",
)
elif getattr(attr, "_of_type", None):
@@ -1580,7 +1583,8 @@ def defer(key, *addl_attrs, **kw):
util.warn_deprecated(
"The *addl_attrs on orm.defer is deprecated. Please use "
"method chaining in conjunction with defaultload() to "
- "indicate a path."
+ "indicate a path.",
+ version="1.3",
)
return _UnboundLoad._from_keys(
_UnboundLoad.defer, (key,) + addl_attrs, False, kw
@@ -1642,7 +1646,8 @@ def undefer(key, *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."
+ "indicate a path.",
+ version="1.3",
)
return _UnboundLoad._from_keys(
_UnboundLoad.undefer, (key,) + addl_attrs, False, {}
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index e605b486b..fc168aa1d 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -191,7 +191,8 @@ class _ColumnCoercions(object):
"column-expression context is deprecated in version 1.4; "
"please use the .scalar_subquery() method to produce a scalar "
"subquery. This automatic coercion will be removed in a "
- "future release."
+ "future release.",
+ version="1.4",
)
def _implicit_coercions(
@@ -614,7 +615,8 @@ class FromClauseImpl(
"Implicit coercion of SELECT and textual SELECT "
"constructs into FROM clauses is deprecated; please call "
".subquery() on any Core select or ORM Query object in "
- "order to produce a subquery object."
+ "order to produce a subquery object.",
+ version="1.4",
)
return resolved._implicit_subquery
elif resolved._is_text_clause:
@@ -637,7 +639,8 @@ class StrictFromClauseImpl(FromClauseImpl, roles.StrictFromClauseRole):
"Implicit coercion of SELECT and textual SELECT constructs "
"into FROM clauses is deprecated; please call .subquery() "
"on any Core select or ORM Query object in order to produce a "
- "subquery object."
+ "subquery object.",
+ version="1.4",
)
return resolved._implicit_subquery
else:
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index b93ed8890..23b15b158 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -434,18 +434,6 @@ class Compiled(object):
self.string, schema_translate_map
)
- @util.deprecated(
- "0.7",
- "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.",
- )
- def compile(self):
- """Produce the internal string representation of this element.
- """
- pass
-
def _execute_on_connection(self, connection, multiparams, params):
if self.can_execute:
return connection._execute_compiled(self, multiparams, params)
@@ -4244,7 +4232,9 @@ class IdentifierPreparer(object):
"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()."
+ "quoted_name().",
+ # deprecated 0.9. warning from 1.3
+ version="0.9",
)
return self.quote(schema)
@@ -4280,7 +4270,9 @@ class IdentifierPreparer(object):
"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()."
+ "quoted_name().",
+ # deprecated 0.9. warning from 1.3
+ version="0.9",
)
force = getattr(ident, "quote", None)
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 57d41b06f..9689c7a8a 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -505,30 +505,6 @@ class ClauseElement(
"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.
- """
- 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.
- """
- return or_(self, other)
-
def __invert__(self):
# undocumented element currently used by the ORM for
# relationship.contains()
@@ -1523,22 +1499,8 @@ class TextClause(
self.text = self._bind_params_regex.sub(repl, text)
@classmethod
- @util.deprecated_params(
- 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.",
- ),
- )
@_document_text_coercion("text", ":func:`.text`", ":paramref:`.text.text`")
- def _create_text(self, text, bind=None, bindparams=None, typemap=None):
+ def _create_text(cls, text, bind=None):
r"""Construct a new :class:`.TextClause` clause, representing
a textual SQL string directly.
@@ -1617,25 +1579,6 @@ class TextClause(
:param bind:
an optional connection or engine to be used for this text query.
- :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)])
-
- :param typemap:
- A dictionary mapping the names of columns represented in the columns
- clause of a ``SELECT`` statement to type objects.
-
- E.g.::
-
- stmt = text("SELECT * FROM table",
- typemap={'id': Integer, 'name': String},
- )
-
.. seealso::
:ref:`sqlexpression_text` - in the Core tutorial
@@ -1643,13 +1586,7 @@ class TextClause(
:ref:`orm_tutorial_literal_sql` - in the ORM tutorial
"""
- stmt = TextClause(text, bind=bind)
- if bindparams:
- stmt = stmt.bindparams(*bindparams)
- if typemap:
- stmt = stmt.columns(**typemap)
-
- return stmt
+ return TextClause(text, bind=bind)
@_generative
def bindparams(self, *binds, **names_to_values):
@@ -2233,7 +2170,8 @@ class BooleanClauseList(ClauseList, ColumnElement):
"continue_on": "True"
if continue_on is True_._singleton
else "False",
- }
+ },
+ version="1.4",
)
return cls._construct_raw(operator)
@@ -3751,21 +3689,6 @@ 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.
-
-
- """
- return self.element
-
@util.memoized_property
def type(self):
return self.element.type
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index eb6c12f80..d1abaed3b 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -408,8 +408,6 @@ 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: the same as :paramref:`.Table.extend_existing`.
-
:param comment: Optional string that will render an SQL comment on table
creation.
@@ -432,14 +430,6 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
def _gen_cache_key(self, anon_map, bindparams):
return (self,) + self._annotations_cache_key
- @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
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index a0df45b52..595b1bdfa 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -365,36 +365,6 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
_use_schema_map = False
- @util.deprecated(
- "1.1",
- 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.",
- )
- @util.preload_module("sqlalchemy.sql.functions")
- def count(self, whereclause=None, **params):
- """return a SELECT COUNT generated against this
- :class:`.FromClause`.
-
- .. seealso::
-
- :class:`.functions.count`
-
- """
- functions = util.preloaded.sql_functions
- if self.primary_key:
- col = list(self.primary_key)[0]
- else:
- col = list(self.columns)[0]
- return Select._create_select_from_fromclause(
- self,
- [functions.func.count(col).label("tbl_row_count")],
- whereclause,
- from_obj=[self],
- **params
- )
-
def select(self, whereclause=None, **params):
"""return a SELECT of this :class:`.FromClause`.
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index af4e4db91..245b809ae 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -329,7 +329,8 @@ class String(Concatenable, TypeEngine):
"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."
+ "will be removed in a future release.",
+ version="1.3",
)
@@ -967,16 +968,6 @@ 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):
- def __init__(self, *arg, **kw):
- LargeBinary.__init__(self, *arg, **kw)
-
-
class SchemaType(SchemaEventTarget):
"""Mark a type as possibly requiring schema-level DDL for usage.
diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py
index e3929fac7..e9632c502 100644
--- a/lib/sqlalchemy/sql/type_api.py
+++ b/lib/sqlalchemy/sql/type_api.py
@@ -692,25 +692,6 @@ class UserDefinedType(util.with_metaclass(VisitableCheckKWArg, TypeEngine)):
ensure_kwarg = "get_col_spec"
- class Comparator(TypeEngine.Comparator):
- __slots__ = ()
-
- def _adapt_expression(self, op, other_comparator):
- if hasattr(self.type, "adapt_operator"):
- util.warn_deprecated(
- "UserDefinedType.adapt_operator is deprecated. Create "
- "a UserDefinedType.Comparator subclass instead which "
- "generates the desired expression constructs, given a "
- "particular operator."
- )
- return self.type.adapt_operator(op), self.type
- else:
- return super(
- UserDefinedType.Comparator, self
- )._adapt_expression(op, other_comparator)
-
- comparator_factory = Comparator
-
def coerce_compared_value(self, op, value):
"""Suggest a type for a 'coerced' Python value in an expression.
diff --git a/lib/sqlalchemy/testing/assertions.py b/lib/sqlalchemy/testing/assertions.py
index 5af29a723..61d272160 100644
--- a/lib/sqlalchemy/testing/assertions.py
+++ b/lib/sqlalchemy/testing/assertions.py
@@ -146,8 +146,8 @@ def _expect_warnings(
def our_warn(msg, *arg, **kw):
if isinstance(msg, exc_cls):
- exception = msg
- msg = str(exception)
+ exception = type(msg)
+ msg = str(msg)
elif arg:
exception = arg[0]
else:
diff --git a/lib/sqlalchemy/testing/suite/test_reflection.py b/lib/sqlalchemy/testing/suite/test_reflection.py
index 51beb0973..708088881 100644
--- a/lib/sqlalchemy/testing/suite/test_reflection.py
+++ b/lib/sqlalchemy/testing/suite/test_reflection.py
@@ -2,7 +2,6 @@ import operator
import re
import sqlalchemy as sa
-from .. import assert_raises_message
from .. import config
from .. import engines
from .. import eq_
@@ -13,7 +12,6 @@ from ..provision import temp_table_keyword_args
from ..schema import Column
from ..schema import Table
from ... import event
-from ... import exc as sa_exc
from ... import ForeignKey
from ... import inspect
from ... import Integer
@@ -654,19 +652,6 @@ class ComponentReflectionTest(fixtures.TablesTest):
def test_get_pk_constraint_with_schema(self):
self._test_get_pk_constraint(schema=testing.config.test_schema)
- @testing.requires.table_reflection
- @testing.provide_metadata
- def test_deprecated_get_primary_keys(self):
- meta = self.metadata
- users = self.tables.users
- insp = inspect(meta.bind)
- assert_raises_message(
- sa_exc.SADeprecationWarning,
- r".*get_primary_keys\(\) method is deprecated",
- insp.get_primary_keys,
- users.name,
- )
-
@testing.provide_metadata
def _test_get_foreign_keys(self, schema=None):
meta = self.metadata
diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py
index 009c96737..719b05018 100644
--- a/lib/sqlalchemy/types.py
+++ b/lib/sqlalchemy/types.py
@@ -46,7 +46,6 @@ __all__ = [
"Date",
"Time",
"LargeBinary",
- "Binary",
"Boolean",
"Unicode",
"Concatenable",
@@ -64,7 +63,6 @@ from .sql.sqltypes import ARRAY # noqa
from .sql.sqltypes import BIGINT # noqa
from .sql.sqltypes import BigInteger # noqa
from .sql.sqltypes import BINARY # noqa
-from .sql.sqltypes import Binary # noqa
from .sql.sqltypes import BLOB # noqa
from .sql.sqltypes import BOOLEAN # noqa
from .sql.sqltypes import Boolean # noqa
diff --git a/lib/sqlalchemy/util/deprecations.py b/lib/sqlalchemy/util/deprecations.py
index e3d4b88c4..4bc37bf04 100644
--- a/lib/sqlalchemy/util/deprecations.py
+++ b/lib/sqlalchemy/util/deprecations.py
@@ -18,14 +18,25 @@ from .langhelpers import inject_param_text
from .. import exc
-def warn_deprecated(msg, stacklevel=3):
- warnings.warn(msg, exc.SADeprecationWarning, stacklevel=stacklevel)
+def _warn_with_version(msg, version, type_, stacklevel):
+ warn = type_(msg)
+ warn.deprecated_since = version
+ warnings.warn(warn, stacklevel=stacklevel + 1)
+
+
+def warn_deprecated(msg, version, stacklevel=3):
+ _warn_with_version(msg, version, exc.SADeprecationWarning, stacklevel)
def warn_deprecated_20(msg, stacklevel=3):
msg += " (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)"
- warnings.warn(msg, exc.RemovedIn20Warning, stacklevel=stacklevel)
+ _warn_with_version(
+ msg,
+ exc.RemovedIn20Warning.deprecated_since,
+ exc.RemovedIn20Warning,
+ stacklevel,
+ )
def deprecated_cls(version, message, constructor="__init__"):
@@ -37,6 +48,7 @@ def deprecated_cls(version, message, constructor="__init__"):
constructor,
exc.SADeprecationWarning,
message % dict(func=constructor),
+ version,
header,
)
@@ -54,7 +66,12 @@ def deprecated_20_cls(clsname, alternative=None, constructor="__init__"):
def decorate(cls):
return _decorate_cls_with_warning(
- cls, constructor, exc.RemovedIn20Warning, message, message
+ cls,
+ constructor,
+ exc.RemovedIn20Warning,
+ message,
+ exc.RemovedIn20Warning.deprecated_since,
+ message,
)
return decorate
@@ -92,7 +109,7 @@ def deprecated(
def decorate(fn):
return _decorate_with_warning(
- fn, warning, message % dict(func=fn.__name__), header
+ fn, warning, message % dict(func=fn.__name__), version, header
)
return decorate
@@ -129,8 +146,10 @@ def deprecated_params(**specs):
"""
messages = {}
+ versions = {}
version_warnings = {}
for param, (version, message) in specs.items():
+ versions[param] = version
messages[param] = _sanitize_restructured_text(message)
version_warnings[param] = (
exc.RemovedIn20Warning
@@ -159,13 +178,19 @@ def deprecated_params(**specs):
if (defaults[m] is None and kwargs[m] is not None) or (
defaults[m] is not None and kwargs[m] != defaults[m]
):
- warnings.warn(
- messages[m], version_warnings[m], stacklevel=3
+ _warn_with_version(
+ messages[m],
+ versions[m],
+ version_warnings[m],
+ stacklevel=3,
)
for m in check_kw:
if m in kwargs:
- warnings.warn(
- messages[m], version_warnings[m], stacklevel=3
+ _warn_with_version(
+ messages[m],
+ versions[m],
+ version_warnings[m],
+ stacklevel=3,
)
return fn(*args, **kwargs)
@@ -186,14 +211,6 @@ def deprecated_params(**specs):
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)
@@ -206,7 +223,7 @@ def _sanitize_restructured_text(text):
def _decorate_cls_with_warning(
- cls, constructor, wtype, message, docstring_header=None
+ cls, constructor, wtype, message, version, docstring_header=None
):
doc = cls.__doc__ is not None and cls.__doc__ or ""
if docstring_header is not None:
@@ -238,12 +255,16 @@ def _decorate_cls_with_warning(
setattr(
cls,
constructor,
- _decorate_with_warning(constructor_fn, wtype, message, None),
+ _decorate_with_warning(
+ constructor_fn, wtype, message, version, None
+ ),
)
return cls
-def _decorate_with_warning(func, wtype, message, docstring_header=None):
+def _decorate_with_warning(
+ func, wtype, message, version, docstring_header=None
+):
"""Wrap a function with a warnings.warn and augmented docstring."""
message = _sanitize_restructured_text(message)
@@ -263,7 +284,9 @@ def _decorate_with_warning(func, wtype, message, docstring_header=None):
def warned(fn, *args, **kwargs):
skip_warning = kwargs.pop("_sa_skip_warning", False)
if not skip_warning:
- warnings.warn(message + warning_only, wtype, stacklevel=3)
+ _warn_with_version(
+ message + warning_only, version, wtype, stacklevel=3
+ )
return fn(*args, **kwargs)
doc = func.__doc__ is not None and func.__doc__ or ""
@@ -276,5 +299,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)
+ decorated._sa_warn = lambda: _warn_with_version(
+ message, version, wtype, stacklevel=3
+ )
return decorated