diff --git a/sqlmesh/core/config/loader.py b/sqlmesh/core/config/loader.py index 7f1789a677..c381252fb9 100644 --- a/sqlmesh/core/config/loader.py +++ b/sqlmesh/core/config/loader.py @@ -184,8 +184,14 @@ def load_config_from_python_module( module_path: Path, config_name: str = "config", ) -> C: - with sys_path(module_path.parent): - config_module = import_python_file(module_path, module_path.parent) + try: + with sys_path(module_path.parent): + config_module = import_python_file(module_path, module_path.parent) + except Exception as e: + raise ConfigError( + f"Failed to load config file: {e}", + location=module_path, + ) try: config_obj = getattr(config_module, config_name) diff --git a/vscode/extension/tests/broken_project.spec.ts b/vscode/extension/tests/broken_project.spec.ts index f2af3e13e0..c6be73e403 100644 --- a/vscode/extension/tests/broken_project.spec.ts +++ b/vscode/extension/tests/broken_project.spec.ts @@ -395,9 +395,46 @@ test.describe('Bad config.py/config.yaml file issues', () => { await runCommand(page, 'View: Focus Problems') // Assert that the error is present in the problems view - await page + const errorElement = page .getByText('Config needs to be a valid object of type') .first() - .isVisible({ timeout: 5_000 }) + await expect(errorElement).toBeVisible({ timeout: 5000 }) + }) + + test('sushi example, bad config.py', async ({ page, sharedCodeServer }) => { + const tempDir = await fs.mkdtemp( + path.join(os.tmpdir(), 'vscode-test-tcloud-'), + ) + await fs.copy(SUSHI_SOURCE_PATH, tempDir) + await createPythonInterpreterSettingsSpecifier(tempDir) + + const configPyPath = path.join(tempDir, 'config.py') + // Write an invalid Python to config.py + await fs.writeFile(configPyPath, 'invalid_python_code = [1, 2, 3') + + await page.goto( + `http://127.0.1:${sharedCodeServer.codeServerPort}/?folder=${tempDir}`, + ) + await page.waitForLoadState('networkidle') + + // Open customers.sql model + await page + .getByRole('treeitem', { name: 'models', exact: true }) + .locator('a') + .click() + await page + .getByRole('treeitem', { name: 'customers.sql', exact: true }) + .locator('a') + .click() + + // Expect the error to appear + await page.waitForSelector('text=Error creating context') + + // Open the problems view + await runCommand(page, 'View: Focus Problems') + + // Assert that the error is present in the problems view + const errorElement = page.getByText('Failed to load config file:').first() + await expect(errorElement).toBeVisible({ timeout: 5000 }) }) })