From fd267bf52ddc4e29e9810466fa2348b38b7a0a00 Mon Sep 17 00:00:00 2001 From: Andrew Snare Date: Mon, 14 Jul 2025 12:14:02 +0200 Subject: [PATCH 1/2] Update call_fixture() to work with pytest 8.4. The implementation retains compatibility with older versions. --- .../labs/pytester/fixtures/unwrap.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/databricks/labs/pytester/fixtures/unwrap.py b/src/databricks/labs/pytester/fixtures/unwrap.py index ca68e62..b03648c 100644 --- a/src/databricks/labs/pytester/fixtures/unwrap.py +++ b/src/databricks/labs/pytester/fixtures/unwrap.py @@ -5,6 +5,8 @@ from typing import TypeVar from unittest.mock import MagicMock, create_autospec +import pytest + from databricks.labs.lsql.backends import MockBackend from databricks.sdk import WorkspaceClient from databricks.sdk.service import iam @@ -14,13 +16,25 @@ T = TypeVar('T') -def call_fixture(fixture_fn: Callable[..., T], *args, **kwargs) -> T: - if not hasattr(fixture_fn, '__pytest_wrapped__'): - raise ValueError(f'{fixture_fn} is not a pytest fixture') - wrapped = getattr(fixture_fn, '__pytest_wrapped__') - if not hasattr(wrapped, 'obj'): - raise ValueError(f'{fixture_fn} is not a pytest fixture') - return wrapped.obj(*args, **kwargs) +# Pytest fixtures are not supposed to be called directly, but historically we hack through the countermeasures. +# TODO: Investigate and fix this if possible, to avoid breakage in future pytest versions. +# Potential solution: use `pytest.FixtureRequest` & `request.getfixturevalue()` to access fixtures. +if pytest.version_tuple >= (8, 4): + def call_fixture(fixture_fn: Callable[..., T], *args, **kwargs) -> T: + if not hasattr(fixture_fn, "_get_wrapped_function"): + raise ValueError(f'{fixture_fn} is not a pytest fixture') + accessor = getattr(fixture_fn, "_get_wrapped_function") + wrapped = accessor() + return wrapped(*args, **kwargs) +else: + # Older versions of pytest use a different mechanism to wrap fixtures. + def call_fixture(fixture_fn: Callable[..., T], *args, **kwargs) -> T: + if not hasattr(fixture_fn, '__pytest_wrapped__'): + raise ValueError(f'{fixture_fn} is not a pytest fixture') + wrapped = getattr(fixture_fn, '__pytest_wrapped__') + if not hasattr(wrapped, 'obj'): + raise ValueError(f'{fixture_fn} is not a pytest fixture') + return wrapped.obj(*args, **kwargs) class CallContext: From a63a89d57fcde587931c100ff6eb5a4e45929d48 Mon Sep 17 00:00:00 2001 From: Andrew Snare Date: Mon, 14 Jul 2025 12:19:06 +0200 Subject: [PATCH 2/2] Formatting. --- src/databricks/labs/pytester/fixtures/unwrap.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/databricks/labs/pytester/fixtures/unwrap.py b/src/databricks/labs/pytester/fixtures/unwrap.py index b03648c..3450ced 100644 --- a/src/databricks/labs/pytester/fixtures/unwrap.py +++ b/src/databricks/labs/pytester/fixtures/unwrap.py @@ -20,12 +20,14 @@ # TODO: Investigate and fix this if possible, to avoid breakage in future pytest versions. # Potential solution: use `pytest.FixtureRequest` & `request.getfixturevalue()` to access fixtures. if pytest.version_tuple >= (8, 4): + def call_fixture(fixture_fn: Callable[..., T], *args, **kwargs) -> T: - if not hasattr(fixture_fn, "_get_wrapped_function"): + if not hasattr(fixture_fn, "_get_wrapped_function"): raise ValueError(f'{fixture_fn} is not a pytest fixture') accessor = getattr(fixture_fn, "_get_wrapped_function") wrapped = accessor() return wrapped(*args, **kwargs) + else: # Older versions of pytest use a different mechanism to wrap fixtures. def call_fixture(fixture_fn: Callable[..., T], *args, **kwargs) -> T: