diff options
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  | 
