diff options
| author | Federico Caselli <cfederico87@gmail.com> | 2021-11-21 21:17:27 +0100 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-11-24 22:51:27 -0500 |
| commit | 31acba8ff7c123a20ae308b7f4ab6df3df264b48 (patch) | |
| tree | a4c39a2123e1b95edf17995ba85bb69ee619f6e4 /lib/sqlalchemy/sql | |
| parent | d3a4e96196cd47858de072ae589c6554088edc24 (diff) | |
| download | sqlalchemy-31acba8ff7c123a20ae308b7f4ab6df3df264b48.tar.gz | |
Clean up most py3k compat
Change-Id: I8172fdcc3103ff92aa049827728484c8779af6b7
Diffstat (limited to 'lib/sqlalchemy/sql')
| -rw-r--r-- | lib/sqlalchemy/sql/base.py | 24 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/coercions.py | 16 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 27 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/crud.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/ddl.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/dml.py | 3 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/elements.py | 31 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/functions.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/lambdas.py | 5 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/operators.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/schema.py | 26 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/selectable.py | 14 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/sqltypes.py | 34 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/traversals.py | 94 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/type_api.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/visitors.py | 6 |
17 files changed, 121 insertions, 177 deletions
diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py index b57da3289..2c74dd523 100644 --- a/lib/sqlalchemy/sql/base.py +++ b/lib/sqlalchemy/sql/base.py @@ -10,7 +10,10 @@ """ +import collections.abc as collections_abc +from functools import reduce import itertools +from itertools import zip_longest import operator import re @@ -27,7 +30,6 @@ from .. import util from ..util import HasMemoized from ..util import hybridmethod - coercions = None elements = None type_api = None @@ -176,7 +178,7 @@ def _cloned_difference(a, b): ) -class _DialectArgView(util.collections_abc.MutableMapping): +class _DialectArgView(collections_abc.MutableMapping): """A dictionary view of dialect-level arguments in the form <dialectname>_<argument_name>. @@ -236,7 +238,7 @@ class _DialectArgView(util.collections_abc.MutableMapping): ) -class _DialectArgDict(util.collections_abc.MutableMapping): +class _DialectArgDict(collections_abc.MutableMapping): """A dictionary view of dialect-level arguments for a specific dialect. @@ -615,7 +617,7 @@ class _MetaOptions(type): return o1 -class Options(util.with_metaclass(_MetaOptions)): +class Options(metaclass=_MetaOptions): """A cacheable option dictionary with defaults.""" def __init__(self, **kw): @@ -638,7 +640,7 @@ class Options(util.with_metaclass(_MetaOptions)): def __eq__(self, other): # TODO: very inefficient. This is used only in test suites # right now. - for a, b in util.zip_longest(self._cache_attrs, other._cache_attrs): + for a, b in zip_longest(self._cache_attrs, other._cache_attrs): if getattr(self, a) != getattr(other, b): return False return True @@ -1238,7 +1240,7 @@ class ColumnCollection: try: return self._index[key] except KeyError as err: - if isinstance(key, util.int_types): + if isinstance(key, int): util.raise_(IndexError(key), replace_context=err) else: raise @@ -1251,7 +1253,7 @@ class ColumnCollection: def __contains__(self, key): if key not in self._index: - if not isinstance(key, util.string_types): + if not isinstance(key, str): raise exc.ArgumentError( "__contains__ requires a string argument" ) @@ -1263,7 +1265,7 @@ class ColumnCollection: """Compare this :class:`_expression.ColumnCollection` to another based on the names of the keys""" - for l, r in util.zip_longest(self, other): + for l, r in zip_longest(self, other): if l is not r: return False else: @@ -1359,7 +1361,7 @@ class ColumnCollection: def contains_column(self, col): """Checks if a column object exists in this collection""" if col not in self._colset: - if isinstance(col, util.string_types): + if isinstance(col, str): raise exc.ArgumentError( "contains_column cannot be used with string arguments. " "Use ``col_name in table.c`` instead." @@ -1451,7 +1453,7 @@ class ColumnCollection: # columns that have no reference to the target # column (also occurs with CompoundSelect) - col_distance = util.reduce( + col_distance = reduce( operator.add, [ sc._annotations.get("weight", 1) @@ -1459,7 +1461,7 @@ class ColumnCollection: if sc.shares_lineage(column) ], ) - c_distance = util.reduce( + c_distance = reduce( operator.add, [ sc._annotations.get("weight", 1) diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py index f051ba12f..480d2c680 100644 --- a/lib/sqlalchemy/sql/coercions.py +++ b/lib/sqlalchemy/sql/coercions.py @@ -5,6 +5,7 @@ # This module is part of SQLAlchemy and is released under # the MIT License: https://www.opensource.org/licenses/mit-license.php +import collections.abc as collections_abc import numbers import re @@ -17,7 +18,6 @@ from .visitors import Visitable from .. import exc from .. import inspection from .. import util -from ..util import collections_abc elements = None @@ -224,7 +224,7 @@ def expect_col_expression_collection(role, expressions): column = None resolved = expect(role, expr) - if isinstance(resolved, util.string_types): + if isinstance(resolved, str): strname = resolved = expr else: cols = [] @@ -303,7 +303,7 @@ class _ReturnsStringKey: def _implicit_coercions( self, original_element, resolved, argname=None, **kw ): - if isinstance(original_element, util.string_types): + if isinstance(original_element, str): return original_element else: self._raise_for_expected(original_element, argname, resolved) @@ -362,7 +362,7 @@ class _NoTextCoercion: __slots__ = () def _literal_coercion(self, element, argname=None, **kw): - if isinstance(element, util.string_types) and issubclass( + if isinstance(element, str) and issubclass( elements.TextClause, self._role_class ): _no_text_coercion(element, argname) @@ -380,7 +380,7 @@ class _CoerceLiterals: return _no_text_coercion(element, argname) def _literal_coercion(self, element, argname=None, **kw): - if isinstance(element, util.string_types): + if isinstance(element, str): if self._coerce_star and element == "*": return elements.ColumnClause("*", is_literal=True) else: @@ -542,7 +542,7 @@ class InElementImpl(RoleImpl): def _literal_coercion(self, element, expr, operator, **kw): if isinstance(element, collections_abc.Iterable) and not isinstance( - element, util.string_types + element, str ): non_literal_expressions = {} element = list(element) @@ -729,7 +729,7 @@ class TruncatedLabelImpl(_StringOnly, RoleImpl): def _implicit_coercions( self, original_element, resolved, argname=None, **kw ): - if isinstance(original_element, util.string_types): + if isinstance(original_element, str): return resolved else: self._raise_for_expected(original_element, argname, resolved) @@ -844,7 +844,7 @@ class StatementImpl(_CoerceLiterals, RoleImpl): def _post_coercion(self, resolved, original_element, argname=None, **kw): if resolved is not original_element and not isinstance( - original_element, util.string_types + original_element, str ): # use same method as Connection uses; this will later raise # ObjectNotExecutableError diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 29aa57faa..0dd61d675 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -22,12 +22,13 @@ To generate user-defined SQL strings, see :doc:`/ext/compiler`. """ - import collections +import collections.abc as collections_abc import contextlib import itertools import operator import re +from time import perf_counter from . import base from . import coercions @@ -453,7 +454,7 @@ class Compiled: self.string = self.preparer._render_schema_translates( self.string, schema_translate_map ) - self._gen_time = util.perf_counter() + self._gen_time = perf_counter() def _execute_on_connection( self, connection, distilled_params, execution_options @@ -505,7 +506,7 @@ class Compiled: return self.construct_params() -class TypeCompiler(util.with_metaclass(util.EnsureKWArgType, object)): +class TypeCompiler(metaclass=util.EnsureKWArgType): """Produces DDL specification for TypeEngine objects.""" ensure_kwarg = r"visit_\w+" @@ -2026,10 +2027,8 @@ class SQLCompiler(Compiled): elif typ_dialect_impl._is_tuple_type or ( typ_dialect_impl._isnull - and isinstance(values[0], util.collections_abc.Sequence) - and not isinstance( - values[0], util.string_types + util.binary_types - ) + and isinstance(values[0], collections_abc.Sequence) + and not isinstance(values[0], (str, bytes)) ): replacement_expression = ( @@ -2077,10 +2076,8 @@ class SQLCompiler(Compiled): elif typ_dialect_impl._is_tuple_type or ( typ_dialect_impl._isnull - and isinstance(values[0], util.collections_abc.Sequence) - and not isinstance( - values[0], util.string_types + util.binary_types - ) + and isinstance(values[0], collections_abc.Sequence) + and not isinstance(values[0], (str, bytes)) ): assert not typ_dialect_impl._is_array to_update = [ @@ -4355,7 +4352,7 @@ class DDLCompiler(Compiled): except exc.CompileError as ce: util.raise_( exc.CompileError( - util.u("(in table '%s', column '%s'): %s") + "(in table '%s', column '%s'): %s" % (table.description, column.name, ce.args[0]) ), from_=ce, @@ -4628,7 +4625,7 @@ class DDLCompiler(Compiled): def get_column_default_string(self, column): if isinstance(column.server_default, schema.DefaultClause): - if isinstance(column.server_default.arg, util.string_types): + if isinstance(column.server_default.arg, str): return self.sql_compiler.render_literal_value( column.server_default.arg, sqltypes.STRINGTYPE ) @@ -5126,14 +5123,14 @@ class IdentifierPreparer: return ( lc_value in self.reserved_words or value[0] in self.illegal_initial_characters - or not self.legal_characters.match(util.text_type(value)) + or not self.legal_characters.match(str(value)) or (lc_value != value) ) def _requires_quotes_illegal_chars(self, value): """Return True if the given identifier requires quoting, but not taking case convention into account.""" - return not self.legal_characters.match(util.text_type(value)) + return not self.legal_characters.match(str(value)) def quote_schema(self, schema, force=None): """Conditionally quote a schema name. diff --git a/lib/sqlalchemy/sql/crud.py b/lib/sqlalchemy/sql/crud.py index a9c9cb4c1..a313257ca 100644 --- a/lib/sqlalchemy/sql/crud.py +++ b/lib/sqlalchemy/sql/crud.py @@ -373,7 +373,7 @@ def _scan_cols( cols = [ stmt.table.c[key] for key in parameter_ordering - if isinstance(key, util.string_types) and key in stmt.table.c + if isinstance(key, str) and key in stmt.table.c ] + [c for c in stmt.table.c if c.key not in ordered_keys] else: diff --git a/lib/sqlalchemy/sql/ddl.py b/lib/sqlalchemy/sql/ddl.py index f732ff2b0..74e7df821 100644 --- a/lib/sqlalchemy/sql/ddl.py +++ b/lib/sqlalchemy/sql/ddl.py @@ -180,7 +180,7 @@ class DDLElement(roles.DDLRole, Executable, _DDLCompiles): self.state = state def _should_execute(self, target, bind, **kw): - if isinstance(self.dialect, util.string_types): + if isinstance(self.dialect, str): if self.dialect != bind.engine.name: return False elif isinstance(self.dialect, (tuple, list, set)): @@ -288,7 +288,7 @@ class DDL(DDLElement): """ - if not isinstance(statement, util.string_types): + if not isinstance(statement, str): raise exc.ArgumentError( "Expected a string or unicode SQL statement, got '%r'" % statement diff --git a/lib/sqlalchemy/sql/dml.py b/lib/sqlalchemy/sql/dml.py index e45c6b888..93cd912a7 100644 --- a/lib/sqlalchemy/sql/dml.py +++ b/lib/sqlalchemy/sql/dml.py @@ -9,6 +9,8 @@ Provide :class:`_expression.Insert`, :class:`_expression.Update` and :class:`_expression.Delete`. """ +import collections.abc as collections_abc + from sqlalchemy.types import NullType from . import coercions from . import roles @@ -31,7 +33,6 @@ from .selectable import ReturnsRows from .visitors import InternalTraversal from .. import exc from .. import util -from ..util import collections_abc class DMLState(CompileState): diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index ca65f2112..76633cdd8 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -10,8 +10,6 @@ """ -from __future__ import unicode_literals - import itertools import operator import re @@ -3869,7 +3867,7 @@ class BinaryExpression(ColumnElement): ): # allow compatibility with libraries that # refer to BinaryExpression directly and pass strings - if isinstance(operator, util.string_types): + if isinstance(operator, str): operator = operators.custom_op(operator) self._orig = (left.__hash__(), right.__hash__()) self._propagate_attrs = left._propagate_attrs or right._propagate_attrs @@ -4638,10 +4636,7 @@ class NamedColumn(ColumnElement): @util.memoized_property def description(self): - if util.py3k: - return self.name - else: - return self.name.encode("ascii", "backslashreplace") + return self.name @HasMemoized.memoized_attribute def _tq_key_label(self): @@ -5068,7 +5063,7 @@ class ReleaseSavepointClause(_IdentifiedClause): __visit_name__ = "release_savepoint" -class quoted_name(util.MemoizedSlots, util.text_type): +class quoted_name(util.MemoizedSlots, str): """Represent a SQL identifier combined with quoting preferences. :class:`.quoted_name` is a Python unicode/str subclass which @@ -5138,19 +5133,19 @@ class quoted_name(util.MemoizedSlots, util.text_type): return self def __reduce__(self): - return quoted_name, (util.text_type(self), self.quote) + return quoted_name, (str(self), self.quote) def _memoized_method_lower(self): if self.quote: return self else: - return util.text_type(self).lower() + return str(self).lower() def _memoized_method_upper(self): if self.quote: return self else: - return util.text_type(self).upper() + return str(self).upper() def _find_columns(clause): @@ -5238,7 +5233,7 @@ class _truncated_label(quoted_name): return super(_truncated_label, cls).__new__(cls, value, quote) def __reduce__(self): - return self.__class__, (util.text_type(self), self.quote) + return self.__class__, (str(self), self.quote) def apply_map(self, map_): return self @@ -5324,26 +5319,26 @@ class _anonymous_label(_truncated_label): def __add__(self, other): if "%" in other and not isinstance(other, _anonymous_label): - other = util.text_type(other).replace("%", "%%") + other = str(other).replace("%", "%%") else: - other = util.text_type(other) + other = str(other) return _anonymous_label( quoted_name( - util.text_type.__add__(self, other), + str.__add__(self, other), self.quote, ) ) def __radd__(self, other): if "%" in other and not isinstance(other, _anonymous_label): - other = util.text_type(other).replace("%", "%%") + other = str(other).replace("%", "%%") else: - other = util.text_type(other) + other = str(other) return _anonymous_label( quoted_name( - util.text_type.__add__(other, self), + str.__add__(other, self), self.quote, ) ) diff --git a/lib/sqlalchemy/sql/functions.py b/lib/sqlalchemy/sql/functions.py index 31f4fab0d..901a3a77c 100644 --- a/lib/sqlalchemy/sql/functions.py +++ b/lib/sqlalchemy/sql/functions.py @@ -55,7 +55,7 @@ def register_function(identifier, fn, package="_default"): """ reg = _registry[package] - identifier = util.text_type(identifier).lower() + identifier = str(identifier).lower() # Check if a function with the same identifier is registered. if identifier in reg: @@ -909,7 +909,7 @@ class _GenericMeta(TraversibleType): super(_GenericMeta, cls).__init__(clsname, bases, clsdict) -class GenericFunction(util.with_metaclass(_GenericMeta, Function)): +class GenericFunction(Function, metaclass=_GenericMeta): """Define a 'generic' function. A generic function is a pre-established :class:`.Function` diff --git a/lib/sqlalchemy/sql/lambdas.py b/lib/sqlalchemy/sql/lambdas.py index 110260799..2256fb5a9 100644 --- a/lib/sqlalchemy/sql/lambdas.py +++ b/lib/sqlalchemy/sql/lambdas.py @@ -5,6 +5,7 @@ # This module is part of SQLAlchemy and is released under # the MIT License: https://www.opensource.org/licenses/mit-license.php +import collections.abc as collections_abc import itertools import operator import sys @@ -24,8 +25,6 @@ from .operators import ColumnOperators from .. import exc from .. import inspection from .. import util -from ..util import collections_abc -from ..util import compat _closure_per_cache_key = util.LRUCache(1000) @@ -1111,7 +1110,7 @@ class AnalyzedFunction: code += " return %s\n" % ", ".join("i%d" % i for i in argrange) code += " return closure.__closure__" vars_ = {"o%d" % i: cell_values[i] for i in argrange} - compat.exec_(code, vars_, vars_) + exec(code, vars_, vars_) closure = vars_["make_cells"]() func = type(f)( diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index 675048cd0..6d45cd033 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -1394,7 +1394,7 @@ def _escaped_like_impl(fn, other, escape, autoescape): if escape is None: escape = "/" - if not isinstance(other, util.compat.string_types): + if not isinstance(other, str): raise TypeError("String value expected when autoescape=True") if escape not in ("%", "_"): diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 4bd49c468..eed2fbba1 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -28,8 +28,6 @@ Since these objects are part of the SQL expression language, they are usable as components in SQL expressions. """ -from __future__ import absolute_import - import collections import sqlalchemy @@ -1572,7 +1570,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): type_ = kwargs.pop("type_", None) args = list(args) if args: - if isinstance(args[0], util.string_types): + if isinstance(args[0], str): if name is not None: raise exc.ArgumentError( "May not pass name positionally and as a keyword." @@ -1819,7 +1817,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): ) if self.index: - if isinstance(self.index, util.string_types): + if isinstance(self.index, str): raise exc.ArgumentError( "The 'index' keyword argument on Column is boolean only. " "To create indexes with a specific name, create an " @@ -1832,7 +1830,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): ) elif self.unique: - if isinstance(self.unique, util.string_types): + if isinstance(self.unique, str): raise exc.ArgumentError( "The 'unique' keyword argument on Column is boolean " "only. To create unique constraints or indexes with a " @@ -2125,7 +2123,7 @@ class ForeignKey(DialectKWArgs, SchemaItem): self._colspec = coercions.expect(roles.DDLReferredColumnRole, column) - if isinstance(self._colspec, util.string_types): + if isinstance(self._colspec, str): self._table_column = None else: self._table_column = self._colspec @@ -2395,7 +2393,7 @@ class ForeignKey(DialectKWArgs, SchemaItem): """ - if isinstance(self._colspec, util.string_types): + if isinstance(self._colspec, str): parenttable, tablekey, colname = self._resolve_col_tokens() @@ -2472,7 +2470,7 @@ class ForeignKey(DialectKWArgs, SchemaItem): table.foreign_keys.add(self) # set up remote ".column" attribute, or a note to pick it # up when the other Table/Column shows up - if isinstance(self._colspec, util.string_types): + if isinstance(self._colspec, str): parenttable, table_key, colname = self._resolve_col_tokens() fk_key = (table_key, colname) if table_key in parenttable.metadata.tables: @@ -3068,9 +3066,7 @@ class DefaultClause(FetchedValue): has_argument = True def __init__(self, arg, for_update=False, _reflected=False): - util.assert_arg_type( - arg, (util.string_types[0], ClauseElement, TextClause), "arg" - ) + util.assert_arg_type(arg, (str, ClauseElement, TextClause), "arg") super(DefaultClause, self).__init__(for_update) self.arg = arg self.reflected = _reflected @@ -3264,7 +3260,7 @@ class ColumnCollectionMixin: def _col_expressions(self, table): return [ - table.c[col] if isinstance(col, util.string_types) else col + table.c[col] if isinstance(col, str) else col for col in self._pending_colargs ] @@ -4422,7 +4418,7 @@ class MetaData(SchemaItem): return "MetaData()" def __contains__(self, table_or_key): - if not isinstance(table_or_key, util.string_types): + if not isinstance(table_or_key, str): table_or_key = table_or_key.key return table_or_key in self.tables @@ -4501,7 +4497,7 @@ class MetaData(SchemaItem): def _bind_to(self, bind): """Bind this MetaData to an Engine, Connection, string or URL.""" url = util.preloaded.engine_url - if isinstance(bind, util.string_types + (url.URL,)): + if isinstance(bind, (str, url.URL)): self._bind = sqlalchemy.create_engine(bind) else: self._bind = bind @@ -4838,7 +4834,7 @@ class ThreadLocalMetaData(MetaData): def _bind_to(self, bind): """Bind to a Connectable in the caller's thread.""" url = util.preloaded.engine_url - if isinstance(bind, util.string_types + (url.URL,)): + if isinstance(bind, (str, url.URL)): try: self.context._engine = self.__engines[bind] except KeyError: diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index a04b205b5..a77cd173b 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -1624,10 +1624,7 @@ class AliasedReturnsRows(NoInit, FromClause): if isinstance(name, _anonymous_label): name = "anon_1" - if util.py3k: - return name - else: - return name.encode("ascii", "backslashreplace") + return name @property def original(self): @@ -2728,10 +2725,7 @@ class TableClause(roles.DMLTableRole, Immutable, FromClause): @util.memoized_property def description(self): - if util.py3k: - return self.name - else: - return self.name.encode("ascii", "backslashreplace") + return self.name def append_column(self, c, **kw): existing = c.table @@ -5267,9 +5261,7 @@ class Select( isinstance(args[0], list) or ( hasattr(args[0], "__iter__") - and not isinstance( - args[0], util.string_types + (ClauseElement,) - ) + and not isinstance(args[0], (str, ClauseElement)) and inspect(args[0], raiseerr=False) is None and not hasattr(args[0], "__clause_element__") ) diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 1687c9f29..8874f0a83 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -9,9 +9,11 @@ """ +import collections.abc as collections_abc import datetime as dt import decimal import json +import pickle from . import coercions from . import elements @@ -38,10 +40,8 @@ from .. import exc from .. import inspection from .. import processors from .. import util -from ..util import compat from ..util import langhelpers from ..util import OrderedDict -from ..util import pickle class _LookupExpressionAdapter: @@ -192,7 +192,7 @@ class String(Concatenable, TypeEngine): @property def python_type(self): - return util.text_type + return str def get_dbapi_type(self, dbapi): return dbapi.STRING @@ -721,7 +721,7 @@ class _Binary(TypeEngine): @property def python_type(self): - return util.binary_type + return bytes # Python 3 - sqlite3 doesn't need the `Binary` conversion # here, though pg8000 does to indicate "bytea" @@ -753,7 +753,7 @@ class _Binary(TypeEngine): def coerce_compared_value(self, op, value): """See :meth:`.TypeEngine.coerce_compared_value` for a description.""" - if isinstance(value, util.string_types): + if isinstance(value, str): return self else: return super(_Binary, self).coerce_compared_value(op, value) @@ -1328,9 +1328,7 @@ class Enum(Emulated, String, SchemaType): # here between an INSERT statement and a criteria used in a SELECT, # for now we're staying conservative w/ behavioral changes (perhaps # someone has a trigger that handles strings on INSERT) - if not self.validate_strings and isinstance( - elem, compat.string_types - ): + if not self.validate_strings and isinstance(elem, str): return elem else: util.raise_( @@ -1513,8 +1511,7 @@ class PickleType(TypeDecorator): :param protocol: defaults to ``pickle.HIGHEST_PROTOCOL``. - :param pickler: defaults to cPickle.pickle or pickle.pickle if - cPickle is not available. May be any object with + :param pickler: defaults to pickle. May be any object with pickle-compatible ``dumps`` and ``loads`` methods. :param comparator: a 2-arg callable predicate used @@ -2123,7 +2120,7 @@ class JSON(Indexable, TypeEngine): def process(value): if int_processor and isinstance(value, int): value = int_processor(value) - elif string_processor and isinstance(value, util.string_types): + elif string_processor and isinstance(value, str): value = string_processor(value) return value @@ -2136,7 +2133,7 @@ class JSON(Indexable, TypeEngine): def process(value): if int_processor and isinstance(value, int): value = int_processor(value) - elif string_processor and isinstance(value, util.string_types): + elif string_processor and isinstance(value, str): value = string_processor(value) return value @@ -2178,8 +2175,8 @@ class JSON(Indexable, TypeEngine): """Define comparison operations for :class:`_types.JSON`.""" def _setup_getitem(self, index): - if not isinstance(index, util.string_types) and isinstance( - index, compat.collections_abc.Sequence + if not isinstance(index, str) and isinstance( + index, collections_abc.Sequence ): index = coercions.expect( roles.BinaryElementRole, @@ -2982,15 +2979,10 @@ _type_map = { dt.time: Time(), dt.timedelta: Interval(), util.NoneType: NULLTYPE, + bytes: LargeBinary(), + str: Unicode(), } -if util.py3k: - _type_map[bytes] = LargeBinary() # noqa - _type_map[str] = Unicode() -else: - _type_map[unicode] = Unicode() # noqa - _type_map[str] = String() - _type_map_get = _type_map.get diff --git a/lib/sqlalchemy/sql/traversals.py b/lib/sqlalchemy/sql/traversals.py index 7973b535f..914a78dae 100644 --- a/lib/sqlalchemy/sql/traversals.py +++ b/lib/sqlalchemy/sql/traversals.py @@ -1,6 +1,8 @@ from collections import deque from collections import namedtuple +import collections.abc as collections_abc import itertools +from itertools import zip_longest import operator from . import operators @@ -8,9 +10,7 @@ from .visitors import ExtendedInternalTraversal from .visitors import InternalTraversal from .. import util from ..inspection import inspect -from ..util import collections_abc from ..util import HasMemoized -from ..util import py37 SKIP_TRAVERSE = util.symbol("skip_traverse") COMPARE_FAILED = False @@ -331,7 +331,7 @@ class CacheKey(namedtuple("CacheKey", ["key", "bindparams"])): s1 = s1[idx] s2 = s2[idx] - for idx, (e1, e2) in enumerate(util.zip_longest(s1, s2)): + for idx, (e1, e2) in enumerate(zip_longest(s1, s2)): if idx < pickup_index: continue if e1 != e2: @@ -669,38 +669,20 @@ class _CacheKey(ExtendedInternalTraversal): ) def visit_dml_values(self, attrname, obj, parent, anon_map, bindparams): - if py37: - # in py37 we can assume two dictionaries created in the same - # insert ordering will retain that sorting - return ( - attrname, - tuple( - ( - k._gen_cache_key(anon_map, bindparams) - if hasattr(k, "__clause_element__") - else k, - obj[k]._gen_cache_key(anon_map, bindparams), - ) - for k in obj - ), - ) - else: - expr_values = {k for k in obj if hasattr(k, "__clause_element__")} - if expr_values: - # expr values can't be sorted deterministically right now, - # so no cache - anon_map[NO_CACHE] = True - return () - - str_values = expr_values.symmetric_difference(obj) - - return ( - attrname, - tuple( - (k, obj[k]._gen_cache_key(anon_map, bindparams)) - for k in sorted(str_values) - ), - ) + # in py37 we can assume two dictionaries created in the same + # insert ordering will retain that sorting + return ( + attrname, + tuple( + ( + k._gen_cache_key(anon_map, bindparams) + if hasattr(k, "__clause_element__") + else k, + obj[k]._gen_cache_key(anon_map, bindparams), + ) + for k in obj + ), + ) def visit_dml_multi_values( self, attrname, obj, parent, anon_map, bindparams @@ -1040,7 +1022,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): for ( (left_attrname, left_visit_sym), (right_attrname, right_visit_sym), - ) in util.zip_longest( + ) in zip_longest( left._traverse_internals, right._traverse_internals, fillvalue=(None, None), @@ -1098,7 +1080,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): def visit_has_cache_key_list( self, attrname, left_parent, left, right_parent, right, **kw ): - for l, r in util.zip_longest(left, right, fillvalue=None): + for l, r in zip_longest(left, right, fillvalue=None): if l._gen_cache_key(self.anon_map[0], []) != r._gen_cache_key( self.anon_map[1], [] ): @@ -1114,7 +1096,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): def visit_fromclause_canonical_column_collection( self, attrname, left_parent, left, right_parent, right, **kw ): - for lcol, rcol in util.zip_longest(left, right, fillvalue=None): + for lcol, rcol in zip_longest(left, right, fillvalue=None): self.stack.append((lcol, rcol)) def visit_fromclause_derived_column_collection( @@ -1125,7 +1107,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): def visit_string_clauseelement_dict( self, attrname, left_parent, left, right_parent, right, **kw ): - for lstr, rstr in util.zip_longest( + for lstr, rstr in zip_longest( sorted(left), sorted(right), fillvalue=None ): if lstr != rstr: @@ -1135,23 +1117,23 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): def visit_clauseelement_tuples( self, attrname, left_parent, left, right_parent, right, **kw ): - for ltup, rtup in util.zip_longest(left, right, fillvalue=None): + for ltup, rtup in zip_longest(left, right, fillvalue=None): if ltup is None or rtup is None: return COMPARE_FAILED - for l, r in util.zip_longest(ltup, rtup, fillvalue=None): + for l, r in zip_longest(ltup, rtup, fillvalue=None): self.stack.append((l, r)) def visit_clauseelement_list( self, attrname, left_parent, left, right_parent, right, **kw ): - for l, r in util.zip_longest(left, right, fillvalue=None): + for l, r in zip_longest(left, right, fillvalue=None): self.stack.append((l, r)) def visit_clauseelement_tuple( self, attrname, left_parent, left, right_parent, right, **kw ): - for l, r in util.zip_longest(left, right, fillvalue=None): + for l, r in zip_longest(left, right, fillvalue=None): self.stack.append((l, r)) def _compare_unordered_sequences(self, seq1, seq2, **kw): @@ -1174,7 +1156,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): def visit_fromclause_ordered_set( self, attrname, left_parent, left, right_parent, right, **kw ): - for l, r in util.zip_longest(left, right, fillvalue=None): + for l, r in zip_longest(left, right, fillvalue=None): self.stack.append((l, r)) def visit_string( @@ -1256,7 +1238,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): def visit_prefix_sequence( self, attrname, left_parent, left, right_parent, right, **kw ): - for (l_clause, l_str), (r_clause, r_str) in util.zip_longest( + for (l_clause, l_str), (r_clause, r_str) in zip_longest( left, right, fillvalue=(None, None) ): if l_str != r_str: @@ -1271,7 +1253,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): for ( (l_target, l_onclause, l_from, l_flags), (r_target, r_onclause, r_from, r_flags), - ) in util.zip_longest(left, right, fillvalue=(None, None, None, None)): + ) in zip_longest(left, right, fillvalue=(None, None, None, None)): if l_flags != r_flags: return COMPARE_FAILED self.stack.append((l_target, r_target)) @@ -1292,7 +1274,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): right_keys = sorted( right, key=lambda elem: (elem[0].fullname, elem[1]) ) - for (ltable, ldialect), (rtable, rdialect) in util.zip_longest( + for (ltable, ldialect), (rtable, rdialect) in zip_longest( left_keys, right_keys, fillvalue=(None, None) ): if ldialect != rdialect: @@ -1317,7 +1299,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): ): # sequence of tuple pairs - for (lk, lv), (rk, rv) in util.zip_longest( + for (lk, lv), (rk, rv) in zip_longest( left, right, fillvalue=(None, None) ): if not self._compare_dml_values_or_ce(lk, rk, **kw): @@ -1349,7 +1331,7 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): return COMPARE_FAILED elif isinstance(right, collections_abc.Sequence): return COMPARE_FAILED - elif py37: + else: # dictionaries guaranteed to support insert ordering in # py37 so that we can compare the keys in order. without # this, we can't compare SQL expression keys because we don't @@ -1359,25 +1341,15 @@ class TraversalComparatorStrategy(InternalTraversal, util.MemoizedSlots): return COMPARE_FAILED if not self._compare_dml_values_or_ce(lv, rv, **kw): return COMPARE_FAILED - else: - for lk in left: - lv = left[lk] - - if lk not in right: - return COMPARE_FAILED - rv = right[lk] - - if not self._compare_dml_values_or_ce(lv, rv, **kw): - return COMPARE_FAILED def visit_dml_multi_values( self, attrname, left_parent, left, right_parent, right, **kw ): - for lseq, rseq in util.zip_longest(left, right, fillvalue=None): + for lseq, rseq in zip_longest(left, right, fillvalue=None): if lseq is None or rseq is None: return COMPARE_FAILED - for ld, rd in util.zip_longest(lseq, rseq, fillvalue=None): + for ld, rd in zip_longest(lseq, rseq, fillvalue=None): if ( self.visit_dml_values( attrname, left_parent, ld, right_parent, rd, **kw diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py index 01763f266..82b8f538a 100644 --- a/lib/sqlalchemy/sql/type_api.py +++ b/lib/sqlalchemy/sql/type_api.py @@ -981,9 +981,7 @@ class ExternalType: return NO_CACHE -class UserDefinedType( - util.with_metaclass(VisitableCheckKWArg, ExternalType, TypeEngine) -): +class UserDefinedType(ExternalType, TypeEngine, metaclass=VisitableCheckKWArg): """Base for user defined types. This should be the base of new types. Note that diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 6394c43a0..8aee6a97a 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -454,7 +454,7 @@ def bind_values(clause): def _quote_ddl_expr(element): - if isinstance(element, util.string_types): + if isinstance(element, str): element = element.replace("'", "''") return "'%s'" % element else: diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py index deb92b081..b08080753 100644 --- a/lib/sqlalchemy/sql/visitors.py +++ b/lib/sqlalchemy/sql/visitors.py @@ -59,7 +59,7 @@ def _generate_compiler_dispatch(cls): cls._original_compiler_dispatch = cls._compiler_dispatch return - if not isinstance(visit_name, util.compat.string_types): + if not isinstance(visit_name, str): raise exc.InvalidRequestError( "__visit_name__ on class %s must be a string at the class level" % cls.__name__ @@ -114,7 +114,7 @@ class TraversibleType(type): super(TraversibleType, cls).__init__(clsname, bases, clsdict) -class Traversible(util.with_metaclass(TraversibleType)): +class Traversible(metaclass=TraversibleType): """Base class for visitable objects, applies the :class:`.visitors.TraversibleType` metaclass. @@ -200,7 +200,7 @@ def _generate_dispatcher(visitor, internal_dispatch, method_name): return langhelpers._exec_code_in_env(meth_text, {}, method_name) -class InternalTraversal(util.with_metaclass(_InternalTraversalType, object)): +class InternalTraversal(metaclass=_InternalTraversalType): r"""Defines visitor symbols used for internal traversal. The :class:`.InternalTraversal` class is used in two ways. One is that |
