summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2020-11-04 16:06:53 +0000
committerGerrit Code Review <gerrit@bbpush.zzzcomputing.com>2020-11-04 16:06:53 +0000
commite87fd72324e824d069351157b41485b0589cb41d (patch)
tree9c653ce778d95c83dc5302a41029b7cc6736630a
parentb0e6dccfb60cb900e327ae8ff6632e8c3339c53d (diff)
parentf016c1ac7f93d2f759aff53ec1494658efd7b496 (diff)
downloadsqlalchemy-e87fd72324e824d069351157b41485b0589cb41d.tar.gz
Merge "Reduce import time overhead"
-rw-r--r--lib/sqlalchemy/engine/create.py2
-rw-r--r--lib/sqlalchemy/event/attr.py16
-rw-r--r--lib/sqlalchemy/sql/__init__.py11
-rw-r--r--lib/sqlalchemy/sql/annotation.py6
-rw-r--r--lib/sqlalchemy/sql/traversals.py7
-rw-r--r--lib/sqlalchemy/sql/visitors.py35
-rw-r--r--lib/sqlalchemy/util/__init__.py1
-rw-r--r--lib/sqlalchemy/util/_concurrency_py3k.py181
-rw-r--r--lib/sqlalchemy/util/_preloaded.py12
-rw-r--r--lib/sqlalchemy/util/concurrency.py47
-rw-r--r--lib/sqlalchemy/util/langhelpers.py43
-rw-r--r--test/aaa_profiling/test_orm.py2
-rw-r--r--test/profiles.txt36
13 files changed, 195 insertions, 204 deletions
diff --git a/lib/sqlalchemy/engine/create.py b/lib/sqlalchemy/engine/create.py
index 365a72a96..4d84687ea 100644
--- a/lib/sqlalchemy/engine/create.py
+++ b/lib/sqlalchemy/engine/create.py
@@ -92,7 +92,7 @@ def create_engine(url, **kwargs):
:ref:`connections_toplevel`
- :param case_sensitive=True: if False, result column names
+ :param case_sensitive: if False, result column names
will match in a case-insensitive fashion, that is,
``row['SomeColumn']``.
diff --git a/lib/sqlalchemy/event/attr.py b/lib/sqlalchemy/event/attr.py
index baa3cd28a..122221d40 100644
--- a/lib/sqlalchemy/event/attr.py
+++ b/lib/sqlalchemy/event/attr.py
@@ -127,10 +127,8 @@ class _ClsLevelDispatch(RefCollection):
raise exc.InvalidRequestError(
"Can't assign an event directly to the %s class" % target
)
- stack = [target]
- while stack:
- cls = stack.pop(0)
- stack.extend(cls.__subclasses__())
+
+ for cls in util.walk_subclasses(target):
if cls is not target and cls not in self._clslevel:
self.update_subclass(cls)
else:
@@ -148,10 +146,7 @@ class _ClsLevelDispatch(RefCollection):
raise exc.InvalidRequestError(
"Can't assign an event directly to the %s class" % target
)
- stack = [target]
- while stack:
- cls = stack.pop(0)
- stack.extend(cls.__subclasses__())
+ for cls in util.walk_subclasses(target):
if cls is not target and cls not in self._clslevel:
self.update_subclass(cls)
else:
@@ -178,10 +173,7 @@ class _ClsLevelDispatch(RefCollection):
def remove(self, event_key):
target = event_key.dispatch_target
- stack = [target]
- while stack:
- cls = stack.pop(0)
- stack.extend(cls.__subclasses__())
+ for cls in util.walk_subclasses(target):
if cls in self._clslevel:
self._clslevel[cls].remove(event_key._listen_fn)
registry._removed_from_collection(event_key, self)
diff --git a/lib/sqlalchemy/sql/__init__.py b/lib/sqlalchemy/sql/__init__.py
index 8cfd20054..645189e76 100644
--- a/lib/sqlalchemy/sql/__init__.py
+++ b/lib/sqlalchemy/sql/__init__.py
@@ -55,10 +55,10 @@ from .expression import literal_column # noqa
from .expression import modifier # noqa
from .expression import not_ # noqa
from .expression import null # noqa
-from .expression import nullsfirst # noqa; deprecated 1.4; see #5435
-from .expression import nullslast # noqa; deprecated 1.4; see #5435
from .expression import nulls_first # noqa
from .expression import nulls_last # noqa
+from .expression import nullsfirst # noqa
+from .expression import nullslast # noqa
from .expression import or_ # noqa
from .expression import outerjoin # noqa
from .expression import outparam # noqa
@@ -106,7 +106,8 @@ def __go(lcls):
from .elements import AnnotatedColumnElement
from .elements import ClauseList # noqa
from .selectable import AnnotatedFromClause # noqa
- from .traversals import _preconfigure_traversals
+
+ # from .traversals import _preconfigure_traversals
from . import base
from . import coercions
@@ -133,7 +134,9 @@ def __go(lcls):
_prepare_annotations(FromClause, AnnotatedFromClause)
_prepare_annotations(ClauseList, Annotated)
- _preconfigure_traversals(ClauseElement)
+ # this is expensive at import time; elements that are used can create
+ # their traversals on demand
+ # _preconfigure_traversals(ClauseElement)
_sa_util.preloaded.import_prefix("sqlalchemy.sql")
diff --git a/lib/sqlalchemy/sql/annotation.py b/lib/sqlalchemy/sql/annotation.py
index 8a0d6ec28..94d37573c 100644
--- a/lib/sqlalchemy/sql/annotation.py
+++ b/lib/sqlalchemy/sql/annotation.py
@@ -354,9 +354,5 @@ def _new_annotation_type(cls, base_cls):
def _prepare_annotations(target_hierarchy, base_cls):
- stack = [target_hierarchy]
- while stack:
- cls = stack.pop()
- stack.extend(cls.__subclasses__())
-
+ for cls in util.walk_subclasses(target_hierarchy):
_new_annotation_type(cls, base_cls)
diff --git a/lib/sqlalchemy/sql/traversals.py b/lib/sqlalchemy/sql/traversals.py
index cb38df6af..a24d010cd 100644
--- a/lib/sqlalchemy/sql/traversals.py
+++ b/lib/sqlalchemy/sql/traversals.py
@@ -33,12 +33,7 @@ def compare(obj1, obj2, **kw):
def _preconfigure_traversals(target_hierarchy):
-
- stack = [target_hierarchy]
- while stack:
- cls = stack.pop()
- stack.extend(cls.__subclasses__())
-
+ for cls in util.walk_subclasses(target_hierarchy):
if hasattr(cls, "_traverse_internals"):
cls._generate_cache_attrs()
_copy_internals.generate_dispatch(
diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py
index 27499b5f7..43b7cb4af 100644
--- a/lib/sqlalchemy/sql/visitors.py
+++ b/lib/sqlalchemy/sql/visitors.py
@@ -24,6 +24,7 @@ http://techspot.zzzeek.org/2008/01/23/expression-transformations/ .
"""
from collections import deque
+import operator
from .. import exc
from .. import util
@@ -63,26 +64,24 @@ def _generate_compiler_dispatch(cls):
% cls.__name__
)
- code = (
- "def _compiler_dispatch(self, visitor, **kw):\n"
- " try:\n"
- " meth = visitor.visit_%(name)s\n"
- " except AttributeError as err:\n"
- " util.raise_(\n"
- " exc.UnsupportedCompilationError(visitor, cls), \n"
- " replace_context=err)\n"
- " else:\n"
- " return meth(self, **kw)\n"
- ) % {"name": visit_name}
-
- _compiler_dispatch = langhelpers._exec_code_in_env(
- code, {"exc": exc, "cls": cls, "util": util}, "_compiler_dispatch"
- )
+ name = "visit_%s" % visit_name
+ getter = operator.attrgetter(name)
+
+ def _compiler_dispatch(self, visitor, **kw):
+ """Look for an attribute named "visit_<visit_name>" on the
+ visitor, and call it with the same kw params.
- _compiler_dispatch.__doc__ = """Look for an attribute named "visit_"
- + self.__visit_name__ on the visitor, and call it with the same
- kw params.
"""
+ try:
+ meth = getter(visitor)
+ except AttributeError as err:
+ util.raise_(
+ exc.UnsupportedCompilationError(visitor, cls),
+ replace_context=err,
+ )
+ else:
+ return meth(self, **kw)
+
cls._compiler_dispatch = (
cls._original_compiler_dispatch
) = _compiler_dispatch
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py
index 00066cbed..7c5257b87 100644
--- a/lib/sqlalchemy/util/__init__.py
+++ b/lib/sqlalchemy/util/__init__.py
@@ -157,6 +157,7 @@ from .langhelpers import set_creation_order # noqa
from .langhelpers import string_or_unprintable # noqa
from .langhelpers import symbol # noqa
from .langhelpers import unbound_method_to_callable # noqa
+from .langhelpers import walk_subclasses # noqa
from .langhelpers import warn # noqa
from .langhelpers import warn_exception # noqa
from .langhelpers import warn_limited # noqa
diff --git a/lib/sqlalchemy/util/_concurrency_py3k.py b/lib/sqlalchemy/util/_concurrency_py3k.py
index ee3abe5fa..5d11bf92c 100644
--- a/lib/sqlalchemy/util/_concurrency_py3k.py
+++ b/lib/sqlalchemy/util/_concurrency_py3k.py
@@ -4,110 +4,103 @@ from typing import Any
from typing import Callable
from typing import Coroutine
+import greenlet
+
from .. import exc
-try:
- import greenlet
- # implementation based on snaury gist at
- # https://gist.github.com/snaury/202bf4f22c41ca34e56297bae5f33fef
- # Issue for context: https://github.com/python-greenlet/greenlet/issues/173
+# implementation based on snaury gist at
+# https://gist.github.com/snaury/202bf4f22c41ca34e56297bae5f33fef
+# Issue for context: https://github.com/python-greenlet/greenlet/issues/173
+
+
+class _AsyncIoGreenlet(greenlet.greenlet):
+ def __init__(self, fn, driver):
+ greenlet.greenlet.__init__(self, fn, driver)
+ self.driver = driver
+
+
+def await_only(awaitable: Coroutine) -> Any:
+ """Awaits an async function in a sync method.
+
+ The sync method must be insice a :func:`greenlet_spawn` context.
+ :func:`await_` calls cannot be nested.
- class _AsyncIoGreenlet(greenlet.greenlet):
- def __init__(self, fn, driver):
- greenlet.greenlet.__init__(self, fn, driver)
- self.driver = driver
+ :param awaitable: The coroutine to call.
- def await_only(awaitable: Coroutine) -> Any:
- """Awaits an async function in a sync method.
+ """
+ # this is called in the context greenlet while running fn
+ current = greenlet.getcurrent()
+ if not isinstance(current, _AsyncIoGreenlet):
+ raise exc.InvalidRequestError(
+ "greenlet_spawn has not been called; can't call await_() here."
+ )
- The sync method must be insice a :func:`greenlet_spawn` context.
- :func:`await_` calls cannot be nested.
+ # returns the control to the driver greenlet passing it
+ # a coroutine to run. Once the awaitable is done, the driver greenlet
+ # switches back to this greenlet with the result of awaitable that is
+ # then returned to the caller (or raised as error)
+ return current.driver.switch(awaitable)
- :param awaitable: The coroutine to call.
- """
- # this is called in the context greenlet while running fn
- current = greenlet.getcurrent()
- if not isinstance(current, _AsyncIoGreenlet):
+def await_fallback(awaitable: Coroutine) -> Any:
+ """Awaits an async function in a sync method.
+
+ The sync method must be insice a :func:`greenlet_spawn` context.
+ :func:`await_` calls cannot be nested.
+
+ :param awaitable: The coroutine to call.
+
+ """
+
+ # this is called in the context greenlet while running fn
+ current = greenlet.getcurrent()
+ if not isinstance(current, _AsyncIoGreenlet):
+ loop = asyncio.get_event_loop()
+ if loop.is_running():
raise exc.InvalidRequestError(
- "greenlet_spawn has not been called; can't call await_() here."
+ "greenlet_spawn has not been called and asyncio event "
+ "loop is already running; can't call await_() here."
)
-
- # returns the control to the driver greenlet passing it
- # a coroutine to run. Once the awaitable is done, the driver greenlet
- # switches back to this greenlet with the result of awaitable that is
- # then returned to the caller (or raised as error)
- return current.driver.switch(awaitable)
-
- def await_fallback(awaitable: Coroutine) -> Any:
- """Awaits an async function in a sync method.
-
- The sync method must be insice a :func:`greenlet_spawn` context.
- :func:`await_` calls cannot be nested.
-
- :param awaitable: The coroutine to call.
-
- """
- # this is called in the context greenlet while running fn
- current = greenlet.getcurrent()
- if not isinstance(current, _AsyncIoGreenlet):
- loop = asyncio.get_event_loop()
- if loop.is_running():
- raise exc.InvalidRequestError(
- "greenlet_spawn has not been called and asyncio event "
- "loop is already running; can't call await_() here."
- )
- return loop.run_until_complete(awaitable)
-
- return current.driver.switch(awaitable)
-
- async def greenlet_spawn(fn: Callable, *args, **kwargs) -> Any:
- """Runs a sync function ``fn`` in a new greenlet.
-
- The sync function can then use :func:`await_` to wait for async
- functions.
-
- :param fn: The sync callable to call.
- :param \\*args: Positional arguments to pass to the ``fn`` callable.
- :param \\*\\*kwargs: Keyword arguments to pass to the ``fn`` callable.
- """
- context = _AsyncIoGreenlet(fn, greenlet.getcurrent())
- # runs the function synchronously in gl greenlet. If the execution
- # is interrupted by await_, context is not dead and result is a
- # coroutine to wait. If the context is dead the function has
- # returned, and its result can be returned.
- try:
- result = context.switch(*args, **kwargs)
- while not context.dead:
- try:
- # wait for a coroutine from await_ and then return its
- # result back to it.
- value = await result
- except Exception:
- # this allows an exception to be raised within
- # the moderated greenlet so that it can continue
- # its expected flow.
- result = context.throw(*sys.exc_info())
- else:
- result = context.switch(value)
- finally:
- # clean up to avoid cycle resolution by gc
- del context.driver
- return result
-
-
-except ImportError: # pragma: no cover
- greenlet = None
-
- def await_fallback(awaitable):
- return asyncio.get_event_loop().run_until_complete(awaitable)
-
- def await_only(awaitable):
- raise ValueError("Greenlet is required to use this function")
-
- async def greenlet_spawn(fn, *args, **kw):
- raise ValueError("Greenlet is required to use this function")
+ return loop.run_until_complete(awaitable)
+
+ return current.driver.switch(awaitable)
+
+
+async def greenlet_spawn(fn: Callable, *args, **kwargs) -> Any:
+ """Runs a sync function ``fn`` in a new greenlet.
+
+ The sync function can then use :func:`await_` to wait for async
+ functions.
+
+ :param fn: The sync callable to call.
+ :param \\*args: Positional arguments to pass to the ``fn`` callable.
+ :param \\*\\*kwargs: Keyword arguments to pass to the ``fn`` callable.
+ """
+
+ context = _AsyncIoGreenlet(fn, greenlet.getcurrent())
+ # runs the function synchronously in gl greenlet. If the execution
+ # is interrupted by await_, context is not dead and result is a
+ # coroutine to wait. If the context is dead the function has
+ # returned, and its result can be returned.
+ try:
+ result = context.switch(*args, **kwargs)
+ while not context.dead:
+ try:
+ # wait for a coroutine from await_ and then return its
+ # result back to it.
+ value = await result
+ except Exception:
+ # this allows an exception to be raised within
+ # the moderated greenlet so that it can continue
+ # its expected flow.
+ result = context.throw(*sys.exc_info())
+ else:
+ result = context.switch(value)
+ finally:
+ # clean up to avoid cycle resolution by gc
+ del context.driver
+ return result
class AsyncAdaptedLock:
diff --git a/lib/sqlalchemy/util/_preloaded.py b/lib/sqlalchemy/util/_preloaded.py
index 1a833a963..e267c008c 100644
--- a/lib/sqlalchemy/util/_preloaded.py
+++ b/lib/sqlalchemy/util/_preloaded.py
@@ -35,8 +35,9 @@ class _ModuleRegistry:
name. Example: ``sqlalchemy.sql.util`` becomes ``preloaded.sql_util``.
"""
- def __init__(self, prefix="sqlalchemy"):
+ def __init__(self, prefix="sqlalchemy."):
self.module_registry = set()
+ self.prefix = prefix
def preload_module(self, *deps):
"""Adds the specified modules to the list to load.
@@ -52,8 +53,13 @@ class _ModuleRegistry:
specified path.
"""
for module in self.module_registry:
- key = module.split("sqlalchemy.")[-1].replace(".", "_")
- if module.startswith(path) and key not in self.__dict__:
+ if self.prefix:
+ key = module.split(self.prefix)[-1].replace(".", "_")
+ else:
+ key = module
+ if (
+ not path or module.startswith(path)
+ ) and key not in self.__dict__:
compat.import_(module, globals(), locals())
self.__dict__[key] = sys.modules[module]
diff --git a/lib/sqlalchemy/util/concurrency.py b/lib/sqlalchemy/util/concurrency.py
index e0883aa68..f78c0971c 100644
--- a/lib/sqlalchemy/util/concurrency.py
+++ b/lib/sqlalchemy/util/concurrency.py
@@ -1,25 +1,40 @@
from . import compat
+have_greenlet = False
if compat.py3k:
- import asyncio
- from ._concurrency_py3k import await_only
- from ._concurrency_py3k import await_fallback
- from ._concurrency_py3k import greenlet
- from ._concurrency_py3k import greenlet_spawn
- from ._concurrency_py3k import AsyncAdaptedLock
-else:
- asyncio = None
- greenlet = None
-
- def await_only(thing):
+ try:
+ import greenlet # noqa F401
+ except ImportError:
+ pass
+ else:
+ have_greenlet = True
+ from ._concurrency_py3k import await_only
+ from ._concurrency_py3k import await_fallback
+ from ._concurrency_py3k import greenlet_spawn
+ from ._concurrency_py3k import AsyncAdaptedLock
+ from ._concurrency_py3k import asyncio # noqa F401
+
+if not have_greenlet:
+
+ asyncio = None # noqa F811
+
+ def _not_implemented():
+ if not compat.py3k:
+ raise ValueError("Cannot use this function in py2.")
+ else:
+ raise ValueError(
+ "the greenlet library is required to use this function."
+ )
+
+ def await_only(thing): # noqa F811
return thing
- def await_fallback(thing):
+ def await_fallback(thing): # noqa F81
return thing
- def greenlet_spawn(fn, *args, **kw):
- raise ValueError("Cannot use this function in py2.")
+ def greenlet_spawn(fn, *args, **kw): # noqa F81
+ _not_implemented()
- def AsyncAdaptedLock(*args, **kw):
- raise ValueError("Cannot use this function in py2.")
+ def AsyncAdaptedLock(*args, **kw): # noqa F81
+ _not_implemented()
diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py
index 4289db812..ce3a28499 100644
--- a/lib/sqlalchemy/util/langhelpers.py
+++ b/lib/sqlalchemy/util/langhelpers.py
@@ -10,6 +10,7 @@ modules, classes, hierarchies, attributes, functions, and methods.
"""
+import collections
from functools import update_wrapper
import hashlib
import inspect
@@ -83,6 +84,20 @@ class safe_reraise(object):
compat.raise_(value, with_traceback=traceback)
+def walk_subclasses(cls):
+ seen = set()
+
+ stack = [cls]
+ while stack:
+ cls = stack.pop()
+ if cls in seen:
+ continue
+ else:
+ seen.add(cls)
+ stack.extend(cls.__subclasses__())
+ yield cls
+
+
def string_or_unprintable(element):
if isinstance(element, compat.string_types):
return element
@@ -1782,15 +1797,22 @@ def inject_docstring_text(doctext, injecttext, pos):
return "\n".join(lines)
+_param_reg = re.compile(r"(\s+):param (.+?):")
+
+
def inject_param_text(doctext, inject_params):
- doclines = doctext.splitlines()
+ doclines = collections.deque(doctext.splitlines())
lines = []
+ # TODO: this is not working for params like ":param case_sensitive=True:"
+
to_inject = None
while doclines:
- line = doclines.pop(0)
+ line = doclines.popleft()
+
+ m = _param_reg.match(line)
+
if to_inject is None:
- m = re.match(r"(\s+):param (.+?):", line)
if m:
param = m.group(2).lstrip("*")
if param in inject_params:
@@ -1805,23 +1827,16 @@ def inject_param_text(doctext, inject_params):
indent = " " * len(m2.group(1))
to_inject = indent + inject_params[param]
- elif line.lstrip().startswith(":param "):
- lines.append("\n")
- lines.append(to_inject)
- lines.append("\n")
+ elif m:
+ lines.extend(["\n", to_inject, "\n"])
to_inject = None
elif not line.rstrip():
- lines.append(line)
- lines.append(to_inject)
- lines.append("\n")
+ lines.extend([line, to_inject, "\n"])
to_inject = None
elif line.endswith("::"):
# TODO: this still wont cover if the code example itself has blank
# lines in it, need to detect those via indentation.
- lines.append(line)
- lines.append(
- doclines.pop(0)
- ) # the blank line following a code example
+ lines.extend([line, doclines.popleft()])
continue
lines.append(line)
diff --git a/test/aaa_profiling/test_orm.py b/test/aaa_profiling/test_orm.py
index 4bc2af93d..1bbfd3658 100644
--- a/test/aaa_profiling/test_orm.py
+++ b/test/aaa_profiling/test_orm.py
@@ -864,7 +864,7 @@ class JoinedEagerLoadTest(NoCache, fixtures.MappedTest):
from sqlalchemy.orm.context import ORMCompileState
- @profiling.function_call_count()
+ @profiling.function_call_count(warmup=1)
def go():
for i in range(100):
# NOTE: this test was broken in
diff --git a/test/profiles.txt b/test/profiles.txt
index 4a21de427..08cdf911b 100644
--- a/test/profiles.txt
+++ b/test/profiles.txt
@@ -1,15 +1,15 @@
# /home/classic/dev/sqlalchemy/test/profiles.txt
# This file is written out on a per-environment basis.
-# For each test in aaa_profiling, the corresponding function and
+# For each test in aaa_profiling, the corresponding function and
# environment is located within this file. If it doesn't exist,
# the test is skipped.
-# If a callcount does exist, it is compared to what we received.
+# If a callcount does exist, it is compared to what we received.
# assertions are raised if the counts do not match.
-#
-# To add a new callcount test, apply the function_call_count
-# decorator and re-run the tests using the --write-profiles
+#
+# To add a new callcount test, apply the function_call_count
+# decorator and re-run the tests using the --write-profiles
# option - this file will be rewritten including the new count.
-#
+#
# TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert
@@ -153,34 +153,10 @@ test.aaa_profiling.test_compiler.CompileTest.test_update x86_64_linux_cpython_3.
# TEST: test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mariadb_mysqldb_dbapiunicode_cextensions 159
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mariadb_mysqldb_dbapiunicode_nocextensions 159
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mariadb_pymysql_dbapiunicode_cextensions 159
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mariadb_pymysql_dbapiunicode_nocextensions 159
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mssql_pyodbc_dbapiunicode_cextensions 159
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mssql_pyodbc_dbapiunicode_nocextensions 159
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mysql_mysqldb_dbapiunicode_cextensions 152
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mysql_mysqldb_dbapiunicode_nocextensions 152
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_cextensions 152
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_mysql_pymysql_dbapiunicode_nocextensions 152
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_cextensions 157
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_oracle_cx_oracle_dbapiunicode_nocextensions 159
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_cextensions 159
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_postgresql_psycopg2_dbapiunicode_nocextensions 159
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_cextensions 159
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_2.7_sqlite_pysqlite_dbapiunicode_nocextensions 159
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_cextensions 165
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mariadb_mysqldb_dbapiunicode_nocextensions 165
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mariadb_pymysql_dbapiunicode_cextensions 165
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mariadb_pymysql_dbapiunicode_nocextensions 165
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_cextensions 165
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mssql_pyodbc_dbapiunicode_nocextensions 165
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_cextensions 158
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mysql_mysqldb_dbapiunicode_nocextensions 158
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mysql_pymysql_dbapiunicode_cextensions 158
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_mysql_pymysql_dbapiunicode_nocextensions 158
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_cextensions 163
-test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_oracle_cx_oracle_dbapiunicode_nocextensions 163
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_cextensions 165
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_postgresql_psycopg2_dbapiunicode_nocextensions 165
test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause x86_64_linux_cpython_3.8_sqlite_pysqlite_dbapiunicode_cextensions 165