66import subprocess
77import sys
88import os
9+ import time
910
1011# Only the specific tests that cause state pollution issues
1112ISOLATED_TESTS = [
@@ -42,14 +43,14 @@ def run_isolated_test(test_path):
4243
4344def main ():
4445 """Run tests with minimal isolation - only isolate known problematic tests."""
45- print ( "Starting minimal isolated test runner for BrainPy..." )
46+ start_time = time . time ( )
4647
4748 # GitHub Actions specific settings
4849 is_github_actions = os .getenv ('IS_GITHUB_ACTIONS' ) == '1'
4950 base_cmd = [sys .executable , "-m" , "pytest" ]
5051 test_args = ["-v" , "--tb=short" ]
5152 if is_github_actions :
52- test_args .extend (["--maxfail=5" , "-q" ])
53+ test_args .extend (["--maxfail=5" ])
5354
5455 # Build ignore list - only ignore files that contain problematic tests
5556 ignore_patterns = []
@@ -64,47 +65,90 @@ def main():
6465 for file_path in all_problematic_files :
6566 ignore_patterns .append (f"--ignore={ file_path } " )
6667
68+ print ("=" * 80 )
69+ print ("BrainPy Test Suite (with state pollution isolation)" )
70+ print ("=" * 80 )
71+
6772 # Run main test suite (excluding problematic files)
68- print ("\n " + "=" * 60 )
69- print ("RUNNING MAIN TEST SUITE (excluding problematic files)" )
70- print ("=" * 60 )
73+ print (f"\n { '🔄 Running main test suite...' :<60} " , end = "" , flush = True )
7174
7275 cmd = base_cmd + ["brainpy/_src/" ] + test_args + ignore_patterns
73- main_result = subprocess .run (cmd )
76+ main_start = time .time ()
77+ main_result = subprocess .run (cmd , capture_output = True , text = True )
78+ main_time = time .time () - main_start
7479 main_passed = main_result .returncode == 0
7580
76- # Run isolated problematic files
77- print ("\n " + "=" * 60 )
78- print ("RUNNING ISOLATED PROBLEMATIC FILES" )
79- print ("=" * 60 )
81+ if main_passed :
82+ print (f"✅ PASSED ({ main_time :.1f} s)" )
83+ else :
84+ print (f"❌ FAILED ({ main_time :.1f} s)" )
85+ if not is_github_actions :
86+ # Extract key info from pytest output
87+ lines = main_result .stdout .split ('\n ' )
88+ failed_lines = [line for line in lines if 'FAILED' in line ][:5 ] # Show first 5 failures
89+ if failed_lines :
90+ print ("\n Recent failures:" )
91+ for line in failed_lines :
92+ print (f" { line } " )
8093
94+ # Run isolated problematic files
8195 isolated_results = []
8296 for file_path in sorted (all_problematic_files ):
8397 if os .path .exists (file_path ):
84- print (f"Running isolated file: { file_path } " )
98+ file_name = file_path .split ("/" )[- 1 ]
99+ print (f"{ '🔄 Isolated: ' + file_name :<60} " , end = "" , flush = True )
100+
85101 cmd = base_cmd + [file_path ] + test_args + ["-x" ]
86- result = subprocess .run (cmd )
87- isolated_results .append (result .returncode == 0 )
102+ iso_start = time .time ()
103+ result = subprocess .run (cmd , capture_output = True , text = True )
104+ iso_time = time .time () - iso_start
105+ passed = result .returncode == 0
106+ isolated_results .append (passed )
107+
108+ if passed :
109+ print (f"✅ PASSED ({ iso_time :.1f} s)" )
110+ else :
111+ print (f"❌ FAILED ({ iso_time :.1f} s)" )
112+ if not is_github_actions :
113+ lines = result .stdout .split ('\n ' )
114+ failed_lines = [line for line in lines if 'FAILED' in line ][:3 ]
115+ if failed_lines :
116+ print (" Failures:" )
117+ for line in failed_lines :
118+ print (f" { line } " )
88119 else :
89- print (f"Skipping non-existent file: { file_path } " )
90120 isolated_results .append (True )
91121
92- # Summary
93- print ("\n " + "=" * 60 )
94- print ("TEST SUMMARY" )
95- print ("=" * 60 )
122+ # Final summary in pytest style
123+ total_time = time .time () - start_time
124+ print ("\n " + "=" * 80 )
96125
97126 all_passed = main_passed and all (isolated_results )
127+ total_groups = 1 + len ([f for f in all_problematic_files if os .path .exists (f )])
128+ passed_groups = (1 if main_passed else 0 ) + sum (isolated_results )
129+ failed_groups = total_groups - passed_groups
98130
99- print (f"Main test suite: { '✓ PASSED' if main_passed else '✗ FAILED' } " )
100- print (f"Isolated files: { '✓ PASSED' if all (isolated_results ) else '✗ FAILED' } ({ len ([r for r in isolated_results if r ])} /{ len (isolated_results )} )" )
101-
102- if not all_passed :
103- print ("\n Some tests failed. Re-run individually to debug." )
104- return 1
131+ if all_passed :
132+ print (f"{ '=' * 25 } ✅ { passed_groups } passed in { total_time :.1f} s { '=' * 25 } " )
105133 else :
106- print ("\n All tests passed!" )
107- return 0
134+ status_parts = []
135+ if failed_groups > 0 :
136+ status_parts .append (f"❌ { failed_groups } failed" )
137+ if passed_groups > 0 :
138+ status_parts .append (f"✅ { passed_groups } passed" )
139+
140+ status = ", " .join (status_parts )
141+ print (f"{ '=' * 20 } { status } in { total_time :.1f} s { '=' * 20 } " )
142+
143+ if not all_passed :
144+ print ("\n Failed test groups:" )
145+ if not main_passed :
146+ print (" • Main test suite" )
147+ for file_path , passed in zip (sorted (all_problematic_files ), isolated_results ):
148+ if os .path .exists (file_path ) and not passed :
149+ print (f" • { file_path } " )
150+
151+ return 0 if all_passed else 1
108152
109153if __name__ == "__main__" :
110154 exit_code = main ()
0 commit comments