summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/base.py24
-rw-r--r--lib/sqlalchemy/sql/coercions.py16
-rw-r--r--lib/sqlalchemy/sql/compiler.py27
-rw-r--r--lib/sqlalchemy/sql/crud.py2
-rw-r--r--lib/sqlalchemy/sql/ddl.py4
-rw-r--r--lib/sqlalchemy/sql/dml.py3
-rw-r--r--lib/sqlalchemy/sql/elements.py31
-rw-r--r--lib/sqlalchemy/sql/functions.py4
-rw-r--r--lib/sqlalchemy/sql/lambdas.py5
-rw-r--r--lib/sqlalchemy/sql/operators.py2
-rw-r--r--lib/sqlalchemy/sql/schema.py26
-rw-r--r--lib/sqlalchemy/sql/selectable.py14
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py34
-rw-r--r--lib/sqlalchemy/sql/traversals.py94
-rw-r--r--lib/sqlalchemy/sql/type_api.py4
-rw-r--r--lib/sqlalchemy/sql/util.py2
-rw-r--r--lib/sqlalchemy/sql/visitors.py6
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