22import importlib
33import shutil
44import time
5+ import gc
56from .loader import omnipkgLoader
67from .core import omnipkg as OmnipkgCore , ConfigManager
8+ from pathlib import Path
9+ import os
10+ import subprocess
711
812def print_header (title ):
913 """Prints a consistent, pretty header for the test stages."""
@@ -20,13 +24,11 @@ def setup():
2024 packages_to_test = ["numpy" , "scipy" ]
2125
2226 for pkg in packages_to_test :
23- # Find all bubble directories for this package
2427 for bubble in omnipkg_core .multiversion_base .glob (f"{ pkg } -*" ):
2528 if bubble .is_dir ():
2629 print (f" - Removing old bubble: { bubble .name } " )
2730 shutil .rmtree (bubble )
2831
29- # Use omnipkg to ensure the 'good' versions are installed
3032 print (" - Setting main environment to a known good state..." )
3133 omnipkg_core .smart_install (["numpy==1.26.4" , "scipy==1.16.1" ])
3234 print ("✅ Environment is clean and ready for testing." )
@@ -39,47 +41,135 @@ def run_test():
3941 print ("\n 💥 NUMPY VERSION JUGGLING:" )
4042 for numpy_ver in ["1.24.3" , "1.26.4" ]:
4143 print (f"\n ⚡ Switching to numpy=={ numpy_ver } " )
44+
4245 if loader .activate_snapshot (f"numpy=={ numpy_ver } " ):
4346 import numpy as np
44- importlib . reload ( np )
47+
4548 print (f" ✅ Version: { np .__version__ } " )
4649 print (f" 🔢 Array sum: { np .array ([1 ,2 ,3 ]).sum ()} " )
50+
51+ if np .__version__ != numpy_ver :
52+ print (f" ⚠️ WARNING: Expected { numpy_ver } , got { np .__version__ } !" )
53+ else :
54+ print (f" 🎯 Version verification: PASSED" )
4755 else :
4856 print (f" ❌ Activation failed for numpy=={ numpy_ver } !" )
4957
5058 # ===== SCIPY C-EXTENSION CHAOS =====
5159 print ("\n \n 🔥 SCIPY C-EXTENSION TEST:" )
5260 for scipy_ver in ["1.12.0" , "1.16.1" ]:
5361 print (f"\n 🌋 Switching to scipy=={ scipy_ver } " )
62+
5463 if loader .activate_snapshot (f"scipy=={ scipy_ver } " ):
64+ import scipy as sp
5565 import scipy .sparse
5666 import scipy .linalg
57- importlib .reload (scipy )
58- print (f" ✅ Version: { scipy .__version__ } " )
59- eye = scipy .sparse .eye (3 )
60- print (f" ♻️ Sparse matrix: { eye .nnz } non-zeros" )
61- det = scipy .linalg .det ([[0 , 2 ], [1 , 1 ]])
62- print (f" 📐 Linalg det: { det } " )
67+
68+ print (f" ✅ Version: { sp .__version__ } " )
69+ print (f" ♻️ Sparse matrix: { sp .sparse .eye (3 ).nnz } non-zeros" )
70+ print (f" 📐 Linalg det: { sp .linalg .det ([[0 , 2 ], [1 , 1 ]])} " )
71+
72+ if sp .__version__ != scipy_ver :
73+ print (f" ⚠️ WARNING: Expected { scipy_ver } , got { sp .__version__ } !" )
74+ else :
75+ print (f" 🎯 Version verification: PASSED" )
6376 else :
6477 print (f" ❌ Activation failed for scipy=={ scipy_ver } !" )
6578
66- # ===== THE IMPOSSIBLE TEST =====
79+ # ===== THE IMPOSSIBLE TEST (using clean process) =====
6780 print ("\n \n 🤯 NUMPY + SCIPY VERSION MIXING:" )
6881 combos = [("1.24.3" , "1.12.0" ), ("1.26.4" , "1.16.1" )]
82+
83+ temp_script_path = Path (os .getcwd ()) / "omnipkg_combo_test.py"
84+
6985 for np_ver , sp_ver in combos :
7086 print (f"\n 🌀 COMBO: numpy=={ np_ver } + scipy=={ sp_ver } " )
71- loader .activate_snapshot (f"numpy=={ np_ver } " )
72- loader .activate_snapshot (f"scipy=={ sp_ver } " )
7387
74- import numpy as np
75- import scipy . sparse
76- importlib . reload ( np )
77- importlib . reload ( scipy )
88+ # Get bubble paths
89+ config_manager = ConfigManager ()
90+ omnipkg_core = OmnipkgCore ( config_manager . config )
91+ multiversion_base = omnipkg_core . multiversion_base
7892
79- print (f" 🧪 numpy: { np .__version__ } , scipy: { scipy .__version__ } " )
80- result = np .array ([1 ,2 ,3 ]) @ scipy .sparse .eye (3 )
81- print (f" 🔗 Compatibility check: { result } " )
93+ numpy_bubble = multiversion_base / f"numpy-{ np_ver } "
94+ scipy_bubble = multiversion_base / f"scipy-{ sp_ver } "
8295
96+ # Build PYTHONPATH with bubbles at the front
97+ bubble_paths = []
98+ if numpy_bubble .exists ():
99+ bubble_paths .append (str (numpy_bubble ))
100+ if scipy_bubble .exists ():
101+ bubble_paths .append (str (scipy_bubble ))
102+
103+ # Write the subprocess script
104+ temp_script_content = f"""
105+ import sys
106+ import os
107+
108+ # Verify the bubbles are in our path
109+ print("🔍 Python path (first 5 entries):")
110+ for idx, path in enumerate(sys.path[:5]):
111+ print(f" {{idx}}: {{path}}")
112+
113+ try:
114+ import numpy as np
115+ import scipy as sp
116+ import scipy.sparse
117+
118+ print(f" 🧪 numpy: {{np.__version__}}, scipy: {{sp.__version__}}")
119+ print(f" 📍 numpy location: {{np.__file__}}")
120+ print(f" 📍 scipy location: {{sp.__file__}}")
121+
122+ result = np.array([1,2,3]) @ sp.sparse.eye(3).toarray()
123+ print(f" 🔗 Compatibility check: {{result}}")
124+
125+ if np.__version__ != "{ np_ver } " or sp.__version__ != "{ sp_ver } ":
126+ print(f" ❌ Version mismatch! Expected numpy=={ np_ver } , scipy=={ sp_ver } but got numpy={{np.__version__}}, scipy={{sp.__version__}}", file=sys.stderr)
127+ sys.exit(1)
128+ else:
129+ print(f" 🎯 Version verification: BOTH PASSED!")
130+
131+ except Exception as e:
132+ print(f" ❌ Test failed in subprocess: {{e}}", file=sys.stderr)
133+ import traceback
134+ traceback.print_exc(file=sys.stderr)
135+ sys.exit(1)
136+ """
137+ try :
138+ with open (temp_script_path , "w" ) as f :
139+ f .write (temp_script_content )
140+
141+ # Create clean environment with bubbles prioritized
142+ clean_env = os .environ .copy ()
143+
144+ # Build PYTHONPATH with bubbles first, then existing paths
145+ existing_pythonpath = clean_env .get ('PYTHONPATH' , '' )
146+ if existing_pythonpath :
147+ new_pythonpath = ':' .join (bubble_paths + [existing_pythonpath ])
148+ else :
149+ new_pythonpath = ':' .join (bubble_paths )
150+
151+ clean_env ['PYTHONPATH' ] = new_pythonpath
152+
153+ # Remove any conda/pip environment variables that might interfere
154+ env_vars_to_remove = ['CONDA_DEFAULT_ENV' , 'CONDA_PREFIX' , 'PIP_TARGET' ]
155+ for var in env_vars_to_remove :
156+ clean_env .pop (var , None )
157+
158+ print (f" 🔧 PYTHONPATH: { new_pythonpath } " )
159+
160+ subprocess .run (
161+ [sys .executable , temp_script_path ],
162+ check = True ,
163+ cwd = os .getcwd (),
164+ env = clean_env
165+ )
166+ except subprocess .CalledProcessError as e :
167+ print (f" ❌ Subprocess test failed for combo numpy=={ np_ver } + scipy=={ sp_ver } " )
168+ print (f" 💥 Exit code: { e .returncode } " )
169+ finally :
170+ if temp_script_path .exists ():
171+ os .remove (temp_script_path )
172+
83173 print ("\n \n 🚨 OMNIPKG SURVIVED NUCLEAR TESTING! 🎇" )
84174
85175def cleanup ():
@@ -103,7 +193,6 @@ def run():
103193 try :
104194 setup ()
105195
106- # --- Create the bubbles for the test ---
107196 print_header ("STEP 2: Creating Test Bubbles with `omnipkg`" )
108197 config_manager = ConfigManager ()
109198 omnipkg_core = OmnipkgCore (config_manager .config )
@@ -115,9 +204,8 @@ def run():
115204 name , version = pkg .split ('==' )
116205 print (f"\n --- Creating bubble for { name } =={ version } ---" )
117206 omnipkg_core .bubble_manager .create_isolated_bubble (name , version )
118- time .sleep (1 ) # Give filesystem a moment to settle
207+ time .sleep (1 )
119208
120- # --- Run the actual test ---
121209 print_header ("STEP 3: Executing the Nuclear Test" )
122210 run_test ()
123211
@@ -126,8 +214,7 @@ def run():
126214 import traceback
127215 traceback .print_exc ()
128216 finally :
129- # --- ALWAYS run the cleanup ---
130217 cleanup ()
131218
132219if __name__ == "__main__" :
133- run ()
220+ run ()
0 commit comments