Skip to content

Commit 92acd19

Browse files
PerchunPakItsDrike
andauthored
Make tests not tag aware (#1133)
Co-authored-by: ItsDrike <itsdrike@protonmail.com>
1 parent aaeb98b commit 92acd19

5 files changed

Lines changed: 125 additions & 81 deletions

File tree

tests/helpers.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import collections.abc as c
2+
import importlib.metadata
3+
from contextlib import contextmanager
4+
from functools import wraps
5+
from unittest.mock import patch
6+
7+
from mcstatus._utils.deprecation import LIB_NAME, _get_project_version
8+
9+
10+
@contextmanager
11+
def patch_project_version(version: str | None) -> c.Iterator[None]:
12+
"""Patch the project version reported by ``importlib.metadata.version``.
13+
14+
This is used to simulate different project versions for testing purposes.
15+
If ``version`` is ``None``, a :exc:`PackageNotFoundError` will be raised
16+
when trying to get the project version.
17+
"""
18+
orig_version_func = importlib.metadata.version
19+
20+
@wraps(orig_version_func)
21+
def patched_version_func(distribution_name: str) -> str:
22+
if distribution_name == LIB_NAME:
23+
if version is None:
24+
raise importlib.metadata.PackageNotFoundError
25+
return version
26+
return orig_version_func(distribution_name)
27+
28+
_get_project_version.cache_clear()
29+
with patch.object(importlib.metadata, "version", new=patched_version_func):
30+
try:
31+
yield
32+
finally:
33+
_get_project_version.cache_clear()

tests/responses/test_bedrock.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from mcstatus.motd import Motd
66
from mcstatus.responses import BedrockStatusPlayers, BedrockStatusResponse, BedrockStatusVersion
7+
from tests.helpers import patch_project_version
78
from tests.responses import BaseResponseTest
89

910

@@ -99,8 +100,13 @@ def build(self, build):
99100
return build.version
100101

101102
def test_deprecated_version_alias(self, build: BedrockStatusVersion):
102-
with pytest.warns(
103-
DeprecationWarning,
104-
match=r"^BedrockStatusVersion\.version is deprecated and scheduled for removal in 13\.0\.0, use name instead\.$",
103+
with (
104+
patch_project_version("0.0.0"),
105+
pytest.deprecated_call(
106+
match=(
107+
r"^BedrockStatusVersion\.version is deprecated and scheduled for removal in 13\.0\.0, "
108+
r"use name instead\.$"
109+
),
110+
),
105111
):
106112
assert build.version == build.name

tests/responses/test_query.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from mcstatus.motd import Motd
66
from mcstatus.responses import QueryPlayers, QueryResponse, QuerySoftware
77
from mcstatus.responses._raw import RawQueryResponse
8+
from tests.helpers import patch_project_version
89
from tests.responses import BaseResponseTest
910

1011

@@ -77,9 +78,11 @@ def test_as_dict(self, build: QueryResponse):
7778
}
7879

7980
def test_deprecated_map_alias(self, build: QueryResponse):
80-
with pytest.warns(
81-
DeprecationWarning,
82-
match=r"^QueryResponse\.map is deprecated and scheduled for removal in 13\.0\.0, use map_name instead\.$",
81+
with (
82+
patch_project_version("0.0.0"),
83+
pytest.deprecated_call(
84+
match=r"^QueryResponse\.map is deprecated and scheduled for removal in 13\.0\.0, use map_name instead\.$",
85+
),
8386
):
8487
assert build.map == build.map_name
8588

@@ -111,9 +114,14 @@ def build(self):
111114
)
112115

113116
def test_deprecated_names_alias(self, build: QueryPlayers):
114-
with pytest.warns(
115-
DeprecationWarning,
116-
match=r"^QueryPlayers\.names is deprecated and scheduled for removal in 13\.0\.0, use 'list' attribute instead\.$",
117+
with (
118+
patch_project_version("0.0.0"),
119+
pytest.deprecated_call(
120+
match=(
121+
r"^QueryPlayers\.names is deprecated and scheduled for removal in 13\.0\.0, "
122+
r"use 'list' attribute instead\.$"
123+
),
124+
),
117125
):
118126
assert build.names == build.list
119127

tests/test_compat.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import importlib
44
import os
55
import shutil
6+
import sys
67
import tarfile
78
import zipfile
89
from collections.abc import Iterator
@@ -13,6 +14,8 @@
1314
import pytest
1415
from hatchling.build import build_sdist, build_wheel
1516

17+
from tests.helpers import patch_project_version
18+
1619

1720
@contextmanager
1821
def _chdir(path: Path) -> Iterator[None]:
@@ -46,23 +49,30 @@ def _extractall_compat(tar: tarfile.TarFile, destination: Path) -> None:
4649
tar.extractall(destination) # noqa: S202
4750

4851

52+
@pytest.mark.parametrize("raises", [False, True])
4953
@pytest.mark.parametrize(
5054
("module", "msg_pattern"),
5155
[
52-
("mcstatus._compat.status_response", r"use mcstatus\.responses instead"),
5356
("mcstatus._compat.forge_data", r"use mcstatus\.responses\.forge instead"),
5457
("mcstatus._compat.motd_transformers", r"MOTD Transformers are no longer a part of mcstatus public API"),
58+
("mcstatus._compat.status_response", r"use mcstatus\.responses instead"),
5559
],
5660
)
57-
def test_deprecated_import_path(module: str, msg_pattern: str):
61+
def test_deprecated_import_path(raises: bool, module: str, msg_pattern: str):
5862
"""Test that the compatibility shims emit deprecation warnings at import time.
5963
6064
Note that this does NOT test the actual inclusion of the compatibility modules into
6165
the source tree at build time. This test intentionally only uses the _compat imports,
6266
as the shim files are only included on build time, which means testing those directly
6367
would fail.
6468
"""
65-
with pytest.deprecated_call(match=msg_pattern):
69+
# importlib.import_module caches module, if it didn't raise
70+
sys.modules.pop(module, None)
71+
72+
context_manager = (
73+
pytest.raises(DeprecationWarning, match=msg_pattern) if raises else pytest.deprecated_call(match=msg_pattern)
74+
)
75+
with patch_project_version("100.0.0" if raises else "0.0.0"), context_manager:
6676
importlib.import_module(module)
6777

6878

tests/utils/test_deprecation.py

Lines changed: 56 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,109 @@
11
from __future__ import annotations
22

3-
import importlib.metadata
43
import re
54
import warnings
6-
from functools import wraps
75

86
import pytest
97

108
from mcstatus._utils.deprecation import _get_project_version, deprecated, deprecation_warn
9+
from tests.helpers import patch_project_version
1110

1211
LIB_NAME = "mcstatus"
1312

1413

15-
def _patch_project_version(monkeypatch: pytest.MonkeyPatch, version: str | None):
16-
"""Patch the project version reported by ``importlib.metadata.version``.
17-
18-
This is used to simulate different project versions for testing purposes.
19-
If ``version`` is ``None``, a :exc:`PackageNotFoundError` will be raised
20-
when trying to get the project version.
21-
"""
22-
orig_version_func = importlib.metadata.version
23-
24-
@wraps(orig_version_func)
25-
def patched_version_func(distribution_name: str) -> str:
26-
if distribution_name == LIB_NAME:
27-
if version is None:
28-
raise importlib.metadata.PackageNotFoundError
29-
return version
30-
return orig_version_func(distribution_name)
31-
32-
_get_project_version.cache_clear()
33-
monkeypatch.setattr(importlib.metadata, "version", patched_version_func)
34-
35-
36-
def test_invalid_lib_version(monkeypatch: pytest.MonkeyPatch):
37-
_patch_project_version(monkeypatch, "foo bar")
38-
39-
with pytest.warns(match=f"^Failed to parse {LIB_NAME} project version \\(foo bar\\), assuming v0\\.0\\.0$"):
14+
def test_invalid_lib_version():
15+
with (
16+
patch_project_version("foo bar"),
17+
pytest.warns(match=f"^Failed to parse {LIB_NAME} project version \\(foo bar\\), assuming v0\\.0\\.0$"),
18+
):
4019
_get_project_version()
4120

4221

43-
def test_epoch_in_lib_version(monkeypatch: pytest.MonkeyPatch):
44-
_patch_project_version(monkeypatch, "2!1.2.3")
45-
46-
with pytest.warns(match=f"^Failed to parse {LIB_NAME} project version, assuming v0\\.0\\.0$"):
22+
def test_epoch_in_lib_version():
23+
with (
24+
patch_project_version("2!1.2.3"),
25+
pytest.warns(
26+
match=f"^Failed to parse {LIB_NAME} project version, assuming v0\\.0\\.0$",
27+
),
28+
):
4729
_get_project_version()
4830

4931

5032
@pytest.mark.parametrize("removal_version", ["0.9.0", (0, 9, 0)])
51-
def test_deprecation_warn_produces_error(monkeypatch: pytest.MonkeyPatch, removal_version: str | tuple[int, int, int]):
33+
def test_deprecation_warn_produces_error(removal_version: str | tuple[int, int, int]):
5234
"""Test deprecation_warn with older removal_version than current version produces exception."""
53-
_patch_project_version(monkeypatch, "1.0.0")
54-
55-
with pytest.raises(DeprecationWarning, match=r"^test is passed its removal version \(0\.9\.0\)\.$"):
35+
with (
36+
patch_project_version("1.0.0"),
37+
pytest.raises(
38+
DeprecationWarning,
39+
match=r"^test is passed its removal version \(0\.9\.0\)\.$",
40+
),
41+
):
5642
deprecation_warn(obj_name="test", removal_version=removal_version)
5743

5844

5945
@pytest.mark.parametrize("removal_version", ["1.0.1", (1, 0, 1)])
60-
def test_deprecation_warn_produces_warning(monkeypatch: pytest.MonkeyPatch, removal_version: str | tuple[int, int, int]):
46+
def test_deprecation_warn_produces_warning(removal_version: str | tuple[int, int, int]):
6147
"""Test deprecation_warn with newer removal_version than current version produces warning."""
62-
_patch_project_version(monkeypatch, "1.0.0")
63-
64-
with pytest.deprecated_call(match=r"^test is deprecated and scheduled for removal in 1\.0\.1\.$"):
48+
with (
49+
patch_project_version("1.0.0"),
50+
pytest.deprecated_call(
51+
match=r"^test is deprecated and scheduled for removal in 1\.0\.1\.$",
52+
),
53+
):
6554
deprecation_warn(obj_name="test", removal_version=removal_version)
6655

6756

68-
def test_deprecation_invalid_removal_version(monkeypatch: pytest.MonkeyPatch):
57+
def test_deprecation_invalid_removal_version():
6958
"""Test deprecation_warn with invalid removal_version."""
70-
_patch_project_version(monkeypatch, "1.0.0")
71-
7259
pattern = re.escape(r"(\d+)\.(\d+)\.(\d+)")
73-
with pytest.raises(ValueError, match=f"^removal_version must follow regex pattern of: {pattern}$"):
60+
with (
61+
patch_project_version("1.0.0"),
62+
pytest.raises(
63+
ValueError,
64+
match=f"^removal_version must follow regex pattern of: {pattern}$",
65+
),
66+
):
7467
deprecation_warn(obj_name="test", removal_version="foo!")
7568

7669

77-
def test_deprecation_warn_unknown_version(monkeypatch: pytest.MonkeyPatch):
70+
def test_deprecation_warn_unknown_version():
7871
"""Test deprecation_warn with unknown project version.
7972
8073
This could occur if the project wasn't installed as a package. (e.g. when running directly from
8174
source, like via a git submodule.)
8275
"""
83-
_patch_project_version(monkeypatch, None)
84-
8576
with (
77+
patch_project_version(None),
8678
pytest.warns(match=f"Failed to get {LIB_NAME} project version", expected_warning=RuntimeWarning),
8779
pytest.deprecated_call(match=r"^test is deprecated and scheduled for removal in 1\.0\.0\.$"),
8880
):
8981
deprecation_warn(obj_name="test", removal_version="1.0.0")
9082

9183

92-
def test_deprecation_decorator_warn(monkeypatch: pytest.MonkeyPatch):
84+
def test_deprecation_decorator_warn():
9385
"""Check deprecated decorator triggers a deprecation warning."""
94-
_patch_project_version(monkeypatch, "1.0.0")
86+
with patch_project_version("1.0.0"):
9587

96-
@deprecated(display_name="func", removal_version="1.0.1")
97-
def func(x: object) -> object:
98-
return x
88+
@deprecated(display_name="func", removal_version="1.0.1")
89+
def func(x: object) -> object:
90+
return x
9991

100-
with pytest.deprecated_call(match=r"^func is deprecated and scheduled for removal in 1\.0\.1\.$"):
101-
assert func(5) == 5
92+
with pytest.deprecated_call(match=r"^func is deprecated and scheduled for removal in 1\.0\.1\.$"):
93+
assert func(5) == 5
10294

10395

104-
def test_deprecation_decorator_inferred_name(monkeypatch: pytest.MonkeyPatch):
96+
def test_deprecation_decorator_inferred_name():
10597
"""Check deprecated decorator properly infers qualified name of decorated object shown in warning."""
106-
_patch_project_version(monkeypatch, "1.0.0")
98+
with patch_project_version("1.0.0"):
10799

108-
@deprecated(removal_version="1.0.1")
109-
def func(x: object) -> object:
110-
return x
100+
@deprecated(removal_version="1.0.1")
101+
def func(x: object) -> object:
102+
return x
111103

112-
qualname = r"test_deprecation_decorator_inferred_name\.<locals>\.func"
113-
with pytest.deprecated_call(match=rf"^{qualname} is deprecated and scheduled for removal in 1\.0\.1\.$"):
114-
assert func(5) == 5
104+
qualname = r"test_deprecation_decorator_inferred_name\.<locals>\.func"
105+
with pytest.deprecated_call(match=rf"^{qualname} is deprecated and scheduled for removal in 1\.0\.1\.$"):
106+
assert func(5) == 5
115107

116108

117109
@pytest.mark.parametrize(
@@ -130,11 +122,9 @@ def func(x: object) -> object:
130122
("1.2.3rc1.post2.dev3+loc.1", (1, 2, 3)),
131123
],
132124
)
133-
def test_project_version_non_normalized_parsing(monkeypatch: pytest.MonkeyPatch, version: str, expected: tuple[int, int, int]):
125+
def test_project_version_non_normalized_parsing(version: str, expected: tuple[int, int, int]):
134126
"""Ensure PEP440 release versions get parsed out properly, with non-release components are ignored."""
135-
_patch_project_version(monkeypatch, version)
136-
137-
with warnings.catch_warnings():
127+
with patch_project_version(version), warnings.catch_warnings():
138128
warnings.simplefilter("error") # raise warnings as errors (test there are no warnings)
139129

140130
assert _get_project_version() == expected
@@ -157,13 +147,10 @@ def test_project_version_non_normalized_parsing(monkeypatch: pytest.MonkeyPatch,
157147
ids=["1.2", "1.2.3.4"],
158148
)
159149
def test_project_version_normalizes_release_components(
160-
monkeypatch: pytest.MonkeyPatch,
161150
version: str,
162151
expected: tuple[int, int, int],
163152
warning: str,
164153
):
165154
"""Ensure release segments normalize to a 3-component version and warn."""
166-
_patch_project_version(monkeypatch, version)
167-
168-
with pytest.warns(RuntimeWarning, match=rf"^{re.escape(warning)}$"):
155+
with patch_project_version(version), pytest.warns(RuntimeWarning, match=rf"^{re.escape(warning)}$"):
169156
assert _get_project_version() == expected

0 commit comments

Comments
 (0)