Skip to content

Commit

Permalink
Centralize warning config (#1214)
Browse files Browse the repository at this point in the history
  • Loading branch information
flying-sheep committed Nov 24, 2023
1 parent 4c2f9d4 commit ff69d1e
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 18 deletions.
16 changes: 2 additions & 14 deletions .azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,8 @@ jobs:
displayName: "PyTest (coverage)"
condition: and(eq(variables['RUN_COVERAGE'], 'yes'), eq(variables['PRERELEASE_DEPENDENCIES'], 'no'))
# TODO: fix all the exceptions here
# TODO: Centralize, see https://github.com/scverse/anndata/issues/1204
- script: >
pytest
-W error
-W 'ignore:Support for Awkward Arrays is currently experimental'
-W 'ignore:Outer joins on awkward.Arrays'
-W 'default:Setting element:UserWarning'
-W 'default:Trying to modify attribute:UserWarning'
-W 'default:Transforming to str index:UserWarning'
-W 'default:Observation names are not unique. To make them unique:UserWarning'
-W 'default:Variable names are not unique. To make them unique:UserWarning'
-W 'default::scipy.sparse._base.SparseEfficiencyWarning'
-W 'default::dask.array.core.PerformanceWarning'
- script: |
pytest --strict-warnings
displayName: "PyTest (treat warnings as errors)"
condition: and(eq(variables['RUN_COVERAGE'], 'no'), eq(variables['PRERELEASE_DEPENDENCIES'], 'yes'))
Expand Down
59 changes: 55 additions & 4 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,35 @@

import re
import warnings
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, cast

import pytest

from anndata.compat import chdir
from anndata.utils import import_name

if TYPE_CHECKING:
from collections.abc import Generator, Iterable
from pathlib import Path


doctest_marker = pytest.mark.usefixtures("doctest_env")


@pytest.fixture
def doctest_env(
request: pytest.FixtureRequest, cache: pytest.Cache, tmp_path: Path
) -> None:
) -> Generator[None, None, None]:
from scanpy import settings

assert isinstance(request.node.parent, pytest.Module)
# request.node.parent is either a DoctestModule or a DoctestTextFile.
# Only DoctestModule has a .obj attribute (the imported module).
if request.node.parent.obj:
func = import_name(request.node.name)
warning_detail: tuple[type[Warning], str, bool] | None
if warning_detail := getattr(func, "__deprecated", None):
cat, msg, _ = warning_detail # type: tuple[type[Warning], str, bool]
cat, msg, _ = warning_detail
warnings.filterwarnings("ignore", category=cat, message=re.escape(msg))

old_dd, settings.datasetdir = settings.datasetdir, cache.mkdir("scanpy-data")
Expand All @@ -39,7 +43,7 @@ def doctest_env(
settings.datasetdir = old_dd


def pytest_itemcollected(item):
def pytest_itemcollected(item: pytest.Item) -> None:
"""Define behavior of pytest.mark.gpu and doctests."""
from importlib.util import find_spec

Expand All @@ -51,3 +55,50 @@ def pytest_itemcollected(item):

if isinstance(item, pytest.DoctestItem):
item.add_marker(doctest_marker)


def pytest_addoption(parser: pytest.Parser) -> None:
"""Hook to register custom CLI options and config values"""
parser.addoption(
"--strict-warnings",
action="store_true",
default=False,
help="Turn warnings into errors that are not overridden by `filterwarnings` or `filterwarnings_when_strict`.",
)

parser.addini(
"filterwarnings_when_strict",
"Filters to apply after `-Werror` when --strict-warnings is active",
type="linelist",
default=[],
)


def pytest_collection_modifyitems(
session: pytest.Session, config: pytest.Config, items: Iterable[pytest.Item]
):
if not config.getoption("--strict-warnings"):
return

warning_filters = [
"error",
*_config_get_strlist(config, "filterwarnings"),
*_config_get_strlist(config, "filterwarnings_when_strict"),
]
warning_marks = [pytest.mark.filterwarnings(f) for f in warning_filters]

# Add warning filters defined in the config to all tests items.
# Test items might already have @pytest.mark.filterwarnings applied,
# so we prepend ours to ensure that an item’s explicit filters override these.
# Reversing then individually prepending ensures that the order is preserved.
for item in items:
for mark in reversed(warning_marks):
item.add_marker(mark, append=False)


def _config_get_strlist(config: pytest.Config, name: str) -> list[str]:
if strs := config.getini(name):
assert isinstance(strs, list)
assert all(isinstance(item, str) for item in strs)
return cast(list[str], strs)
return []
10 changes: 10 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ addopts = [
filterwarnings = [
'ignore:Support for Awkward Arrays is currently experimental',
'ignore:Outer joins on awkward\.Arrays',
# TODO: replace both lines above with this one once we figured out how prevent ImportPathMismatchError
# 'ignore::anndata._warnings.ExperimentalFeatureWarning',
]
# When `--strict-warnings` is used, all warnings are treated as errors, except those:
filterwarnings_when_strict = [
"default::anndata._warnings.ImplicitModificationWarning",
"default:Transforming to str index:UserWarning",
"default:(Observation|Variable) names are not unique. To make them unique:UserWarning",
"default::scipy.sparse.SparseEfficiencyWarning",
"default::dask.array.core.PerformanceWarning",
]
python_files = "test_*.py"
testpaths = ["anndata", "docs/concatenation.rst"]
Expand Down

0 comments on commit ff69d1e

Please sign in to comment.