From a4b0b3a2d36bd3661784ddee9d619a46259cb359 Mon Sep 17 00:00:00 2001 From: Alex Pentland Date: Sat, 18 Jan 2025 16:04:23 -0500 Subject: [PATCH 1/2] Improve reporting of unparsable code Show the unparseable code in the error message when directly running a notebook via the python command. Fixes #2265 --- .gitignore | 1 + marimo/_ast/app.py | 25 ++++++++++++++++++++++--- tests/_ast/test_app.py | 3 ++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 5bbefcb172d..9a3912a742f 100644 --- a/.gitignore +++ b/.gitignore @@ -111,6 +111,7 @@ marimo/_lsp/ .vscode .vercel +.idea .marimo.toml .mypy_cache/ diff --git a/marimo/_ast/app.py b/marimo/_ast/app.py index dd051b01382..d427caca229 100644 --- a/marimo/_ast/app.py +++ b/marimo/_ast/app.py @@ -1,8 +1,10 @@ # Copyright 2024 Marimo. All rights reserved. from __future__ import annotations +import ast import inspect from dataclasses import asdict, dataclass, field +from textwrap import dedent from typing import ( TYPE_CHECKING, Any, @@ -155,6 +157,7 @@ def __init__(self, **kwargs: Any) -> None: self._execution_context: ExecutionContext | None = None self._runner = dataflow.Runner(self._graph) + self._unparsable_code: list[str] = [] self._unparsable = False self._initialized = False # injection hook set by contexts like tests such that script traces are @@ -222,14 +225,30 @@ def _unparsable_cell( name, CellConfig.from_dict(config), ) + self._unparsable_code.append(code) self._unparsable = True def _maybe_initialize(self) -> None: if self._unparsable: + errors = [] + for code in self._unparsable_code: + try: + ast.parse(dedent(code)) + except SyntaxError as e: + error_line = e.text + error_marker = " " * (e.offset - 1) + "^" + err = ( + f"{error_line}" + f"{error_marker}\n" + f"{e.msg}" + ) + errors.append(err) + syntax_errors = "\n-----\n".join(errors) + raise UnparsableError( - "This notebook has cells with syntax errors, " - "so it cannot be initialized." - ) + f"The notebook '{self._filename}' has cells with syntax errors, " + + f"so it cannot be initialized:\n {syntax_errors}" + ) from None if self._initialized: return diff --git a/tests/_ast/test_app.py b/tests/_ast/test_app.py index 6ec2123d5ab..eeb7de1435e 100644 --- a/tests/_ast/test_app.py +++ b/tests/_ast/test_app.py @@ -159,8 +159,9 @@ def one() -> tuple[int]: app._unparsable_cell("_ _") app._unparsable_cell("_ _", name="foo") - with pytest.raises(UnparsableError): + with pytest.raises(UnparsableError) as e: app.run() + e.match("_ _") @staticmethod def test_init_not_rewritten_as_local() -> None: From f9d2be1597f219d7becfe9227c4a521ae6ba30d6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 21:23:29 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- marimo/_ast/app.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/marimo/_ast/app.py b/marimo/_ast/app.py index d427caca229..7f07a2234be 100644 --- a/marimo/_ast/app.py +++ b/marimo/_ast/app.py @@ -237,17 +237,13 @@ def _maybe_initialize(self) -> None: except SyntaxError as e: error_line = e.text error_marker = " " * (e.offset - 1) + "^" - err = ( - f"{error_line}" - f"{error_marker}\n" - f"{e.msg}" - ) + err = f"{error_line}{error_marker}\n{e.msg}" errors.append(err) syntax_errors = "\n-----\n".join(errors) raise UnparsableError( - f"The notebook '{self._filename}' has cells with syntax errors, " + - f"so it cannot be initialized:\n {syntax_errors}" + f"The notebook '{self._filename}' has cells with syntax errors, " + + f"so it cannot be initialized:\n {syntax_errors}" ) from None if self._initialized: