diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2020-04-10 17:52:47 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2020-04-10 17:52:47 +0000 |
commit | 1ff644d2f16a7517df7f175e1291ddaa501646dd (patch) | |
tree | a8f6e624e1500f3b77e43a22eaeb0e7b8ff20100 /lib/sqlalchemy | |
parent | fe591913030a244a9ccfdd47b371609f1f1b44af (diff) | |
parent | a9b068ae564e5e775e312373088545b75aeaa1b0 (diff) | |
download | sqlalchemy-1ff644d2f16a7517df7f175e1291ddaa501646dd.tar.gz |
Merge "Remove code deprecated before version 1.1"
Diffstat (limited to 'lib/sqlalchemy')
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 |