pytest-fastcollect 0.5.2__cp312-cp312-musllinux_1_2_i686.whl
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.
- pytest_fastcollect/__init__.py +12 -0
- pytest_fastcollect/cache.py +171 -0
- pytest_fastcollect/constants.py +89 -0
- pytest_fastcollect/daemon.py +943 -0
- pytest_fastcollect/daemon_client.py +581 -0
- pytest_fastcollect/filter.py +204 -0
- pytest_fastcollect/plugin.py +601 -0
- pytest_fastcollect/py.typed +0 -0
- pytest_fastcollect/pytest_fastcollect.cpython-312-i386-linux-musl.so +0 -0
- pytest_fastcollect/socket_strategy.py +217 -0
- pytest_fastcollect-0.5.2.dist-info/METADATA +747 -0
- pytest_fastcollect-0.5.2.dist-info/RECORD +16 -0
- pytest_fastcollect-0.5.2.dist-info/WHEEL +4 -0
- pytest_fastcollect-0.5.2.dist-info/entry_points.txt +2 -0
- pytest_fastcollect-0.5.2.dist-info/licenses/LICENSE +21 -0
- pytest_fastcollect.libs/libgcc_s-27e5a392.so.1 +0 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Test filtering logic for selective import optimization."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Dict, List, Set, Any, Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestFilter:
|
|
8
|
+
"""Filter tests based on pytest's -k and -m options."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, keyword_expr: Optional[str] = None, marker_expr: Optional[str] = None):
|
|
11
|
+
"""Initialize filter with keyword and marker expressions.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
keyword_expr: The -k expression (e.g., "test_foo and not slow")
|
|
15
|
+
marker_expr: The -m expression (e.g., "smoke and not slow")
|
|
16
|
+
"""
|
|
17
|
+
self.keyword_expr = keyword_expr
|
|
18
|
+
self.marker_expr = marker_expr
|
|
19
|
+
|
|
20
|
+
def matches(self, test_item: Dict[str, Any]) -> bool:
|
|
21
|
+
"""Check if a test item matches the filter criteria.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
test_item: Test item dict with keys: name, markers, class, etc.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
True if the test matches the filter
|
|
28
|
+
"""
|
|
29
|
+
# If no filters, everything matches
|
|
30
|
+
if not self.keyword_expr and not self.marker_expr:
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
# Check keyword filter
|
|
34
|
+
if self.keyword_expr:
|
|
35
|
+
if not self._matches_keyword(test_item):
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
# Check marker filter
|
|
39
|
+
if self.marker_expr:
|
|
40
|
+
if not self._matches_marker(test_item):
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
return True
|
|
44
|
+
|
|
45
|
+
def _matches_keyword(self, test_item: Dict[str, Any]) -> bool:
|
|
46
|
+
"""Check if test matches keyword expression (-k).
|
|
47
|
+
|
|
48
|
+
The keyword expression can match against:
|
|
49
|
+
- Test function name
|
|
50
|
+
- Test class name
|
|
51
|
+
- Test file path
|
|
52
|
+
|
|
53
|
+
Supports: 'and', 'or', 'not', and parentheses.
|
|
54
|
+
"""
|
|
55
|
+
# Build a searchable string from the test item
|
|
56
|
+
parts = [test_item['name']]
|
|
57
|
+
|
|
58
|
+
if 'class' in test_item and test_item['class'] is not None:
|
|
59
|
+
parts.append(test_item['class'])
|
|
60
|
+
|
|
61
|
+
# Add file path components
|
|
62
|
+
file_path = test_item.get('file_path', '')
|
|
63
|
+
if file_path:
|
|
64
|
+
# Extract file name without extension
|
|
65
|
+
import os
|
|
66
|
+
filename = os.path.splitext(os.path.basename(file_path))[0]
|
|
67
|
+
parts.append(filename)
|
|
68
|
+
|
|
69
|
+
search_text = ' '.join(parts).lower()
|
|
70
|
+
|
|
71
|
+
# Evaluate the keyword expression
|
|
72
|
+
return self._evaluate_expression(self.keyword_expr, search_text)
|
|
73
|
+
|
|
74
|
+
def _matches_marker(self, test_item: Dict[str, Any]) -> bool:
|
|
75
|
+
"""Check if test matches marker expression (-m).
|
|
76
|
+
|
|
77
|
+
Supports: 'and', 'or', 'not', and parentheses.
|
|
78
|
+
"""
|
|
79
|
+
markers = test_item.get('markers', [])
|
|
80
|
+
marker_set = set(m.lower() for m in markers)
|
|
81
|
+
|
|
82
|
+
# Evaluate the marker expression
|
|
83
|
+
return self._evaluate_marker_expression(self.marker_expr, marker_set)
|
|
84
|
+
|
|
85
|
+
def _evaluate_expression(self, expr: str, search_text: str) -> bool:
|
|
86
|
+
"""Evaluate a keyword expression against search text.
|
|
87
|
+
|
|
88
|
+
Simple implementation that handles common cases:
|
|
89
|
+
- Single keywords: "test_foo"
|
|
90
|
+
- AND: "test_foo and test_bar"
|
|
91
|
+
- OR: "test_foo or test_bar"
|
|
92
|
+
- NOT: "not slow"
|
|
93
|
+
- Combinations: "test_foo and not slow"
|
|
94
|
+
"""
|
|
95
|
+
expr = expr.lower().strip()
|
|
96
|
+
|
|
97
|
+
# Handle simple case: single keyword
|
|
98
|
+
if ' and ' not in expr and ' or ' not in expr and not expr.startswith('not '):
|
|
99
|
+
return expr in search_text
|
|
100
|
+
|
|
101
|
+
# Handle NOT
|
|
102
|
+
if expr.startswith('not '):
|
|
103
|
+
keyword = expr[4:].strip()
|
|
104
|
+
return keyword not in search_text
|
|
105
|
+
|
|
106
|
+
# Handle AND
|
|
107
|
+
if ' and ' in expr:
|
|
108
|
+
parts = expr.split(' and ')
|
|
109
|
+
return all(self._evaluate_expression(p.strip(), search_text) for p in parts)
|
|
110
|
+
|
|
111
|
+
# Handle OR
|
|
112
|
+
if ' or ' in expr:
|
|
113
|
+
parts = expr.split(' or ')
|
|
114
|
+
return any(self._evaluate_expression(p.strip(), search_text) for p in parts)
|
|
115
|
+
|
|
116
|
+
return expr in search_text
|
|
117
|
+
|
|
118
|
+
def _evaluate_marker_expression(self, expr: str, markers: Set[str]) -> bool:
|
|
119
|
+
"""Evaluate a marker expression against a set of markers.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
expr: Marker expression like "smoke and not slow"
|
|
123
|
+
markers: Set of marker names on this test
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
True if the expression matches
|
|
127
|
+
"""
|
|
128
|
+
expr = expr.lower().strip()
|
|
129
|
+
|
|
130
|
+
# Handle simple case: single marker
|
|
131
|
+
if ' and ' not in expr and ' or ' not in expr and not expr.startswith('not '):
|
|
132
|
+
return expr in markers
|
|
133
|
+
|
|
134
|
+
# Handle NOT
|
|
135
|
+
if expr.startswith('not '):
|
|
136
|
+
marker = expr[4:].strip()
|
|
137
|
+
return marker not in markers
|
|
138
|
+
|
|
139
|
+
# Handle AND
|
|
140
|
+
if ' and ' in expr:
|
|
141
|
+
parts = expr.split(' and ')
|
|
142
|
+
return all(self._evaluate_marker_expression(p.strip(), markers) for p in parts)
|
|
143
|
+
|
|
144
|
+
# Handle OR
|
|
145
|
+
if ' or ' in expr:
|
|
146
|
+
parts = expr.split(' or ')
|
|
147
|
+
return any(self._evaluate_marker_expression(p.strip(), markers) for p in parts)
|
|
148
|
+
|
|
149
|
+
return expr in markers
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def filter_collected_data(
|
|
153
|
+
collected_data: Dict[str, List[Dict[str, Any]]],
|
|
154
|
+
keyword_expr: Optional[str] = None,
|
|
155
|
+
marker_expr: Optional[str] = None
|
|
156
|
+
) -> Dict[str, List[Dict[str, Any]]]:
|
|
157
|
+
"""Filter collected test data based on keyword and marker expressions.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
collected_data: Dict mapping file paths to lists of test items
|
|
161
|
+
keyword_expr: Optional -k expression
|
|
162
|
+
marker_expr: Optional -m expression
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Filtered dict with only matching tests and their files
|
|
166
|
+
"""
|
|
167
|
+
# If no filters, return everything
|
|
168
|
+
if not keyword_expr and not marker_expr:
|
|
169
|
+
return collected_data
|
|
170
|
+
|
|
171
|
+
test_filter = TestFilter(keyword_expr, marker_expr)
|
|
172
|
+
filtered_data = {}
|
|
173
|
+
|
|
174
|
+
for file_path, test_items in collected_data.items():
|
|
175
|
+
# Filter test items in this file
|
|
176
|
+
matching_items = [item for item in test_items if test_filter.matches(item)]
|
|
177
|
+
|
|
178
|
+
# Only include file if it has matching tests
|
|
179
|
+
if matching_items:
|
|
180
|
+
filtered_data[file_path] = matching_items
|
|
181
|
+
|
|
182
|
+
return filtered_data
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_files_with_matching_tests(
|
|
186
|
+
collected_data: Dict[str, List[Dict[str, Any]]],
|
|
187
|
+
keyword_expr: Optional[str] = None,
|
|
188
|
+
marker_expr: Optional[str] = None
|
|
189
|
+
) -> Set[str]:
|
|
190
|
+
"""Get the set of file paths that contain matching tests.
|
|
191
|
+
|
|
192
|
+
This is used to populate _test_files_cache with only files
|
|
193
|
+
that have tests matching the filter criteria.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
collected_data: Dict mapping file paths to lists of test items
|
|
197
|
+
keyword_expr: Optional -k expression
|
|
198
|
+
marker_expr: Optional -m expression
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Set of file paths containing matching tests
|
|
202
|
+
"""
|
|
203
|
+
filtered_data = filter_collected_data(collected_data, keyword_expr, marker_expr)
|
|
204
|
+
return set(filtered_data.keys())
|