66from sqlmesh .utils import yaml
77import shutil
88import site
9+ import uuid
910
1011pytestmark = pytest .mark .slow
1112
@@ -16,6 +17,10 @@ def __call__(
1617 ) -> subprocess .CompletedProcess : ...
1718
1819
20+ class CreateSitePackageType (t .Protocol ):
21+ def __call__ (self , name : str ) -> t .Tuple [str , Path ]: ...
22+
23+
1924@pytest .fixture
2025def invoke_cli (tmp_path : Path ) -> InvokeCliType :
2126 # Fetch the full path to the SQLMesh binary so that when we use `cwd` to run in the context of a test dir, the correct SQLMesh binary is executed
@@ -65,10 +70,36 @@ def _fetch() -> str:
6570 return _fetch
6671
6772
73+ @pytest .fixture
74+ def create_site_package () -> t .Iterator [CreateSitePackageType ]:
75+ created_package_path = None
76+
77+ def _create (name : str ) -> t .Tuple [str , Path ]:
78+ nonlocal created_package_path
79+
80+ unique_id = str (uuid .uuid4 ())[0 :8 ]
81+ package_name = f"{ name } _{ unique_id } " # so that multiple tests using the same name dont clobber each other
82+
83+ site_packages = site .getsitepackages ()[0 ]
84+ package_path = Path (site_packages ) / package_name
85+ package_path .mkdir ()
86+
87+ created_package_path = package_path
88+
89+ return package_name , package_path
90+
91+ yield _create
92+
93+ if created_package_path :
94+ # cleanup
95+ shutil .rmtree (created_package_path , ignore_errors = True )
96+
97+
6898def test_load_snapshots_that_reference_nonexistent_python_libraries (
6999 invoke_cli : InvokeCliType ,
70100 duckdb_example_project : Path ,
71101 last_log_file_contents : t .Callable [[], str ],
102+ create_site_package : CreateSitePackageType ,
72103) -> None :
73104 """
74105 Scenario:
@@ -84,10 +115,8 @@ def test_load_snapshots_that_reference_nonexistent_python_libraries(
84115 project_path = duckdb_example_project
85116
86117 # simulate a 3rd party library that provides a macro
87- site_packages = site .getsitepackages ()[0 ]
88- sqlmesh_test_macros_package_path = Path (site_packages ) / "sqlmesh_test_macros"
89- sqlmesh_test_macros_package_path .mkdir ()
90- (sqlmesh_test_macros_package_path / "macros.py" ).write_text ("""
118+ package_name , package_path = create_site_package ("sqlmesh_test_macros" )
119+ (package_path / "macros.py" ).write_text ("""
91120from sqlmesh import macro
92121
93122@macro()
@@ -96,8 +125,8 @@ def do_something(evaluator):
96125""" )
97126
98127 # reference the macro from site-packages
99- (project_path / "macros" / "__init__.py" ).write_text ("""
100- from sqlmesh_test_macros .macros import do_something
128+ (project_path / "macros" / "__init__.py" ).write_text (f """
129+ from { package_name } .macros import do_something
101130""" )
102131
103132 (project_path / "models" / "example.sql" ).write_text ("""
@@ -125,7 +154,7 @@ def do_something(evaluator):
125154
126155 # deleting this removes the 'do_something()' macro used by the version of the snapshot stored in state
127156 # when loading the old snapshot from state in the local python env, this will create an ImportError
128- shutil .rmtree (sqlmesh_test_macros_package_path )
157+ shutil .rmtree (package_path )
129158
130159 # Move the macro inline so its no longer being loaded from a library but still exists with the same signature
131160 (project_path / "macros" / "__init__.py" ).write_text ("""
@@ -150,7 +179,7 @@ def do_something(evaluator):
150179 assert "Virtual layer updated" in result .stdout
151180
152181 log_file_contents = last_log_file_contents ()
153- assert "ModuleNotFoundError: No module named 'sqlmesh_test_macros '" in log_file_contents
182+ assert f "ModuleNotFoundError: No module named '{ package_name } '" in log_file_contents
154183 assert (
155184 "ERROR - Failed to cache optimized query for model 'example.test_model'"
156185 in log_file_contents
@@ -165,6 +194,7 @@ def test_model_selector_snapshot_references_nonexistent_python_libraries(
165194 invoke_cli : InvokeCliType ,
166195 duckdb_example_project : Path ,
167196 last_log_file_contents : t .Callable [[], str ],
197+ create_site_package : CreateSitePackageType ,
168198) -> None :
169199 """
170200 Scenario:
@@ -180,10 +210,8 @@ def test_model_selector_snapshot_references_nonexistent_python_libraries(
180210 project_path = duckdb_example_project
181211
182212 # simulate a 3rd party library that provides a macro
183- site_packages = site .getsitepackages ()[0 ]
184- sqlmesh_test_macros_package_path = Path (site_packages ) / "sqlmesh_test_macros"
185- sqlmesh_test_macros_package_path .mkdir ()
186- (sqlmesh_test_macros_package_path / "macros.py" ).write_text ("""
213+ package_name , package_path = create_site_package ("sqlmesh_test_macros" )
214+ (package_path / "macros.py" ).write_text ("""
187215from sqlmesh import macro
188216
189217@macro()
@@ -192,8 +220,8 @@ def do_something(evaluator):
192220""" )
193221
194222 # reference the macro from site-packages
195- (project_path / "macros" / "__init__.py" ).write_text ("""
196- from sqlmesh_test_macros .macros import do_something
223+ (project_path / "macros" / "__init__.py" ).write_text (f """
224+ from { package_name } .macros import do_something
197225""" )
198226
199227 (project_path / "models" / "example.sql" ).write_text ("""
@@ -216,7 +244,7 @@ def do_something(evaluator):
216244
217245 # deleting this removes the 'do_something()' macro used by the version of the snapshot stored in state
218246 # when loading the old snapshot from state in the local python env, this will create an ImportError
219- shutil .rmtree (sqlmesh_test_macros_package_path )
247+ shutil .rmtree (package_path )
220248
221249 # Move the macro inline so its no longer being loaded from a library but still exists with the same signature
222250 (project_path / "macros" / "__init__.py" ).write_text ("""
@@ -267,15 +295,15 @@ def do_something(evaluator):
267295 "Model 'sqlmesh_example.test_model' sourced from state cannot be rendered in the local environment"
268296 in result .stdout
269297 )
270- assert "No module named 'sqlmesh_test_macros '" in result .stdout
298+ assert f "No module named '{ package_name } '" in result .stdout
271299 assert (
272300 "If the model has been fixed locally, please ensure that the --select-model expression includes it"
273301 in result .stdout
274302 )
275303
276304 # verify the full stack trace was logged
277305 log_file_contents = last_log_file_contents ()
278- assert "ModuleNotFoundError: No module named 'sqlmesh_test_macros '" in log_file_contents
306+ assert f "ModuleNotFoundError: No module named '{ package_name } '" in log_file_contents
279307 assert (
280308 "The above exception was the direct cause of the following exception:" in log_file_contents
281309 )
0 commit comments