pytest-sort 1.3.1__tar.gz → 1.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {pytest-sort-1.3.1/src/pytest_sort.egg-info → pytest_sort-1.3.3}/PKG-INFO +6 -4
  2. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/README.md +2 -2
  3. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/pyproject.toml +23 -18
  4. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort/core.py +15 -12
  5. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort/database.py +4 -16
  6. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort/diffcov.py +7 -4
  7. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort/plugin.py +9 -7
  8. {pytest-sort-1.3.1 → pytest_sort-1.3.3/src/pytest_sort.egg-info}/PKG-INFO +6 -4
  9. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort.egg-info/requires.txt +1 -0
  10. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/test/test_config.py +5 -5
  11. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/test/test_core.py +39 -45
  12. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/LICENSE +0 -0
  13. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/setup.cfg +0 -0
  14. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort/__init__.py +0 -0
  15. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort/config.py +0 -0
  16. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort.egg-info/SOURCES.txt +0 -0
  17. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort.egg-info/dependency_links.txt +0 -0
  18. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort.egg-info/entry_points.txt +0 -0
  19. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/src/pytest_sort.egg-info/top_level.txt +0 -0
  20. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/test/test_database.py +0 -0
  21. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/test/test_diffcov.py +0 -0
  22. {pytest-sort-1.3.1 → pytest_sort-1.3.3}/test/test_plugin.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pytest-sort
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Tools for sorting test cases
5
5
  Author-email: WiredNerd <pbuschmail-pytestsort@yahoo.com>
6
6
  Maintainer-email: WiredNerd <pbuschmail-pytestsort@yahoo.com>
@@ -34,15 +34,17 @@ Classifier: Programming Language :: Python :: 3
34
34
  Classifier: License :: OSI Approved :: MIT License
35
35
  Classifier: Operating System :: OS Independent
36
36
  Classifier: Framework :: Pytest
37
- Requires-Python: >=3.8
37
+ Requires-Python: >=3.10
38
38
  Description-Content-Type: text/markdown
39
39
  License-File: LICENSE
40
40
  Requires-Dist: pytest>=7.4.0
41
41
  Requires-Dist: whatthepatch>=1.0.5
42
42
  Requires-Dist: coverage>=7.3.1
43
+ Requires-Dist: zipp>=3.19.1
44
+ Dynamic: license-file
43
45
 
44
46
  [![Homepage](https://img.shields.io/badge/Homepage-github-white?logo=github)](https://github.com/WiredNerd/pytest-sort)
45
- [![python>=3.8](https://img.shields.io/badge/python->=3.8-orange?logo=python&logoColor=green)](https://pypi.org/project/pytest-sort)
47
+ [![python>=3.10](https://img.shields.io/badge/python->=3.10-orange?logo=python&logoColor=green)](https://pypi.org/project/pytest-sort)
46
48
  [![PyPI - Version](https://img.shields.io/pypi/v/pytest-sort?logo=pypi&logoColor=white)](https://pypi.org/project/pytest-sort)
47
49
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/pytest-sort)](https://pypistats.org/packages/pytest-sort)
48
50
  [![PyPI - License](https://img.shields.io/pypi/l/pytest-sort)](https://github.com/WiredNerd/pytest-sort/blob/main/LICENSE)
@@ -1,5 +1,5 @@
1
1
  [![Homepage](https://img.shields.io/badge/Homepage-github-white?logo=github)](https://github.com/WiredNerd/pytest-sort)
2
- [![python>=3.8](https://img.shields.io/badge/python->=3.8-orange?logo=python&logoColor=green)](https://pypi.org/project/pytest-sort)
2
+ [![python>=3.10](https://img.shields.io/badge/python->=3.10-orange?logo=python&logoColor=green)](https://pypi.org/project/pytest-sort)
3
3
  [![PyPI - Version](https://img.shields.io/pypi/v/pytest-sort?logo=pypi&logoColor=white)](https://pypi.org/project/pytest-sort)
4
4
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/pytest-sort)](https://pypistats.org/packages/pytest-sort)
5
5
  [![PyPI - License](https://img.shields.io/pypi/l/pytest-sort)](https://github.com/WiredNerd/pytest-sort/blob/main/LICENSE)
@@ -61,4 +61,4 @@ Or by opening an issue: https://github.com/WiredNerd/pytest-sort/issues
61
61
 
62
62
  ## License
63
63
 
64
- The project is licensed under the MIT license.
64
+ The project is licensed under the MIT license.
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "pytest-sort"
7
7
  description = "Tools for sorting test cases"
8
- version = "1.3.1"
8
+ version = "1.3.3"
9
9
  license = { file = "LICENSE" }
10
10
  keywords = [
11
11
  "test",
@@ -24,14 +24,14 @@ maintainers = [
24
24
  { name = "WiredNerd", email = "pbuschmail-pytestsort@yahoo.com" },
25
25
  ]
26
26
  readme = "README.md"
27
- requires-python = ">=3.8"
27
+ requires-python = ">=3.10"
28
28
  classifiers = [
29
29
  "Programming Language :: Python :: 3",
30
30
  "License :: OSI Approved :: MIT License",
31
31
  "Operating System :: OS Independent",
32
32
  "Framework :: Pytest",
33
33
  ]
34
- dependencies = ["pytest>=7.4.0", "whatthepatch>=1.0.5", "coverage>=7.3.1"]
34
+ dependencies = ["pytest>=7.4.0", "whatthepatch>=1.0.5", "coverage>=7.3.1", "zipp>=3.19.1"]
35
35
 
36
36
  [project.urls]
37
37
  "Documentation" = "https://pytest-sort.readthedocs.io/"
@@ -64,7 +64,7 @@ command_line = "pytest -x --assert=plain -o pythonpath='{PYTHONPATH}' --sort-mod
64
64
 
65
65
  [tool.black]
66
66
  line-length = 120
67
- target-version = ['py38', 'py39', 'py310', 'py311']
67
+ target-version = ['py310', 'py311', 'py312', 'py313', 'py314']
68
68
  skip-string-normalization = true
69
69
  color = true
70
70
 
@@ -76,19 +76,8 @@ files = "src"
76
76
  mypy_path = "src"
77
77
 
78
78
  [tool.ruff]
79
- target-version = "py38"
80
- show-source = true
81
- select = ["ALL"]
82
- ignore = [
83
- "ANN101", # Missing type annotation for self in method
84
- "COM812", # missing-trailing-comma
85
- "D203", # 1 blank line required before class docstring
86
- "D213", # multi-line-summary-second-line
87
- "EM101", # Exception must not use a string literal, assign to variable first
88
- "ISC001", # single-line-implicit-string-concatenation
89
- "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
90
- "TRY003", # Avoid specifying long messages outside the exception class
91
- ]
79
+ target-version = "py310"
80
+ output-format = "full"
92
81
  line-length = 120
93
82
  exclude = [
94
83
  ".eggs",
@@ -104,10 +93,25 @@ exclude = [
104
93
  "venv",
105
94
  ]
106
95
 
96
+ [tool.ruff.lint]
97
+ select = ["ALL"]
98
+ ignore = [
99
+ "COM812", # missing-trailing-comma
100
+ "D203", # 1 blank line required before class docstring
101
+ "D213", # multi-line-summary-second-line
102
+ "EM101", # Exception must not use a string literal, assign to variable first
103
+ "ISC001", # single-line-implicit-string-concatenation
104
+ "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
105
+ "TRY003", # Avoid specifying long messages outside the exception class
106
+ ]
107
+
108
+ [tool.ruff.lint.flake8-pytest-style]
109
+ fixture-parentheses = true
110
+
107
111
  [tool.ruff.lint.isort]
108
112
  known-first-party = ["pytest_sort"]
109
113
 
110
- [tool.ruff.per-file-ignores]
114
+ [tool.ruff.lint.per-file-ignores]
111
115
  "src/pytest_sort/core.py" = [
112
116
  "ARG005", # Unused lambda argument
113
117
  "T201", # print found
@@ -136,4 +140,5 @@ known-first-party = ["pytest_sort"]
136
140
  "PLR2004", # Magic value used in comparison
137
141
  "S101", # Use of `assert` detected
138
142
  "SLF001", # Private member accessed
143
+ "RUF059", # Unpacked variable is never used
139
144
  ]
@@ -4,9 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  import hashlib
6
6
  import random
7
- import sys
8
7
  from functools import partial
9
- from typing import TYPE_CHECKING, Any, Callable
8
+ from typing import TYPE_CHECKING, Any
10
9
 
11
10
  import pytest
12
11
  from _pytest import nodes as pytest_nodes
@@ -15,14 +14,18 @@ from pytest_sort.config import SortConfig
15
14
  from pytest_sort.database import get_all_totals, get_stats
16
15
  from pytest_sort.diffcov import get_diff_test_scores, get_mut_test_scores
17
16
 
18
- md5: Callable = hashlib.md5
19
- if sys.version_info >= (3, 9):
20
- md5: Callable = partial(hashlib.md5, usedforsecurity=False) # type: ignore[no-redef]
21
-
22
-
23
17
  if TYPE_CHECKING:
18
+ import sys
19
+
24
20
  from _pytest.terminal import TerminalReporter
25
21
 
22
+ if sys.version_info < (3, 14): # nomut
23
+ from typing import Callable # noqa: UP035 # pragma: no cover
24
+ else:
25
+ from collections.abc import Callable
26
+
27
+ md5: Callable = partial(hashlib.md5, usedforsecurity=False) # type: ignore[no-redef]
28
+
26
29
 
27
30
  def create_bucket_id_from_node(node: pytest_nodes.Node | None) -> str:
28
31
  """Extract portion of nodeid needed for bucket key."""
@@ -141,7 +144,7 @@ def validate_sort_marker(sort_marker: pytest.Mark, node_id: str) -> tuple:
141
144
  return (mode, bucket)
142
145
 
143
146
  try:
144
- (mode, bucket_temp) = mark_sort_parse(*sort_marker.args, **sort_marker.kwargs)
147
+ mode, bucket_temp = mark_sort_parse(*sort_marker.args, **sort_marker.kwargs)
145
148
  except TypeError as e:
146
149
  msg = f"Incorrect arguments on marker 'sort'. Target:{node_id}"
147
150
  raise TypeError(msg) from e
@@ -169,7 +172,7 @@ def get_marker_settings(node: pytest_nodes.Node) -> tuple:
169
172
  node_id = node.nodeid
170
173
 
171
174
  if node.parent:
172
- (mode, bucket, bucket_id, bucket_sort_key, item_sort_key) = get_marker_settings(node.parent)
175
+ mode, bucket, bucket_id, bucket_sort_key, item_sort_key = get_marker_settings(node.parent)
173
176
 
174
177
  for order in node.iter_markers("order"):
175
178
  sort_key = validate_order_marker(order, node_id)
@@ -180,7 +183,7 @@ def get_marker_settings(node: pytest_nodes.Node) -> tuple:
180
183
  bucket_id = create_bucket_id_from_node(node)
181
184
 
182
185
  for sort in node.iter_markers("sort"):
183
- (mode, bucket_temp) = validate_sort_marker(sort, node_id)
186
+ mode, bucket_temp = validate_sort_marker(sort, node_id)
184
187
 
185
188
  if bucket_temp == "self":
186
189
  bucket_id = create_bucket_id_from_node(node)
@@ -200,7 +203,7 @@ def create_sort_keys(item: pytest.Item, idx: int, count: int) -> None:
200
203
 
201
204
  Store in SortConfig.item_sort_keys and SortConfig.bucket_sort_keys
202
205
  """
203
- (mode, bucket, bucket_id, bucket_sort_key, item_sort_key) = get_marker_settings(item)
206
+ mode, bucket, bucket_id, bucket_sort_key, item_sort_key = get_marker_settings(item)
204
207
 
205
208
  SortConfig.item_sort_keys[item.nodeid] = item_sort_key or create_item_key[mode or SortConfig.mode](item, idx, count)
206
209
 
@@ -254,7 +257,7 @@ def print_recorded_times_report(terminal_reporter: TerminalReporter) -> None:
254
257
 
255
258
  print(
256
259
  f"\n*** {'pytest-sort maximum recorded times'.ljust(node_id_width)}"
257
- f"{'Nanoseconds'.center(stat_width*4 - 4)} ***",
260
+ f"{'Nanoseconds'.center(stat_width * 4 - 4)} ***",
258
261
  )
259
262
  print(
260
263
  f"{'Test Case'.ljust(node_id_width)} {'setup'.rjust(stat_width)} "
@@ -31,24 +31,12 @@ def update_test_cases(recorded_times: dict) -> None:
31
31
  """Update Test Case Data with specfiied duration(s) and recalculate total(s)."""
32
32
  _load_data()
33
33
 
34
- for nodeid in recorded_times:
34
+ for nodeid, recorded_node in recorded_times.items():
35
35
  node_data = _sort_data.get(nodeid, {})
36
36
 
37
- node_data["setup"] = node_data.get("setup", 0)
38
- node_data["call"] = node_data.get("call", 0)
39
- node_data["teardown"] = node_data.get("teardown", 0)
40
-
41
- setup = recorded_times[nodeid].get("setup", 0)
42
- if node_data["setup"] < setup:
43
- node_data["setup"] = setup
44
-
45
- call = recorded_times[nodeid].get("call", 0)
46
- if node_data["call"] < call:
47
- node_data["call"] = call
48
-
49
- teardown = recorded_times[nodeid].get("teardown", 0)
50
- if node_data["teardown"] < teardown:
51
- node_data["teardown"] = teardown
37
+ node_data["setup"] = max(node_data.get("setup", 0), recorded_node.get("setup", 0))
38
+ node_data["call"] = max(node_data.get("call", 0), recorded_node.get("call", 0))
39
+ node_data["teardown"] = max(node_data.get("teardown", 0), recorded_node.get("teardown", 0))
52
40
 
53
41
  node_data["total"] = node_data["setup"] + node_data["call"] + node_data["teardown"]
54
42
 
@@ -7,11 +7,14 @@ import re
7
7
  import shlex
8
8
  import subprocess
9
9
  from pathlib import Path
10
- from typing import Any, Generator
10
+ from typing import TYPE_CHECKING, Any
11
11
 
12
12
  import whatthepatch
13
13
  from coverage.sqldata import CoverageData
14
14
 
15
+ if TYPE_CHECKING:
16
+ from collections.abc import Generator
17
+
15
18
  # pytest-cov populates test context as <nodeid>|(setup|run|teardown)
16
19
  PARSE_TEST_CONTEXT = re.compile(r"(?P<nodeid>.*)\|(?P<when>setup|run|teardown)")
17
20
 
@@ -50,10 +53,10 @@ def get_mut_changed_lines() -> dict[Path, set[int]]:
50
53
  """
51
54
  changed_lines = {}
52
55
  mut_source_file = os.environ.get("MUT_SOURCE_FILE", None)
53
- mut_lineno = os.environ.get("MUT_LINENO", 0)
56
+ mut_lineno = os.environ.get("MUT_LINENO", "0")
54
57
  mut_end_lineno = os.environ.get("MUT_END_LINENO", mut_lineno)
55
58
 
56
- if mut_source_file and mut_lineno:
59
+ if mut_source_file and int(mut_lineno):
57
60
  rpath = Path(mut_source_file).resolve()
58
61
  changed_lines[rpath] = set(range(int(mut_lineno), int(mut_end_lineno) + 1))
59
62
 
@@ -73,7 +76,7 @@ def get_line_coverage() -> Generator[tuple[Path, str, str, int], Any, None]:
73
76
  for test in tests:
74
77
  match = PARSE_TEST_CONTEXT.search(test)
75
78
  if match:
76
- (nodeid, when) = match.group("nodeid", "when")
79
+ nodeid, when = match.group("nodeid", "when")
77
80
  yield rpath, nodeid, when, line
78
81
 
79
82
 
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import argparse
6
- from typing import TYPE_CHECKING, Generator
6
+ from typing import TYPE_CHECKING
7
7
 
8
8
  import pytest
9
9
 
@@ -12,10 +12,12 @@ from pytest_sort.core import print_recorded_times_report, sort_items
12
12
  from pytest_sort.database import clear_db, update_test_cases
13
13
 
14
14
  if TYPE_CHECKING:
15
+ from collections.abc import Generator
16
+
15
17
  from _pytest.terminal import TerminalReporter
16
18
 
17
19
 
18
- @pytest.hookimpl
20
+ @pytest.hookimpl # nomut: Decorator
19
21
  def pytest_addoption(parser: pytest.Parser) -> None:
20
22
  """pytest_sort: Add command line and ini options to pytest."""
21
23
  group = parser.getgroup("pytest-sort")
@@ -63,7 +65,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
63
65
  group.addoption("--sort_debug", action="store_true", dest="sort_debug", help=argparse.SUPPRESS)
64
66
 
65
67
 
66
- @pytest.hookimpl
68
+ @pytest.hookimpl # nomut: Decorator
67
69
  def pytest_configure(config: pytest.Config) -> None:
68
70
  """pytest_sort: Add markers to pytest."""
69
71
  config.addinivalue_line(
@@ -78,7 +80,7 @@ def pytest_configure(config: pytest.Config) -> None:
78
80
  SortConfig.from_pytest(config)
79
81
 
80
82
 
81
- @pytest.hookimpl
83
+ @pytest.hookimpl # nomut: Decorator
82
84
  def pytest_report_header(config: pytest.Config) -> str: # noqa: ARG001
83
85
  """pytest_sort: Build Header for pytest to display."""
84
86
  header = "pytest-sort:"
@@ -89,7 +91,7 @@ def pytest_report_header(config: pytest.Config) -> str: # noqa: ARG001
89
91
  return header
90
92
 
91
93
 
92
- @pytest.hookimpl
94
+ @pytest.hookimpl # nomut: Decorator
93
95
  def pytest_collection_modifyitems(
94
96
  session: pytest.Session, # noqa: ARG001
95
97
  config: pytest.Config, # noqa: ARG001
@@ -102,7 +104,7 @@ def pytest_collection_modifyitems(
102
104
  sort_items(items)
103
105
 
104
106
 
105
- @pytest.hookimpl(hookwrapper=True) # pragma: no mutate
107
+ @pytest.hookimpl(hookwrapper=True) # nomut
106
108
  def pytest_runtest_makereport(item: pytest.Item, call: pytest.CallInfo) -> Generator:
107
109
  """pytest_sort: Record test runtimes in memory."""
108
110
  if SortConfig.record and call.when in ("setup", "call", "teardown"):
@@ -116,7 +118,7 @@ def pytest_runtest_makereport(item: pytest.Item, call: pytest.CallInfo) -> Gener
116
118
  yield
117
119
 
118
120
 
119
- @pytest.hookimpl
121
+ @pytest.hookimpl # nomut: Decorator
120
122
  def pytest_terminal_summary(
121
123
  terminalreporter: TerminalReporter,
122
124
  exitstatus: int, # noqa: ARG001
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pytest-sort
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Tools for sorting test cases
5
5
  Author-email: WiredNerd <pbuschmail-pytestsort@yahoo.com>
6
6
  Maintainer-email: WiredNerd <pbuschmail-pytestsort@yahoo.com>
@@ -34,15 +34,17 @@ Classifier: Programming Language :: Python :: 3
34
34
  Classifier: License :: OSI Approved :: MIT License
35
35
  Classifier: Operating System :: OS Independent
36
36
  Classifier: Framework :: Pytest
37
- Requires-Python: >=3.8
37
+ Requires-Python: >=3.10
38
38
  Description-Content-Type: text/markdown
39
39
  License-File: LICENSE
40
40
  Requires-Dist: pytest>=7.4.0
41
41
  Requires-Dist: whatthepatch>=1.0.5
42
42
  Requires-Dist: coverage>=7.3.1
43
+ Requires-Dist: zipp>=3.19.1
44
+ Dynamic: license-file
43
45
 
44
46
  [![Homepage](https://img.shields.io/badge/Homepage-github-white?logo=github)](https://github.com/WiredNerd/pytest-sort)
45
- [![python>=3.8](https://img.shields.io/badge/python->=3.8-orange?logo=python&logoColor=green)](https://pypi.org/project/pytest-sort)
47
+ [![python>=3.10](https://img.shields.io/badge/python->=3.10-orange?logo=python&logoColor=green)](https://pypi.org/project/pytest-sort)
46
48
  [![PyPI - Version](https://img.shields.io/pypi/v/pytest-sort?logo=pypi&logoColor=white)](https://pypi.org/project/pytest-sort)
47
49
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/pytest-sort)](https://pypistats.org/packages/pytest-sort)
48
50
  [![PyPI - License](https://img.shields.io/pypi/l/pytest-sort)](https://github.com/WiredNerd/pytest-sort/blob/main/LICENSE)
@@ -1,3 +1,4 @@
1
1
  pytest>=7.4.0
2
2
  whatthepatch>=1.0.5
3
3
  coverage>=7.3.1
4
+ zipp>=3.19.1
@@ -104,7 +104,7 @@ class TestSortConfig:
104
104
 
105
105
  def test_from_pytest_mode_invalid(self):
106
106
  pytest_config = self.PytestConfig({"sort_mode": "September"}, {})
107
- with pytest.raises(ValueError, match="^Invalid Value for sort-mode='September'$"):
107
+ with pytest.raises(ValueError, match=r"^Invalid Value for sort-mode='September'$"):
108
108
  config.SortConfig.from_pytest(pytest_config)
109
109
 
110
110
  @pytest.mark.parametrize(
@@ -128,7 +128,7 @@ class TestSortConfig:
128
128
 
129
129
  def test_from_pytest_bucket_invalid(self):
130
130
  pytest_config = self.PytestConfig({"sort_bucket": "September"}, {})
131
- with pytest.raises(ValueError, match="^Invalid Value for sort-bucket='September'$"):
131
+ with pytest.raises(ValueError, match=r"^Invalid Value for sort-bucket='September'$"):
132
132
  config.SortConfig.from_pytest(pytest_config)
133
133
 
134
134
  @pytest.mark.parametrize(
@@ -155,12 +155,12 @@ class TestSortConfig:
155
155
 
156
156
  def test_from_pytest_bucket_mode_invalid(self):
157
157
  pytest_config = self.PytestConfig({"sort_bucket_mode": "September"}, {})
158
- with pytest.raises(ValueError, match="^Invalid Value for sort-bucket-mode='September'$"):
158
+ with pytest.raises(ValueError, match=r"^Invalid Value for sort-bucket-mode='September'$"):
159
159
  config.SortConfig.from_pytest(pytest_config)
160
160
 
161
161
  def test_from_pytest_sort_record_conflict(self):
162
162
  pytest_config = self.PytestConfig({"sort_no_record": True, "sort_record": True}, {})
163
- with pytest.raises(ValueError, match="^Do not use both --sort-record-times and --sort-no-record-times$"):
163
+ with pytest.raises(ValueError, match=r"^Do not use both --sort-record-times and --sort-no-record-times$"):
164
164
  config.SortConfig.from_pytest(pytest_config)
165
165
 
166
166
  @pytest.mark.parametrize(
@@ -202,7 +202,7 @@ class TestSortConfig:
202
202
 
203
203
  def test_from_pytest_seed_invalid(self):
204
204
  pytest_config = self.PytestConfig({}, {"sort_seed": "ABC"})
205
- with pytest.raises(ValueError, match="^Invalid seed value 'ABC' must be int$"):
205
+ with pytest.raises(ValueError, match=r"^Invalid seed value 'ABC' must be int$"):
206
206
  config.SortConfig.from_pytest(pytest_config)
207
207
 
208
208
  @pytest.mark.parametrize(
@@ -2,7 +2,7 @@ import hashlib
2
2
  import importlib
3
3
  import sys
4
4
  from functools import partial
5
- from typing import Callable, ClassVar
5
+ from typing import ClassVar
6
6
  from unittest import mock
7
7
 
8
8
  import pytest
@@ -10,9 +10,12 @@ from _pytest import nodes as pytest_nodes
10
10
 
11
11
  from pytest_sort import config, core
12
12
 
13
- md5: Callable = hashlib.md5
14
- if sys.version_info >= (3, 9):
15
- md5: Callable = partial(hashlib.md5, usedforsecurity=False) # type: ignore[no-redef]
13
+ if sys.version_info < (3, 14): # nomut
14
+ from typing import Callable # noqa: UP035 # pragma: no cover
15
+ else:
16
+ from collections.abc import Callable
17
+
18
+ md5: Callable = partial(hashlib.md5, usedforsecurity=False) # type: ignore[no-redef]
16
19
 
17
20
 
18
21
  class TestImports:
@@ -21,23 +24,12 @@ class TestImports:
21
24
  with mock.patch("hashlib.md5") as mock_md5:
22
25
  yield mock_md5
23
26
 
24
- @pytest.fixture()
25
- def version_info(self):
26
- with mock.patch("sys.version_info") as version_info:
27
- yield version_info
28
-
29
27
  @pytest.fixture(autouse=True)
30
28
  def _cleanup(self):
31
29
  yield
32
30
  importlib.reload(core)
33
31
 
34
- def test_import_md5_38(self, version_info, mock_md5):
35
- version_info.__ge__ = lambda _, __: False
36
- importlib.reload(core)
37
- assert core.md5 == mock_md5
38
-
39
- def test_import_md5_39(self, version_info, mock_md5):
40
- version_info.__ge__ = lambda _, v: v == (3, 9)
32
+ def test_import_md5_39(self, mock_md5):
41
33
  importlib.reload(core)
42
34
  assert isinstance(core.md5, partial)
43
35
  assert core.md5.func == mock_md5
@@ -92,7 +84,7 @@ class TestCreateBucketIdForNode:
92
84
  assert core.create_bucket_id_from_node(node) == bucket_id
93
85
 
94
86
  def test_create_bucket_id_for_package(self, mock_objects):
95
- (session, package, module, cls, func) = mock_objects
87
+ session, package, module, cls, func = mock_objects
96
88
 
97
89
  assert core.create_bucket_id_for_package(session) == "session"
98
90
  assert core.create_bucket_id_for_package(package) == "tests/core/"
@@ -104,7 +96,7 @@ class TestCreateBucketIdForNode:
104
96
  assert core.create_bucket_id_for_package(module) == ""
105
97
 
106
98
  def test_create_bucket_id_for_module(self, mock_objects):
107
- (session, package, module, cls, func) = mock_objects
99
+ session, package, module, cls, func = mock_objects
108
100
 
109
101
  assert core.create_bucket_id_for_module(session) == "session"
110
102
  assert core.create_bucket_id_for_module(package) == "tests/core/"
@@ -116,7 +108,7 @@ class TestCreateBucketIdForNode:
116
108
  assert core.create_bucket_id_for_module(cls) == ""
117
109
 
118
110
  def test_create_bucket_id_for_class(self, mock_objects):
119
- (session, package, module, cls, func) = mock_objects
111
+ session, package, module, cls, func = mock_objects
120
112
 
121
113
  assert core.create_bucket_id_for_class(session) == "session"
122
114
  assert core.create_bucket_id_for_class(package) == "tests/core/"
@@ -130,7 +122,7 @@ class TestCreateBucketIdForNode:
130
122
 
131
123
  class TestCreateBucketId:
132
124
  def test_create_bucket_id(self, mock_objects):
133
- (session, package, module, cls, func) = mock_objects
125
+ session, package, module, cls, func = mock_objects
134
126
 
135
127
  assert core.create_bucket_id["session"](func) == ""
136
128
  assert core.create_bucket_id["package"](func) == "tests/core/"
@@ -141,7 +133,7 @@ class TestCreateBucketId:
141
133
  assert core.create_bucket_id["grandparent"](func) == "tests/core/test_core.py"
142
134
 
143
135
  def test_create_item_key(self, mock_objects):
144
- (session, package, module, cls, func) = mock_objects
136
+ session, package, module, cls, func = mock_objects
145
137
 
146
138
  assert core.create_item_key["ordered"](func, 5, 20) == 6
147
139
  assert core.create_item_key["reverse"](func, 5, 20) == 15
@@ -152,21 +144,21 @@ class TestCreateBucketId:
152
144
  assert 0 <= core.create_item_key["random"](func, 5, 20) < 1
153
145
 
154
146
  def test_create_item_key_fastest(self, mock_objects):
155
- (session, package, module, cls, func) = mock_objects
147
+ session, package, module, cls, func = mock_objects
156
148
 
157
149
  assert core.create_item_key["fastest"](func, 5, 20) == 0
158
150
  core.SortConfig.item_totals = {func.nodeid: 123}
159
151
  assert core.create_item_key["fastest"](func, 5, 20) == 123
160
152
 
161
153
  def test_create_item_key_diffcov(self, mock_objects):
162
- (session, package, module, cls, func) = mock_objects
154
+ session, package, module, cls, func = mock_objects
163
155
 
164
156
  assert core.create_item_key["diffcov"](func, 5, 20) == 0
165
157
  core.SortConfig.diff_cov_scores = {func.nodeid: -123}
166
158
  assert core.create_item_key["diffcov"](func, 5, 20) == -123
167
159
 
168
160
  def test_create_item_key_mutcov(self, mock_objects):
169
- (session, package, module, cls, func) = mock_objects
161
+ session, package, module, cls, func = mock_objects
170
162
 
171
163
  assert core.create_item_key["mutcov"](func, 5, 20) == 0
172
164
  core.SortConfig.mut_cov_scores = {func.nodeid: -123}
@@ -232,10 +224,12 @@ class TestValidateMarker:
232
224
  order_marker.args = []
233
225
  order_marker.kwargs = {}
234
226
 
235
- with pytest.raises(TypeError, match="^Incorrect arguments on marker 'order'. Target:testnodeid$") as type_error:
227
+ with pytest.raises(
228
+ TypeError, match=r"^Incorrect arguments on marker 'order'. Target:testnodeid$"
229
+ ) as type_error:
236
230
  core.validate_order_marker(order_marker, "testnodeid")
237
231
 
238
- assert type(type_error.value.__cause__) == TypeError
232
+ assert isinstance(type_error.value.__cause__, TypeError)
239
233
 
240
234
  @pytest.mark.parametrize(
241
235
  ("args", "kwargs", "key"),
@@ -258,10 +252,10 @@ class TestValidateMarker:
258
252
  sort_marker.args = []
259
253
  sort_marker.kwargs = {}
260
254
 
261
- with pytest.raises(TypeError, match="^Incorrect arguments on marker 'sort'. Target:testnodeid$") as type_error:
255
+ with pytest.raises(TypeError, match=r"^Incorrect arguments on marker 'sort'. Target:testnodeid$") as type_error:
262
256
  core.validate_sort_marker(sort_marker, "testnodeid")
263
257
 
264
- assert type(type_error.value.__cause__) == TypeError
258
+ assert isinstance(type_error.value.__cause__, TypeError)
265
259
 
266
260
  def test_validate_sort_marker_value_error(self):
267
261
  sort_marker = mock.MagicMock()
@@ -269,7 +263,7 @@ class TestValidateMarker:
269
263
  sort_marker.kwargs = {}
270
264
 
271
265
  with pytest.raises(
272
- ValueError, match="^Invalid Value for 'mode' on 'sort' marker. Value:invalid Target:testnodeid$"
266
+ ValueError, match=r"^Invalid Value for 'mode' on 'sort' marker. Value:invalid Target:testnodeid$"
273
267
  ) as type_error:
274
268
  core.validate_sort_marker(sort_marker, "testnodeid")
275
269
 
@@ -278,7 +272,7 @@ class TestValidateMarker:
278
272
 
279
273
  class TestMarkerSettings:
280
274
  def test_get_marker_settings_order_function(self, mock_objects):
281
- (session, package, module, cls, func) = mock_objects
275
+ session, package, module, cls, func = mock_objects
282
276
 
283
277
  order_1 = mock.MagicMock()
284
278
  order_1.args = [1]
@@ -296,7 +290,7 @@ class TestMarkerSettings:
296
290
  )
297
291
 
298
292
  def test_get_marker_settings_order_cls(self, mock_objects):
299
- (session, package, module, cls, func) = mock_objects
293
+ session, package, module, cls, func = mock_objects
300
294
 
301
295
  order_1 = mock.MagicMock()
302
296
  order_1.args = [1]
@@ -319,7 +313,7 @@ class TestMarkerSettings:
319
313
  )
320
314
 
321
315
  def test_get_marker_settings_order_mod(self, mock_objects):
322
- (session, package, module, cls, func) = mock_objects
316
+ session, package, module, cls, func = mock_objects
323
317
 
324
318
  order_1 = mock.MagicMock()
325
319
  order_1.args = [1]
@@ -342,7 +336,7 @@ class TestMarkerSettings:
342
336
  )
343
337
 
344
338
  def test_get_marker_settings_sort_self(self, mock_objects):
345
- (session, package, module, cls, func) = mock_objects
339
+ session, package, module, cls, func = mock_objects
346
340
 
347
341
  order_1 = mock.MagicMock()
348
342
  order_1.args = [1]
@@ -370,7 +364,7 @@ class TestMarkerSettings:
370
364
  )
371
365
 
372
366
  def test_get_marker_settings_sort_bucket(self, mock_objects):
373
- (session, package, module, cls, func) = mock_objects
367
+ session, package, module, cls, func = mock_objects
374
368
 
375
369
  order_1 = mock.MagicMock()
376
370
  order_1.args = [1]
@@ -391,12 +385,12 @@ class TestMarkerSettings:
391
385
  assert core.get_marker_settings(func) == ("random", "parent", None, None, 1)
392
386
 
393
387
  def test_get_marker_settings_no_markers(self, mock_objects):
394
- (session, package, module, cls, func) = mock_objects
388
+ session, package, module, cls, func = mock_objects
395
389
 
396
390
  assert core.get_marker_settings(func) == (None, None, None, None, None)
397
391
 
398
392
  def test_get_marker_settings_error(self, mock_objects):
399
- (session, package, module, cls, func) = mock_objects
393
+ session, package, module, cls, func = mock_objects
400
394
 
401
395
  sort_random = mock.MagicMock()
402
396
  sort_random.args = ["random", "hello"]
@@ -424,7 +418,7 @@ class TestCreateSortKey:
424
418
  def test_marker_bucketid_sortkey(self, get_marker_settings, mock_objects):
425
419
  get_marker_settings.return_value = (None, None, "test/core", None, 1234)
426
420
  config.SortConfig.bucket_mode = "ordered"
427
- (session, package, module, cls, func) = mock_objects
421
+ session, package, module, cls, func = mock_objects
428
422
 
429
423
  core.create_sort_keys(func, 6, 60)
430
424
 
@@ -438,7 +432,7 @@ class TestCreateSortKey:
438
432
  get_marker_settings.return_value = ("reverse", "class", None, None, None)
439
433
  config.SortConfig.mode = "ordered"
440
434
  config.SortConfig.bucket_mode = "ordered"
441
- (session, package, module, cls, func) = mock_objects
435
+ session, package, module, cls, func = mock_objects
442
436
 
443
437
  core.create_sort_keys(func, 6, 60)
444
438
 
@@ -453,7 +447,7 @@ class TestCreateSortKey:
453
447
  config.SortConfig.mode = "ordered"
454
448
  config.SortConfig.bucket_mode = "ordered"
455
449
  config.SortConfig.bucket = "module"
456
- (session, package, module, cls, func) = mock_objects
450
+ session, package, module, cls, func = mock_objects
457
451
 
458
452
  core.create_sort_keys(func, 6, 60)
459
453
 
@@ -468,7 +462,7 @@ class TestCreateSortKey:
468
462
  config.SortConfig.mode = "ordered"
469
463
  config.SortConfig.bucket = "module"
470
464
  config.SortConfig.bucket_mode = "reverse"
471
- (session, package, module, cls, func) = mock_objects
465
+ session, package, module, cls, func = mock_objects
472
466
 
473
467
  core.create_sort_keys(func, 6, 60)
474
468
 
@@ -481,7 +475,7 @@ class TestCreateSortKey:
481
475
  config.SortConfig.mode = "reverse"
482
476
  config.SortConfig.bucket = "module"
483
477
  config.SortConfig.bucket_mode = "ordered"
484
- (session, package, module, cls, func) = mock_objects
478
+ session, package, module, cls, func = mock_objects
485
479
 
486
480
  core.create_sort_keys(func, 6, 60)
487
481
 
@@ -494,7 +488,7 @@ class TestCreateSortKey:
494
488
  config.SortConfig.mode = "fastest"
495
489
  config.SortConfig.bucket = "class"
496
490
  config.SortConfig.bucket_mode = "fastest"
497
- (session, package, module, cls, func) = mock_objects
491
+ session, package, module, cls, func = mock_objects
498
492
 
499
493
  config.SortConfig.item_totals = {
500
494
  func.nodeid: 1.1,
@@ -512,7 +506,7 @@ class TestCreateSortKey:
512
506
  config.SortConfig.mode = "ordered"
513
507
  config.SortConfig.bucket = "module"
514
508
  config.SortConfig.bucket_mode = "ordered"
515
- (session, package, module, cls, func) = mock_objects
509
+ session, package, module, cls, func = mock_objects
516
510
 
517
511
  core.create_sort_keys(func, 0, 60)
518
512
  core.create_sort_keys(func, 1, 60)
@@ -526,7 +520,7 @@ class TestCreateSortKey:
526
520
  config.SortConfig.mode = "ordered"
527
521
  config.SortConfig.bucket = "module"
528
522
  config.SortConfig.bucket_mode = "md5"
529
- (session, package, module, cls, func) = mock_objects
523
+ session, package, module, cls, func = mock_objects
530
524
 
531
525
  md5.return_value.digest.side_effect = [b"DEF", b"ABC", b"GHI"]
532
526
 
@@ -537,7 +531,7 @@ class TestCreateSortKey:
537
531
  assert config.SortConfig.bucket_sort_keys == {module.nodeid: b"ABC"}
538
532
 
539
533
  def test_get_item_sort_key(self, mock_objects):
540
- (session, package, module, cls, func) = mock_objects
534
+ session, package, module, cls, func = mock_objects
541
535
 
542
536
  core.SortConfig.item_sort_keys = {func.nodeid: 1.1}
543
537
  core.SortConfig.item_bucket_id = {func.nodeid: cls.nodeid}
File without changes
File without changes