]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
ensure all modules are importable without pytest harnesses
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 7 Sep 2023 21:37:13 +0000 (17:37 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 7 Sep 2023 22:05:25 +0000 (18:05 -0400)
Fixed very old issue where the full extent of SQLAlchemy modules, including
``sqlalchemy.testing.fixtures``, could not be imported outside of a pytest
run. This suits inspection utilities such as ``pkgutil`` that attempt to
import all installed modules in all packages.

Fixes: #10321
Change-Id: Ic2247c59b98f462036ad0d734aef9a96f290d778

doc/build/changelog/unreleased_20/10321.rst [new file with mode: 0644]
lib/sqlalchemy/testing/config.py
lib/sqlalchemy/testing/plugin/plugin_base.py
lib/sqlalchemy/testing/requirements.py
tools/walk_packages.py [new file with mode: 0644]
tox.ini

diff --git a/doc/build/changelog/unreleased_20/10321.rst b/doc/build/changelog/unreleased_20/10321.rst
new file mode 100644 (file)
index 0000000..6186133
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, setup
+    :tickets: 10321
+
+    Fixed very old issue where the full extent of SQLAlchemy modules, including
+    ``sqlalchemy.testing.fixtures``, could not be imported outside of a pytest
+    run. This suits inspection utilities such as ``pkgutil`` that attempt to
+    import all installed modules in all packages.
index b8f03362f9aa4a7b8d62770aa46f199794a5bc8f..8430203dee28824464877e98d5750b61a497dd3f 100644 (file)
@@ -22,10 +22,15 @@ from typing import Tuple
 from typing import TypeVar
 from typing import Union
 
+from . import mock
+from . import requirements as _requirements
 from .util import fail
 from .. import util
 
-requirements = None
+# default requirements; this is replaced by plugin_base when pytest
+# is run
+requirements = _requirements.SuiteRequirements()
+
 db = None
 db_url = None
 db_opts = None
@@ -42,7 +47,42 @@ if typing.TYPE_CHECKING:
 
     _fixture_functions: FixtureFunctions
 else:
-    _fixture_functions = None  # installed by plugin_base
+
+    class _NullFixtureFunctions:
+        def _null_decorator(self):
+            def go(fn):
+                return fn
+
+            return go
+
+        def skip_test_exception(self, *arg, **kw):
+            return Exception()
+
+        @property
+        def add_to_marker(self):
+            return mock.Mock()
+
+        def mark_base_test_class(self):
+            return self._null_decorator()
+
+        def combinations(self, *arg_sets, **kw):
+            return self._null_decorator()
+
+        def param_ident(self, *parameters):
+            return self._null_decorator()
+
+        def fixture(self, *arg, **kw):
+            return self._null_decorator()
+
+        def get_current_test_name(self):
+            return None
+
+        def async_test(self, fn):
+            return fn
+
+    # default fixture functions; these are replaced by plugin_base when
+    # pytest runs
+    _fixture_functions = _NullFixtureFunctions()
 
 
 _FN = TypeVar("_FN", bound=Callable[..., Any])
@@ -121,10 +161,7 @@ def combinations(
     )
 
 
-def combinations_list(
-    arg_iterable: Iterable[Tuple[Any,]],
-    **kw,
-):
+def combinations_list(arg_iterable: Iterable[Tuple[Any, ...]], **kw):
     "As combination, but takes a single iterable"
     return combinations(*arg_iterable, **kw)
 
index 393070d08c24d49c55fbfb551f0bfcfbaab96a69..563d8f68c2ed9d9e352db01b55069b35e7d958fa 100644 (file)
@@ -473,9 +473,6 @@ def _setup_requirements(argument):
     from sqlalchemy.testing import config
     from sqlalchemy import testing
 
-    if config.requirements is not None:
-        return
-
     modname, clsname = argument.split(":")
 
     # importlib.import_module() only introduced in 2.7, a little
index 479e1beb6faa8bf59925f3516468223564088bd0..d13c548baf4940f05c3816e48282e93e7e742994 100644 (file)
@@ -22,9 +22,8 @@ from __future__ import annotations
 import platform
 
 from . import asyncio as _test_asyncio
-from . import config
 from . import exclusions
-from . import only_on
+from .exclusions import only_on
 from .. import create_engine
 from .. import util
 from ..pool import QueuePool
@@ -59,6 +58,12 @@ class SuiteRequirements(Requirements):
 
         return exclusions.closed()
 
+    @property
+    def uuid_data_type(self):
+        """Return databases that support the UUID datatype."""
+
+        return exclusions.closed()
+
     @property
     def foreign_keys(self):
         """Target database must support foreign keys."""
@@ -1448,10 +1453,14 @@ class SuiteRequirements(Requirements):
 
     @property
     def timing_intensive(self):
+        from . import config
+
         return config.add_to_marker.timing_intensive
 
     @property
     def memory_intensive(self):
+        from . import config
+
         return config.add_to_marker.memory_intensive
 
     @property
diff --git a/tools/walk_packages.py b/tools/walk_packages.py
new file mode 100644 (file)
index 0000000..efafbe9
--- /dev/null
@@ -0,0 +1,5 @@
+import pkgutil
+
+import sqlalchemy
+
+list(pkgutil.walk_packages(sqlalchemy.__path__, sqlalchemy.__name__ + "."))
diff --git a/tox.ini b/tox.ini
index db1b15cccaf874875262b3c5816d742a1b814467..ec31a0bff0a176093bc4e83373515eb14e3a6a1a 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -240,6 +240,7 @@ commands =
      python ./tools/generate_proxy_methods.py --check
      python ./tools/sync_test_files.py --check
      python ./tools/generate_sql_functions.py --check
+     python ./tools/walk_packages.py
 
 
 # "pep8" env was renamed to "lint".