]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- coverage was not working (and needs to be fixed in SQLAlchemy too),
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 14 Sep 2014 19:49:04 +0000 (15:49 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 14 Sep 2014 19:51:19 +0000 (15:51 -0400)
go back to using a "bootstrap" system where we load in pytestplugin/
noseplugin via file importing, plugin/ is not used as a package.
- identify the pytest_sessionstart hook as the best place to do
plugin_base.post_begin() and actually begin importing main modules;
this is where coverage has actually started.
- we're now targeting 1.0.0 as this has to be ported to SQLAlchemy.
- start using .coveragerc

17 files changed:
.coveragerc [new file with mode: 0644]
alembic/ddl/__init__.py
alembic/testing/config.py
alembic/testing/engines.py
alembic/testing/env.py
alembic/testing/exclusions.py
alembic/testing/mock.py
alembic/testing/plugin/__init__.py
alembic/testing/plugin/bootstrap.py [new file with mode: 0644]
alembic/testing/plugin/noseplugin.py
alembic/testing/plugin/plugin_base.py
alembic/testing/plugin/pytestplugin.py
alembic/testing/provision.py [moved from alembic/testing/plugin/provision.py with 98% similarity]
alembic/testing/runner.py
run_tests.py
tests/conftest.py
tox.ini

diff --git a/.coveragerc b/.coveragerc
new file mode 100644 (file)
index 0000000..1b33a56
--- /dev/null
@@ -0,0 +1,5 @@
+[run]
+include=alembic/*
+
+[report]
+omit=alembic/testing/*
\ No newline at end of file
index bfc8ab46b375305bc5d37d122c852c59a9894dd6..d225c45c148deb051bbc4ee82c5046d54231de06 100644 (file)
@@ -1,2 +1,2 @@
-from . import postgresql, mysql, sqlite, mssql, oracle
-from .impl import DefaultImpl
+from . import postgresql, mysql, sqlite, mssql, oracle  # pragma: no cover
+from .impl import DefaultImpl  # pragma: no cover
index 98006f262c5d8c07bd5a7c03a6302a3ecf9c5c95..474fde4a8ef988942f50552ed8a8a3119f7b3de9 100644 (file)
@@ -5,7 +5,7 @@
 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 """NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+   this should be removable when Alembic targets SQLAlchemy 1.0.0
 """
 
 import collections
index 22d04f2471eab5c0878c77e2ea52ea9573ff3bce..35aa8b53ebcb465bc178d69333d39059aef4074b 100644 (file)
@@ -5,7 +5,7 @@
 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 """NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+   this should be removable when Alembic targets SQLAlchemy 1.0.0.
 """
 
 from __future__ import absolute_import
index bf043784a77b48df816f744417df198218517bbb..6c449a52da0ffc87962ed5846c1fc98e116687a4 100644 (file)
@@ -8,12 +8,12 @@ from alembic.compat import u
 from alembic.script import Script, ScriptDirectory
 from alembic import util
 from . import engines
-from alembic.testing.plugin import plugin_base
+from . import provision
 
 
 def _get_staging_directory():
-    if plugin_base.FOLLOWER_IDENT:
-        return "scratch_%s" % plugin_base.FOLLOWER_IDENT
+    if provision.FOLLOWER_IDENT:
+        return "scratch_%s" % provision.FOLLOWER_IDENT
     else:
         return 'scratch'
 
index 1b572e531c1e213858edc21c258d98ea1b670714..a64fe352847a2c1bcc0e32157734a1ad02e59ae5 100644 (file)
@@ -5,7 +5,7 @@
 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 """NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+   this should be removable when Alembic targets SQLAlchemy 1.0.0
 """
 
 
index 8d0c0512a30bb897d3929ba98188b33e262a142c..cdfcb88a0695882e8f2101cbd222d805e7ab32df 100644 (file)
@@ -8,7 +8,7 @@
 """Import stub for mock library.
 
     NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+   this should be removable when Alembic targets SQLAlchemy 1.0.0
 
 """
 from __future__ import absolute_import
@@ -18,7 +18,7 @@ if py33:
     from unittest.mock import MagicMock, Mock, call, patch
 else:
     try:
-        from mock import MagicMock, Mock, call, patch
+        from mock import MagicMock, Mock, call, patch  # noqa
     except ImportError:
         raise ImportError(
             "SQLAlchemy's test suite requires the "
index 3e00e406c57b91f7d0bf9df1c208a3091601b145..98616f497e151a6af2a519529cd3bdb7419954c2 100644 (file)
@@ -1,3 +1,3 @@
 """NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+   this should be removable when Alembic targets SQLAlchemy 1.0.0
 """
diff --git a/alembic/testing/plugin/bootstrap.py b/alembic/testing/plugin/bootstrap.py
new file mode 100644 (file)
index 0000000..1560b03
--- /dev/null
@@ -0,0 +1,44 @@
+"""
+Bootstrapper for nose/pytest plugins.
+
+The entire rationale for this system is to get the modules in plugin/
+imported without importing all of the supporting library, so that we can
+set up things for testing before coverage starts.
+
+The rationale for all of plugin/ being *in* the supporting library in the
+first place is so that the testing and plugin suite is available to other
+libraries, mainly external SQLAlchemy and Alembic dialects, to make use
+of the same test environment and standard suites available to
+SQLAlchemy/Alembic themselves without the need to ship/install a separate
+package outside of SQLAlchemy.
+
+NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
+this should be removable when Alembic targets SQLAlchemy 1.0.0.
+
+"""
+
+import os
+import sys
+
+bootstrap_file = locals()['bootstrap_file']
+to_bootstrap = locals()['to_bootstrap']
+
+
+def load_file_as_module(name):
+    path = os.path.join(os.path.dirname(bootstrap_file), "%s.py" % name)
+    if sys.version_info >= (3, 3):
+        from importlib import machinery
+        mod = machinery.SourceFileLoader(name, path).load_module()
+    else:
+        import imp
+        mod = imp.load_source(name, path)
+    return mod
+
+if to_bootstrap == "pytest":
+    sys.modules["alembic_plugin_base"] = load_file_as_module("plugin_base")
+    sys.modules["alembic_pytestplugin"] = load_file_as_module("pytestplugin")
+elif to_bootstrap == "nose":
+    sys.modules["alembic_plugin_base"] = load_file_as_module("plugin_base")
+    sys.modules["alembic_noseplugin"] = load_file_as_module("noseplugin")
+else:
+    raise Exception("unknown bootstrap: %s" % to_bootstrap)  # noqa
index ec3eebef5bbd7f12ee3e6b4a7f9426259ebda4b3..3235d4fbbfa9630db4a859d54763c5966602b287 100644 (file)
@@ -5,15 +5,22 @@
 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-"""NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
 """
+Enhance nose with extra options and behaviors for running SQLAlchemy tests.
 
-"""Enhance nose with extra options and behaviors for running SQLAlchemy tests.
 
+NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
+this should be removable when Alembic targets SQLAlchemy 1.0.0.
 
 """
 
+try:
+    # installed by bootstrap.py
+    import alembic_plugin_base as plugin_base
+except ImportError:
+    # assume we're a package, use traditional import
+    from . import plugin_base
+
 import os
 import sys
 
@@ -21,16 +28,6 @@ from nose.plugins import Plugin
 fixtures = None
 
 py3k = sys.version_info >= (3, 0)
-# no package imports yet!  this prevents us from tripping coverage
-# too soon.
-path = os.path.join(os.path.dirname(__file__), "plugin_base.py")
-if sys.version_info >= (3, 3):
-    from importlib import machinery
-    plugin_base = machinery.SourceFileLoader(
-        "plugin_base", path).load_module()
-else:
-    import imp
-    plugin_base = imp.load_source("plugin_base", path)
 
 
 class NoseSQLAlchemy(Plugin):
@@ -60,10 +57,10 @@ class NoseSQLAlchemy(Plugin):
 
         plugin_base.set_coverage_flag(options.enable_plugin_coverage)
 
+    def begin(self):
         global fixtures
         from alembic.testing import fixtures  # noqa
 
-    def begin(self):
         plugin_base.post_begin()
 
     def describeTest(self, test):
@@ -77,7 +74,6 @@ class NoseSQLAlchemy(Plugin):
             cls = fn.__self__.cls
         else:
             cls = fn.im_class
-        print "METH:", fn, "CLS:", cls
         return plugin_base.want_method(cls, fn)
 
     def wantClass(self, cls):
index c4d1f838be8da3d1604b07db33f78e6d251a9e3c..c4c600d581a737a8848142994ec583b7fc5f3d92 100644 (file)
@@ -11,7 +11,7 @@ so that we can continue to support nose and also begin adding new
 functionality via py.test.
 
 NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+this should be removable when Alembic targets SQLAlchemy 1.0.0
 
 
 """
@@ -34,11 +34,10 @@ if py3k:
 else:
     import ConfigParser as configparser
 
-FOLLOWER_IDENT = None
-
 # late imports
 fixtures = None
 engines = None
+provision = None
 exclusions = None
 warnings = None
 assertions = None
@@ -111,8 +110,8 @@ def configure_follower(follower_ident):
     database creation.
 
     """
-    global FOLLOWER_IDENT
-    FOLLOWER_IDENT = follower_ident
+    from alembic.testing import provision
+    provision.FOLLOWER_IDENT = follower_ident
 
 
 def memoize_important_follower_config(dict_):
@@ -164,6 +163,7 @@ def set_coverage_flag(value):
 
 def post_begin():
     """things to set up later, once we know coverage is running."""
+
     # Lazy setup of other options (post coverage)
     for fn in post_configure:
         fn(options, file_config)
@@ -245,7 +245,7 @@ def _monkeypatch_cdecimal(options, file_config):
 @post
 def _engine_uri(options, file_config):
     from alembic.testing import config
-    from alembic.testing.plugin import provision
+    from alembic.testing import provision
 
     if options.dburi:
         db_urls = list(options.dburi)
@@ -268,7 +268,7 @@ def _engine_uri(options, file_config):
 
     for db_url in db_urls:
         cfg = provision.setup_config(
-            db_url, db_opts, options, file_config, FOLLOWER_IDENT)
+            db_url, db_opts, options, file_config, provision.FOLLOWER_IDENT)
 
         if not config._current:
             cfg.set_as_current(cfg)
index 26f188fd481f3e963509e31a4d6e255098871d6c..78194a325f42d3ebe4bf5bdf6c4e3f4e7a6398e5 100644 (file)
@@ -1,10 +1,21 @@
 """NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+   this should be removable when Alembic targets SQLAlchemy 1.0.0.
 """
+
+try:
+    # installed by bootstrap.py
+    import alembic_plugin_base as plugin_base
+except ImportError:
+    # assume we're a package, use traditional import
+    from . import plugin_base
+
+import sys
+
+py3k = sys.version_info >= (3, 0)
+
 import pytest
 import argparse
 import inspect
-from . import plugin_base
 import collections
 import itertools
 
@@ -42,9 +53,11 @@ def pytest_configure(config):
 
     plugin_base.pre_begin(config.option)
 
-    plugin_base.set_coverage_flag(bool(getattr(config.option,
-                                               "cov_source", False)))
+    coverage = bool(getattr(config.option, "cov_source", False))
+    plugin_base.set_coverage_flag(coverage)
 
+
+def pytest_sessionstart(session):
     plugin_base.post_begin()
 
 if has_xdist:
@@ -57,11 +70,11 @@ if has_xdist:
         plugin_base.memoize_important_follower_config(node.slaveinput)
 
         node.slaveinput["follower_ident"] = "test_%s" % next(_follower_count)
-        from . import provision
+        from alembic.testing import provision
         provision.create_follower_db(node.slaveinput["follower_ident"])
 
     def pytest_testnodedown(node, error):
-        from . import provision
+        from alembic.testing import provision
         provision.drop_follower_db(node.slaveinput["follower_ident"])
 
 
@@ -121,6 +134,7 @@ def pytest_pycollect_makeitem(collector, name, obj):
 
 _current_class = None
 
+
 def pytest_runtest_setup(item):
     # here we seem to get called only based on what we collected
     # in pytest_collection_modifyitems.   So to do class-based stuff
similarity index 98%
rename from alembic/testing/plugin/provision.py
rename to alembic/testing/provision.py
index d0edbefe14c519c6feaae9d81bedf65209692a10..801d36be051282ae1734fd8cfec1b268a5d3fa85 100644 (file)
@@ -1,5 +1,5 @@
 """NOTE:  copied/adapted from SQLAlchemy master for backwards compatibility;
-   this should be removable when Alembic targets SQLAlchemy 0.9.4.
+   this should be removable when Alembic targets SQLAlchemy 1.0.0
 """
 from sqlalchemy.engine import url as sa_url
 from sqlalchemy import text
@@ -7,6 +7,8 @@ from alembic import compat
 from alembic.testing import config, engines
 from alembic.testing.compat import get_url_backend_name
 
+FOLLOWER_IDENT = None
+
 
 class register(object):
     def __init__(self):
index 2810b88abc58bf1d99339e17818ff10548e7af7d..2ad938730545e31ed44a3325dc6b2b16537e971f 100644 (file)
@@ -29,9 +29,7 @@ plugin in a special (somewhat hacky) way so that coverage against
 SQLAlchemy itself is possible.
 
 """
-
-from alembic.testing.plugin.noseplugin import NoseSQLAlchemy
-
+from .plugin.noseplugin import NoseSQLAlchemy
 import nose
 
 
index cab050252c82ebea2930e2236a4243b1bdf10da5..71770fc0262ae0e82b11b2de8853d56ac8522bbf 100755 (executable)
@@ -1,3 +1,17 @@
-from alembic.testing import runner
+import os
+# use bootstrapping so that test plugins are loaded
+# without touching the main library before coverage starts
+bootstrap_file = os.path.join(
+    os.path.dirname(__file__), "alembic",
+    "testing", "plugin", "bootstrap.py"
+)
 
-runner.main()
+with open(bootstrap_file) as f:
+    code = compile(f.read(), "bootstrap.py", 'exec')
+    to_bootstrap = "nose"
+    exec(code, globals(), locals())
+
+
+from noseplugin import NoseSQLAlchemy
+import nose
+nose.main(addplugins=[NoseSQLAlchemy()])
index bdb361af622bde7bffd855228dbfc7bc52e664cd..608d90399a659a395d82927763d86fbfff50bcd7 100755 (executable)
@@ -6,10 +6,17 @@ This script is an extension to py.test which
 installs SQLAlchemy's testing plugin into the local environment.
 
 """
-import sys
+import os
 
-from os import path
-for pth in ['../lib']:
-    sys.path.insert(0, path.join(path.dirname(path.abspath(__file__)), pth))
+# use bootstrapping so that test plugins are loaded
+# without touching the main library before coverage starts
+bootstrap_file = os.path.join(
+    os.path.dirname(__file__), "..", "alembic",
+    "testing", "plugin", "bootstrap.py"
+)
 
-from alembic.testing.plugin.pytestplugin import *
+with open(bootstrap_file) as f:
+    code = compile(f.read(), "bootstrap.py", 'exec')
+    to_bootstrap = "pytest"
+    exec(code, globals(), locals())
+    from pytestplugin import *  # noqa
diff --git a/tox.ini b/tox.ini
index 00cd075ea3fb6a4293bf205416c662c1fd6e5509..c27041a8c7f76169554fa573798708fd9e35b832 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -32,10 +32,10 @@ recreate=True
 recreate=True
 
 [testenv:coverage]
+# see also .coveragerc
 deps=coverage
 commands=
-  python -m pytest --cov=alembic {posargs}
-  python -m coverage xml --include=alembic/*
+  python -m pytest --cov=alembic --cov-report term --cov-report xml {posargs}
 
 [testenv:pep8]
 deps=flake8