Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/guides/lint_rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ These issues may cause runtime problems.
| Code | Name | Description | Fixable |
|------|------|-------------|----------|
| [MR001](rules/self_import.md) | self-import | Importing a module with the same name as the file | ❌ |
| [MR002](rules/branch_expression.md) | branch-expression | Branch statements with output expressions that won't be displayed | ❌ |

### ✨ Formatting Rules

Expand All @@ -53,7 +54,7 @@ These are style and formatting issues.
| [MF004](rules/empty_cells.md) | empty-cells | Empty cells that can be safely removed. | ⚠️ |
| [MF005](rules/sql_parse_error.md) | sql-parse-error | SQL parsing errors during dependency analysis | ❌ |
| [MF006](rules/misc_log_capture.md) | misc-log-capture | Miscellaneous log messages during processing | ❌ |
| [MF007](rules/markdown_indentation.md) | markdown-indentation | Markdown cells in `mo.md()` should be dedented. | 🛠️ |
| [MF007](rules/markdown_indentation.md) | markdown-indentation | Markdown cells in `mo.md()` should be properly indented. | 🛠️ |

## Legend

Expand Down
76 changes: 76 additions & 0 deletions docs/guides/lint_rules/rules/branch_expression.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# MR002: branch-expression

⚠️ **Runtime** ❌ Not Fixable

MR002: Branch statements with output expressions that won't be displayed.

## Why is this bad?

When output expressions are nested inside branches at the end of a cell:
- The expressions execute but produce no visible output
- Users expect to see the result (like mo.md(), string literals, etc.)
- This can lead to confusion about whether code is running correctly
- It violates the principle of least surprise

This is a runtime issue because it causes unexpected behavior where the user's
intended output is silently ignored.

## Examples

**Problematic:**
```python
if condition:
mo.md("Result A") # Won't be displayed
else:
mo.md("Result B") # Won't be displayed
```

**Problematic:**
```python
match value:
case 1:
"Too short" # Won't be displayed
case _:
"Just right" # Won't be displayed
```

**Not flagged (side effects only):**
```python
if condition:
print("Debug message") # Side effect only, not flagged
else:
logger.info("Something") # Side effect only, not flagged
```

**Solution:**
```python
# Assign to a variable that marimo will display
result = mo.md("Result A") if condition else mo.md("Result B")
result
```

**Solution:**
```python
# Create a default variable for response.
result = None
if condition:
result = expr()
else:
result = other()
result
```

**Alternative Solution (if no output intended):**
```python
# Use a dummy variable to indicate intentional suppression
if condition:
_ = expr()
else:
_ = other()
```

## References

- [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/)
- [Reactivity](https://docs.marimo.io/guides/reactivity/)

6 changes: 2 additions & 4 deletions examples/ai/chat/streaming_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,14 @@ def _(mo):
@app.cell
def _(chatbot, mo):
# Show chat history
if hasattr(chatbot, "value"):
mo.md(f"**Chat history:** {len(chatbot.value)} messages")
mo.md(f"**Chat history:** {len(chatbot.value)} messages") if hasattr(chatbot, "value") else None
return


@app.cell
def _(chatbot):
# Display full history
if hasattr(chatbot, "value"):
chatbot.value
chatbot.value if hasattr(chatbot, "value") else None
return


Expand Down
14 changes: 7 additions & 7 deletions examples/outputs/conditional_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ def _(checkbox):
@app.cell(hide_code=True)
def _(mo):
mo.md("""
The next cell does **not** show anything, since an if statement does not
have a value:
""")
return

The following cell would **not** show anything, since an if statement does
not have a value:

@app.cell
def _(checkbox, mo):
```python
# Intentionally demonstrates that if statements don't display expressions
# Using _ to suppress the lint warning while keeping the example
if checkbox.value:
mo.md("Checkbox is checked")
else:
mo.md("Checkbox is not checked")
```
""")
return


Expand Down
2 changes: 1 addition & 1 deletion examples/sql/misc/database_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def _(mo, os):
@app.cell
def _(database_url, duckdb):
if database_url.value:
duckdb.sql(
_ = duckdb.sql(
f"""
INSTALL postgres;
LOAD postgres;
Expand Down
2 changes: 1 addition & 1 deletion examples/third_party/cvxpy/signals/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def __init__(self, sticky_bool):
[complib.Components.TREND_LINE, complib.Components.PERIODIC]
)
if solved.now:
solved_ever.set()
_ = solved_ever.set()
return (solved,)


Expand Down
3 changes: 3 additions & 0 deletions marimo/_lint/rules/runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
from __future__ import annotations

from marimo._lint.rules.base import LintRule
from marimo._lint.rules.runtime.branch_expression import BranchExpressionRule
from marimo._lint.rules.runtime.self_import import SelfImportRule

RUNTIME_RULE_CODES: dict[str, type[LintRule]] = {
"MR001": SelfImportRule,
"MR002": BranchExpressionRule,
}

__all__ = [
"BranchExpressionRule",
"SelfImportRule",
"RUNTIME_RULE_CODES",
]
Loading
Loading