Skip to content

Commit 8aa59a4

Browse files
committed
2 parents 1da91f9 + 8ad7d26 commit 8aa59a4

File tree

7 files changed

+1340
-166
lines changed

7 files changed

+1340
-166
lines changed

eval_protocol/cli_commands/upload.py

Lines changed: 108 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ def _is_eval_protocol_test(obj: Any) -> bool:
8181
return False
8282
# Must have pytest marks from evaluation_test
8383
marks = getattr(obj, "pytestmark", [])
84+
# Handle pytest proxy objects (APIRemovedInV1Proxy)
85+
if not isinstance(marks, (list, tuple)):
86+
try:
87+
marks = list(marks) if marks else []
88+
except (TypeError, AttributeError):
89+
return False
8490
return len(marks) > 0
8591

8692

@@ -91,6 +97,14 @@ def _extract_param_info_from_marks(obj: Any) -> tuple[bool, int, list[str]]:
9197
(has_parametrize, param_count, param_ids)
9298
"""
9399
marks = getattr(obj, "pytestmark", [])
100+
101+
# Handle pytest proxy objects (APIRemovedInV1Proxy) - same as _is_eval_protocol_test
102+
if not isinstance(marks, (list, tuple)):
103+
try:
104+
marks = list(marks) if marks else []
105+
except (TypeError, AttributeError):
106+
marks = []
107+
94108
has_parametrize = False
95109
total_combinations = 0
96110
all_param_ids: list[str] = []
@@ -131,51 +145,103 @@ def _discover_tests(root: str) -> list[DiscoveredTest]:
131145

132146
discovered: list[DiscoveredTest] = []
133147

134-
# Collect all test functions from Python files
135-
for file_path in _iter_python_files(root):
148+
class CollectionPlugin:
149+
"""Plugin to capture collected items without running code."""
150+
151+
def __init__(self):
152+
self.items = []
153+
154+
def pytest_ignore_collect(self, collection_path, config):
155+
"""Ignore problematic files before pytest tries to import them."""
156+
# Ignore specific files
157+
ignored_files = ["setup.py", "versioneer.py", "conf.py", "__main__.py"]
158+
if collection_path.name in ignored_files:
159+
return True
160+
161+
# Ignore hidden files (starting with .)
162+
if collection_path.name.startswith("."):
163+
return True
164+
165+
# Ignore test_discovery files
166+
if collection_path.name.startswith("test_discovery"):
167+
return True
168+
169+
return None
170+
171+
def pytest_collection_modifyitems(self, items):
172+
"""Hook called after collection is done."""
173+
self.items = items
174+
175+
plugin = CollectionPlugin()
176+
177+
# Run pytest collection only (--collect-only prevents code execution)
178+
# Override python_files to collect from ANY .py file
179+
args = [
180+
abs_root,
181+
"--collect-only",
182+
"-q",
183+
"--pythonwarnings=ignore",
184+
"-o",
185+
"python_files=*.py", # Override to collect all .py files
186+
]
187+
188+
try:
189+
# Suppress pytest output
190+
import io
191+
import contextlib
192+
193+
with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
194+
pytest.main(args, plugins=[plugin])
195+
except Exception:
196+
# If pytest collection fails, fall back to empty list
197+
return []
198+
199+
# Process collected items
200+
for item in plugin.items:
201+
if not hasattr(item, "obj"):
202+
continue
203+
204+
obj = item.obj
205+
if not _is_eval_protocol_test(obj):
206+
continue
207+
208+
origin = getattr(obj, "_origin_func", obj)
136209
try:
137-
unique_name = "ep_upload_" + re.sub(r"[^a-zA-Z0-9_]", "_", os.path.abspath(file_path))
138-
spec = importlib.util.spec_from_file_location(unique_name, file_path)
139-
if spec and spec.loader:
140-
module = importlib.util.module_from_spec(spec)
141-
sys.modules[spec.name] = module
142-
spec.loader.exec_module(module) # type: ignore[attr-defined]
143-
else:
144-
continue
210+
src_file = inspect.getsourcefile(origin) or str(item.path)
211+
_, lineno = inspect.getsourcelines(origin)
145212
except Exception:
146-
continue
213+
src_file, lineno = str(item.path), None
147214

148-
for name, obj in inspect.getmembers(module):
149-
if _is_eval_protocol_test(obj):
150-
origin = getattr(obj, "_origin_func", obj)
151-
try:
152-
src_file = inspect.getsourcefile(origin) or file_path
153-
_, lineno = inspect.getsourcelines(origin)
154-
except Exception:
155-
src_file, lineno = file_path, None
156-
157-
# Extract parametrization info from marks
158-
has_parametrize, param_count, param_ids = _extract_param_info_from_marks(obj)
159-
160-
# Generate synthetic nodeids for display
161-
base_nodeid = f"{os.path.basename(file_path)}::{name}"
162-
if has_parametrize and param_ids:
163-
nodeids = [f"{base_nodeid}[{pid}]" for pid in param_ids]
164-
else:
165-
nodeids = [base_nodeid]
166-
167-
discovered.append(
168-
DiscoveredTest(
169-
module_path=module.__name__,
170-
module_name=module.__name__,
171-
qualname=f"{module.__name__}.{name}",
172-
file_path=os.path.abspath(src_file),
173-
lineno=lineno,
174-
has_parametrize=has_parametrize,
175-
param_count=param_count,
176-
nodeids=nodeids,
177-
)
178-
)
215+
# Extract parametrization info from marks
216+
has_parametrize, param_count, param_ids = _extract_param_info_from_marks(obj)
217+
218+
# Get module name and function name
219+
module_name = (
220+
item.module.__name__
221+
if hasattr(item, "module")
222+
else item.nodeid.split("::")[0].replace("/", ".").replace(".py", "")
223+
)
224+
func_name = item.name.split("[")[0] if "[" in item.name else item.name
225+
226+
# Generate nodeids
227+
base_nodeid = f"{os.path.basename(src_file)}::{func_name}"
228+
if param_ids:
229+
nodeids = [f"{base_nodeid}[{pid}]" for pid in param_ids]
230+
else:
231+
nodeids = [base_nodeid]
232+
233+
discovered.append(
234+
DiscoveredTest(
235+
module_path=module_name,
236+
module_name=module_name,
237+
qualname=f"{module_name}.{func_name}",
238+
file_path=os.path.abspath(src_file),
239+
lineno=lineno,
240+
has_parametrize=has_parametrize,
241+
param_count=param_count,
242+
nodeids=nodeids,
243+
)
244+
)
179245

180246
# Deduplicate by qualname (in case same test appears multiple times)
181247
by_qual: dict[str, DiscoveredTest] = {}

0 commit comments

Comments
 (0)