summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/testing/assertions.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2022-01-21 18:46:37 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2022-01-22 19:18:37 -0500
commit4a99fc26ab5f95ef605d975b7c8d003dc28c205b (patch)
tree3e8747ee46e4c42a99568a0ee54928343df92767 /lib/sqlalchemy/testing/assertions.py
parent328041d21d9f96db12caac79bbf7251a0dbd01e1 (diff)
downloadsqlalchemy-4a99fc26ab5f95ef605d975b7c8d003dc28c205b.tar.gz
dont use exception catches for warnings; modernize xdist detection
Improvements to the test suite's integration with pytest such that the "warnings" plugin, if manually enabled, will not interfere with the test suite, such that third parties can enable the warnings plugin or make use of the ``-W`` parameter and SQLAlchemy's test suite will continue to pass. Additionally, modernized the detection of the "pytest-xdist" plugin so that plugins can be globally disabled using PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 without breaking the test suite if xdist were still installed. Warning filters that promote deprecation warnings to errors are now localized to SQLAlchemy-specific warnings, or within SQLAlchemy-specific sources for general Python deprecation warnings, so that non-SQLAlchemy deprecation warnings emitted from pytest plugins should also not impact the test suite. Identified a bit of cleanup for the PostgreSQL provisioning as a result. Fixes: #7599 Change-Id: Ibcf09af25228d39ee5a943fda82d8a9302433726 (cherry picked from commit a0f1914b903de6c130ab1c3267138b8ad208e144)
Diffstat (limited to 'lib/sqlalchemy/testing/assertions.py')
-rw-r--r--lib/sqlalchemy/testing/assertions.py59
1 files changed, 54 insertions, 5 deletions
diff --git a/lib/sqlalchemy/testing/assertions.py b/lib/sqlalchemy/testing/assertions.py
index 02e688022..aa8edd9af 100644
--- a/lib/sqlalchemy/testing/assertions.py
+++ b/lib/sqlalchemy/testing/assertions.py
@@ -143,14 +143,16 @@ def _expect_warnings(
exc_cls,
messages,
regex=True,
+ search_msg=False,
assert_=True,
py2konly=False,
raise_on_any_unexpected=False,
+ squelch_other_warnings=False,
):
global _FILTERS, _SEEN, _EXC_CLS
- if regex:
+ if regex or search_msg:
filters = [re.compile(msg, re.I | re.S) for msg in messages]
else:
filters = list(messages)
@@ -188,19 +190,23 @@ def _expect_warnings(
exception = None
if not exception or not issubclass(exception, _EXC_CLS):
- return real_warn(msg, *arg, **kw)
+ if not squelch_other_warnings:
+ return real_warn(msg, *arg, **kw)
if not filters and not raise_on_any_unexpected:
return
for filter_ in filters:
- if (regex and filter_.match(msg)) or (
- not regex and filter_ == msg
+ if (
+ (search_msg and filter_.search(msg))
+ or (regex and filter_.match(msg))
+ or (not regex and filter_ == msg)
):
seen.discard(filter_)
break
else:
- real_warn(msg, *arg, **kw)
+ if not squelch_other_warnings:
+ real_warn(msg, *arg, **kw)
with mock.patch("warnings.warn", our_warn), mock.patch(
"sqlalchemy.util.SQLALCHEMY_WARN_20", True
@@ -357,6 +363,40 @@ def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
)
+def assert_warns(except_cls, callable_, *args, **kwargs):
+ """legacy adapter function for functions that were previously using
+ assert_raises with SAWarning or similar.
+
+ has some workarounds to accommodate the fact that the callable completes
+ with this approach rather than stopping at the exception raise.
+
+
+ """
+ with _expect_warnings(except_cls, [".*"], squelch_other_warnings=True):
+ return callable_(*args, **kwargs)
+
+
+def assert_warns_message(except_cls, msg, callable_, *args, **kwargs):
+ """legacy adapter function for functions that were previously using
+ assert_raises with SAWarning or similar.
+
+ has some workarounds to accommodate the fact that the callable completes
+ with this approach rather than stopping at the exception raise.
+
+ Also uses regex.search() to match the given message to the error string
+ rather than regex.match().
+
+ """
+ with _expect_warnings(
+ except_cls,
+ [msg],
+ search_msg=True,
+ regex=False,
+ squelch_other_warnings=True,
+ ):
+ return callable_(*args, **kwargs)
+
+
def assert_raises_message_context_ok(
except_cls, msg, callable_, *args, **kwargs
):
@@ -378,6 +418,15 @@ class _ErrorContainer(object):
@contextlib.contextmanager
def _expect_raises(except_cls, msg=None, check_context=False):
+ if (
+ isinstance(except_cls, type)
+ and issubclass(except_cls, Warning)
+ or isinstance(except_cls, Warning)
+ ):
+ raise TypeError(
+ "Use expect_warnings for warnings, not "
+ "expect_raises / assert_raises"
+ )
ec = _ErrorContainer()
if check_context:
are_we_already_in_a_traceback = sys.exc_info()[0]