From 598f2f7e557073f29563d4d567f43931fc03013f Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 3 Mar 2020 16:03:39 -0500 Subject: [PATCH] Don't import provision.py unconditionally Removed the imports for provision.py from each dialect and instead added a call in the central provision.py to a new dialect level method load_provisioning(). The provisioning registry works in the same way, so an existing dialect that is using the provision.py system right now by importing it as part of the package will still continue to function. However, to avoid pulling in the testing package when the dialect is used in a non-testing context, the new hook may be used. Also removed a module-level dependency of the testing framework on the orm package. Revised an internal change to the test system added as a result of :ticket:`5085` where a testing-related module per dialect would be loaded unconditionally upon making use of that dialect, pulling in SQLAlchemy's testing framework as well as the ORM into the module import space. This would only impact initial startup time and memory to a modest extent, however it's best that these additional modules aren't reverse-dependent on straight Core usage. Fixes: #5180 Change-Id: I6355601da5f6f44d85a2bbc3acb5928559942b9c --- doc/build/changelog/unreleased_13/5180.rst | 11 +++++++ lib/sqlalchemy/dialects/mssql/__init__.py | 1 - lib/sqlalchemy/dialects/mysql/__init__.py | 1 - lib/sqlalchemy/dialects/oracle/__init__.py | 1 - .../dialects/postgresql/__init__.py | 1 - lib/sqlalchemy/dialects/sqlite/__init__.py | 1 - lib/sqlalchemy/engine/default.py | 8 +++++ lib/sqlalchemy/engine/interfaces.py | 29 +++++++++++++++++++ lib/sqlalchemy/orm/query.py | 1 - lib/sqlalchemy/testing/assertions.py | 3 +- lib/sqlalchemy/testing/provision.py | 5 ++-- 11 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 doc/build/changelog/unreleased_13/5180.rst diff --git a/doc/build/changelog/unreleased_13/5180.rst b/doc/build/changelog/unreleased_13/5180.rst new file mode 100644 index 0000000000..85ac9a64e5 --- /dev/null +++ b/doc/build/changelog/unreleased_13/5180.rst @@ -0,0 +1,11 @@ +.. change:: + :tags: bug, performance + :tickets: 5180 + + Revised an internal change to the test system added as a result of + :ticket:`5085` where a testing-related module per dialect would be loaded + unconditionally upon making use of that dialect, pulling in SQLAlchemy's + testing framework as well as the ORM into the module import space. This + would only impact initial startup time and memory to a modest extent, + however it's best that these additional modules aren't reverse-dependent on + straight Core usage. diff --git a/lib/sqlalchemy/dialects/mssql/__init__.py b/lib/sqlalchemy/dialects/mssql/__init__.py index cbee8c0dc2..67830affe3 100644 --- a/lib/sqlalchemy/dialects/mssql/__init__.py +++ b/lib/sqlalchemy/dialects/mssql/__init__.py @@ -8,7 +8,6 @@ from . import adodbapi # noqa from . import base # noqa from . import mxodbc # noqa -from . import provision # noqa from . import pymssql # noqa from . import pyodbc # noqa from .base import BIGINT diff --git a/lib/sqlalchemy/dialects/mysql/__init__.py b/lib/sqlalchemy/dialects/mysql/__init__.py index 12eb673a73..f1f1cce371 100644 --- a/lib/sqlalchemy/dialects/mysql/__init__.py +++ b/lib/sqlalchemy/dialects/mysql/__init__.py @@ -11,7 +11,6 @@ from . import gaerdbms # noqa from . import mysqlconnector # noqa from . import mysqldb # noqa from . import oursql # noqa -from . import provision # noqa from . import pymysql # noqa from . import pyodbc # noqa from .base import BIGINT diff --git a/lib/sqlalchemy/dialects/oracle/__init__.py b/lib/sqlalchemy/dialects/oracle/__init__.py index 90157bd67b..a4dee02ff9 100644 --- a/lib/sqlalchemy/dialects/oracle/__init__.py +++ b/lib/sqlalchemy/dialects/oracle/__init__.py @@ -7,7 +7,6 @@ from . import base # noqa from . import cx_oracle # noqa -from . import provision # noqa from .base import BFILE from .base import BINARY_DOUBLE from .base import BINARY_FLOAT diff --git a/lib/sqlalchemy/dialects/postgresql/__init__.py b/lib/sqlalchemy/dialects/postgresql/__init__.py index c6482222d2..06d22872a9 100644 --- a/lib/sqlalchemy/dialects/postgresql/__init__.py +++ b/lib/sqlalchemy/dialects/postgresql/__init__.py @@ -7,7 +7,6 @@ from . import base from . import pg8000 # noqa -from . import provision # noqa from . import psycopg2 # noqa from . import psycopg2cffi # noqa from . import pygresql # noqa diff --git a/lib/sqlalchemy/dialects/sqlite/__init__.py b/lib/sqlalchemy/dialects/sqlite/__init__.py index c35cb9251c..142131f631 100644 --- a/lib/sqlalchemy/dialects/sqlite/__init__.py +++ b/lib/sqlalchemy/dialects/sqlite/__init__.py @@ -6,7 +6,6 @@ # the MIT License: http://www.opensource.org/licenses/mit-license.php from . import base # noqa -from . import provision # noqa from . import pysqlcipher # noqa from . import pysqlite # noqa from .base import BLOB diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 28a59e6601..8775a88136 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -293,6 +293,14 @@ class DefaultDialect(interfaces.Dialect): def get_pool_class(cls, url): return getattr(cls, "poolclass", pool.QueuePool) + @classmethod + def load_provisioning(cls): + package = ".".join(cls.__module__.split(".")[0:-1]) + try: + __import__(package + ".provision") + except ImportError: + pass + def initialize(self, connection): try: self.server_version_info = self._get_server_version_info( diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py index 04e572c2d2..84def853f2 100644 --- a/lib/sqlalchemy/engine/interfaces.py +++ b/lib/sqlalchemy/engine/interfaces.py @@ -865,6 +865,35 @@ class Dialect(object): """ return cls + @classmethod + def load_provisioning(cls): + """set up the provision.py module for this dialect. + + For dialects that include a provision.py module that sets up + provisioning followers, this method should initiate that process. + + A typical implementation would be:: + + @classmethod + def load_provisioning(cls): + __import__("mydialect.provision") + + The default method assumes a module named ``provision.py`` inside + the owning package of the current dialect, based on the ``__module__`` + attribute:: + + @classmethod + def load_provisioning(cls): + package = ".".join(cls.__module__.split(".")[0:-1]) + try: + __import__(package + ".provision") + except ImportError: + pass + + .. versionadded:: 1.3.14 + + """ + @classmethod def engine_created(cls, engine): """A convenience hook called before returning the final :class:`.Engine`. diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index e29e6eeeeb..830cede93d 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -59,7 +59,6 @@ from ..sql.base import Generative from ..sql.selectable import ForUpdateArg from ..util import collections_abc - __all__ = ["Query", "QueryContext", "aliased"] diff --git a/lib/sqlalchemy/testing/assertions.py b/lib/sqlalchemy/testing/assertions.py index c97202516b..07a70bf6cd 100644 --- a/lib/sqlalchemy/testing/assertions.py +++ b/lib/sqlalchemy/testing/assertions.py @@ -19,7 +19,6 @@ from . import mock from .exclusions import db_spec from .util import fail from .. import exc as sa_exc -from .. import orm from .. import schema from .. import types as sqltypes from .. import util @@ -386,6 +385,8 @@ class AssertsCompiledSQL(object): if render_postcompile: compile_kwargs["render_postcompile"] = True + from sqlalchemy import orm + if isinstance(clause, orm.Query): context = clause._compile_context() context.statement.use_labels = True diff --git a/lib/sqlalchemy/testing/provision.py b/lib/sqlalchemy/testing/provision.py index 6e2e1ccf50..543d91a533 100644 --- a/lib/sqlalchemy/testing/provision.py +++ b/lib/sqlalchemy/testing/provision.py @@ -6,7 +6,6 @@ from . import engines from ..engine import url as sa_url from ..util import compat - log = logging.getLogger(__name__) FOLLOWER_IDENT = None @@ -51,7 +50,9 @@ def setup_config(db_url, options, file_config, follower_ident): # load the dialect, which should also have it set up its provision # hooks - sa_url.make_url(db_url).get_dialect() + dialect = sa_url.make_url(db_url).get_dialect() + dialect.load_provisioning() + if follower_ident: db_url = follower_url_from_main(db_url, follower_ident) db_opts = {} -- 2.39.5