diff --git a/.github/workflows/test_cli.yaml b/.github/workflows/test_cli.yaml index 22525beebad..b0d155355cc 100644 --- a/.github/workflows/test_cli.yaml +++ b/.github/workflows/test_cli.yaml @@ -166,8 +166,22 @@ jobs: uv add pytest pytest-asyncio uv pip install marimo*whl - - name: Check notebook quality with marimo check + - name: Check example quality with marimo check shell: bash run: | echo "Checking examples directory..." uv run marimo check --ignore-scripts --strict examples/**.py + + - name: Check tutorial quality with marimo check + shell: bash + run: | + echo "Checking tutorials..." + uv run marimo check --ignore-scripts --fix \ + marimo/_tutorials/**.py >> /dev/null \ + || echo "Errors expected" + # Fail if there's a git diff + if [[ -n "$(git status --porcelain marimo/_tutorials)" ]]; then + echo "marimo check found issues in tutorials." + git --no-pager diff marimo/_tutorials + exit 1 + fi diff --git a/development_docs/adding_lint_rules.md b/development_docs/adding_lint_rules.md index 7104f625250..261534456cb 100644 --- a/development_docs/adding_lint_rules.md +++ b/development_docs/adding_lint_rules.md @@ -183,7 +183,7 @@ if __name__ == "__main__": #### b) Add snapshot test -Add to `tests/_lint/test_runtime_errors_snapshot.py`: +Add to `tests/_lint/test_snapshot.py`: ```python def test_your_rule_snapshot(): @@ -280,7 +280,7 @@ uv run hatch run test:test tests/_lint uv run hatch run test:test tests/_lint/test_your_rule.py # Update snapshots if needed -uv run hatch run test:test tests/_lint/test_runtime_errors_snapshot.py --snapshot-update +uv run hatch run test:test tests/_lint/test_snapshots.py --snapshot-update ``` ## Rule Implementation Guidelines @@ -359,7 +359,7 @@ tests/_lint/ ├── snapshots/ # Expected outputs │ └── your_rule_name_errors.txt ├── test_your_rule.py # Unit tests -└── test_runtime_errors_snapshot.py # Snapshot tests +└── test_snapshots.py # Snapshot tests ``` ## Documentation Requirements diff --git a/docs/guides/lint_rules/index.md b/docs/guides/lint_rules/index.md index eee07f992ac..60d7288280c 100644 --- a/docs/guides/lint_rules/index.md +++ b/docs/guides/lint_rules/index.md @@ -53,6 +53,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. | 🛠️ | ## Legend diff --git a/docs/guides/lint_rules/rules/markdown_dedent.md b/docs/guides/lint_rules/rules/markdown_dedent.md new file mode 100644 index 00000000000..e0e3aa0c79a --- /dev/null +++ b/docs/guides/lint_rules/rules/markdown_dedent.md @@ -0,0 +1,50 @@ +# MF007: markdown-indentation + +✨ **Formatting** 🛠️ Fixable + +MF007: Markdown strings in `mo.md()` should be dedented. + +## What it does + +Checks cells containing `mo.md()` calls to see if the markdown string +content has unnecessary leading whitespace that should be removed. + +## Why is this bad? + +Indented markdown strings: + +- Are harder to read when viewing the source code +- Produce larger diffs when making changes +- Don't match the standard marimo formatting style +- Can be confusing when the indentation doesn't reflect the markdown structure + +## Examples + +**Problematic:** + +```python +mo.md( + r""" + # Title + + Some content here. + """ +) +``` + +**Solution:** + +```python +mo.md(r""" +# Title + +Some content here. +""") +``` + +**Note:** This fix is automatically applied with `marimo check --fix`. + +## References + +- [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) +- [Best Practices](https://docs.marimo.io/guides/best_practices/) diff --git a/docs/guides/lint_rules/rules/markdown_indentation.md b/docs/guides/lint_rules/rules/markdown_indentation.md new file mode 100644 index 00000000000..90c51465098 --- /dev/null +++ b/docs/guides/lint_rules/rules/markdown_indentation.md @@ -0,0 +1,48 @@ +# MF007: markdown-indentation + +✨ **Formatting** 🛠️ Fixable + +MF007: Markdown strings in `mo.md()` should be properly indented. + +## What it does + +Checks cells containing `mo.md()` calls to see if the markdown string +content has unnecessary leading whitespace that should be removed. + +## Why is this bad? + +Indented markdown strings: +- Are harder to read when viewing the source code +- Produce larger diffs when making changes +- Don't match the standard marimo formatting style +- Can be confusing when the indentation doesn't reflect the markdown structure + +## Examples + +**Problematic:** +```python +mo.md( + r""" + # Title + + Some content here. + """ +) +``` + +**Solution:** +```python +mo.md(r""" +# Title + +Some content here. +""") +``` + +**Note:** This fix is automatically applied with `marimo check --fix`. + +## References + +- [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) +- [Best Practices](https://docs.marimo.io/guides/best_practices/) + diff --git a/examples/ai/chat/anthropic_example.py b/examples/ai/chat/anthropic_example.py index a354883adcf..b911cbb0ba2 100644 --- a/examples/ai/chat/anthropic_example.py +++ b/examples/ai/chat/anthropic_example.py @@ -8,7 +8,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -20,13 +20,11 @@ def _(): @app.cell def _(mo): - mo.md( - r""" + mo.md(r""" # Using Anthropic This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by Anthropic. - """ - ) + """) return @@ -76,7 +74,9 @@ def _(key, mo): @app.cell def _(mo): - mo.md("""Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""") + mo.md( + """Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""" + ) return diff --git a/examples/ai/chat/bedrock_example.py b/examples/ai/chat/bedrock_example.py index e18f33e9365..231d462acb5 100644 --- a/examples/ai/chat/bedrock_example.py +++ b/examples/ai/chat/bedrock_example.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -21,8 +21,7 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" # AWS Bedrock Chat Example This example demonstrates using AWS Bedrock with marimo's chat interface. @@ -30,8 +29,7 @@ def _(mo): AWS Bedrock provides access to foundation models from leading AI companies like Anthropic, Meta, and others. ⚠️ **Note:** You'll need an AWS account with access to the AWS Bedrock service and the specific model you want to use. - """ - ) + """) return @@ -227,8 +225,7 @@ def create_chat(config_form): @app.cell def _(mo): - mo.md( - r""" + mo.md(r""" ## Notes on AWS Bedrock Usage 1. **Model Access**: You need to request access to the specific models you want to use in the AWS Bedrock console. @@ -243,8 +240,7 @@ def _(mo): - That your AWS credentials are configured correctly - That you have requested model access in the AWS Bedrock console - That you're using a region where the selected model is available - """ - ) + """) return diff --git a/examples/ai/chat/custom.py b/examples/ai/chat/custom.py index c87ba5ed464..172f55cbce9 100644 --- a/examples/ai/chat/custom.py +++ b/examples/ai/chat/custom.py @@ -7,7 +7,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -19,15 +19,13 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Custom chatbot - - This example shows how to make a custom chatbot: just supply a function that takes two arguments, - `messages` and `config`, and returns the chatbot's response. This response can be any object; it - doesn't have to be a string! - """ - ) + mo.md(""" + # Custom chatbot + + This example shows how to make a custom chatbot: just supply a function that takes two arguments, + `messages` and `config`, and returns the chatbot's response. This response can be any object; it + doesn't have to be a string! + """) return diff --git a/examples/ai/chat/dagger_code_interpreter.py b/examples/ai/chat/dagger_code_interpreter.py index 2b86ce9d75e..0965166a885 100644 --- a/examples/ai/chat/dagger_code_interpreter.py +++ b/examples/ai/chat/dagger_code_interpreter.py @@ -11,7 +11,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -25,15 +25,13 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Chatbot code-interpreter with [Dagger](https://dagger.io/) + mo.md(""" + # Chatbot code-interpreter with [Dagger](https://dagger.io/) - This example shows how to create a code-interpreter that executes code using [Dagger](https://dagger.io/) so the code is run in an isolated container. + This example shows how to create a code-interpreter that executes code using [Dagger](https://dagger.io/) so the code is run in an isolated container. - This example requires Docker running on your computer. - """ - ) + This example requires Docker running on your computer. + """) return diff --git a/examples/ai/chat/deepseek_example.py b/examples/ai/chat/deepseek_example.py index 955e18462e7..5a1700e691c 100644 --- a/examples/ai/chat/deepseek_example.py +++ b/examples/ai/chat/deepseek_example.py @@ -8,7 +8,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -20,13 +20,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Using DeepSeek + mo.md(r""" + # Using DeepSeek - This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat/?h=mo.ui.chat) to make a chatbot backed by [Deepseek](https://deepseek.com/). - """ - ) + This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat/?h=mo.ui.chat) to make a chatbot backed by [Deepseek](https://deepseek.com/). + """) return @@ -88,7 +86,9 @@ def _(key, mo): @app.cell(hide_code=True) def _(mo): - mo.md("""Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""") + mo.md( + """Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""" + ) return diff --git a/examples/ai/chat/gemini.py b/examples/ai/chat/gemini.py index 9cce85561c9..0a244f9ba66 100644 --- a/examples/ai/chat/gemini.py +++ b/examples/ai/chat/gemini.py @@ -7,7 +7,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -19,13 +19,11 @@ def _(): @app.cell def _(mo): - mo.md( - r""" - # Using Gemini + mo.md(r""" + # Using Gemini - This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by Gemini. - """ - ) + This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by Gemini. + """) return @@ -70,7 +68,9 @@ def _(key, mo): @app.cell(hide_code=True) def _(mo): - mo.md("""Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""") + mo.md( + """Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""" + ) return diff --git a/examples/ai/chat/groq_example.py b/examples/ai/chat/groq_example.py index a111d943a0f..60ac7be0889 100644 --- a/examples/ai/chat/groq_example.py +++ b/examples/ai/chat/groq_example.py @@ -8,7 +8,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -20,13 +20,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Using Groq + mo.md(r""" + # Using Groq - This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by [Groq](https://groq.com/). - """ - ) + This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by [Groq](https://groq.com/). + """) return @@ -88,7 +86,9 @@ def _(key, mo): @app.cell(hide_code=True) def _(mo): - mo.md("""Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""") + mo.md( + """Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""" + ) return diff --git a/examples/ai/chat/mlx_chat.py b/examples/ai/chat/mlx_chat.py index a89b212b956..a71b2801f22 100644 --- a/examples/ai/chat/mlx_chat.py +++ b/examples/ai/chat/mlx_chat.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -24,23 +24,21 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Using MLX with Marimo + mo.md(r""" + # Using MLX with Marimo - ## Chat Example - This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by Apple's MLX, using the `mlx_lm` library and marimo. - [`mlx_lm`](https://github.com/ml-explore/mlx-examples/tree/main/llm) is a library for running large language models on Apple Silicon. - [`mlx`](https://github.com/ml-explore/mlx) is a framework for running machine learning models on Apple Silicon. + ## Chat Example + This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by Apple's MLX, using the `mlx_lm` library and marimo. + [`mlx_lm`](https://github.com/ml-explore/mlx-examples/tree/main/llm) is a library for running large language models on Apple Silicon. + [`mlx`](https://github.com/ml-explore/mlx) is a framework for running machine learning models on Apple Silicon. - Convert your own models to MLX, or find community-converted ones at various quantizations [here](https://huggingface.co/mlx-community). + Convert your own models to MLX, or find community-converted ones at various quantizations [here](https://huggingface.co/mlx-community). - ### Things you can do to improve this example: - - [`prompt caching`](https://github.com/ml-explore/mlx-examples/blob/main/llms/README.md#long-prompts-and-generations) - - completions / notebook mode - - assistant pre-fill - """ - ) + ### Things you can do to improve this example: + - [`prompt caching`](https://github.com/ml-explore/mlx-examples/blob/main/llms/README.md#long-prompts-and-generations) + - completions / notebook mode + - assistant pre-fill + """) return diff --git a/examples/ai/chat/openai_example.py b/examples/ai/chat/openai_example.py index 90cd5540d9b..c6ff383bd24 100644 --- a/examples/ai/chat/openai_example.py +++ b/examples/ai/chat/openai_example.py @@ -8,7 +8,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -20,13 +20,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Using OpenAI + mo.md(r""" + # Using OpenAI - This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by OpenAI. - """ - ) + This example shows how to use [`mo.ui.chat`](https://docs.marimo.io/api/inputs/chat.html#marimo.ui.chat) to make a chatbot backed by OpenAI. + """) return @@ -75,7 +73,9 @@ def _(mo, openai_key): @app.cell def _(mo): - mo.md("""Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""") + mo.md( + """Access the chatbot's historical messages with [`chatbot.value`](https://docs.marimo.io/api/inputs/chat.html#accessing-chat-history).""" + ) return diff --git a/examples/ai/chat/simplemind_example.py b/examples/ai/chat/simplemind_example.py index 0333246b5a0..c4c6413d776 100644 --- a/examples/ai/chat/simplemind_example.py +++ b/examples/ai/chat/simplemind_example.py @@ -8,13 +8,15 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @app.cell(hide_code=True) def _(mo): - mo.md(r"""## Using [simplemind](https://github.com/kennethreitz/simplemind) with `mo.ui.chat()`""") + mo.md( + r"""## Using [simplemind](https://github.com/kennethreitz/simplemind) with `mo.ui.chat()`""" + ) return diff --git a/examples/ai/data/model_comparison.py b/examples/ai/data/model_comparison.py index 5d6cd8ecf0d..441da3e14f8 100644 --- a/examples/ai/data/model_comparison.py +++ b/examples/ai/data/model_comparison.py @@ -7,7 +7,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -19,12 +19,10 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - !!! tip "This notebook is best viewed as an app." - Hit `Cmd/Ctrl+.` or click the "app view" button in the bottom right. - """ - ) + mo.md(r""" + !!! tip "This notebook is best viewed as an app." + Hit `Cmd/Ctrl+.` or click the "app view" button in the bottom right. + """) return diff --git a/examples/ai/misc/micrograd_mlp.py b/examples/ai/misc/micrograd_mlp.py index 99683998e95..af9aeffa0f9 100644 --- a/examples/ai/misc/micrograd_mlp.py +++ b/examples/ai/misc/micrograd_mlp.py @@ -11,7 +11,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -23,18 +23,16 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - This marimo notebook trains a tiny **neural network** using - Andrej Karpathy's [micrograd - library](https://github.com/karpathy/micrograd). - Micrograd is an implementation of PyTorch-like automatic - differentiation using only Python scalar operations. This notebook was - adapted from a [demo - notebook](https://github.com/karpathy/micrograd/blob/master/demo.ipynb) by - Andrej. - """ - ) + mo.md(""" + This marimo notebook trains a tiny **neural network** using + Andrej Karpathy's [micrograd + library](https://github.com/karpathy/micrograd). + Micrograd is an implementation of PyTorch-like automatic + differentiation using only Python scalar operations. This notebook was + adapted from a [demo + notebook](https://github.com/karpathy/micrograd/blob/master/demo.ipynb) by + Andrej. + """) return @@ -58,13 +56,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - We start by generating a synthetic dataset of points labeled +1 or -1. - Our goal is to train a network that can classify these points according - to their labels, learning a decision boundary that separates them. - """ - ) + mo.md(""" + We start by generating a synthetic dataset of points labeled +1 or -1. + Our goal is to train a network that can classify these points according + to their labels, learning a decision boundary that separates them. + """) return @@ -86,28 +82,24 @@ def _(X, mo, plt, y): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Note that the decision boundary must be **nonlinear**, which can be readily - learned by neural networks. This could also be achieved by "shallow" or - classical machine learning methods with the appropriate featurization or - [kernelization](https://scikit-learn.org/stable/modules/svm.html). - """ - ) + mo.md(""" + Note that the decision boundary must be **nonlinear**, which can be readily + learned by neural networks. This could also be achieved by "shallow" or + classical machine learning methods with the appropriate featurization or + [kernelization](https://scikit-learn.org/stable/modules/svm.html). + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - **Try it!** Train a neural network by hitting the "Train" button. The - learned decision boundary will be plotted below. + mo.md(""" + **Try it!** Train a neural network by hitting the "Train" button. The + learned decision boundary will be plotted below. - _Try experimenting with the parameters. What happens if you change - the number of layers and their sizes?_ - """ - ) + _Try experimenting with the parameters. What happens if you change + the number of layers and their sizes?_ + """) return diff --git a/examples/ai/tools/chat_with_tools.py b/examples/ai/tools/chat_with_tools.py index 6d38db20042..c05fad44aee 100644 --- a/examples/ai/tools/chat_with_tools.py +++ b/examples/ai/tools/chat_with_tools.py @@ -16,7 +16,7 @@ import marimo -__generated_with = "0.16.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -35,13 +35,11 @@ def _(): @app.cell def _(mo): - mo.md( - """ - # Creating rich tools with ell + mo.md(""" + # Creating rich tools with ell - This example shows how to use [`ell`](https://docs.ell.so/) with tools to analyze a dataset and return rich responses like charts and tables. - """ - ) + This example shows how to use [`ell`](https://docs.ell.so/) with tools to analyze a dataset and return rich responses like charts and tables. + """) return diff --git a/examples/ai/tools/code_interpreter.py b/examples/ai/tools/code_interpreter.py index 30e94c07e7a..d7bdc11839e 100644 --- a/examples/ai/tools/code_interpreter.py +++ b/examples/ai/tools/code_interpreter.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -23,13 +23,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Creating a code interpreter + mo.md(""" + # Creating a code interpreter - This example shows how to create a code-interpreter in a few lines of code. - """ - ) + This example shows how to create a code-interpreter in a few lines of code. + """) return diff --git a/examples/ai/tools/dataset_analysis.py b/examples/ai/tools/dataset_analysis.py index de6b546e616..52ad29da35f 100644 --- a/examples/ai/tools/dataset_analysis.py +++ b/examples/ai/tools/dataset_analysis.py @@ -16,7 +16,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -35,13 +35,11 @@ def _(): @app.cell def _(mo): - mo.md( - """ - # Using tools with ell + mo.md(""" + # Using tools with ell - This example shows how to use [`ell`](https://docs.ell.so/) with tools to analyze a dataset and return rich responses like charts and tables. - """ - ) + This example shows how to use [`ell`](https://docs.ell.so/) with tools to analyze a dataset and return rich responses like charts and tables. + """) return diff --git a/examples/layouts/columns.py b/examples/layouts/columns.py index 6fe7e3ae87f..63b7d3f101a 100644 --- a/examples/layouts/columns.py +++ b/examples/layouts/columns.py @@ -12,7 +12,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="columns") @@ -96,16 +96,14 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Here's a PCA **embedding of numerical digits**: each point represents a - digit, with similar digits close to each other. The data is from the UCI - ML handwritten digits dataset. - - This notebook will automatically drill down into points you **select with - your mouse**; try it! - """ - ) + mo.md(""" + Here's a PCA **embedding of numerical digits**: each point represents a + digit, with similar digits close to each other. The data is from the UCI + ML handwritten digits dataset. + + This notebook will automatically drill down into points you **select with + your mouse**; try it! + """) return diff --git a/examples/layouts/grid-dashboard.py b/examples/layouts/grid-dashboard.py index 972ad082f65..52c1f6c92f7 100644 --- a/examples/layouts/grid-dashboard.py +++ b/examples/layouts/grid-dashboard.py @@ -15,7 +15,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App( width="medium", layout_file="layouts/grid-dashboard.grid.json", @@ -47,13 +47,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" If you would like to see _how_ this application is made, continue down. This application is adapted from - """ - ) + """) return @@ -386,13 +384,11 @@ def _(hvplot_view, show_legend, year): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## Add any extra flair Next we will toggle to "App view" (hit `Cmd/Ctrl+.` or click the "app view") in order to layout our dashboard with the grid layout editor. - """ - ) + """) return @@ -404,15 +400,13 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## 🎓 Info Here you can try out four different plotting libraries controlled by a couple of widgets, for Hans Rosling's [gapminder](https://demo.bokeh.org/gapminder) example. This application is inspired by [Panel](https://examples.holoviz.org/gallery/gapminders/gapminders.html). - """ - ) + """) return diff --git a/examples/layouts/sidebar.py b/examples/layouts/sidebar.py index c21aa31619c..a2aaa676ad5 100644 --- a/examples/layouts/sidebar.py +++ b/examples/layouts/sidebar.py @@ -9,18 +9,16 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - !!! tip "This notebook is best viewed as an app." - Hit `Cmd/Ctrl+.` or click the "app view" button in the bottom right. - """ - ) + mo.md(r""" + !!! tip "This notebook is best viewed as an app." + Hit `Cmd/Ctrl+.` or click the "app view" button in the bottom right. + """) return diff --git a/examples/layouts/slides.py b/examples/layouts/slides.py index e282d15021d..c66bc0ed650 100644 --- a/examples/layouts/slides.py +++ b/examples/layouts/slides.py @@ -10,47 +10,41 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium", layout_file="layouts/slides.slides.json") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - !!! tip "This notebook is best viewed as an app." - Hit `Cmd/Ctrl+.` or click the "app view" button in the bottom right. - """ - ) + mo.md(r""" + !!! tip "This notebook is best viewed as an app." + Hit `Cmd/Ctrl+.` or click the "app view" button in the bottom right. + """) return @app.cell def _(mo): - mo.md( - """ - # DuckDB Tricks 🦆 + mo.md(""" + # DuckDB Tricks 🦆 - We use a simple example data set to present a few tricks that are useful when using DuckDB. + We use a simple example data set to present a few tricks that are useful when using DuckDB. - > - > Turned into slides from - """ - ) + > + > Turned into slides from + """) return @app.cell def _(mo): - mo.md( - r""" - ## Installation + mo.md(r""" + ## Installation - ```bash - uv add duckdb - ``` - """ - ) + ```bash + uv add duckdb + ``` + """) return @@ -204,13 +198,11 @@ def _(mo, print_and_run, rerun): @app.cell def _(mo): - mo.md( - """ - # Closing thoughts + mo.md(""" + # Closing thoughts - That’s it for today. The tricks shown in this post are available on [duckdbsnippets.com](https://duckdbsnippets.com). - """ - ) + That’s it for today. The tricks shown in this post are available on [duckdbsnippets.com](https://duckdbsnippets.com). + """) return diff --git a/examples/markdown/admonitions.py b/examples/markdown/admonitions.py index 604156c6eb3..0eaee146fdc 100644 --- a/examples/markdown/admonitions.py +++ b/examples/markdown/admonitions.py @@ -1,38 +1,36 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md(r"""Use **admonitions** in markdown to bring attention to text. Here are some examples.""") + mo.md( + r"""Use **admonitions** in markdown to bring attention to text. Here are some examples.""" + ) return @app.cell def _(mo): - mo.md( - """ - /// admonition | Heads up. + mo.md(""" + /// admonition | Heads up. - Here's some information. - /// - """ - ) + Here's some information. + /// + """) return @app.cell def _(mo): - mo.md( - """ - /// attention | Attention! + mo.md(""" + /// attention | Attention! - This is important. - /// - """ - ) + This is important. + /// + """) return diff --git a/examples/markdown/details.py b/examples/markdown/details.py index 060b941c987..0ae04e0a645 100644 --- a/examples/markdown/details.py +++ b/examples/markdown/details.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -12,15 +12,13 @@ def _(mo): @app.cell def _(mo): - mo.md( - """ - /// details | Hello, details! + mo.md(""" + /// details | Hello, details! - Some additional content. + Some additional content. - /// - """ - ) + /// + """) return @@ -32,57 +30,49 @@ def _(mo): @app.cell def _(mo): - mo.md( - """ - /// details | Info details - type: info - - Some additional content. - /// - """ - ) + mo.md(""" + /// details | Info details + type: info + + Some additional content. + /// + """) return @app.cell def _(mo): - mo.md( - """ - /// details | Warning details - type: warn - - This highlights something to watch out for - /// - """ - ) + mo.md(""" + /// details | Warning details + type: warn + + This highlights something to watch out for + /// + """) return @app.cell def _(mo): - mo.md( - """ - /// details | Danger details - type: danger - - This indicates a critical warning or dangerous situation - /// - """ - ) + mo.md(""" + /// details | Danger details + type: danger + + This indicates a critical warning or dangerous situation + /// + """) return @app.cell def _(mo): - mo.md( - """ - /// details | Success details - type: success - - This indicates a successful outcome or positive note - /// - """ - ) + mo.md(""" + /// details | Success details + type: success + + This indicates a successful outcome or positive note + /// + """) return diff --git a/examples/markdown/dynamic_markdown.py b/examples/markdown/dynamic_markdown.py index 69ffdbcbd4b..8c27130825a 100644 --- a/examples/markdown/dynamic_markdown.py +++ b/examples/markdown/dynamic_markdown.py @@ -1,12 +1,14 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md(r"""Use `mo.md` with an `f-string` to create markdown that depends on the value of Python objects.""") + mo.md( + r"""Use `mo.md` with an `f-string` to create markdown that depends on the value of Python objects.""" + ) return @@ -52,7 +54,9 @@ def _(mo, text_input): @app.cell(hide_code=True) def _(mo): - mo.md(r"""Wrap plots and data structures in `mo.as_html()` to hook into marimo's rich media viewer:""") + mo.md( + r"""Wrap plots and data structures in `mo.as_html()` to hook into marimo's rich media viewer:""" + ) return diff --git a/examples/misc/colliding_blocks_and_pi.py b/examples/misc/colliding_blocks_and_pi.py index ed02514e5b3..3d6cb4f5bc6 100644 --- a/examples/misc/colliding_blocks_and_pi.py +++ b/examples/misc/colliding_blocks_and_pi.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.16.0" +__generated_with = "0.17.2" app = marimo.App() @@ -21,15 +21,13 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Finding $\pi$ in colliding blocks + mo.md(r""" + # Finding $\pi$ in colliding blocks - One of the remarkable things about mathematical constants like $\pi$ is how frequently they arise in nature, in the most surprising of places. + One of the remarkable things about mathematical constants like $\pi$ is how frequently they arise in nature, in the most surprising of places. - Inspired by 3Blue1Brown, this [marimo notebook](https://github.com/marimo-team/marimo) shows how the number of collisions incurred in a particular system involving two blocks converges to the digits in $\pi$. - """ - ) + Inspired by 3Blue1Brown, this [marimo notebook](https://github.com/marimo-team/marimo) shows how the number of collisions incurred in a particular system involving two blocks converges to the digits in $\pi$. + """) return @@ -86,13 +84,11 @@ def _(ani, mo, run_button): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## The 3Blue1Brown video + mo.md(r""" + ## The 3Blue1Brown video - If you haven't seen it, definitely check out the video that inspired this notebook: - """ - ) + If you haven't seen it, definitely check out the video that inspired this notebook: + """) return diff --git a/examples/misc/create_your_own_shape.py b/examples/misc/create_your_own_shape.py index f93b3582317..87eded14b84 100644 --- a/examples/misc/create_your_own_shape.py +++ b/examples/misc/create_your_own_shape.py @@ -7,19 +7,17 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Inputs + mo.md(r""" + # Inputs - There are many way that a user can input with your notebook, such as text boxes, sliders, dates, and more. - """ - ) + There are many way that a user can input with your notebook, such as text boxes, sliders, dates, and more. + """) return diff --git a/examples/misc/custom_configuration.py b/examples/misc/custom_configuration.py index dc95ba206fa..cf66ae4216a 100644 --- a/examples/misc/custom_configuration.py +++ b/examples/misc/custom_configuration.py @@ -13,7 +13,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -25,17 +25,15 @@ def _(): @app.cell def _(mo): - mo.md( - r""" - This is not auto-run because it has custom marimo configuration in the file header: - - ```toml - [tool.marimo.runtime] - auto_instantiate = false - on_cell_change = "lazy" - ``` - """ - ) + mo.md(r""" + This is not auto-run because it has custom marimo configuration in the file header: + + ```toml + [tool.marimo.runtime] + auto_instantiate = false + on_cell_change = "lazy" + ``` + """) return diff --git a/examples/misc/monotonic_splines.py b/examples/misc/monotonic_splines.py index fc9d2abfd60..4fe0ff0cf76 100644 --- a/examples/misc/monotonic_splines.py +++ b/examples/misc/monotonic_splines.py @@ -13,7 +13,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -35,17 +35,15 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Introduction to monotonic splines + mo.md(r""" + ## Introduction to monotonic splines - > It turns out that you can generate features that can help turn (linear) machine learning models into models that respent monotonicity. While this technique isn't going to be useful for every application out there, it is a nice exercise in feature engineering because it does show off some lesser known and unconventional techniques. - > - > This document reflects the code discussed in [this probabl livestream](https://www.youtube.com/watch?v=BLsWIJSKcGg) which in turn was heavily insired by [this blogpost](https://matekadlicsko.github.io/posts/monotonic-splines/). + > It turns out that you can generate features that can help turn (linear) machine learning models into models that respent monotonicity. While this technique isn't going to be useful for every application out there, it is a nice exercise in feature engineering because it does show off some lesser known and unconventional techniques. + > + > This document reflects the code discussed in [this probabl livestream](https://www.youtube.com/watch?v=BLsWIJSKcGg) which in turn was heavily insired by [this blogpost](https://matekadlicsko.github.io/posts/monotonic-splines/). - We are going to dive into feature engineering in this document, but before going there it would help to have a dataset first. So let's draw one! **Draw some points below**, but make sure that you only draw a single class of points here. We're going for a regression dataset here where the x-values need to predict the y-values. - """ - ) + We are going to dive into feature engineering in this document, but before going there it would help to have a dataset first. So let's draw one! **Draw some points below**, but make sure that you only draw a single class of points here. We're going for a regression dataset here where the x-values need to predict the y-values. + """) return @@ -72,15 +70,13 @@ def _(mo, widget): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## General splines + mo.md(""" + ## General splines - You have probably drawn something that is very much non-linear. So you might expect a linear model to perform quite badly here. However, thanks to non-linear feature-engineering, we might still be able to get a nice fit. After all, getting the right features is 90% of the work towards a good model. + You have probably drawn something that is very much non-linear. So you might expect a linear model to perform quite badly here. However, thanks to non-linear feature-engineering, we might still be able to get a nice fit. After all, getting the right features is 90% of the work towards a good model. - So let's build a pipeline that uses the [SplineTransformer](https://scikit-learn.org/1.5/modules/generated/sklearn.preprocessing.SplineTransformer.html) from scikit-learn. This featurizer can generate "hills" on our behalf that span the input space of the x-axis. - """ - ) + So let's build a pipeline that uses the [SplineTransformer](https://scikit-learn.org/1.5/modules/generated/sklearn.preprocessing.SplineTransformer.html) from scikit-learn. This featurizer can generate "hills" on our behalf that span the input space of the x-axis. + """) return @@ -97,15 +93,13 @@ def _(X, np, plt, tfm): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - You can see the x-values that our drawing widget can provide and you can also see all the generated features. Each feature is represented with a different colored line and you should also see how each hill goes up and typically goes back down again. At the edges of the samples that we have we see straight lines in an attempt to also have some features for extrapolation. + mo.md(""" + You can see the x-values that our drawing widget can provide and you can also see all the generated features. Each feature is represented with a different colored line and you should also see how each hill goes up and typically goes back down again. At the edges of the samples that we have we see straight lines in an attempt to also have some features for extrapolation. - There are some inputs for this `SplineTransformer` though. We can ask the transformer to add more hills, each hill also has a polynomial degree attached to it that we may alter and we can also tell the component to have the placement of each hill be determined by the quantiles in the dataset. + There are some inputs for this `SplineTransformer` though. We can ask the transformer to add more hills, each hill also has a polynomial degree attached to it that we may alter and we can also tell the component to have the placement of each hill be determined by the quantiles in the dataset. - Feel free to change the drawing and the parameters at this point to try and get a feeling for this. - """ - ) + Feel free to change the drawing and the parameters at this point to try and get a feeling for this. + """) return @@ -133,7 +127,9 @@ def _(degree, knots, n_knots): @app.cell(hide_code=True) def _(mo): - mo.md(r"""When you then take these generated features and pass them to a linear model, you should be able to see that we're indeed able to fit a very non-linear curve with a linear model.""") + mo.md( + r"""When you then take these generated features and pass them to a linear model, you should be able to see that we're indeed able to fit a very non-linear curve with a linear model.""" + ) return @@ -161,15 +157,13 @@ def _(X_tfm, df, y): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Towards monotonic features + mo.md(r""" + ## Towards monotonic features - But let's now do a trick. We will take the features that we generated and then we will cumsum over each single feature. + But let's now do a trick. We will take the features that we generated and then we will cumsum over each single feature. - That means that these features ... - """ - ) + That means that these features ... + """) return @@ -187,19 +181,19 @@ def _(plt, x_range, x_range_tfm): @app.cell(hide_code=True) def _(mo): - mo.md(r"""Note the correspondence between the lines here. The color in the chart above has a direct correspondence with the line below.""") + mo.md( + r"""Note the correspondence between the lines here. The color in the chart above has a direct correspondence with the line below.""" + ) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - You could wonder ... what would happen if I use these 'cumsum' features? Would I still be able to get a nice fit? + mo.md(r""" + You could wonder ... what would happen if I use these 'cumsum' features? Would I still be able to get a nice fit? - The chart below shows you the new predictions. - """ - ) + The chart below shows you the new predictions. + """) return @@ -249,17 +243,15 @@ def _(Ridge, X, X_tfm, alt, pd, pltr, show_iso, strictly_positive, y): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - You can choose to compare the results with a prediction made by an [IsotonicRegression](https://scikit-learn.org/1.5/modules/isotonic.html) model. It may help to appreciate the feature generation technique, especially when you force the linear model to only learn strictly positive weights. + mo.md(r""" + You can choose to compare the results with a prediction made by an [IsotonicRegression](https://scikit-learn.org/1.5/modules/isotonic.html) model. It may help to appreciate the feature generation technique, especially when you force the linear model to only learn strictly positive weights. - There are a few things to notice here: + There are a few things to notice here: - 1. Take the chart with a grain of salt. It does demonstrate the idea, but it does not represent a proper benchmark and we are showing everything being fit on a train set here. - 2. Notice how the feature approach has a slightly more smooth prediction over here compared to the isotonic regressor. - 3. Note that this technique is very general. It can be used on whatever estimator that enables you to learn strictly positive weights. - """ - ) + 1. Take the chart with a grain of salt. It does demonstrate the idea, but it does not represent a proper benchmark and we are showing everything being fit on a train set here. + 2. Notice how the feature approach has a slightly more smooth prediction over here compared to the isotonic regressor. + 3. Note that this technique is very general. It can be used on whatever estimator that enables you to learn strictly positive weights. + """) return diff --git a/examples/misc/mortgage_calculator.py b/examples/misc/mortgage_calculator.py index 778eb36d32a..6001486a45f 100644 --- a/examples/misc/mortgage_calculator.py +++ b/examples/misc/mortgage_calculator.py @@ -10,7 +10,7 @@ import marimo -__generated_with = "0.16.0" +__generated_with = "0.17.2" app = marimo.App() @@ -223,13 +223,11 @@ def _(mo): @app.cell def _(mo): - mo.md( - """ - In addition to paying for your home, you'll have monthly expenses on - necessities and entertainment. Let's estimate these to see how much - you'll save per month, after all expenses. - """ - ) + mo.md(""" + In addition to paying for your home, you'll have monthly expenses on + necessities and entertainment. Let's estimate these to see how much + you'll save per month, after all expenses. + """) return diff --git a/examples/misc/movies_by_the_decade.py b/examples/misc/movies_by_the_decade.py index 9a6c59773aa..448f853f2b3 100644 --- a/examples/misc/movies_by_the_decade.py +++ b/examples/misc/movies_by_the_decade.py @@ -10,19 +10,17 @@ import marimo -__generated_with = "0.16.0" +__generated_with = "0.17.2" app = marimo.App(width="full") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - !!! tip "This notebook is best viewed as an app." - If you're editing this notebook and see code cells, hit `Cmd/Ctrl+.` or - click the "app view" button in the bottom right. - """ - ) + mo.md(r""" + !!! tip "This notebook is best viewed as an app." + If you're editing this notebook and see code cells, hit `Cmd/Ctrl+.` or + click the "app view" button in the bottom right. + """) return diff --git a/examples/misc/public_folder.py b/examples/misc/public_folder.py index e9e2a025119..0270a176d48 100644 --- a/examples/misc/public_folder.py +++ b/examples/misc/public_folder.py @@ -1,20 +1,18 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell def _(mo): - mo.md( - r""" - Load images under the public folder. This will search for files in the /public folder next to the notebook. - - - - - """ - ) + mo.md(r""" + Load images under the public folder. This will search for files in the /public folder next to the notebook. + + + + + """) return diff --git a/examples/misc/seam_carving.py b/examples/misc/seam_carving.py index 7522c0034fc..9b096a26c5a 100644 --- a/examples/misc/seam_carving.py +++ b/examples/misc/seam_carving.py @@ -11,36 +11,34 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Seam Carving + mo.md(""" + # Seam Carving - _Example adapted from work by [Vincent Warmerdam](https://x.com/fishnets88)_. + _Example adapted from work by [Vincent Warmerdam](https://x.com/fishnets88)_. - ## The seam carving algorithm - This marimo demonstration is partially an homage to [a great video by Grant - Sanderson](https://www.youtube.com/watch?v=rpB6zQNsbQU) of 3Blue1Brown, which demonstrates - the seam carving algorithm in [Pluto.jl](https://plutojl.org/): + ## The seam carving algorithm + This marimo demonstration is partially an homage to [a great video by Grant + Sanderson](https://www.youtube.com/watch?v=rpB6zQNsbQU) of 3Blue1Brown, which demonstrates + the seam carving algorithm in [Pluto.jl](https://plutojl.org/): - + - As Grant explains, the seam carving algorithm preserves the shapes of the main content in the image, while killing the "dead space": the image is resized, but the clocks and other content are not resized or deformed. + As Grant explains, the seam carving algorithm preserves the shapes of the main content in the image, while killing the "dead space": the image is resized, but the clocks and other content are not resized or deformed. - This notebook is a Python version of the seam carving algorithm, but it is also a - demonstration of marimo's [persistent caching - feature](https://docs.marimo.io/recipes.html#persistent-caching-for-very-expensive-computations), - which is helpful because the algorithm is compute intensive even when you - use [Numba](https://numba.pydata.org/). + This notebook is a Python version of the seam carving algorithm, but it is also a + demonstration of marimo's [persistent caching + feature](https://docs.marimo.io/recipes.html#persistent-caching-for-very-expensive-computations), + which is helpful because the algorithm is compute intensive even when you + use [Numba](https://numba.pydata.org/). - Try it out by playing with the slider! - """ - ) + Try it out by playing with the slider! + """) return diff --git a/examples/outputs/basic_markdown.py b/examples/outputs/basic_markdown.py index 6e0f0cb5cd5..445c341cad5 100644 --- a/examples/outputs/basic_markdown.py +++ b/examples/outputs/basic_markdown.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -12,16 +12,14 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Create a "Markdown" cell by clicking the `Markdown` button below, - or through the cell action menu. - - Markdown is represented as Python under-the-hood, using the `mo.md()` - function — so you'll need to import marimo as mo into your notebook - first! - """ - ) + mo.md(""" + Create a "Markdown" cell by clicking the `Markdown` button below, + or through the cell action menu. + + Markdown is represented as Python under-the-hood, using the `mo.md()` + function — so you'll need to import marimo as mo into your notebook + first! + """) return diff --git a/examples/outputs/cell_output.py b/examples/outputs/cell_output.py index 2f63357bec5..5dab20234a9 100644 --- a/examples/outputs/cell_output.py +++ b/examples/outputs/cell_output.py @@ -1,23 +1,21 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell def _(mo): - mo.md( - """ - The last expression of a cell is its visual output. This output - appears above the cell when editing a notebook, with notebook code - serving as a "caption" for the output. Outputs can be configured - to appear below cells in the user settings. - - If running - a notebook as an app, the output is the visual representation - of the cell (code is hidden by default). - """ - ) + mo.md(""" + The last expression of a cell is its visual output. This output + appears above the cell when editing a notebook, with notebook code + serving as a "caption" for the output. Outputs can be configured + to appear below cells in the user settings. + + If running + a notebook as an app, the output is the visual representation + of the cell (code is hidden by default). + """) return diff --git a/examples/outputs/conditional_output.py b/examples/outputs/conditional_output.py index 6f394511e46..4d9eb50afed 100644 --- a/examples/outputs/conditional_output.py +++ b/examples/outputs/conditional_output.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -31,12 +31,10 @@ 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: - """ - ) + mo.md(""" + The next cell does **not** show anything, since an if statement does not + have a value: + """) return diff --git a/examples/outputs/dataframes.py b/examples/outputs/dataframes.py index d428661f835..077d0f5732b 100644 --- a/examples/outputs/dataframes.py +++ b/examples/outputs/dataframes.py @@ -8,7 +8,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -32,17 +32,15 @@ def _(data): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - marimo has a rich dataframe viewer built-in: - - - built-in global search - - per-column sorting and filtering - - per-column histograms - - download filtered views - - paginate through the whole dataframe - """ - ) + mo.md(""" + marimo has a rich dataframe viewer built-in: + + - built-in global search + - per-column sorting and filtering + - per-column histograms + - download filtered views + - paginate through the whole dataframe + """) return diff --git a/examples/outputs/plots.py b/examples/outputs/plots.py index 453ea2b791f..fe0be22e6d8 100644 --- a/examples/outputs/plots.py +++ b/examples/outputs/plots.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -43,12 +43,10 @@ def _(plt): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Calling `show()` methods displays the plot in the console area, which can be - helpful for debugging because console outputs do not show up in the "app" preview. - """ - ) + mo.md(""" + Calling `show()` methods displays the plot in the console area, which can be + helpful for debugging because console outputs do not show up in the "app" preview. + """) return diff --git a/examples/running_as_a_script/sharing_arguments.py b/examples/running_as_a_script/sharing_arguments.py index e549499845e..0bc1ae9e20f 100644 --- a/examples/running_as_a_script/sharing_arguments.py +++ b/examples/running_as_a_script/sharing_arguments.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -18,37 +18,35 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - This notebook shows how to parametrize a notebook with optional command-line arguments. + mo.md(""" + This notebook shows how to parametrize a notebook with optional command-line arguments. - Run the notebook with + Run the notebook with - ```bash - marimo edit sharing_arguments.py - ``` + ```bash + marimo edit sharing_arguments.py + ``` - or + or - ```bash - marimo edit sharing_arguments.py -- -learning_rate=1e-3 - ``` + ```bash + marimo edit sharing_arguments.py -- -learning_rate=1e-3 + ``` - (Note the `--` separating the filename from the arguments.) + (Note the `--` separating the filename from the arguments.) - or + or - ```bash - python sharing_arguments.py -learning_rate=1e-3 - ``` + ```bash + python sharing_arguments.py -learning_rate=1e-3 + ``` - See help for the notebook's arguments with + See help for the notebook's arguments with - ```python - python sharing_arguments.py --help - ``` - """ - ) + ```python + python sharing_arguments.py --help + ``` + """) return diff --git a/examples/running_cells/basics.py b/examples/running_cells/basics.py index 4a77dface3b..b2d85036a50 100644 --- a/examples/running_cells/basics.py +++ b/examples/running_cells/basics.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -12,17 +12,15 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - marimo knows how your cells are related, and can automatically update - outputs like a spreadsheet. This eliminates hidden state and hidden bugs, accelerates data exploration, - and makes it possible for marimo to run your notebooks as scripts and web apps. - For expensive notebooks, you can [turn this - behavior off](https://docs.marimo.io/guides/expensive_notebooks/) via the notebook footer. - - Try updating the values of variables below and see what happens! You can also try deleting a cell. - """ - ) + mo.md(""" + marimo knows how your cells are related, and can automatically update + outputs like a spreadsheet. This eliminates hidden state and hidden bugs, accelerates data exploration, + and makes it possible for marimo to run your notebooks as scripts and web apps. + For expensive notebooks, you can [turn this + behavior off](https://docs.marimo.io/guides/expensive_notebooks/) via the notebook footer. + + Try updating the values of variables below and see what happens! You can also try deleting a cell. + """) return diff --git a/examples/running_cells/in_memory_cache.py b/examples/running_cells/in_memory_cache.py index 7155abeaa42..7e9d3680c0b 100644 --- a/examples/running_cells/in_memory_cache.py +++ b/examples/running_cells/in_memory_cache.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(app_title="In Memory Cache") @@ -24,16 +24,14 @@ def sleep_for(t: int): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Use `mo.cache` to cache the outputs of expensive functions. The first - time the function is called with unseen arguments, it will execute and - return the computed value. Subsequent calls with the same arguments will - return cached results. - - Experiment with the invocation below to get a feel for how this works. - """ - ) + mo.md(""" + Use `mo.cache` to cache the outputs of expensive functions. The first + time the function is called with unseen arguments, it will execute and + return the computed value. Subsequent calls with the same arguments will + return cached results. + + Experiment with the invocation below to get a feel for how this works. + """) return diff --git a/examples/running_cells/multiple_definitions.py b/examples/running_cells/multiple_definitions.py index 20e07b6a6b8..1375bdd3309 100644 --- a/examples/running_cells/multiple_definitions.py +++ b/examples/running_cells/multiple_definitions.py @@ -8,7 +8,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -20,13 +20,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Use local variables + mo.md(r""" + ## Use local variables - Variables prefixed with an underscore are local to a cell, and can be redefined. - """ - ) + Variables prefixed with an underscore are local to a cell, and can be redefined. + """) return @@ -53,13 +51,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Wrap code in functions + mo.md(r""" + ## Wrap code in functions - Wrap cells in functions to minimize the number of temporary globals you introduce. - """ - ) + Wrap cells in functions to minimize the number of temporary globals you introduce. + """) return diff --git a/examples/running_cells/persistent_cache.py b/examples/running_cells/persistent_cache.py index a1b17db941d..53a519fc435 100644 --- a/examples/running_cells/persistent_cache.py +++ b/examples/running_cells/persistent_cache.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(app_title="In Memory Cache") @@ -24,16 +24,14 @@ def sleep_for(t: int): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Use `mo.persistent_cache` to cache the outputs of expensive computations to persistent storage. The first - time the function is called with unseen arguments, it will execute and - return the computed value. Subsequent calls with the same arguments will - return cached results. - - Experiment with the invocation below to get a feel for how this works. - """ - ) + mo.md(""" + Use `mo.persistent_cache` to cache the outputs of expensive computations to persistent storage. The first + time the function is called with unseen arguments, it will execute and + return the computed value. Subsequent calls with the same arguments will + return cached results. + + Experiment with the invocation below to get a feel for how this works. + """) return diff --git a/examples/sql/connect_to_motherduck.py b/examples/sql/connect_to_motherduck.py index 7a003c22516..681499174fb 100644 --- a/examples/sql/connect_to_motherduck.py +++ b/examples/sql/connect_to_motherduck.py @@ -11,21 +11,19 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # MotherDuck 🧡 marimo + mo.md(r""" + # MotherDuck 🧡 marimo - Throughout this notebook, we will explore using [MotherDuck](https://motherduck.com) inside marimo. If you’re new to marimo, check out our [GitHub](https://github.com/marimo-team/marimo) repo: marimo is free and open source. + Throughout this notebook, we will explore using [MotherDuck](https://motherduck.com) inside marimo. If you’re new to marimo, check out our [GitHub](https://github.com/marimo-team/marimo) repo: marimo is free and open source. - _You can expand the code of any cells to see how the output are being created._ - """ - ) + _You can expand the code of any cells to see how the output are being created._ + """) return @@ -78,12 +76,10 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - !!! tip "Explore data sources" - If you open the "Explore data sources" panel on the left side bar (3rd icon), you will see all your tables including any news ones we will create below - """ - ) + mo.md(""" + !!! tip "Explore data sources" + If you open the "Explore data sources" panel on the left side bar (3rd icon), you will see all your tables including any news ones we will create below + """) return @@ -157,13 +153,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Let's make some charts 📈 + mo.md(r""" + ## Let's make some charts 📈 - Now that we have made some queries and named the results, we can chart those resulting dataframes in Python, using our favorite charting libraries (e.g [altair](https://altair-viz.github.io/), [matplotlib](https://matplotlib.org/), or [plotly](https://plotly.com/)). - """ - ) + Now that we have made some queries and named the results, we can chart those resulting dataframes in Python, using our favorite charting libraries (e.g [altair](https://altair-viz.github.io/), [matplotlib](https://matplotlib.org/), or [plotly](https://plotly.com/)). + """) return @@ -190,13 +184,11 @@ def _(most_shared_websites): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Adding reactivity ⚡ + mo.md(r""" + ## Adding reactivity ⚡ - We can also parameterize our SQL using marimo UI elements. This not only makes our SQL reactive, but also any downstream logic, including our charts. - """ - ) + We can also parameterize our SQL using marimo UI elements. This not only makes our SQL reactive, but also any downstream logic, including our charts. + """) return diff --git a/examples/sql/connect_to_persistent_db.py b/examples/sql/connect_to_persistent_db.py index 62e60691c81..17014210b15 100644 --- a/examples/sql/connect_to_persistent_db.py +++ b/examples/sql/connect_to_persistent_db.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -12,7 +12,9 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md("""Connect to duckdb [persistent storage](https://duckdb.org/docs/connect/overview.html#persistent-database) using the `ATTACH` command:""") + mo.md( + """Connect to duckdb [persistent storage](https://duckdb.org/docs/connect/overview.html#persistent-database) using the `ATTACH` command:""" + ) return diff --git a/examples/sql/connect_to_postgres.py b/examples/sql/connect_to_postgres.py index b65fee6838f..1a23046ba0c 100644 --- a/examples/sql/connect_to_postgres.py +++ b/examples/sql/connect_to_postgres.py @@ -11,23 +11,21 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell def _(mo): - mo.md( - r""" - # Connect to Postgres + mo.md(r""" + # Connect to Postgres - You can use marimo's SQL cells to read from and write to Postgres databases. + You can use marimo's SQL cells to read from and write to Postgres databases. - The first step is to attach a Postgres database, which we do below. + The first step is to attach a Postgres database, which we do below. - For advanced usage, see [duckdb's documentation](https://duckdb.org/docs/extensions/postgres). - """ - ) + For advanced usage, see [duckdb's documentation](https://duckdb.org/docs/extensions/postgres). + """) return @@ -104,12 +102,10 @@ def _(PASSWORD, mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - Once the database is attached, you can query it with SQL. Note that this involves copying data from Postgres SQL and - executing it in duckdb. See later sections of this example on how to execute queries directly in Postgres. - """ - ) + mo.md(r""" + Once the database is attached, you can query it with SQL. Note that this involves copying data from Postgres SQL and + executing it in duckdb. See later sections of this example on how to execute queries directly in Postgres. + """) return @@ -137,13 +133,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Copy data from Postgres to duckdb + mo.md(r""" + ## Copy data from Postgres to duckdb - To prevent duckdb from continuously re-reading tables from PostgresSQL, you can copy the PostgresSQL databases into DuckDB. Note that this will consume your system's RAM. - """ - ) + To prevent duckdb from continuously re-reading tables from PostgresSQL, you can copy the PostgresSQL databases into DuckDB. Note that this will consume your system's RAM. + """) return @@ -161,13 +155,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Execute queries directly in PostgresSQL + mo.md(r""" + ## Execute queries directly in PostgresSQL - Run queries directly in PostgresSQL using duckdb's `postgres_query` function. In some cases this may be faster than executing queries in duckdb. - """ - ) + Run queries directly in PostgresSQL using duckdb's `postgres_query` function. In some cases this may be faster than executing queries in duckdb. + """) return diff --git a/examples/sql/connect_to_sqlite.py b/examples/sql/connect_to_sqlite.py index aab4f13e1bb..a8423b1756b 100644 --- a/examples/sql/connect_to_sqlite.py +++ b/examples/sql/connect_to_sqlite.py @@ -12,23 +12,21 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Connect to SQLite + mo.md(r""" + # Connect to SQLite - You can use marimo's SQL cells to read from and write to SQLite databases. + You can use marimo's SQL cells to read from and write to SQLite databases. - The first step is to attach a SQLite database. We attach to a sample database in a read-only mode below. + The first step is to attach a SQLite database. We attach to a sample database in a read-only mode below. - For advanced usage, see [duckdb's documentation](https://duckdb.org/docs/extensions/sqlite). - """ - ) + For advanced usage, see [duckdb's documentation](https://duckdb.org/docs/extensions/sqlite). + """) return @@ -93,7 +91,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md(r"""Once the database is attached, you can query it with SQL. For example, the next cell computes the average track length of each composer in the chinook database.""") + mo.md( + r"""Once the database is attached, you can query it with SQL. For example, the next cell computes the average track length of each composer in the chinook database.""" + ) return diff --git a/examples/sql/histograms.py b/examples/sql/histograms.py index a10170e1348..a1690acad48 100644 --- a/examples/sql/histograms.py +++ b/examples/sql/histograms.py @@ -12,19 +12,17 @@ import marimo -__generated_with = "0.17.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell def _(mo): - mo.md( - r""" - # SQL Histograms + mo.md(r""" + # SQL Histograms - This notebook shows how to create a histogram of a column using built-in duckdb aggregate functions. - """ - ) + This notebook shows how to create a histogram of a column using built-in duckdb aggregate functions. + """) return @@ -60,7 +58,7 @@ def _(URL, mo): FROM dataset """ ) - return + return (dataset,) @app.cell @@ -85,7 +83,9 @@ def _(column, mo): @app.cell def _(mo): - mo.md(r"""Now we will take the histogram result and plot it using [Altair](https://altair-viz.github.io/).""") + mo.md( + r"""Now we will take the histogram result and plot it using [Altair](https://altair-viz.github.io/).""" + ) return diff --git a/examples/sql/misc/database_explorer.py b/examples/sql/misc/database_explorer.py index b6bd5231b9a..58a6751f201 100644 --- a/examples/sql/misc/database_explorer.py +++ b/examples/sql/misc/database_explorer.py @@ -13,7 +13,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @@ -28,13 +28,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" # Database explorer This notebook lets you explore the contents of a database. Start by providing a database URL. - """ - ) + """) return diff --git a/examples/sql/misc/electric_vehicles.py b/examples/sql/misc/electric_vehicles.py index 73b109b9601..55e0c74034e 100644 --- a/examples/sql/misc/electric_vehicles.py +++ b/examples/sql/misc/electric_vehicles.py @@ -11,19 +11,17 @@ import marimo -__generated_with = "0.17.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Electric Vehicle Population Data + mo.md(r""" + # Electric Vehicle Population Data - > This dataset shows the Battery Electric Vehicles (BEVs) and Plug-in Hybrid Electric Vehicles (PHEVs) that are currently registered through Washington State Department of Licensing (DOL). - """ - ) + > This dataset shows the Battery Electric Vehicles (BEVs) and Plug-in Hybrid Electric Vehicles (PHEVs) that are currently registered through Washington State Department of Licensing (DOL). + """) return @@ -111,7 +109,7 @@ def _(mo): @app.cell -def _(evs, mo): +def _(mo): years = mo.sql( f""" SELECT DISTINCT CAST(evs."Model Year" AS VARCHAR) AS "Model Year" FROM evs; @@ -121,7 +119,7 @@ def _(evs, mo): @app.cell -def _(evs, mo): +def _(mo): cities = mo.sql( f""" SELECT DISTINCT CAST(evs."City" AS VARCHAR) AS "City" FROM evs WHERE "City" != 'null'; @@ -131,7 +129,7 @@ def _(evs, mo): @app.cell -def _(evs, mo): +def _(mo): makes = mo.sql( f""" SELECT DISTINCT CAST(evs."Make" AS VARCHAR) AS "Make" FROM evs; @@ -141,7 +139,7 @@ def _(evs, mo): @app.cell -def _(cast_to_ints, city_select, evs, make_select, mo, sql_list, year_select): +def _(cast_to_ints, city_select, make_select, mo, sql_list, year_select): grouped_by_city = mo.sql( f""" SELECT COUNT(*) AS "count", "City", "Model Year" @@ -161,7 +159,7 @@ def _(cast_to_ints, city_select, evs, make_select, mo, sql_list, year_select): @app.cell -def _(cast_to_ints, city_select, evs, make_select, mo, sql_list, year_select): +def _(cast_to_ints, city_select, make_select, mo, sql_list, year_select): grouped_by_make = mo.sql( f""" SELECT COUNT(*) AS "count", "Make", "Model Year" diff --git a/examples/sql/misc/sql_cars.py b/examples/sql/misc/sql_cars.py index fc838c67755..b209162ff7e 100644 --- a/examples/sql/misc/sql_cars.py +++ b/examples/sql/misc/sql_cars.py @@ -12,7 +12,7 @@ import marimo -__generated_with = "0.17.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -25,7 +25,7 @@ def _(data): @app.cell -def _(cars_df, mo): +def _(mo): _df = mo.sql( f""" CREATE OR REPLACE TABLE cars AS SELECT * FROM cars_df; @@ -82,7 +82,7 @@ def _(mo): @app.cell -def _(cars, mo, year_range): +def _(mo, year_range): _df = mo.sql( f""" WITH ranked_cars AS ( @@ -173,7 +173,7 @@ def _(alt, duckdb, mo, year_range): def _(chart, mo): mo.stop(chart.value.empty, mo.callout("Select cars from the chart above.")) selected_cars = chart.value - return (selected_cars,) + return @app.cell(hide_code=True) @@ -205,7 +205,7 @@ def diff(column): @app.cell(hide_code=True) -def _(cars, mo, selected_cars): +def _(mo): aggs_selected = mo.sql(""" SELECT COUNT(*) as count, diff --git a/examples/sql/parametrizing_sql_queries.py b/examples/sql/parametrizing_sql_queries.py index 53d478a7ab4..6dce5bdd6bf 100644 --- a/examples/sql/parametrizing_sql_queries.py +++ b/examples/sql/parametrizing_sql_queries.py @@ -11,7 +11,7 @@ import marimo -__generated_with = "0.16.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -23,15 +23,13 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Parametrizing SQL Queries + mo.md(""" + # Parametrizing SQL Queries - This notebook shows parametrize SQL queries with Python values, using Python f-string interpolation. + This notebook shows parametrize SQL queries with Python values, using Python f-string interpolation. - First, we create a dataframe called `df`. - """ - ) + First, we create a dataframe called `df`. + """) return @@ -41,7 +39,7 @@ def _(): df = data.iris() df - return (df,) + return @app.cell(hide_code=True) @@ -59,15 +57,13 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Next, we **create a SQL cell** that filters the table to the selected species. - - Notice that we can reference the Python variable `species_dropdown` in our query - using **curly braces**. This is because marimo represents SQL queries as Python - f-strings. - """ - ) + mo.md(""" + Next, we **create a SQL cell** that filters the table to the selected species. + + Notice that we can reference the Python variable `species_dropdown` in our query + using **curly braces**. This is because marimo represents SQL queries as Python + f-strings. + """) return @@ -92,7 +88,7 @@ def _(mo): @app.cell -def _(df, mo, species_dropdown): +def _(mo, species_dropdown): result = mo.sql( f""" SELECT * FROM df where species == '{species_dropdown.value}' @@ -103,17 +99,15 @@ def _(df, mo, species_dropdown): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - The query output is returned to Python as a dataframe (Polars if you have it installed, Pandas otherwise). + mo.md(r""" + The query output is returned to Python as a dataframe (Polars if you have it installed, Pandas otherwise). - Choose the dataframe name via the **output variable** input in the bottom-left - of the cell. If the name starts with an underscore, it won't be made available - to other cells. In this case, we've named the output `result`. + Choose the dataframe name via the **output variable** input in the bottom-left + of the cell. If the name starts with an underscore, it won't be made available + to other cells. In this case, we've named the output `result`. - Try changing the selected species in the `species_dropdown`, and watch how the query result changes. - """ - ) + Try changing the selected species in the `species_dropdown`, and watch how the query result changes. + """) return diff --git a/examples/sql/querying_dataframes.py b/examples/sql/querying_dataframes.py index 4f889ec5809..d8c118f99b3 100644 --- a/examples/sql/querying_dataframes.py +++ b/examples/sql/querying_dataframes.py @@ -11,7 +11,7 @@ import marimo -__generated_with = "0.16.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -23,15 +23,13 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Querying dataframes + mo.md(""" + # Querying dataframes - This notebook shows how to use SQL to query Python dataframes. + This notebook shows how to use SQL to query Python dataframes. - First, we create a dataframe called `df`. - """ - ) + First, we create a dataframe called `df`. + """) return @@ -41,7 +39,7 @@ def _(): df = data.iris() df.head() - return (df,) + return @app.cell(hide_code=True) @@ -62,7 +60,7 @@ def _(mo): @app.cell -def _(df, mo): +def _(mo): result = mo.sql( f""" SELECT species, mean(petalLength) as meanPetalLength FROM df GROUP BY species ORDER BY meanPetalLength @@ -73,15 +71,13 @@ def _(df, mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - The query output is returned to Python as a dataframe (Polars if you have it installed, Pandas otherwise). + mo.md(r""" + The query output is returned to Python as a dataframe (Polars if you have it installed, Pandas otherwise). - Choose the dataframe name via the **output variable** input in the bottom-left of the cell. If the name starts with an underscore, it won't be made available to other cells. + Choose the dataframe name via the **output variable** input in the bottom-left of the cell. If the name starts with an underscore, it won't be made available to other cells. - In this case, we've named the output `result`. - """ - ) + In this case, we've named the output `result`. + """) return diff --git a/examples/sql/read_csv.py b/examples/sql/read_csv.py index 2bd5b74d1fb..7d33f8bcf61 100644 --- a/examples/sql/read_csv.py +++ b/examples/sql/read_csv.py @@ -11,19 +11,17 @@ import marimo -__generated_with = "0.17.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Read CSV + mo.md(""" + # Read CSV - This notebook shows how to read a CSV file from a local file or a URL into an in-memory table. - """ - ) + This notebook shows how to read a CSV file from a local file or a URL into an in-memory table. + """) return @@ -38,7 +36,9 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md("""Reading from a local CSV is as easy as `SELECT * from "data.csv"`, where `data.csv` is the path to your local file (or a URL to a CSV file).""") + mo.md( + """Reading from a local CSV is as easy as `SELECT * from "data.csv"`, where `data.csv` is the path to your local file (or a URL to a CSV file).""" + ) return @@ -101,13 +101,11 @@ def _(result): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Create an in-memory table from a CSV file + mo.md(r""" + ## Create an in-memory table from a CSV file - You can also create a table from a CSV file, so you can easily query it in subsequent cells. This table will appear in marimo's data sources panel. - """ - ) + You can also create a table from a CSV file, so you can easily query it in subsequent cells. This table will appear in marimo's data sources panel. + """) return @@ -122,7 +120,7 @@ def _(mo): @app.cell -def _(mo, mytable): +def _(mo): _df = mo.sql( f""" SELECT * FROM myTable @@ -139,7 +137,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md(r"""To customize how your CSV is read, including specifying the delimiter type, use [duckdb's `read_csv` function](https://duckdb.org/docs/data/csv/overview.html).""") + mo.md( + r"""To customize how your CSV is read, including specifying the delimiter type, use [duckdb's `read_csv` function](https://duckdb.org/docs/data/csv/overview.html).""" + ) return diff --git a/examples/sql/read_json.py b/examples/sql/read_json.py index 41d34642142..a2476864abb 100644 --- a/examples/sql/read_json.py +++ b/examples/sql/read_json.py @@ -11,19 +11,17 @@ import marimo -__generated_with = "0.17.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Read JSON + mo.md(""" + # Read JSON - This notebook shows how to read a JSON file from a local file or a URL into an in-memory table. - """ - ) + This notebook shows how to read a JSON file from a local file or a URL into an in-memory table. + """) return @@ -38,17 +36,15 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Reading from a JSON file is as easy as + mo.md(""" + Reading from a JSON file is as easy as - ```sql - SELECT * from 'data.json' - ``` + ```sql + SELECT * from 'data.json' + ``` - where `data.json` is the path or URL to your json file. - """ - ) + where `data.json` is the path or URL to your json file. + """) return @@ -111,13 +107,11 @@ def _(result): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Create an in-memory table from a JSON file + mo.md(r""" + ## Create an in-memory table from a JSON file - You can also create a table from a JSON file, so you can easily query it in subsequent cells. This table will appear in marimo's data sources panel. - """ - ) + You can also create a table from a JSON file, so you can easily query it in subsequent cells. This table will appear in marimo's data sources panel. + """) return @@ -132,7 +126,7 @@ def _(mo): @app.cell -def _(mo, mytable): +def _(mo): _df = mo.sql( f""" SELECT * FROM myTable @@ -149,7 +143,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md(r"""To customize how your json file is read, use [duckdb's `read_json` function](https://duckdb.org/docs/data/json/overview.html).""") + mo.md( + r"""To customize how your json file is read, use [duckdb's `read_json` function](https://duckdb.org/docs/data/json/overview.html).""" + ) return diff --git a/examples/sql/read_parquet.py b/examples/sql/read_parquet.py index 162c15d07f6..2656f56f2bb 100644 --- a/examples/sql/read_parquet.py +++ b/examples/sql/read_parquet.py @@ -11,19 +11,17 @@ import marimo -__generated_with = "0.17.0" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Read Parquet + mo.md(""" + # Read Parquet - This notebook shows how to read a Parquet file from a local file or a URL into an in-memory table. - """ - ) + This notebook shows how to read a Parquet file from a local file or a URL into an in-memory table. + """) return @@ -38,7 +36,9 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md("""Reading from a Parquet file is as easy as `SELECT * from "data.parquet"`, where `data.parquet` is the path or URL to your parquet file.""") + mo.md( + """Reading from a Parquet file is as easy as `SELECT * from "data.parquet"`, where `data.parquet` is the path or URL to your parquet file.""" + ) return @@ -100,13 +100,11 @@ def _(result): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Create an in-memory table from a Parquet file + mo.md(r""" + ## Create an in-memory table from a Parquet file - You can also create a table from a Parquet file, so you can easily query it in subsequent cells. This table will appear in marimo's data sources panel. - """ - ) + You can also create a table from a Parquet file, so you can easily query it in subsequent cells. This table will appear in marimo's data sources panel. + """) return @@ -121,7 +119,7 @@ def _(mo): @app.cell -def _(mo, mytable): +def _(mo): _df = mo.sql( f""" SELECT * FROM myTable @@ -138,7 +136,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md(r"""To customize how your parquet file is read, use [duckdb's `read_parquet` function](https://duckdb.org/docs/data/parquet/overview.html).""") + mo.md( + r"""To customize how your parquet file is read, use [duckdb's `read_parquet` function](https://duckdb.org/docs/data/parquet/overview.html).""" + ) return diff --git a/examples/third_party/chroma/multimodal_retrieval.py b/examples/third_party/chroma/multimodal_retrieval.py index be1153cb28f..92a14343f95 100644 --- a/examples/third_party/chroma/multimodal_retrieval.py +++ b/examples/third_party/chroma/multimodal_retrieval.py @@ -13,7 +13,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -25,29 +25,25 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Multimodal Retrieval + mo.md(r""" + # Multimodal Retrieval - Chroma supports multimodal collections, i.e. collections which contain, and can be queried by, multiple modalities of data. + Chroma supports multimodal collections, i.e. collections which contain, and can be queried by, multiple modalities of data. - This notebook shows an example of how to create and query a collection with both text and images, using Chroma's built-in features. - """ - ) + This notebook shows an example of how to create and query a collection with both text and images, using Chroma's built-in features. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Dataset + mo.md(r""" + ## Dataset - We us a small subset of the [coco object detection dataset](https://huggingface.co/datasets/detection-datasets/coco), hosted on HuggingFace. + We us a small subset of the [coco object detection dataset](https://huggingface.co/datasets/detection-datasets/coco), hosted on HuggingFace. - We download a small fraction of all the images in the dataset locally, and use it to create a multimodal collection. - """ - ) + We download a small fraction of all the images in the dataset locally, and use it to create a multimodal collection. + """) return @@ -120,28 +116,24 @@ def as_image(src): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Ingesting multimodal data + mo.md(r""" + ## Ingesting multimodal data - Chroma supports multimodal collections by referencing external URIs for data types other than text. - All you have to do is specify a data loader when creating the collection, and then provide the URI for each entry. + Chroma supports multimodal collections by referencing external URIs for data types other than text. + All you have to do is specify a data loader when creating the collection, and then provide the URI for each entry. - For this example, we are only adding images, though you can also add text. - """ - ) + For this example, we are only adding images, though you can also add text. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ### Creating a multi-modal collection + mo.md(r""" + ### Creating a multi-modal collection - First we create the default Chroma client. - """ - ) + First we create the default Chroma client. + """) return @@ -155,13 +147,11 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - Next we specify an embedding function and a data loader. + mo.md(r""" + Next we specify an embedding function and a data loader. - The built-in `OpenCLIPEmbeddingFunction` works with both text and image data. The `ImageLoader` is a simple data loader that loads images from a local directory. - """ - ) + The built-in `OpenCLIPEmbeddingFunction` works with both text and image data. The `ImageLoader` is a simple data loader that loads images from a local directory. + """) return @@ -177,7 +167,9 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md(r"""We create a collection with the embedding function and data loader.""") + mo.md( + r"""We create a collection with the embedding function and data loader.""" + ) return @@ -205,25 +197,21 @@ def _(IMAGE_FOLDER, client, embedding_function, image_loader, os): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ### Adding multi-modal data + mo.md(r""" + ### Adding multi-modal data - We add image data to the collection using the image URIs. The data loader and embedding functions we specified earlier will ingest data from the provided URIs automatically. - """ - ) + We add image data to the collection using the image URIs. The data loader and embedding functions we specified earlier will ingest data from the provided URIs automatically. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Querying a multi-modal collection + mo.md(r""" + ## Querying a multi-modal collection - We can query the collection using text as normal, since the `OpenCLIPEmbeddingFunction` works with both text and images. - """ - ) + We can query the collection using text as normal, since the `OpenCLIPEmbeddingFunction` works with both text and images. + """) return @@ -249,13 +237,11 @@ def _(collection, mo, query): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - /// admonition | One more thing! - We can also query by images directly, by using the `query_images` field in the `collection.query` method. - /// - """ - ) + mo.md(r""" + /// admonition | One more thing! + We can also query by images directly, by using the `query_images` field in the `collection.query` method. + /// + """) return @@ -297,7 +283,9 @@ def _(mo, results, selected): @app.cell(hide_code=True) def _(mo): - mo.md(r"""This example was adapted from [multimodal_retrieval.ipynb](https://github.com/chroma-core/chroma/blob/main/examples/multimodal/multimodal_retrieval.ipynb), using `marimo convert`.""") + mo.md( + r"""This example was adapted from [multimodal_retrieval.ipynb](https://github.com/chroma-core/chroma/blob/main/examples/multimodal/multimodal_retrieval.ipynb), using `marimo convert`.""" + ) return diff --git a/examples/third_party/cvxpy/regularization_and_sparsity.py b/examples/third_party/cvxpy/regularization_and_sparsity.py index e6cf73dbcd7..a55d8b78782 100644 --- a/examples/third_party/cvxpy/regularization_and_sparsity.py +++ b/examples/third_party/cvxpy/regularization_and_sparsity.py @@ -10,7 +10,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -22,39 +22,37 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - This app shows how the choice of regularization in a least squares regression - problem can affect the sparsity of solutions. + mo.md(r""" + This app shows how the choice of regularization in a least squares regression + problem can affect the sparsity of solutions. - We will use CVXPY to solve the problem + We will use CVXPY to solve the problem - \[ - \begin{equation*} - \begin{array}{ll} - \text{minimize} & \|A x - b\|_2^2 + \lambda \|x \|_p \\ - \end{array} - \end{equation*} - \] + \[ + \begin{equation*} + \begin{array}{ll} + \text{minimize} & \|A x - b\|_2^2 + \lambda \|x \|_p \\ + \end{array} + \end{equation*} + \] - where $A \in \mathbf{R}^{m \times n}$ and $b \in \mathbf{R}^{m}$ are problem - data, $x \in \mathbf{R}^n$ is the optimization variable, and - $\lambda > 0$ is - a scalar that controls the strength of the regularization. + where $A \in \mathbf{R}^{m \times n}$ and $b \in \mathbf{R}^{m}$ are problem + data, $x \in \mathbf{R}^n$ is the optimization variable, and + $\lambda > 0$ is + a scalar that controls the strength of the regularization. - Let's experiment how solutions to this problem differ for $p=1$, + Let's experiment how solutions to this problem differ for $p=1$, - \[ - \|x\|_1 = |x_1| + |x_2| + \cdots + |x_n|, - \] + \[ + \|x\|_1 = |x_1| + |x_2| + \cdots + |x_n|, + \] - and $p=2$, + and $p=2$, - \[ - \|x\|_2 = \sqrt{x_1^2 + x_2^2 + \cdots + x_n^2}. - \] - """ - ) + \[ + \|x\|_2 = \sqrt{x_1^2 + x_2^2 + \cdots + x_n^2}. + \] + """) return @@ -149,19 +147,17 @@ def _(cdf, plt, x_l1, x_l2): @app.cell def _(mo): - mo.md( - r""" - ## Sparsity + mo.md(r""" + ## Sparsity - The $\ell_1$ norm, when used as a regularizer, encourages solutions - to be _sparse_: to have many zeros and only a few nonzeros. + The $\ell_1$ norm, when used as a regularizer, encourages solutions + to be _sparse_: to have many zeros and only a few nonzeros. - A sparse regressor (if it is a good model) encodes which features - are important for making predictions, and which are not: If a component - of $x$ is $0$, then the corresponding feature or measurement - must not be important in making predictions. - """ - ) + A sparse regressor (if it is a good model) encodes which features + are important for making predictions, and which are not: If a component + of $x$ is $0$, then the corresponding feature or measurement + must not be important in making predictions. + """) return diff --git a/examples/third_party/cvxpy/signals/app.py b/examples/third_party/cvxpy/signals/app.py index 99eee86616b..eef00cbcaa6 100644 --- a/examples/third_party/cvxpy/signals/app.py +++ b/examples/third_party/cvxpy/signals/app.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -12,28 +12,24 @@ def _(mo): @app.cell def _(mo): - mo.md( - """ - This app is a hands-on introduction to _signal decomposition_, an - age-old problem about breaking down a complex signal, also known as a - time series, into the sum of simpler interpretable ones. - """ - ) + mo.md(""" + This app is a hands-on introduction to _signal decomposition_, an + age-old problem about breaking down a complex signal, also known as a + time series, into the sum of simpler interpretable ones. + """) return @app.cell def _(mo): - mo.md( - """ - The simpler signals that come out of a decomposition are called - _components_. When doing a signal decomposition, we have to specify - two things: - - 1. How many components do we want? - 2. What kinds of components, or "component classes", do we want? - """ - ) + mo.md(""" + The simpler signals that come out of a decomposition are called + _components_. When doing a signal decomposition, we have to specify + two things: + + 1. How many components do we want? + 2. What kinds of components, or "component classes", do we want? + """) return diff --git a/examples/third_party/cvxpy/smallest_enclosing_circle.py b/examples/third_party/cvxpy/smallest_enclosing_circle.py index bcfd46d67c1..84633859072 100644 --- a/examples/third_party/cvxpy/smallest_enclosing_circle.py +++ b/examples/third_party/cvxpy/smallest_enclosing_circle.py @@ -10,26 +10,24 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Smallest Enclosing Circle + mo.md(""" + # Smallest Enclosing Circle - This program computes the circle of smallest radius that encloses a given - randomly sampled set of circles. This is a generalization of the - [smallest-circle problem](https://en.wikipedia.org/wiki/Smallest-circle_problem). + This program computes the circle of smallest radius that encloses a given + randomly sampled set of circles. This is a generalization of the + [smallest-circle problem](https://en.wikipedia.org/wiki/Smallest-circle_problem). - We solve this problem using [CVXPY](https://www.cvxpy.org), a Python library for specifying and - solving convex optimization problems. + We solve this problem using [CVXPY](https://www.cvxpy.org), a Python library for specifying and + solving convex optimization problems. - _Use the slider below to choose the number of circles to sample:_ - """ - ) + _Use the slider below to choose the number of circles to sample:_ + """) return @@ -109,45 +107,43 @@ def _(mo): @app.cell def _(mo): - mo.md( - r""" - We can write down a convex optimization problem whose solution gives us - the smallest circle enclosing the $n$ given circles. Once we do this, - we can just code up the problem in CVXPY to obtain a solution. - - Here's the problem: - - We seek a circle, parameterized by a center $c = (x, y) \in \mathbf{R}^2$ - and a radius $r \in \mathbf{R}$ satisfying - - \[ - \begin{equation*} - \begin{array}{ll} - \text{minimize} & r \\ - \text{subject to } & \|c - c_i\|_2 + r_i \leq r, \quad i=1, \ldots, n, - \end{array} - \end{equation*} - \] - - where $c_1, \ldots, c_n$ and $r_1, \ldots, r_n$ are the centers and radii - of the $n$ given circles. - - And here's the code: - - ```python3 - def smallest_enclosing_circle(circles): - radius = cp.Variable() - center = cp.Variable(2) - constraints = [ - cp.norm(center - c_i) + r_i <= radius - for (c_i, r_i) in circles - ] - objective = cp.Minimize(radius) - cp.Problem(objective, constraints).solve() - return (center.value, radius.value) - ``` - """ - ) + mo.md(r""" + We can write down a convex optimization problem whose solution gives us + the smallest circle enclosing the $n$ given circles. Once we do this, + we can just code up the problem in CVXPY to obtain a solution. + + Here's the problem: + + We seek a circle, parameterized by a center $c = (x, y) \in \mathbf{R}^2$ + and a radius $r \in \mathbf{R}$ satisfying + + \[ + \begin{equation*} + \begin{array}{ll} + \text{minimize} & r \\ + \text{subject to } & \|c - c_i\|_2 + r_i \leq r, \quad i=1, \ldots, n, + \end{array} + \end{equation*} + \] + + where $c_1, \ldots, c_n$ and $r_1, \ldots, r_n$ are the centers and radii + of the $n$ given circles. + + And here's the code: + + ```python3 + def smallest_enclosing_circle(circles): + radius = cp.Variable() + center = cp.Variable(2) + constraints = [ + cp.norm(center - c_i) + r_i <= radius + for (c_i, r_i) in circles + ] + objective = cp.Minimize(radius) + cp.Problem(objective, constraints).solve() + return (center.value, radius.value) + ``` + """) return diff --git a/examples/third_party/duckdb/duckdb_example.py b/examples/third_party/duckdb/duckdb_example.py index 8cd4003fee6..f19f08cc4b8 100644 --- a/examples/third_party/duckdb/duckdb_example.py +++ b/examples/third_party/duckdb/duckdb_example.py @@ -10,20 +10,18 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # 🤗 Hugging Face dataset search and exploration + mo.md(""" + # 🤗 Hugging Face dataset search and exploration - This notebook allows you to search and explore the datasets available on Hugging Face. - First you can search for a dataset using the filters provided. Then you can select a dataset and explore the parquet files that are available for that dataset. Finally you can use the SQL editor to query the parquet files and the dataframe editor to explore the results of your query. - """ - ) + This notebook allows you to search and explore the datasets available on Hugging Face. + First you can search for a dataset using the filters provided. Then you can select a dataset and explore the parquet files that are available for that dataset. Finally you can use the SQL editor to query the parquet files and the dataframe editor to explore the results of your query. + """) return diff --git a/examples/third_party/great_tables/great_tables_example.py b/examples/third_party/great_tables/great_tables_example.py index 98b71f2fa4b..8c80526b67d 100644 --- a/examples/third_party/great_tables/great_tables_example.py +++ b/examples/third_party/great_tables/great_tables_example.py @@ -9,19 +9,17 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" # [Great-tables](https://github.com/posit-dev/great-tables) + marimo Adapted from https://github.com/machow/coffee-sales-data - """ - ) + """) return diff --git a/examples/third_party/ibis/ibis_example.py b/examples/third_party/ibis/ibis_example.py index 07da37b100b..1f2ee0d14ab 100644 --- a/examples/third_party/ibis/ibis_example.py +++ b/examples/third_party/ibis/ibis_example.py @@ -9,19 +9,17 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @app.cell(hide_code=True) def _(mo): - mo.md( - f""" + mo.md(f""" # Using `Ibis` in `marimo` > Ibis is a Python data analysis library that allows for expressive, efficient, and scalable data manipulation and query processing. - """ - ) + """) return diff --git a/examples/third_party/leafmap/leafmap_example.py b/examples/third_party/leafmap/leafmap_example.py index c043971426e..dd0bb4735de 100644 --- a/examples/third_party/leafmap/leafmap_example.py +++ b/examples/third_party/leafmap/leafmap_example.py @@ -8,19 +8,17 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Using Leafmap + mo.md(""" + # Using Leafmap - This example shows how to render a `leafmap.Map` in marimo; just output it like any other object. - """ - ) + This example shows how to render a `leafmap.Map` in marimo; just output it like any other object. + """) return diff --git a/examples/third_party/matplotlib/mandelbrot.py b/examples/third_party/matplotlib/mandelbrot.py index 462593af842..734dc81a251 100644 --- a/examples/third_party/matplotlib/mandelbrot.py +++ b/examples/third_party/matplotlib/mandelbrot.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -21,27 +21,25 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - This program computes uses an iterative algorithm to visualize the - [_Mandelbrot set_](https://mathworld.wolfram.com/MandelbrotSet.html), - the set of complex numbers $c$ for which the sequence defined by the - iteration + mo.md(r""" + This program computes uses an iterative algorithm to visualize the + [_Mandelbrot set_](https://mathworld.wolfram.com/MandelbrotSet.html), + the set of complex numbers $c$ for which the sequence defined by the + iteration - \[ - z_n = z_{n-1}^2 + c, \quad z_0 = 0 - \] + \[ + z_n = z_{n-1}^2 + c, \quad z_0 = 0 + \] - is bounded in absolute value. + is bounded in absolute value. - In the visualization, every point not in the set is colored by the - number of iterations the algorithm required to disprove its membership in - the set. In any iteration, points in the darkest region may - be in the computed set; once the number of iterations is very high, we - can be confident that the dark region is the desired Mandelbrot set. - """ - ) + In the visualization, every point not in the set is colored by the + number of iterations the algorithm required to disprove its membership in + the set. In any iteration, points in the darkest region may + be in the computed set; once the number of iterations is very high, we + can be confident that the dark region is the desired Mandelbrot set. + """) return diff --git a/examples/third_party/plotly/mapbox.py b/examples/third_party/plotly/mapbox.py index 17532e57d2f..e6e20056e28 100644 --- a/examples/third_party/plotly/mapbox.py +++ b/examples/third_party/plotly/mapbox.py @@ -9,19 +9,17 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Mapping Example + mo.md(""" + # Mapping Example - This example uses Mapbox in `plotly.express` to build a scatter plot on a street map. The switch enables the satellite view. - """ - ) + This example uses Mapbox in `plotly.express` to build a scatter plot on a street map. The switch enables the satellite view. + """) return diff --git a/examples/third_party/plotly/scatter_map.py b/examples/third_party/plotly/scatter_map.py index 10954aee304..76ce720c638 100644 --- a/examples/third_party/plotly/scatter_map.py +++ b/examples/third_party/plotly/scatter_map.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @@ -21,14 +21,12 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Selectable scatter map - - This example shows how to overlay a scatter plot on a map using `Plotly`, and make the plot reactive using [`mo.ui.plotly`](https://docs.marimo.io/guides/working_with_data/plotting.html#plotly) — select plots in the scatter - plot and get them back in Python! - """ - ) + mo.md(r""" + # Selectable scatter map + + This example shows how to overlay a scatter plot on a map using `Plotly`, and make the plot reactive using [`mo.ui.plotly`](https://docs.marimo.io/guides/working_with_data/plotting.html#plotly) — select plots in the scatter + plot and get them back in Python! + """) return diff --git a/examples/third_party/polars/polars_example.py b/examples/third_party/polars/polars_example.py index abe8d1ef10d..9ce93c66143 100644 --- a/examples/third_party/polars/polars_example.py +++ b/examples/third_party/polars/polars_example.py @@ -10,19 +10,17 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Using `Polars` in `marimo` + mo.md(""" + # Using `Polars` in `marimo` - > Lightning-fast DataFrame library for Rust and Python - """ - ) + > Lightning-fast DataFrame library for Rust and Python + """) return diff --git a/examples/third_party/pyiceberg/data_catalog.py b/examples/third_party/pyiceberg/data_catalog.py index d488a31999a..2fa9b952976 100644 --- a/examples/third_party/pyiceberg/data_catalog.py +++ b/examples/third_party/pyiceberg/data_catalog.py @@ -9,7 +9,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -22,35 +22,31 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # PyIceberg REST Catalog + mo.md(r""" + # PyIceberg REST Catalog - This notebook shows you how to connect to an Apache Iceberg data catalog over REST. - """ - ) + This notebook shows you how to connect to an Apache Iceberg data catalog over REST. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - /// details | Create a new catalog with Cloudflare + mo.md(r""" + /// details | Create a new catalog with Cloudflare - 1. Create a Cloudflare account - 2. Go to + 1. Create a Cloudflare account + 2. Go to - /// - """ - ) + /// + """) return @app.cell(hide_code=True) def _(mo): - mo.md(r"""## Connect to a data catalog """) + mo.md(r"""## Connect to a data catalog""") return diff --git a/examples/third_party/pymde/debugging_embeddings.py b/examples/third_party/pymde/debugging_embeddings.py index cd431ccbee6..cfa1651eb11 100644 --- a/examples/third_party/pymde/debugging_embeddings.py +++ b/examples/third_party/pymde/debugging_embeddings.py @@ -7,33 +7,29 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell def _(mo): - mo.md( - """ - # Sanity-Checking Embeddings + mo.md(""" + # Sanity-Checking Embeddings - This notebook shows you the basics of sanity-checking an embedding made - with the `PyMDE` library. We'll use MNIST as a case study. - """ - ) + This notebook shows you the basics of sanity-checking an embedding made + with the `PyMDE` library. We'll use MNIST as a case study. + """) return @app.cell def _(mo): - mo.md( - """ - We'll start by making a simple neighborhood-preserving embedding. This - means that we'll try to identify pairs of images that are similar, using - a heuristic, and we'll tell PyMDE to place these pairs near each other in - the embedding. - """ - ) + mo.md(""" + We'll start by making a simple neighborhood-preserving embedding. This + means that we'll try to identify pairs of images that are similar, using + a heuristic, and we'll tell PyMDE to place these pairs near each other in + the embedding. + """) return diff --git a/examples/third_party/pymde/embedding_numbers.py b/examples/third_party/pymde/embedding_numbers.py index 9744680af09..2f90f383895 100644 --- a/examples/third_party/pymde/embedding_numbers.py +++ b/examples/third_party/pymde/embedding_numbers.py @@ -7,26 +7,24 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell def _(mo): - mo.md( - """ - # Embedding MNIST - - This app shows how to use the function `pymde.preserve_neighbors` - to produce embeddings that highlight the local structure of your - data, using MNIST as a case study. In these embeddings similar - digits are near each other, and dissimilar digits are not near each other. - - ## Data - The data we'll embed are 70,000 28x28 grayscale images of handwritten - digits: - """ - ) + mo.md(""" + # Embedding MNIST + + This app shows how to use the function `pymde.preserve_neighbors` + to produce embeddings that highlight the local structure of your + data, using MNIST as a case study. In these embeddings similar + digits are near each other, and dissimilar digits are not near each other. + + ## Data + The data we'll embed are 70,000 28x28 grayscale images of handwritten + digits: + """) return diff --git a/examples/third_party/pymde/google_scholar.py b/examples/third_party/pymde/google_scholar.py index 3c6fb9c25d2..3a1c636544f 100644 --- a/examples/third_party/pymde/google_scholar.py +++ b/examples/third_party/pymde/google_scholar.py @@ -7,24 +7,22 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell def _(mo): - mo.md( - r""" - # Embedding Google Scholar - - This notebook shows how to use the function `pymde.preserve_distances` to - produce embeddings of networks, in which the goal is to preserve the - shortest-path distances in the network. - - It uses an academic co-authorship network collected from Google Scholar as - a case study. - """ - ) + mo.md(r""" + # Embedding Google Scholar + + This notebook shows how to use the function `pymde.preserve_distances` to + produce embeddings of networks, in which the goal is to preserve the + shortest-path distances in the network. + + It uses an academic co-authorship network collected from Google Scholar as + a case study. + """) return diff --git a/examples/third_party/pymde/interactive_cluster_analysis.py b/examples/third_party/pymde/interactive_cluster_analysis.py index c0ce909cbe6..4543c82d31a 100644 --- a/examples/third_party/pymde/interactive_cluster_analysis.py +++ b/examples/third_party/pymde/interactive_cluster_analysis.py @@ -8,7 +8,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -20,12 +20,10 @@ def _(mo): @app.cell def _(mo): - mo.md( - """ - Here's an **embedding of MNIST**: each point represents a digit, - with similar digits close to each other. - """ - ) + mo.md(""" + Here's an **embedding of MNIST**: each point represents a digit, + with similar digits close to each other. + """) return diff --git a/examples/third_party/pymde/us_counties.py b/examples/third_party/pymde/us_counties.py index c0dd62f04cb..86944db24a7 100644 --- a/examples/third_party/pymde/us_counties.py +++ b/examples/third_party/pymde/us_counties.py @@ -8,34 +8,32 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell def _(mo): - mo.md( - """ - # Embedding 🇺🇸 Counties - - This notebook accompanies chapter 10 of the monograph - [Minimum-Distortion Embedding](https://web.stanford.edu/~boyd/papers/min_dist_emb.html). - - 🇺🇸 In this example notebook, we use PyMDE to embed and visualize 3,220 - US counties, described by their demographic data (collected between 2013- - 2017 by an ACS longitudinal survey). - - 🌎 We then color each county by the fraction of voters who voted for a - democratic candidate in the 2016 presidential election. Interestingly, the - embedding vaguely resembles a map of the US, clustered by political party - preference, though no geographic or party preference data were - used to compute the embedding! - - ⚡ We use `mo.ui.altair_chart` to create a reactive and interactive - scatter plot of the embedding: this makes it possible to see where counties - land in the embedding! - """ - ) + mo.md(""" + # Embedding 🇺🇸 Counties + + This notebook accompanies chapter 10 of the monograph + [Minimum-Distortion Embedding](https://web.stanford.edu/~boyd/papers/min_dist_emb.html). + + 🇺🇸 In this example notebook, we use PyMDE to embed and visualize 3,220 + US counties, described by their demographic data (collected between 2013- + 2017 by an ACS longitudinal survey). + + 🌎 We then color each county by the fraction of voters who voted for a + democratic candidate in the 2016 presidential election. Interestingly, the + embedding vaguely resembles a map of the US, clustered by political party + preference, though no geographic or party preference data were + used to compute the embedding! + + ⚡ We use `mo.ui.altair_chart` to create a reactive and interactive + scatter plot of the embedding: this makes it possible to see where counties + land in the embedding! + """) return @@ -53,13 +51,11 @@ def _(pymde): @app.cell def _(mo): - mo.md( - """ - ## The data + mo.md(""" + ## The data - The data we embed includes demographic information about each county. - """ - ) + The data we embed includes demographic information about each county. + """) return @@ -71,14 +67,12 @@ def _(dataset, mo): @app.cell def _(mo): - mo.md( - """ - ## The embedding + mo.md(""" + ## The embedding - We now make a neighbor-preserving embedding, to explore the local - relationships in the data. - """ - ) + We now make a neighbor-preserving embedding, to explore the local + relationships in the data. + """) return @@ -96,17 +90,15 @@ def _(mde): @app.cell def _(mo): - mo.md( - """ - Finally we visualize the embedding, rotating it so that it vaguely - resembles a map of the US. Note that counties that voted Republican tend - to cluster together, as do counties that voted Democratic, even though - our original data had no information about political party preference! - - In some real sense, the embedding "discovered" political preference - from demographic data. - """ - ) + mo.md(""" + Finally we visualize the embedding, rotating it so that it vaguely + resembles a map of the US. Note that counties that voted Republican tend + to cluster together, as do counties that voted Democratic, even though + our original data had no information about political party preference! + + In some real sense, the embedding "discovered" political preference + from demographic data. + """) return @@ -139,14 +131,12 @@ def _(dataset, pd, rotated_embedding): @app.cell def _(mo): - mo.md( - """ - ### Try it! 👆 + mo.md(""" + ### Try it! 👆 - Select points in the scatter plot below with your cursor: they're - automatically sent back to Python, letting you investigate further! - """ - ) + Select points in the scatter plot below with your cursor: they're + automatically sent back to Python, letting you investigate further! + """) return diff --git a/examples/third_party/unsloth/llama_3_1_8b_2x_faster_finetuning.py b/examples/third_party/unsloth/llama_3_1_8b_2x_faster_finetuning.py index fcb19329467..f5eb8859396 100644 --- a/examples/third_party/unsloth/llama_3_1_8b_2x_faster_finetuning.py +++ b/examples/third_party/unsloth/llama_3_1_8b_2x_faster_finetuning.py @@ -14,7 +14,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="full") @@ -35,42 +35,38 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - - - - - - This example shows how to use [Unsloth](https://github.com/unslothai/unsloth) to finetune Llama-3.1 8b. It uses - marimo's UI elements to make the experience interactive, so you don't need to edit any code! + mo.md(""" + + + + + + This example shows how to use [Unsloth](https://github.com/unslothai/unsloth) to finetune Llama-3.1 8b. It uses + marimo's UI elements to make the experience interactive, so you don't need to edit any code! - _Join Discord if you need help + ⭐ Star us on Github⭐_ + _Join Discord if you need help + ⭐ Star us on Github⭐_ - To install Unsloth on your own computer, follow the installation instructions on our Github page [here](https://github.com/unslothai/unsloth?tab=readme-ov-file#-installation-instructions). + To install Unsloth on your own computer, follow the installation instructions on our Github page [here](https://github.com/unslothai/unsloth?tab=readme-ov-file#-installation-instructions). - You will learn how to do [data prep](#Data), how to [train](#Train), how to [run the model](#Inference), & [how to save it](#Save) (eg for Llama.cpp). + You will learn how to do [data prep](#Data), how to [train](#Train), how to [run the model](#Inference), & [how to save it](#Save) (eg for Llama.cpp). - [NEW] Llama-3.1 8b, 70b & 405b are trained on a crazy 15 trillion tokens with 128K long context lengths! + [NEW] Llama-3.1 8b, 70b & 405b are trained on a crazy 15 trillion tokens with 128K long context lengths! - **[NEW] Try 2x faster inference in a free Colab for Llama-3.1 8b Instruct [here](https://colab.research.google.com/drive/1T-YBVfnphoVc8E2E854qF3jdia2Ll2W2?usp=sharing)** - """ - ) + **[NEW] Try 2x faster inference in a free Colab for Llama-3.1 8b Instruct [here](https://colab.research.google.com/drive/1T-YBVfnphoVc8E2E854qF3jdia2Ll2W2?usp=sharing)** + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - * We support Llama, Mistral, Phi-3, Gemma, Yi, DeepSeek, Qwen, TinyLlama, Vicuna, Open Hermes etc - * We support 16bit LoRA or 4bit QLoRA. Both 2x faster. - * `max_seq_length` can be set to anything, since we do automatic RoPE Scaling via [kaiokendev's](https://kaiokendev.github.io/til) method. - * [**NEW**] We make Gemma-2 9b / 27b **2x faster**! See our [Gemma-2 9b notebook](https://colab.research.google.com/drive/1vIrqH5uYDQwsJ4-OO3DErvuv4pBgVwk4?usp=sharing) - * [**NEW**] To finetune and auto export to Ollama, try our [Ollama notebook](https://colab.research.google.com/drive/1WZDi7APtQ9VsvOrQSSC5DDtxq159j8iZ?usp=sharing) - * [**NEW**] We make Mistral NeMo 12B 2x faster and fit in under 12GB of VRAM! [Mistral NeMo notebook](https://colab.research.google.com/drive/17d3U-CAIwzmbDRqbZ9NnpHxCkmXB6LZ0?usp=sharing) - """ - ) + mo.md(r""" + * We support Llama, Mistral, Phi-3, Gemma, Yi, DeepSeek, Qwen, TinyLlama, Vicuna, Open Hermes etc + * We support 16bit LoRA or 4bit QLoRA. Both 2x faster. + * `max_seq_length` can be set to anything, since we do automatic RoPE Scaling via [kaiokendev's](https://kaiokendev.github.io/til) method. + * [**NEW**] We make Gemma-2 9b / 27b **2x faster**! See our [Gemma-2 9b notebook](https://colab.research.google.com/drive/1vIrqH5uYDQwsJ4-OO3DErvuv4pBgVwk4?usp=sharing) + * [**NEW**] To finetune and auto export to Ollama, try our [Ollama notebook](https://colab.research.google.com/drive/1WZDi7APtQ9VsvOrQSSC5DDtxq159j8iZ?usp=sharing) + * [**NEW**] We make Mistral NeMo 12B 2x faster and fit in under 12GB of VRAM! [Mistral NeMo notebook](https://colab.research.google.com/drive/17d3U-CAIwzmbDRqbZ9NnpHxCkmXB6LZ0?usp=sharing) + """) return @@ -106,7 +102,9 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md(r"""We now add LoRA adapters so we only need to update 1 to 10% of all parameters!""") + mo.md( + r"""We now add LoRA adapters so we only need to update 1 to 10% of all parameters!""" + ) return @@ -145,21 +143,19 @@ def _(FastLanguageModel, dtype, load_in_4bit, max_seq_length): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - - ### Data Prep - We now use the Alpaca dataset from [yahma](https://huggingface.co/datasets/yahma/alpaca-cleaned), which is a filtered version of 52K of the original [Alpaca dataset](https://crfm.stanford.edu/2023/03/13/alpaca.html). You can replace this code section with your own data prep. + mo.md(r""" + + ### Data Prep + We now use the Alpaca dataset from [yahma](https://huggingface.co/datasets/yahma/alpaca-cleaned), which is a filtered version of 52K of the original [Alpaca dataset](https://crfm.stanford.edu/2023/03/13/alpaca.html). You can replace this code section with your own data prep. - **[NOTE]** To train only on completions (ignoring the user's input) read TRL's docs [here](https://huggingface.co/docs/trl/sft_trainer#train-on-completions-only). + **[NOTE]** To train only on completions (ignoring the user's input) read TRL's docs [here](https://huggingface.co/docs/trl/sft_trainer#train-on-completions-only). - **[NOTE]** Remember to add the **EOS_TOKEN** to the tokenized output!! Otherwise you'll get infinite generations! + **[NOTE]** Remember to add the **EOS_TOKEN** to the tokenized output!! Otherwise you'll get infinite generations! - If you want to use the `llama-3` template for ShareGPT datasets, try our conversational [notebook](https://colab.research.google.com/drive/1XamvWYinY6FOSX9GLvnqSjjsNflxdhNc?usp=sharing). + If you want to use the `llama-3` template for ShareGPT datasets, try our conversational [notebook](https://colab.research.google.com/drive/1XamvWYinY6FOSX9GLvnqSjjsNflxdhNc?usp=sharing). - For text completions like novel writing, try this [notebook](https://colab.research.google.com/drive/1ef-tab5bhkvWmBOObepl1WgJvfvSzn5Q?usp=sharing). - """ - ) + For text completions like novel writing, try this [notebook](https://colab.research.google.com/drive/1ef-tab5bhkvWmBOObepl1WgJvfvSzn5Q?usp=sharing). + """) return @@ -207,12 +203,10 @@ def formatting_prompts_func(examples): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ### Train the model - Now let's use Huggingface TRL's `SFTTrainer`! More docs here: [TRL SFT docs](https://huggingface.co/docs/trl/sft_trainer). We do 60 steps to speed things up, but you can set `num_train_epochs=1` for a full run, and turn off `max_steps=None`. We also support TRL's `DPOTrainer`! - """ - ) + mo.md(r""" + ### Train the model + Now let's use Huggingface TRL's `SFTTrainer`! More docs here: [TRL SFT docs](https://huggingface.co/docs/trl/sft_trainer). We do 60 steps to speed things up, but you can set `num_train_epochs=1` for a full run, and turn off `max_steps=None`. We also support TRL's `DPOTrainer`! + """) return @@ -302,15 +296,13 @@ def _(max_memory, mo, start_gpu_memory, torch, trainer_stats): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - - ### Inference - Let's run the model! You can change the instruction and input - leave the output blank! + mo.md(r""" + + ### Inference + Let's run the model! You can change the instruction and input - leave the output blank! - **[NEW] Try 2x faster inference in a free Colab for Llama-3.1 8b Instruct [here](https://colab.research.google.com/drive/1T-YBVfnphoVc8E2E854qF3jdia2Ll2W2?usp=sharing)** - """ - ) + **[NEW] Try 2x faster inference in a free Colab for Llama-3.1 8b Instruct [here](https://colab.research.google.com/drive/1T-YBVfnphoVc8E2E854qF3jdia2Ll2W2?usp=sharing)** + """) return @@ -355,31 +347,29 @@ def _(FastLanguageModel, alpaca_prompt, inf_instr_inp, mo, model, tokenizer): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - And we're done! If you have any questions on Unsloth, we have a [Discord](https://discord.gg/u54VK8m8tk) channel! If you find any bugs or want to keep updated with the latest LLM stuff, or need help, join projects etc, feel free to join our Discord! - - Some other links: - 1. Zephyr DPO 2x faster [free Colab](https://colab.research.google.com/drive/15vttTpzzVXv_tJwEk-hIcQ0S9FcEWvwP?usp=sharing) - 2. Llama 7b 2x faster [free Colab](https://colab.research.google.com/drive/1lBzz5KeZJKXjvivbYvmGarix9Ao6Wxe5?usp=sharing) - 3. TinyLlama 4x faster full Alpaca 52K in 1 hour [free Colab](https://colab.research.google.com/drive/1AZghoNBQaMDgWJpi4RbffGM1h6raLUj9?usp=sharing) - 4. CodeLlama 34b 2x faster [A100 on Colab](https://colab.research.google.com/drive/1y7A0AxE3y8gdj4AVkl2aZX47Xu3P1wJT?usp=sharing) - 5. Mistral 7b [free Kaggle version](https://www.kaggle.com/code/danielhanchen/kaggle-mistral-7b-unsloth-notebook) - 6. We also did a [blog](https://huggingface.co/blog/unsloth-trl) with 🤗 HuggingFace, and we're in the TRL [docs](https://huggingface.co/docs/trl/main/en/sft_trainer#accelerate-fine-tuning-2x-using-unsloth)! - 7. `ChatML` for ShareGPT datasets, [conversational notebook](https://colab.research.google.com/drive/1Aau3lgPzeZKQ-98h69CCu1UJcvIBLmy2?usp=sharing) - 8. Text completions like novel writing [notebook](https://colab.research.google.com/drive/1ef-tab5bhkvWmBOObepl1WgJvfvSzn5Q?usp=sharing) - 9. [**NEW**] We make Phi-3 Medium / Mini **2x faster**! See our [Phi-3 Medium notebook](https://colab.research.google.com/drive/1hhdhBa1j_hsymiW9m-WzxQtgqTH_NHqi?usp=sharing) - 10. [**NEW**] We make Gemma-2 9b / 27b **2x faster**! See our [Gemma-2 9b notebook](https://colab.research.google.com/drive/1vIrqH5uYDQwsJ4-OO3DErvuv4pBgVwk4?usp=sharing) - 11. [**NEW**] To finetune and auto export to Ollama, try our [Ollama notebook](https://colab.research.google.com/drive/1WZDi7APtQ9VsvOrQSSC5DDtxq159j8iZ?usp=sharing) - 12. [**NEW**] We make Mistral NeMo 12B 2x faster and fit in under 12GB of VRAM! [Mistral NeMo notebook](https://colab.research.google.com/drive/17d3U-CAIwzmbDRqbZ9NnpHxCkmXB6LZ0?usp=sharing) - -
- - - Support our work if you can! Thanks! -
- """ - ) + mo.md(r""" + And we're done! If you have any questions on Unsloth, we have a [Discord](https://discord.gg/u54VK8m8tk) channel! If you find any bugs or want to keep updated with the latest LLM stuff, or need help, join projects etc, feel free to join our Discord! + + Some other links: + 1. Zephyr DPO 2x faster [free Colab](https://colab.research.google.com/drive/15vttTpzzVXv_tJwEk-hIcQ0S9FcEWvwP?usp=sharing) + 2. Llama 7b 2x faster [free Colab](https://colab.research.google.com/drive/1lBzz5KeZJKXjvivbYvmGarix9Ao6Wxe5?usp=sharing) + 3. TinyLlama 4x faster full Alpaca 52K in 1 hour [free Colab](https://colab.research.google.com/drive/1AZghoNBQaMDgWJpi4RbffGM1h6raLUj9?usp=sharing) + 4. CodeLlama 34b 2x faster [A100 on Colab](https://colab.research.google.com/drive/1y7A0AxE3y8gdj4AVkl2aZX47Xu3P1wJT?usp=sharing) + 5. Mistral 7b [free Kaggle version](https://www.kaggle.com/code/danielhanchen/kaggle-mistral-7b-unsloth-notebook) + 6. We also did a [blog](https://huggingface.co/blog/unsloth-trl) with 🤗 HuggingFace, and we're in the TRL [docs](https://huggingface.co/docs/trl/main/en/sft_trainer#accelerate-fine-tuning-2x-using-unsloth)! + 7. `ChatML` for ShareGPT datasets, [conversational notebook](https://colab.research.google.com/drive/1Aau3lgPzeZKQ-98h69CCu1UJcvIBLmy2?usp=sharing) + 8. Text completions like novel writing [notebook](https://colab.research.google.com/drive/1ef-tab5bhkvWmBOObepl1WgJvfvSzn5Q?usp=sharing) + 9. [**NEW**] We make Phi-3 Medium / Mini **2x faster**! See our [Phi-3 Medium notebook](https://colab.research.google.com/drive/1hhdhBa1j_hsymiW9m-WzxQtgqTH_NHqi?usp=sharing) + 10. [**NEW**] We make Gemma-2 9b / 27b **2x faster**! See our [Gemma-2 9b notebook](https://colab.research.google.com/drive/1vIrqH5uYDQwsJ4-OO3DErvuv4pBgVwk4?usp=sharing) + 11. [**NEW**] To finetune and auto export to Ollama, try our [Ollama notebook](https://colab.research.google.com/drive/1WZDi7APtQ9VsvOrQSSC5DDtxq159j8iZ?usp=sharing) + 12. [**NEW**] We make Mistral NeMo 12B 2x faster and fit in under 12GB of VRAM! [Mistral NeMo notebook](https://colab.research.google.com/drive/17d3U-CAIwzmbDRqbZ9NnpHxCkmXB6LZ0?usp=sharing) + +
+ + + Support our work if you can! Thanks! +
+ """) return diff --git a/examples/ui/arrays_and_dicts.py b/examples/ui/arrays_and_dicts.py index 55061b06a14..2bdcdc6b178 100644 --- a/examples/ui/arrays_and_dicts.py +++ b/examples/ui/arrays_and_dicts.py @@ -7,7 +7,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -26,16 +26,14 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Use `mo.ui.array` and `mo.ui.dictionary` to create UI elements that wrap - other elements. - - Because UI elements must be assigned to global variables, - these functions are required when the set of elements to create is not - known until runtime. - """ - ) + mo.md(""" + Use `mo.ui.array` and `mo.ui.dictionary` to create UI elements that wrap + other elements. + + Because UI elements must be assigned to global variables, + these functions are required when the set of elements to create is not + known until runtime. + """) return @@ -87,13 +85,11 @@ def _(array, dictionary, mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - Key difference between marimo dict and standard python dict: + mo.md(r""" + Key difference between marimo dict and standard python dict: - The main reason to use `mo.ui.dictionary` is for reactive execution — when you interact with an element in a `mo.ui.dictionary`, all cells that reference the `mo.ui.dictionary` run automatically, just like all other ui elements. When you use a regular dictionary, you don't get this reactivity. - """ - ) + The main reason to use `mo.ui.dictionary` is for reactive execution — when you interact with an element in a `mo.ui.dictionary`, all cells that reference the `mo.ui.dictionary` run automatically, just like all other ui elements. When you use a regular dictionary, you don't get this reactivity. + """) return @@ -146,7 +142,9 @@ def _(mo, mo_d, py_d): @app.cell(hide_code=True) def _(mo): - mo.md(r"""Notice that when you interact with the UI elements in the marimo dict, the reference of marimo dict updates automatically. However, when you interact with the elements in the python dict, you need to manually re-run the cell to see the updated values.""") + mo.md( + r"""Notice that when you interact with the UI elements in the marimo dict, the reference of marimo dict updates automatically. However, when you interact with the elements in the python dict, you need to manually re-run the cell to see the updated values.""" + ) return diff --git a/examples/ui/batch_and_form.py b/examples/ui/batch_and_form.py index 416109d12fc..a41c2d5ee88 100644 --- a/examples/ui/batch_and_form.py +++ b/examples/ui/batch_and_form.py @@ -7,7 +7,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -25,12 +25,10 @@ def _(mo): @app.cell def _(mo): - mo.md( - """ - Make custom UI elements using `batch()`, and turn any UI element - into a form with `form()`. - """ - ) + mo.md(""" + Make custom UI elements using `batch()`, and turn any UI element + into a form with `form()`. + """) return diff --git a/examples/ui/data_editor.py b/examples/ui/data_editor.py index 838fad6c803..5ecc4559993 100644 --- a/examples/ui/data_editor.py +++ b/examples/ui/data_editor.py @@ -1,6 +1,6 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @@ -38,7 +38,9 @@ def _(DATA_FILE, mo, os): @app.cell(hide_code=True) def _(mo): - mo.md("""The following cell writes the updated dataframe to disk when the submit button is clicked.""") + mo.md( + """The following cell writes the updated dataframe to disk when the submit button is clicked.""" + ) return diff --git a/examples/ui/image_comparison_demo.py b/examples/ui/image_comparison_demo.py index 78beaed76f8..01ad5186b58 100644 --- a/examples/ui/image_comparison_demo.py +++ b/examples/ui/image_comparison_demo.py @@ -9,14 +9,13 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" # Image Comparison Demo This demo showcases the `mo.image_compare` feature, which allows for side-by-side comparison of images. @@ -24,8 +23,7 @@ def _(mo): ## Basic Usage - Horizontal Comparison The default orientation is horizontal, where you can slide left and right to compare images: - """ - ) + """) return @@ -45,13 +43,11 @@ def _(after_image_path, before_image_path, mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" ## Custom Initial Position You can set the initial position of the slider: - """ - ) + """) return @@ -68,13 +64,11 @@ def _(after_image_path, before_image_path, mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" ## Vertical Comparison You can also use a vertical comparison slider: - """ - ) + """) return diff --git a/examples/ui/layout.py b/examples/ui/layout.py index 5451b7528a5..ccc811258c8 100644 --- a/examples/ui/layout.py +++ b/examples/ui/layout.py @@ -7,7 +7,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -19,7 +19,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md("""Use `mo.hstack` and `mo.vstack` to layout outputs in rows and columns.""") + mo.md( + """Use `mo.hstack` and `mo.vstack` to layout outputs in rows and columns.""" + ) return diff --git a/examples/ui/table_advanced.py b/examples/ui/table_advanced.py index dca2d37383e..7d2f43a4f84 100644 --- a/examples/ui/table_advanced.py +++ b/examples/ui/table_advanced.py @@ -7,7 +7,7 @@ import marimo -__generated_with = "0.16.0" +__generated_with = "0.17.2" app = marimo.App() @@ -19,14 +19,12 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Tables + mo.md(""" + # Tables - > “Sometimes I’ll start a sentence and I don’t even know where it’s going. I just hope I find it along the way.” - — Michael Scott - """ - ) + > “Sometimes I’ll start a sentence and I don’t even know where it’s going. I just hope I find it along the way.” + — Michael Scott + """) return diff --git a/frontend/src/core/codemirror/language/__tests__/extension.test.ts b/frontend/src/core/codemirror/language/__tests__/extension.test.ts index ee1f621f868..ca082a42776 100644 --- a/frontend/src/core/codemirror/language/__tests__/extension.test.ts +++ b/frontend/src/core/codemirror/language/__tests__/extension.test.ts @@ -163,23 +163,19 @@ describe("switchLanguage", () => { // Switch back to python switchLanguage(mockEditor, { language: "python", keepCodeAsIs: false }); expect(mockEditor.state.doc.toString()).toMatchInlineSnapshot(` - "mo.md( - r""" + "mo.md(r""" print('Hello') print('Goodbye') - """ - )" + """)" `); // Switch to sql switchLanguage(mockEditor, { language: "sql", keepCodeAsIs: false }); expect(mockEditor.state.doc.toString()).toMatchInlineSnapshot(` - "mo.md( - r""" + "mo.md(r""" print('Hello') print('Goodbye') - """ - )" + """)" `); // Switch back to python @@ -187,12 +183,10 @@ describe("switchLanguage", () => { expect(mockEditor.state.doc.toString()).toMatchInlineSnapshot(` "_df = mo.sql( f""" - mo.md( - r\\""" + mo.md(r\\""" print('Hello') print('Goodbye') - \\""" - ) + \\""") """ )" `); diff --git a/frontend/src/core/codemirror/language/__tests__/markdown.test.ts b/frontend/src/core/codemirror/language/__tests__/markdown.test.ts index 16a0da963b8..8c2f5b18ebe 100644 --- a/frontend/src/core/codemirror/language/__tests__/markdown.test.ts +++ b/frontend/src/core/codemirror/language/__tests__/markdown.test.ts @@ -185,11 +185,10 @@ describe("MarkdownLanguageAdapter", () => { }); it("should preserve indentation in f-strings", () => { - const pythonCode = - 'mo.md(\n f"""\n```python\n{some_variable}\n```\n"""\n)'; + const pythonCode = 'mo.md(f"""\n```python\n{some_variable}\n```\n""")'; const [innerCode, offset, metadata] = adapter.transformIn(pythonCode); expect(innerCode).toBe("```python\n{some_variable}\n```"); - expect(offset).toBe(15); + expect(offset).toBe(10); expect(metadata.quotePrefix).toBe("f"); // Transform out @@ -198,7 +197,7 @@ describe("MarkdownLanguageAdapter", () => { metadata, ); expect(outerCode).toMatch(pythonCode); - expect(outerOffset).toBe(17); + expect(outerOffset).toBe(12); }); it("should handle f-strings", () => { @@ -252,41 +251,35 @@ describe("MarkdownLanguageAdapter", () => { const code = '"Hello" world'; const [wrappedCode, offset] = adapter.transformOut(code, metadata); expect(wrappedCode).toMatchInlineSnapshot(` - "mo.md( - """ + "mo.md(""" "Hello" world - """ - )" + """)" `); - expect(offset).toBe(16); + expect(offset).toBe(11); }); it("ends with quote", () => { const code = 'Hello "world"'; const [wrappedCode, offset] = adapter.transformOut(code, metadata); expect(wrappedCode).toMatchInlineSnapshot(` - "mo.md( - """ + "mo.md(""" Hello "world" - """ - )" + """)" `); - expect(offset).toBe(16); + expect(offset).toBe(11); }); it("should wrap Markdown code with triple double-quoted string format", () => { const code = "# Markdown Title\n\nSome content here."; const [wrappedCode, offset] = adapter.transformOut(code, metadata); expect(wrappedCode).toMatchInlineSnapshot(` - "mo.md( - """ + "mo.md(""" # Markdown Title Some content here. - """ - )" + """)" `); - expect(offset).toBe(16); + expect(offset).toBe(11); }); it("should escape triple quotes in the Markdown code", () => { @@ -312,14 +305,12 @@ describe("MarkdownLanguageAdapter", () => { metadata.quotePrefix = "f"; const [wrappedCode, offset] = adapter.transformOut(code, metadata); expect(wrappedCode).toMatchInlineSnapshot(` - "mo.md( - f""" + "mo.md(f""" # Title {some_variable} - """ - )" + """)" `); - expect(offset).toBe(17); + expect(offset).toBe(12); }); it("should handle rf-strings in transformOut", () => { @@ -327,14 +318,12 @@ describe("MarkdownLanguageAdapter", () => { metadata.quotePrefix = "rf"; const [wrappedCode, offset] = adapter.transformOut(code, metadata); expect(wrappedCode).toMatchInlineSnapshot(` - "mo.md( - rf""" + "mo.md(rf""" # Title {some_variable} - """ - )" + """)" `); - expect(offset).toBe(18); + expect(offset).toBe(13); }); }); @@ -369,13 +358,11 @@ describe("MarkdownLanguageAdapter", () => { it("should return true for complex nested markdown", () => { const pythonCode = String.raw` - mo.md( - rf""" - \`\`\`python - {pathlib.Path(__file__).read_text(encoding="utf-8")} - \`\`\` - """ - ) + mo.md(rf""" + \`\`\`python + {pathlib.Path(__file__).read_text(encoding="utf-8")} + \`\`\` + """) `; expect(adapter.isSupported(pythonCode)).toBe(true); }); diff --git a/marimo/_ast/codegen.py b/marimo/_ast/codegen.py index 6e69e95f16b..9adecfd5583 100644 --- a/marimo/_ast/codegen.py +++ b/marimo/_ast/codegen.py @@ -2,10 +2,12 @@ from __future__ import annotations import ast +import io import os import re import sys import textwrap +import tokenize from typing import TYPE_CHECKING, Any, Literal, Optional from marimo import _loggers @@ -84,6 +86,7 @@ def format_tuple_elements( elems: tuple[str, ...], indent: bool = False, allowed_naked: bool = False, + trail_comma: bool = True, brace: Literal["(", "["] = "(", ) -> str: """ @@ -92,6 +95,7 @@ def format_tuple_elements( """ left, right = BRACES[brace] maybe_indent = indent_text if indent else (lambda x: x) + suffix = "," if trail_comma else "" if not elems: if allowed_naked: return maybe_indent(code.replace("(...)", "").rstrip()) @@ -99,7 +103,7 @@ def format_tuple_elements( if allowed_naked and len(elems) == 1: allowed_naked = False - elems = (f"{elems[0]},",) + elems = (f"{elems[0]}{suffix}",) tuple_str = ", ".join(elems) if allowed_naked: @@ -116,7 +120,7 @@ def format_tuple_elements( elems = (elems[0].strip(","),) multiline_tuple = "\n".join( - [left, indent_text(",\n".join(elems)) + ",", right] + [left, indent_text(",\n".join(elems)) + suffix, right] ) return maybe_indent(code.replace("(...)", multiline_tuple)) @@ -138,6 +142,78 @@ def to_decorator( ) +def format_markdown(cell: CellImpl) -> str: + markdown = cell.markdown or "" + # AST does not preserve string quote types or types, so directly use + # tokenize. + tokens = tokenize.tokenize(io.BytesIO(cell.code.encode("utf-8")).readline) + tag = "" + quote = '"' + # Comment capture + comments = { + "prefix": "", + "suffix": "", + } + key: Optional[str] = "prefix" + tokenizes_fstring = sys.version_info >= (3, 12) + start_tokens = ( + (tokenize.STRING, tokenize.FSTRING_START) + if tokenizes_fstring + else (tokenize.STRING,) + ) + fstring = False + for tok in tokens: + # if string + if tok.type in start_tokens: + tag = "" + # rf"""/ f"/ r"/ "more + start = tok.string[:5] + for _ in range(2): + if start[0].lower() in "rtf": + tag += start[0] + start = start[1:] + quote = start[0] + if start[:3] == quote * 3: + quote = start[:3] + fstring = "f" in tag.lower() + elif tok.string == "mo": + key = None + elif tok.string == ")": + key = "suffix" + elif key in comments and tok.type != tokenize.ENCODING: + comments[key] += tok.string + + if fstring: + # We can blanket replace, because cell.markdown is not set + # on f-strings with values. + markdown = markdown.replace("{", "{{").replace("}", "}}") + + body = construct_markdown_call(markdown, quote, tag) + return "".join([comments["prefix"], body, comments["suffix"]]) + + +def construct_markdown_call(markdown: str, quote: str, tag: str) -> str: + # If quotes are on either side, we need to use the multiline format. + quote_type = quote[:1] + bounded_by_quotes = markdown.startswith(quote_type) or markdown.endswith( + quote_type + ) + + if (len(quote) == 3 and "\n" in markdown) or bounded_by_quotes: + return "\n".join( + [ + f"mo.md({tag}{quote}", + markdown, + f"{quote})", + ] + ) + return format_tuple_elements( + "mo.md(...)", + (f"{tag}{quote}{markdown}{quote}",), + trail_comma=False, + ) + + def build_setup_section(setup_cell: Optional[CellImpl]) -> str: if setup_cell is None: return "" @@ -260,7 +336,10 @@ def to_functiondef( signature = format_tuple_elements(f"{prefix}def {name}(...):", refs) definition_body = [decorator, signature] - if body := indent_text(cell.code): + # Handle markdown cells with formatting + if cell.markdown: + definition_body.append(indent_text(format_markdown(cell))) + elif body := indent_text(cell.code): definition_body.append(body) returns = format_tuple_elements( diff --git a/marimo/_convert/utils.py b/marimo/_convert/utils.py index 06b93f52763..31f47e091fe 100644 --- a/marimo/_convert/utils.py +++ b/marimo/_convert/utils.py @@ -13,23 +13,7 @@ def markdown_to_marimo(source: str) -> str: # 6 quotes in a row breaks if not source: source = " " - - # If quotes are on either side, we need to use the multiline format. - bounded_by_quotes = source.startswith('"') or source.endswith('"') - - if "\n" not in source and not bounded_by_quotes: - return f'mo.md(r"""{source}""")' - - return "\n".join( - [ - "mo.md(", - # r-string: a backslash is just a backslash! - codegen.indent_text('r"""'), - source, - '"""', - ")", - ] - ) + return codegen.construct_markdown_call(source, '"""', "r") def sql_to_marimo( diff --git a/marimo/_lint/context.py b/marimo/_lint/context.py index e593358079a..9df6a5d182e 100644 --- a/marimo/_lint/context.py +++ b/marimo/_lint/context.py @@ -33,11 +33,13 @@ class LintContext: def __init__( self, notebook: NotebookSerialization, + contents: str = "", stderr: str = "", stdout: str = "", logs: list[logging.LogRecord] | None = None, ): self.notebook = notebook + self.contents = contents.splitlines() self._diagnostics: list[tuple[int, int, Diagnostic]] = [] self._graph: DirectedGraph | None = None self._graph_lock = threading.Lock() @@ -269,6 +271,11 @@ def get_graph(self) -> DirectedGraph: """Access to the dependency graph.""" return self.global_context.get_graph() + @property + def contents(self) -> list[str]: + """Access to file contents being linted.""" + return self.global_context.contents + @property def notebook(self) -> NotebookSerialization: """Access to the notebook being linted.""" diff --git a/marimo/_lint/linter.py b/marimo/_lint/linter.py index eabc5ae9488..641c0ee9e10 100644 --- a/marimo/_lint/linter.py +++ b/marimo/_lint/linter.py @@ -25,7 +25,7 @@ from marimo._lint.rules.base import LintRule -def _contents_differ_excluding_generated_with( +def contents_differ_excluding_generated_with( original: str, generated: str ) -> bool: """Compare file contents while ignoring __generated_with differences. @@ -183,6 +183,7 @@ async def _process_single_file(self, file: Path) -> FileStatus: file_status.diagnostics = ( await self.rule_engine.check_notebook( load_result.notebook, + load_result.contents or "", # Add parsing rule if there's captured output stdout=stdout.getvalue().strip(), stderr=stderr.getvalue().strip(), @@ -351,7 +352,7 @@ async def fix(self, file_status: FileStatus) -> bool: ) # Only write if content changed (excluding __generated_with differences) - if _contents_differ_excluding_generated_with( + if contents_differ_excluding_generated_with( file_status.contents, generated_contents ): await asyncio.to_thread( diff --git a/marimo/_lint/rule_engine.py b/marimo/_lint/rule_engine.py index 27c1ec68ab3..5b3cb92668a 100644 --- a/marimo/_lint/rule_engine.py +++ b/marimo/_lint/rule_engine.py @@ -66,12 +66,13 @@ def __init__( async def check_notebook_streaming( self, notebook: NotebookSerialization, + contents: str = "", stdout: str = "", stderr: str = "", logs: list[logging.LogRecord] | None = None, ) -> AsyncIterator[Diagnostic]: """Check notebook and yield diagnostics as they become available.""" - ctx = LintContext(notebook, stdout, stderr, logs) + ctx = LintContext(notebook, contents, stdout, stderr, logs) # Create tasks for all rules with their completion tracking pending_tasks = { @@ -115,6 +116,7 @@ async def check_notebook_streaming( async def check_notebook( self, notebook: NotebookSerialization, + contents: str = "", stdout: str = "", stderr: str = "", logs: list[logging.LogRecord] | None = None, @@ -122,7 +124,7 @@ async def check_notebook( """Check notebook for all lint rule violations using async execution.""" diagnostics = [] async for diagnostic in self.check_notebook_streaming( - notebook, stdout, stderr, logs + notebook, contents, stdout, stderr, logs ): diagnostics.append(diagnostic) return diagnostics diff --git a/marimo/_lint/rules/formatting/__init__.py b/marimo/_lint/rules/formatting/__init__.py index cd79b20446d..1c36d762968 100644 --- a/marimo/_lint/rules/formatting/__init__.py +++ b/marimo/_lint/rules/formatting/__init__.py @@ -4,6 +4,7 @@ from marimo._lint.rules.base import LintRule, UnsafeFixRule from marimo._lint.rules.formatting.empty_cells import EmptyCellRule from marimo._lint.rules.formatting.general import GeneralFormattingRule +from marimo._lint.rules.formatting.markdown_dedent import MarkdownDedentRule from marimo._lint.rules.formatting.parsing import ( MiscLogRule, SqlParseRule, @@ -18,6 +19,7 @@ "MF004": EmptyCellRule, "MF005": SqlParseRule, "MF006": MiscLogRule, + "MF007": MarkdownDedentRule, } __all__ = [ @@ -28,5 +30,6 @@ "EmptyCellRule", "SqlParseRule", "MiscLogRule", + "MarkdownDedentRule", "UnsafeFixRule", ] diff --git a/marimo/_lint/rules/formatting/markdown_dedent.py b/marimo/_lint/rules/formatting/markdown_dedent.py new file mode 100644 index 00000000000..bd0cf751ebe --- /dev/null +++ b/marimo/_lint/rules/formatting/markdown_dedent.py @@ -0,0 +1,128 @@ +# Copyright 2025 Marimo. All rights reserved. +from __future__ import annotations + +from typing import TYPE_CHECKING + +from marimo._ast.codegen import format_markdown +from marimo._lint.diagnostic import Diagnostic, Severity +from marimo._lint.rules.base import LintRule + +if TYPE_CHECKING: + from marimo._lint.context import RuleContext + + +class MarkdownDedentRule(LintRule): + """MF007: Markdown strings in `mo.md()` should be properly indented. + + This rule detects markdown strings in `mo.md()` calls that have unnecessary + leading indentation. Proper markdown indentation improves readability and produces + cleaner diffs in version control. + + ## What it does + + Checks cells containing `mo.md()` calls to see if the markdown string + content has unnecessary leading whitespace that should be removed. + + ## Why is this bad? + + Indented markdown strings: + - Are harder to read when viewing the source code + - Produce larger diffs when making changes + - Don't match the standard marimo formatting style + - Can be confusing when the indentation doesn't reflect the markdown structure + + ## Examples + + **Problematic:** + ```python + mo.md( + r\"\"\" + # Title + + Some content here. + \"\"\" + ) + ``` + + **Solution:** + ```python + mo.md(r\"\"\" + # Title + + Some content here. + \"\"\") + ``` + + **Note:** This fix is automatically applied with `marimo check --fix`. + + ## References + + - [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) + - [Best Practices](https://docs.marimo.io/guides/best_practices/) + """ + + code = "MF007" + name = "markdown-indentation" + description = "Markdown cells in `mo.md()` should be properly indented." + severity = Severity.FORMATTING + fixable = True + + async def check(self, ctx: RuleContext) -> None: + """Check for markdown cells with indented content.""" + from marimo._lint.linter import ( + contents_differ_excluding_generated_with, + ) + + graph = ctx.get_graph() + + # Check each cell in the graph + for cell in graph.cells.values(): + # Only check markdown cells + if cell.markdown is None: + continue + + notebook_cell = None + for nb_cell in ctx.notebook.cells: + if nb_cell.code.strip() == cell.code.strip(): + notebook_cell = nb_cell + break + + if not notebook_cell: + return + + # Check if the markdown string needs dedenting + # Use tokenize like codegen does to extract quote style + needs_dedent = contents_differ_excluding_generated_with( + format_markdown(cell), cell.code + ) + + # Only applicable in python context + overly_dedented = False + if ctx.notebook.filename and ctx.notebook.filename.endswith(".py"): + line_count = len(cell.code.splitlines()) + line_start = notebook_cell.lineno + 1 + overly_dedented = any( + [ + line[0] != " " + for line in ctx.contents[ + line_start : line_start + line_count + ] + if line + ] + ) + + if needs_dedent or overly_dedented: + # Find the corresponding notebook cell for position info + notebook_cell = None + for nb_cell in ctx.notebook.cells: + if nb_cell.code.strip() == cell.code.strip(): + notebook_cell = nb_cell + break + + if notebook_cell: + diagnostic = Diagnostic( + message="Markdown cell should be dedented for better readability", + line=notebook_cell.lineno - 1, + column=notebook_cell.col_offset + 1, + ) + await ctx.add_diagnostic(diagnostic) diff --git a/marimo/_server/export/exporter.py b/marimo/_server/export/exporter.py index 57808baa094..27d3e6ccd1e 100644 --- a/marimo/_server/export/exporter.py +++ b/marimo/_server/export/exporter.py @@ -248,7 +248,6 @@ def export_as_md( filename: Optional[str], previous: Path | None = None, ) -> tuple[str, str]: - from marimo._ast import codegen from marimo._ast.app_config import _AppConfig from marimo._ast.compiler import compile_cell from marimo._convert.markdown.markdown import ( @@ -361,6 +360,10 @@ def export_as_md( previous_was_markdown = True document.append(markdown) continue + # In which case we need to format it like our python blocks. + elif cell_impl.markdown: + code = codegen.format_markdown(cell_impl) + attributes["language"] = language # Definitely a code cell, but need to determine if it can be # formatted as non-python. diff --git a/marimo/_smoke_tests/cache_kwargs.py b/marimo/_smoke_tests/cache_kwargs.py new file mode 100644 index 00000000000..97d18c61798 --- /dev/null +++ b/marimo/_smoke_tests/cache_kwargs.py @@ -0,0 +1,60 @@ +import marimo + +__generated_with = "0.15.5" +app = marimo.App(width="medium") + + +@app.cell +def _(): + import marimo as mo + return (mo,) + + +@app.cell +def _(): + kw = {"some_kw_arg": 30} + some_arg1 = 1 + return (kw,) + + +@app.cell +def _(): + 1 + return + + +@app.cell +def _(mo): + class C: + @mo.persistent_cache + def my_cached_func(self, *args, **kwargs): + return args[0] + kwargs["some_kw_arg"] + + + my_cached_func = C().my_cached_func + return (my_cached_func,) + + +@app.cell +def _(kw, my_cached_func): + # Expect (persistent) caching correctly capture changes in kw, but it doesn't. + # breakpoint() + my_cached_func(**kw) + return + + +@app.cell +def _(my_cached_func): + my_cached_func.hits + return + + +@app.cell +def _(): + + + return + + +if __name__ == "__main__": + app.run() diff --git a/marimo/_tutorials/dataflow.py b/marimo/_tutorials/dataflow.py index 13ca869fa0a..097c39bacca 100644 --- a/marimo/_tutorials/dataflow.py +++ b/marimo/_tutorials/dataflow.py @@ -10,78 +10,70 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # How marimo notebooks run + mo.md(""" + # How marimo notebooks run - Reactive execution is based on a single rule: when a cell is run, all other - cells that reference any of the global variables it defines run - automatically. + Reactive execution is based on a single rule: when a cell is run, all other + cells that reference any of the global variables it defines run + automatically. - To provide reactive execution, marimo creates a dataflow graph out of your - cells. - """ - ) + To provide reactive execution, marimo creates a dataflow graph out of your + cells. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - **Tip: disabling automatic execution.** + mo.md(r""" + **Tip: disabling automatic execution.** - marimo lets you disable automatic execution: in the notebook - footer, change "On Cell Change" to "lazy". + marimo lets you disable automatic execution: in the notebook + footer, change "On Cell Change" to "lazy". - When the runtime is lazy, after running a cell, marimo marks its - descendants as stale instead of automatically running them. The lazy - runtime puts you in control over when cells are run, while still giving - guarantees about the notebook state. - """ - ) + When the runtime is lazy, after running a cell, marimo marks its + descendants as stale instead of automatically running them. The lazy + runtime puts you in control over when cells are run, while still giving + guarantees about the notebook state. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## References and definitions + mo.md(""" + ## References and definitions - A marimo notebook is a directed acyclic graph in which nodes represent - cells and edges represent data dependencies. marimo creates this graph by - analyzing each cell (without running it) to determine its + A marimo notebook is a directed acyclic graph in which nodes represent + cells and edges represent data dependencies. marimo creates this graph by + analyzing each cell (without running it) to determine its - - references ("refs*), the global variables it reads but doesn't define; - - definitions ("defs"), the global variables it defines. + - references ("refs*), the global variables it reads but doesn't define; + - definitions ("defs"), the global variables it defines. - There is an edge from one cell to another if the latter cell references any - global variables defined by the former cell. + There is an edge from one cell to another if the latter cell references any + global variables defined by the former cell. - The rule for reactive execution can be restated in terms of the graph: when - a cell is run, its descendants are run automatically. - """ - ) + The rule for reactive execution can be restated in terms of the graph: when + a cell is run, its descendants are run automatically. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Example + mo.md(""" + ### Example - The next four cells plot a sine wave with a given period and amplitude. - Each cell is labeled with its refs and defs. - """ - ) + The next four cells plot a sine wave with a given period and amplitude. + Each cell is labeled with its refs and defs. + """) return @@ -167,89 +159,79 @@ def plot_wave(amplitude, period): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - 🌊 **Try it!** In the above cells, try changing the value `period` or - `amplitude`, then click the run button ( ▷ ) to register your changes. - See what happens to the sine wave. - """ - ) + mo.md(""" + 🌊 **Try it!** In the above cells, try changing the value `period` or + `amplitude`, then click the run button ( ▷ ) to register your changes. + See what happens to the sine wave. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Here is the dataflow graph for the cells that make the sine wave plot, plus - the cells that import libraries. Each cell is labeled with its defs. - - ``` - +------+ +-----------+ - +-----------| {mo} |-----------+ | {np, plt} | - | +---+--+ | +----+------+ - | | | | - | | | | - v v v v - +----------+ +-------------+ +--+----------+ - | {period} | | {amplitude} | | {plot_wave} | - +---+------+ +-----+-------+ +------+------+ - | | | - | v | - | +----+ | - +------------> | {} | <-------------+ - +----+ - ``` - - The last cell, which doesn't define anything, produces the plot. - """ - ) + mo.md(""" + Here is the dataflow graph for the cells that make the sine wave plot, plus + the cells that import libraries. Each cell is labeled with its defs. + + ``` + +------+ +-----------+ + +-----------| {mo} |-----------+ | {np, plt} | + | +---+--+ | +----+------+ + | | | | + | | | | + v v v v + +----------+ +-------------+ +--+----------+ + | {period} | | {amplitude} | | {plot_wave} | + +---+------+ +-----+-------+ +------+------+ + | | | + | v | + | +----+ | + +------------> | {} | <-------------+ + +----+ + ``` + + The last cell, which doesn't define anything, produces the plot. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Dataflow programming + mo.md(""" + ## Dataflow programming - marimo's runtime rule has some important consequences that may seem - surprising if you are not used to dataflow programming. We list these - below. - """ - ) + marimo's runtime rule has some important consequences that may seem + surprising if you are not used to dataflow programming. We list these + below. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Execution order is not cell order + mo.md(""" + ### Execution order is not cell order - The order in which cells are executed is determined entirely by the - dataflow graph. This makes marimo notebooks more reproducible than - traditional notebooks. It also lets you place boilerplate, like - imports or long markdown strings, at the bottom of the editor. - """ - ) + The order in which cells are executed is determined entirely by the + dataflow graph. This makes marimo notebooks more reproducible than + traditional notebooks. It also lets you place boilerplate, like + imports or long markdown strings, at the bottom of the editor. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Global variable names must be unique + mo.md(""" + ### Global variable names must be unique - Every global variable can be defined by only one cell. Without this - constraint, there would be no way for marimo to know which order to - execute cells in. + Every global variable can be defined by only one cell. Without this + constraint, there would be no way for marimo to know which order to + execute cells in. - If you violate this constraint, marimo provides a helpful - error message, like below: - """ - ) + If you violate this constraint, marimo provides a helpful + error message, like below: + """) return @@ -269,27 +251,23 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - **🌊 Try it!** In the previous cell, change the name `planet` to `home`, - then run the cell. - """ - ) + mo.md(""" + **🌊 Try it!** In the previous cell, change the name `planet` to `home`, + then run the cell. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - Because defs must be unique, global variables cannot be modified with - operators like `+=` or `-=` in cells other than the one that created - them; these operators count as redefinitions of a name. + mo.md(""" + Because defs must be unique, global variables cannot be modified with + operators like `+=` or `-=` in cells other than the one that created + them; these operators count as redefinitions of a name. - **🌊 Try it!** Get rid of the following errors by merging the next two - cells into a single cell. - """ - ) + **🌊 Try it!** Get rid of the following errors by merging the next two + cells into a single cell. + """) return @@ -307,18 +285,16 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Underscore-prefixed variables are local to cells + mo.md(""" + ### Underscore-prefixed variables are local to cells - Global variables prefixed with an underscore are "private" to the cells - that define them. This means that multiple cells can define the same - underscore-prefixed name, and one cell's private variables won't be - made available to other cells. + Global variables prefixed with an underscore are "private" to the cells + that define them. This means that multiple cells can define the same + underscore-prefixed name, and one cell's private variables won't be + made available to other cells. - **Example**. - """ - ) + **Example**. + """) return @@ -345,16 +321,14 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Deleting a cell deletes its variables + mo.md(""" + ### Deleting a cell deletes its variables - Deleting a cell deletes its global variables and - then runs all cells that reference them. This prevents severe bugs that - can arise when state has been deleted from the editor but not from the - program memory. - """ - ) + Deleting a cell deletes its global variables and + then runs all cells that reference them. This prevents severe bugs that + can arise when state has been deleted from the editor but not from the + program memory. + """) return @@ -380,13 +354,11 @@ def _(to_be_deleted): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Cycles are not allowed + mo.md(""" + ### Cycles are not allowed - Cycles among cells are not allowed. For example: - """ - ) + Cycles among cells are not allowed. For example: + """) return @@ -404,17 +376,15 @@ def _(one): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### marimo doesn't track attributes + mo.md(""" + ### marimo doesn't track attributes - marimo only tracks global variables. Writing object attributes does not - trigger reactive execution. + marimo only tracks global variables. Writing object attributes does not + trigger reactive execution. - **🌊 Example**. Change the value of `state.number` in the next cell, then - run the cell. Notice how the subsequent cell isn't updated. - """ - ) + **🌊 Example**. Change the value of `state.number` in the next cell, then + run the cell. Notice how the subsequent cell isn't updated. + """) return @@ -456,15 +426,13 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### marimo doesn't track mutations + mo.md(""" + ### marimo doesn't track mutations - In Python, it's impossible to know whether code will - mutate an object without running it. So: mutations (such as - appending to a list) will not trigger reactive execution. - """ - ) + In Python, it's impossible to know whether code will + mutate an object without running it. So: mutations (such as + appending to a list) will not trigger reactive execution. + """) return @@ -486,21 +454,19 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Best practices + mo.md(""" + ## Best practices - The constraints marimo puts on your notebooks are all natural consequences - of the fact that marimo programs are directed acyclic graphs. As long as - you keep this fact in mind, you'll quickly adapt to the marimo way of - writing notebooks. + The constraints marimo puts on your notebooks are all natural consequences + of the fact that marimo programs are directed acyclic graphs. As long as + you keep this fact in mind, you'll quickly adapt to the marimo way of + writing notebooks. - Ultimately, these constraints will enable you to create powerful notebooks - and apps, and they'll encourage you to write clean, reproducible code. + Ultimately, these constraints will enable you to create powerful notebooks + and apps, and they'll encourage you to write clean, reproducible code. - Follow these tips to stay on the marimo way: - """ - ) + Follow these tips to stay on the marimo way: + """) return @@ -512,17 +478,15 @@ def _(mo, tips): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## What's next? + mo.md(""" + ## What's next? - Check out the tutorial on interactivity for a tour of UI elements: + Check out the tutorial on interactivity for a tour of UI elements: - ``` - marimo tutorial ui - ``` - """ - ) + ``` + marimo tutorial ui + ``` + """) return diff --git a/marimo/_tutorials/fileformat.py b/marimo/_tutorials/fileformat.py index 7fb99e9e9a1..233b51eb0f7 100644 --- a/marimo/_tutorials/fileformat.py +++ b/marimo/_tutorials/fileformat.py @@ -2,7 +2,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() with app.setup: @@ -18,120 +18,112 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # File Format + mo.md(r""" + # File Format - marimo apps are stored as pure Python files. + marimo apps are stored as pure Python files. - These files are: + These files are: - - 🤖 legible for both humans and machines - - ✏️ formattable using your tool of choice - - ➕ easily versioned with git, producing small diffs - - 🐍 usable as Python scripts, with UI elements taking their default values - - 🧩 modular, exposing functions and classes that can be imported from the notebook - """ - ) + - 🤖 legible for both humans and machines + - ✏️ formattable using your tool of choice + - ➕ easily versioned with git, producing small diffs + - 🐍 usable as Python scripts, with UI elements taking their default values + - 🧩 modular, exposing functions and classes that can be imported from the notebook + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Example - - Consider a marimo notebook with the following four cells. - - First cell: - ```python3 - print(text.value) - ``` - - Second cell: - ```python3 - def say_hello(name="World"): - return f"Hello, {name}!" - ``` - - Third cell: - ```python3 - text = mo.ui.text(value=say_hello()) - text - ``` - - Fourth cell: - ```python3 - import marimo as mo - ``` - """ - ) + mo.md(""" + ## Example + + Consider a marimo notebook with the following four cells. + + First cell: + ```python3 + print(text.value) + ``` + + Second cell: + ```python3 + def say_hello(name="World"): + return f"Hello, {name}!" + ``` + + Third cell: + ```python3 + text = mo.ui.text(value=say_hello()) + text + ``` + + Fourth cell: + ```python3 + import marimo as mo + ``` + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - For the above example, marimo would generate the following file - contents: + mo.md(""" + For the above example, marimo would generate the following file + contents: - ```python3 - import marimo + ```python3 + import marimo - __generated_with = "0.0.0" - app = marimo.App() + __generated_with = "0.0.0" + app = marimo.App() - @app.cell - def _(text): - print(text.value) - return + @app.cell + def _(text): + print(text.value) + return - @app.function - def say_hello(name="World"): - return f"Hello, {name}!" + @app.function + def say_hello(name="World"): + return f"Hello, {name}!" - @app.cell - def _(mo): - text = mo.ui.text(value=say_hello()) - text - return (text,) + @app.cell + def _(mo): + text = mo.ui.text(value=say_hello()) + text + return (text,) - @app.cell - def _(): - import marimo as mo - return mo, + @app.cell + def _(): + import marimo as mo + return mo, - if __name__ == "__main__": - app.run() - ``` + if __name__ == "__main__": + app.run() + ``` - As you can see, this is _pure Python_. This is part of the reason why - marimo's generated files are **git-friendly**: small changes made using - the marimo editor result in small changes to the file that marimo - generates. + As you can see, this is _pure Python_. This is part of the reason why + marimo's generated files are **git-friendly**: small changes made using + the marimo editor result in small changes to the file that marimo + generates. - Moreover, the cell defining a single pure function `say_hello` was saved "top-level" in the notebook file, making it possible for you to import it into other Python files or notebooks. - """ - ) + Moreover, the cell defining a single pure function `say_hello` was saved "top-level" in the notebook file, making it possible for you to import it into other Python files or notebooks. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Properties + mo.md(""" + ## Properties - marimo's file format was designed to be easy to read and easy - to work with, while also serving the needs of the marimo library. You can - even edit the generated file's cells directly, using your favorite text - editor, and format the file with your favorite code formatter. + marimo's file format was designed to be easy to read and easy + to work with, while also serving the needs of the marimo library. You can + even edit the generated file's cells directly, using your favorite text + editor, and format the file with your favorite code formatter. - We explain some properties of marimo's file format below. - """ - ) + We explain some properties of marimo's file format below. + """) return @@ -247,60 +239,54 @@ def echo(text): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Importing functions and classes from notebooks + mo.md(r""" + ## Importing functions and classes from notebooks - The details of marimo's file format are important if you want to import - functions and classes defined in your notebook into other Python modules. If you - don't intend to do so, you can skip this section. - """ - ) + The details of marimo's file format are important if you want to import + functions and classes defined in your notebook into other Python modules. If you + don't intend to do so, you can skip this section. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ### Declaring imports used by functions and classes + mo.md(r""" + ### Declaring imports used by functions and classes - marimo can serialize functions and classes into the top-level of a file, so you can import them with regular Python syntax: + marimo can serialize functions and classes into the top-level of a file, so you can import them with regular Python syntax: - ```python - from my_notebook import my_function - ``` + ```python + from my_notebook import my_function + ``` - In particular, if a cell defines just a single function or class, and if that function or class is pure - save for references to variables defined in a special **setup cell**, it will be serialized top-level. + In particular, if a cell defines just a single function or class, and if that function or class is pure + save for references to variables defined in a special **setup cell**, it will be serialized top-level. - **Setup cell.** Notebooks can optionally include a setup cell that imports modules, - written in the file as: + **Setup cell.** Notebooks can optionally include a setup cell that imports modules, + written in the file as: - - ```python - with app.setup: - import marimo as mo - import dataclasses - ``` + + ```python + with app.setup: + import marimo as mo + import dataclasses + ``` - Modules imported in a setup cell can be used in "top-level" functions or - classes. You can add the setup cell from the general menu of the editor under: - ::lucide:diamond-plus:: Add setup cell. - """ - ) + Modules imported in a setup cell can be used in "top-level" functions or + classes. You can add the setup cell from the general menu of the editor under: + ::lucide:diamond-plus:: Add setup cell. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ### Functions and classes + mo.md(r""" + ### Functions and classes - Notebook files expose functions and classes that depend only on variables defined in the setup cell (or on other such functions or classes). For example, the following cell: - """ - ) + Notebook files expose functions and classes that depend only on variables defined in the setup cell (or on other such functions or classes). For example, the following cell: + """) return @@ -316,29 +302,27 @@ def roll_die(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ... is saved in the notebook file as - - ```python - @app.function - def roll_die(): - ''' - A reusable function. - - Notice the indicator in the bottom right of the cell. - ''' - return random.randint(1, 7) - ``` + mo.md(r""" + ... is saved in the notebook file as + ```python + @app.function + def roll_die(): + ''' + A reusable function. - Making it importable as + Notice the indicator in the bottom right of the cell. + ''' + return random.randint(1, 7) + ``` - ```python - from my_notebook import roll_die - ``` - """ - ) + + Making it importable as + + ```python + from my_notebook import roll_die + ``` + """) return @@ -359,39 +343,35 @@ def simulate(self) -> list[int]: @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - This class is saved in the file as - - ```python - @app.class_definition - @dataclasses.dataclass - class SimulationExample: - n_rolls: int - - def simulate(self) -> list[int]: - return [roll_die() for _ in range(self.n_rolls)] - ``` - """ - ) + mo.md(r""" + This class is saved in the file as + + ```python + @app.class_definition + @dataclasses.dataclass + class SimulationExample: + n_rolls: int + + def simulate(self) -> list[int]: + return [roll_die() for _ in range(self.n_rolls)] + ``` + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - /// attention | Heads up - /// + mo.md(r""" + /// attention | Heads up + /// - Not all standalone functions will be exposed in the module. If your - function depends on variables that are defined in other cells, then it won't - be exposed top-level. + Not all standalone functions will be exposed in the module. If your + function depends on variables that are defined in other cells, then it won't + be exposed top-level. - For example, this function will not be exposed: - """ - ) + For example, this function will not be exposed: + """) return @@ -416,36 +396,32 @@ def not_a_top_level_function(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## FAQ + mo.md(r""" + ## FAQ - ### I want to edit notebooks in a different editor, what do I need to know? + ### I want to edit notebooks in a different editor, what do I need to know? - See the docs on [using your own editor](https://docs.marimo.io/guides/editor_features/watching/). + See the docs on [using your own editor](https://docs.marimo.io/guides/editor_features/watching/). - ### I want to import functions from a marimo notebook, what do I need to know? + ### I want to import functions from a marimo notebook, what do I need to know? - See the docs on [reusable functions and - classes](https://links.marimo.app/reusable-functions). + See the docs on [reusable functions and + classes](https://links.marimo.app/reusable-functions). - ### I want to run pytest on marimo notebooks, what do I need to know? + ### I want to run pytest on marimo notebooks, what do I need to know? - See the docs on [testing](https://docs.marimo.io/guides/testing/). - """ - ) + See the docs on [testing](https://docs.marimo.io/guides/testing/). + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## This notebook's source code + mo.md(r""" + ## This notebook's source code - The source code of this notebook is shown below: - """ - ) + The source code of this notebook is shown below: + """) return diff --git a/marimo/_tutorials/for_jupyter_users.py b/marimo/_tutorials/for_jupyter_users.py index 76db05c82cb..6e55b4f0410 100644 --- a/marimo/_tutorials/for_jupyter_users.py +++ b/marimo/_tutorials/for_jupyter_users.py @@ -2,34 +2,30 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(app_title="marimo for Jupyter users") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # marimo for Jupyter users + mo.md(r""" + # marimo for Jupyter users - This notebook explains important differences between Jupyter and marimo. If you're - familiar with Jupyter and are trying out marimo for the first time, read on! - """ - ) + This notebook explains important differences between Jupyter and marimo. If you're + familiar with Jupyter and are trying out marimo for the first time, read on! + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Reactive execution + mo.md(r""" + ## Reactive execution - The biggest difference between marimo and Jupyter is *reactive execution*. + The biggest difference between marimo and Jupyter is *reactive execution*. - Try updating the value of x in the next cell, then run it. - """ - ) + Try updating the value of x in the next cell, then run it. + """) return @@ -47,51 +43,45 @@ def _(x): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - marimo 'reacts' to the change in `x` and automatically recalculates `y`! + mo.md(r""" + marimo 'reacts' to the change in `x` and automatically recalculates `y`! - **Explanation.** marimo reads the code in your cells and understands the - dependences between them, based on the variables that each cell declares and - references. When you execute one cell, marimo automatically executes all other - cells that depend on it, not unlike a spreadsheet. + **Explanation.** marimo reads the code in your cells and understands the + dependences between them, based on the variables that each cell declares and + references. When you execute one cell, marimo automatically executes all other + cells that depend on it, not unlike a spreadsheet. - In contrast, Jupyter requires you to manually run each cell. - """ - ) + In contrast, Jupyter requires you to manually run each cell. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ### Why? + mo.md(r""" + ### Why? - Reactive execution frees you from the tedious task of manually re-running cells. + Reactive execution frees you from the tedious task of manually re-running cells. - It also ensures that your code and outputs remain in sync: + It also ensures that your code and outputs remain in sync: - - You don't have to worry about whether you forgot to re-run a cell. - - When you delete a cell, its variables are automatically removed from - program memory. Affected cells are automatically invalidated. + - You don't have to worry about whether you forgot to re-run a cell. + - When you delete a cell, its variables are automatically removed from + program memory. Affected cells are automatically invalidated. - This makes marimo notebooks as reproducible as regular Python scripts. - """ - ) + This makes marimo notebooks as reproducible as regular Python scripts. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Interactive elements built-in + mo.md(""" + ## Interactive elements built-in - marimo comes with a [large library of UI elements](https://docs.marimo.io/guides/interactivity.html) that are automatically - synchronized with Python. - """ - ) + marimo comes with a [large library of UI elements](https://docs.marimo.io/guides/interactivity.html) that are automatically + synchronized with Python. + """) return @@ -116,50 +106,44 @@ def _(slider): @app.cell(hide_code=True) def _(mo): - mo.md( - rf""" - **Explanation.** marimo is both a notebook and a library. Import `marimo as - mo` and use `mo.ui` to get access to powerful UI elements. + mo.md(rf""" + **Explanation.** marimo is both a notebook and a library. Import `marimo as + mo` and use `mo.ui` to get access to powerful UI elements. - UI elements assigned to variables are automatically plugged into marimo's - reactive execution model: interactions automatically trigger execution of - cells that refer to them. + UI elements assigned to variables are automatically plugged into marimo's + reactive execution model: interactions automatically trigger execution of + cells that refer to them. - In contrast, Jupyter's lack of reactivity makes IPyWidgets difficult to use. - """ - ) + In contrast, Jupyter's lack of reactivity makes IPyWidgets difficult to use. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Shareable as apps + mo.md(r""" + ## Shareable as apps - marimo notebooks can be shared as read-only web apps: just serve it with + marimo notebooks can be shared as read-only web apps: just serve it with - ```marimo run your_notebook.py``` + ```marimo run your_notebook.py``` - at the command-line. + at the command-line. - Not every marimo notebook needs to be shared as an app, but marimo makes it - seamless to do so if you want to. In this way, marimo works as a replacement - for both Jupyter and Streamlit. - """ - ) + Not every marimo notebook needs to be shared as an app, but marimo makes it + seamless to do so if you want to. In this way, marimo works as a replacement + for both Jupyter and Streamlit. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Cell order + mo.md(r""" + ## Cell order - In marimo, cells can be arranged in any order — marimo figures out the one true way to execute them based on variable declarations and references (in a ["topologically sorted"](https://en.wikipedia.org/wiki/Topological_sorting#:~:text=In%20computer%20science%2C%20a%20topological,before%20v%20in%20the%20ordering.) order) - """ - ) + In marimo, cells can be arranged in any order — marimo figures out the one true way to execute them based on variable declarations and references (in a ["topologically sorted"](https://en.wikipedia.org/wiki/Topological_sorting#:~:text=In%20computer%20science%2C%20a%20topological,before%20v%20in%20the%20ordering.) order) + """) return @@ -177,25 +161,21 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - This lets you arrange your cells in the way that makes the most sense to you. For example, put helper functions and imports at the bottom of a notebook, like an appendix. + mo.md(r""" + This lets you arrange your cells in the way that makes the most sense to you. For example, put helper functions and imports at the bottom of a notebook, like an appendix. - In contrast, Jupyter notebooks implicitly assume a top-to-bottom execution order. - """ - ) + In contrast, Jupyter notebooks implicitly assume a top-to-bottom execution order. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Re-assigning variables + mo.md(r""" + ## Re-assigning variables - marimo disallows variable re-assignment. Here is something commonly done in Jupyter notebooks that cannot be done in marimo: - """ - ) + marimo disallows variable re-assignment. Here is something commonly done in Jupyter notebooks that cannot be done in marimo: + """) return @@ -219,29 +199,25 @@ def _(df): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - **Explanation.** `results` depends on `df`, but which value of `df` should it use? Reactivity makes it impossible to answer this question in a sensible way, so marimo disallows variable reassignment. + mo.md(r""" + **Explanation.** `results` depends on `df`, but which value of `df` should it use? Reactivity makes it impossible to answer this question in a sensible way, so marimo disallows variable reassignment. - If you run into this error, here are your options: + If you run into this error, here are your options: - 1. combine definitions into one cell - 2. prefix variables with an underscore (`_df`) to make them local to the cell - 3. wrap your code in functions, or give your variables more descriptive names - """ - ) + 1. combine definitions into one cell + 2. prefix variables with an underscore (`_df`) to make them local to the cell + 3. wrap your code in functions, or give your variables more descriptive names + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - rf""" - ## Markdown + mo.md(rf""" + ## Markdown - marimo only has Python cells, but you can still write Markdown: `import marimo as mo` and use `mo.md` to write Markdown. - """ - ) + marimo only has Python cells, but you can still write Markdown: `import marimo as mo` and use `mo.md` to write Markdown. + """) return @@ -257,59 +233,53 @@ def _(mo, slider): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - **Explanation.** By lifting Markdown into Python, marimo lets you construct - dynamic Markdown parameterized by arbitrary Python elements. marimo knows - how to render its own elements, and you can use `mo.as_html` to render other - objects, like plots. - - _Tip: toggle a markdown view via `Cmd/Ctrl-Shift-M` in an empty cell._ - """ - ) + mo.md(r""" + **Explanation.** By lifting Markdown into Python, marimo lets you construct + dynamic Markdown parameterized by arbitrary Python elements. marimo knows + how to render its own elements, and you can use `mo.as_html` to render other + objects, like plots. + + _Tip: toggle a markdown view via `Cmd/Ctrl-Shift-M` in an empty cell._ + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Notebook files + mo.md(r""" + ## Notebook files - Jupyter saves notebooks as JSON files, with outputs serialized in them. This is helpful as a record of your plots and other results, but makes notebooks difficult to version and reuse. + Jupyter saves notebooks as JSON files, with outputs serialized in them. This is helpful as a record of your plots and other results, but makes notebooks difficult to version and reuse. - ### marimo notebooks are Python scripts - marimo notebooks are stored as pure Python scripts. This lets you version them with git, execute them with the command line, and re-use logic from one notebook in another. + ### marimo notebooks are Python scripts + marimo notebooks are stored as pure Python scripts. This lets you version them with git, execute them with the command line, and re-use logic from one notebook in another. - ### marimo notebooks do not store outputs - marimo does _not_ save your outputs in the file; if you want them saved, make sure to save them to disk with Python, or export to HTML via the notebook menu. + ### marimo notebooks do not store outputs + marimo does _not_ save your outputs in the file; if you want them saved, make sure to save them to disk with Python, or export to HTML via the notebook menu. - ### marimo notebooks are versionable with git + ### marimo notebooks are versionable with git - marimo is designed so that small changes in your code yield small git diffs! - """ - ) + marimo is designed so that small changes in your code yield small git diffs! + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Parting thoughts + mo.md(r""" + ## Parting thoughts - marimo is a **reinvention** of the Python notebook as a reproducible, interactive, and shareable Python program, instead of an error-prone scratchpad. + marimo is a **reinvention** of the Python notebook as a reproducible, interactive, and shareable Python program, instead of an error-prone scratchpad. - We believe that the tools we use shape the way we think — better tools, for better minds. With marimo, we hope to provide the Python community with a better programming environment to do research and communicate it; to experiment with code and share it; to learn computational science and teach it. + We believe that the tools we use shape the way we think — better tools, for better minds. With marimo, we hope to provide the Python community with a better programming environment to do research and communicate it; to experiment with code and share it; to learn computational science and teach it. - The marimo editor and library have many features not discussed here. - Check out [our docs](https://docs.marimo.io/) to learn more! + The marimo editor and library have many features not discussed here. + Check out [our docs](https://docs.marimo.io/) to learn more! - _This guide was adapted from [Pluto for Jupyter - users](https://featured.plutojl.org/basic/pluto%20for%20jupyter%20users). - We ❤️ Pluto.jl!_ - """ - ) + _This guide was adapted from [Pluto for Jupyter + users](https://featured.plutojl.org/basic/pluto%20for%20jupyter%20users). + We ❤️ Pluto.jl!_ + """) return diff --git a/marimo/_tutorials/intro.py b/marimo/_tutorials/intro.py index 0c87ab31a18..09ccfce0513 100644 --- a/marimo/_tutorials/intro.py +++ b/marimo/_tutorials/intro.py @@ -2,7 +2,7 @@ import marimo -__generated_with = "0.16.2" +__generated_with = "0.17.2" app = marimo.App() @@ -69,8 +69,7 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## 1. Reactive execution A marimo notebook is made up of small blocks of Python code called @@ -83,8 +82,7 @@ def _(mo): Reactivity keeps your program state and outputs in sync with your code, making for a dynamic programming environment that prevents bugs before they happen. - """ - ) + """) return @@ -141,13 +139,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" **Global names must be unique.** To enable reactivity, marimo imposes a constraint on how names appear in cells: no two cells may define the same variable. - """ - ) + """) return @@ -183,8 +179,7 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## 2. UI elements Cells can output interactive UI elements. Interacting with a UI @@ -194,8 +189,7 @@ def _(mo): marimo provides a library of UI elements to choose from under `marimo.ui`. - """ - ) + """) return @@ -231,8 +225,7 @@ def _(icon, mo, repetitions): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## 3. marimo is just Python marimo cells parse Python (and only Python), and marimo notebooks are @@ -247,15 +240,13 @@ def _(mo): - usable as Python scripts, with UI elements taking their default values, and - importable by other modules (more on that in the future). - """ - ) + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## 4. Running notebooks as apps marimo notebooks can double as apps. Click the app window icon in the @@ -264,15 +255,13 @@ def _(mo): Serve a notebook as an app with `marimo run` at the command-line. Of course, you can use marimo just to level-up your notebooking, without ever making apps. - """ - ) + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## 5. The `marimo` command-line tool **Creating and editing notebooks.** Use @@ -322,20 +311,17 @@ def _(mo): In addition to tutorials, we have examples in our [our GitHub repo](https://www.github.com/marimo-team/marimo/tree/main/examples). - """ - ) + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## 6. The marimo editor Here are some tips to help you get started with the marimo editor. - """ - ) + """) return @@ -353,14 +339,12 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" The name "marimo" is a reference to a type of algae that, under the right conditions, clumps together to form a small sphere called a "marimo moss ball". Made of just strands of algae, these beloved assemblages are greater than the sum of their parts. - """ - ) + """) return diff --git a/marimo/_tutorials/layout.py b/marimo/_tutorials/layout.py index 6261ca37dd1..ea272b7cdf3 100644 --- a/marimo/_tutorials/layout.py +++ b/marimo/_tutorials/layout.py @@ -2,32 +2,28 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # Layout + mo.md(""" + # Layout - `marimo` provides functions to help you lay out your output, such as - in rows and columns, accordions, tabs, and callouts. - """ - ) + `marimo` provides functions to help you lay out your output, such as + in rows and columns, accordions, tabs, and callouts. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Rows and columns + mo.md(""" + ## Rows and columns - Arrange objects into rows and columns with `mo.hstack` and `mo.vstack`. - """ - ) + Arrange objects into rows and columns with `mo.hstack` and `mo.vstack`. + """) return @@ -74,13 +70,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - **Customization.** - The presentation of stacked elements can be customized with some arguments - that are best understood by example. - """ - ) + mo.md(""" + **Customization.** + The presentation of stacked elements can be customized with some arguments + that are best understood by example. + """) return @@ -156,14 +150,12 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - **Justifying `Html`.** While you can center or right-justify any object - using `mo.hstack`, `Html` objects (returned by most marimo - functions, and subclassed by most marimo classes) have a shortcut using - via their `center`, `right`, and `left` methods. - """ - ) + mo.md(""" + **Justifying `Html`.** While you can center or right-justify any object + using `mo.hstack`, `Html` objects (returned by most marimo + functions, and subclassed by most marimo classes) have a shortcut using + via their `center`, `right`, and `left` methods. + """) return @@ -199,13 +191,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Accordion + mo.md(""" + ## Accordion - Create expandable shelves of content using `mo.accordion`: - """ - ) + Create expandable shelves of content using `mo.accordion`: + """) return @@ -233,13 +223,11 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Tabs + mo.md(""" + ## Tabs - Use `mo.ui.tabs` to display multiple objects in a single tabbed output: - """ - ) + Use `mo.ui.tabs` to display multiple objects in a single tabbed output: + """) return @@ -305,14 +293,12 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Callout + mo.md(""" + ## Callout - Turn any markdown or HTML into an emphasized callout with the `callout` - method: - """ - ) + Turn any markdown or HTML into an emphasized callout with the `callout` + method: + """) return diff --git a/marimo/_tutorials/markdown.py b/marimo/_tutorials/markdown.py index bb9a1b85add..6f333d2e6d3 100644 --- a/marimo/_tutorials/markdown.py +++ b/marimo/_tutorials/markdown.py @@ -11,14 +11,13 @@ import marimo -__generated_with = "0.16.2" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" # Hello, Markdown! Use marimo's "`md`" function to write markdown. This function compiles Markdown into HTML that marimo can display. @@ -37,15 +36,13 @@ def _(mo): ''' ) ``` - """ - ) + """) return @app.cell def _(mo): - mo.md( - r""" + mo.md(r""" **Tip: toggling between the Markdown and Python editor** Although markdown is written with `mo.md`, marimo provides a markdown editor @@ -59,15 +56,13 @@ def _(mo): **Tip:** To interpolate Python values into markdown strings, you'll need to use a Python f-string; do this by checking the `f` box in the bottom-right corner of the markdown editor, or with `mo.md(f"...")` in the Python view. - """ - ) + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" ## LaTeX You can embed LaTeX in Markdown. @@ -94,8 +89,7 @@ def _(mo): \[ f: \mathbf{R} \to \mathbf{R}. \] - """ - ) + """) return @@ -131,8 +125,7 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## Interpolating Python values You can interpolate Python values into markdown using @@ -140,8 +133,7 @@ def _(mo): markdown whose contents depend on data that changes at runtime. Here are some examples. - """ - ) + """) return @@ -261,15 +253,13 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ + mo.md(""" ## Putting it all together Here's a more interesting example that puts together everything we've learned: rendering markdown with LaTeX that depends on the values of Python objects. - """ - ) + """) return diff --git a/marimo/_tutorials/markdown_format.md b/marimo/_tutorials/markdown_format.md index bef431a04c9..28f18189653 100644 --- a/marimo/_tutorials/markdown_format.md +++ b/marimo/_tutorials/markdown_format.md @@ -155,6 +155,8 @@ values, just use a Python cell: mo.md(f"""Like so: {"🍃" * 7}""") ``` +`````python {.marimo hide_code="true"} +mo.md(r""" ### Limitations on conversion Whenever you try to implement a cell block like this: @@ -167,16 +169,16 @@ mo.md("This is a markdown cell") The markdown format will know to automatically keep this as markdown. However, some ambiguous cases can't be converted to markdown like this: +""") +````` ````python {.marimo} -mo.md( - """ - This is a markdown cell with an execution block in it - ```python {.marimo} - # Too ambiguous to convert - ``` - """ -) +mo.md(""" +This is a markdown cell with an execution block in it +```python {.marimo} +# Too ambiguous to convert +``` +""") ```` It's not likely that you'll run into this issue, but rest assured that marimo @@ -275,4 +277,4 @@ more information on to type-set and render markdown in marimo. ```python {.marimo hide_code="true"} import marimo as mo -``` +``` \ No newline at end of file diff --git a/marimo/_tutorials/plots.py b/marimo/_tutorials/plots.py index 22aa95b9b3b..9d0ce5b6ccf 100644 --- a/marimo/_tutorials/plots.py +++ b/marimo/_tutorials/plots.py @@ -10,7 +10,7 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @@ -28,15 +28,13 @@ def _(check_dependencies): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - marimo supports several popular plotting libraries, including matplotlib, - plotly, seaborn, and altair. + mo.md(""" + marimo supports several popular plotting libraries, including matplotlib, + plotly, seaborn, and altair. - This tutorial gives examples using matplotlib; other libraries are - used similarly. - """ - ) + This tutorial gives examples using matplotlib; other libraries are + used similarly. + """) return @@ -48,18 +46,16 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - To show a plot, include it in the last expression of a cell (just - like any other output). + mo.md(""" + To show a plot, include it in the last expression of a cell (just + like any other output). - ```python3 - # create the plot in the last line of the cell - import matplotlib.pyplot as plt - plt.plot([1, 2]) - ``` - """ - ) + ```python3 + # create the plot in the last line of the cell + import matplotlib.pyplot as plt + plt.plot([1, 2]) + ``` + """) return @@ -71,17 +67,15 @@ def _(plt): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ```python3 - # create a plot - plt.plot([1, 2]) - # ... do some work ... - # make plt.gca() the last line of the cell - plt.gca() - ``` - """ - ) + mo.md(""" + ```python3 + # create a plot + plt.plot([1, 2]) + # ... do some work ... + # make plt.gca() the last line of the cell + plt.gca() + ``` + """) return @@ -102,12 +96,10 @@ def _(mo, plt_show_explainer): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - **A new figure every cell.** Every cell starts with an empty figure for - the imperative `pyplot` API. - """ - ) + mo.md(""" + **A new figure every cell.** Every cell starts with an empty figure for + the imperative `pyplot` API. + """) return @@ -133,12 +125,10 @@ def _(plt, x): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - To build a figure over multiple cells, use the object-oriented API and - create your own axis: - """ - ) + mo.md(""" + To build a figure over multiple cells, use the object-oriented API and + create your own axis: + """) return @@ -160,13 +150,11 @@ def _(axis, x): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Draw plots interactively + mo.md(""" + ### Draw plots interactively - Draw plots interactively by parametrizing them with UI elements. - """ - ) + Draw plots interactively by parametrizing them with UI elements. + """) return @@ -218,21 +206,19 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - marimo also supports these other plotting libraries: + mo.md(""" + marimo also supports these other plotting libraries: - - Plotly - - Seaborn - - Altair + - Plotly + - Seaborn + - Altair - Just output their figure objects as the last expression of a cell, - or embed them in markdown with `mo.as_html`. + Just output their figure objects as the last expression of a cell, + or embed them in markdown with `mo.as_html`. - If you would like another library to be integrated into marimo, please - get in touch. - """ - ) + If you would like another library to be integrated into marimo, please + get in touch. + """) return diff --git a/marimo/_tutorials/sql.py b/marimo/_tutorials/sql.py index 7b1354ea028..934b88b9524 100644 --- a/marimo/_tutorials/sql.py +++ b/marimo/_tutorials/sql.py @@ -13,35 +13,31 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - # Hello, SQL! + mo.md(r""" + # Hello, SQL! - _Let's dive into the world of SQL where we don't just address tables, we also join them!_ - """ - ) + _Let's dive into the world of SQL where we don't just address tables, we also join them!_ + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - With marimo, you can mix-and-match both **Python and SQL**. To create a - SQL cell, you first need to install some additional dependencies, - including [duckdb](https://duckdb.org/). Obtain these dependencies with - - ```bash - pip install 'marimo[sql]' - ``` - """ - ) + mo.md(r""" + With marimo, you can mix-and-match both **Python and SQL**. To create a + SQL cell, you first need to install some additional dependencies, + including [duckdb](https://duckdb.org/). Obtain these dependencies with + + ```bash + pip install 'marimo[sql]' + ``` + """) return @@ -101,36 +97,34 @@ def _(has_duckdb_installed, mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ## Creating SQL cells - - Once the required dependencies are installed, you can create SQL cells - in one of the following ways: - - - right click the **Add Cell** ::lucide:circle-plus:: buttons on the left of - a cell; - - click the **Convert to SQL** ::lucide:database:: button in the cell menu ::lucide:ellipsis:: - - click the **Add SQL Cell** at the bottom of the page; - - ## Python representation - marimo is still just Python, even when using SQL. Here is an example of - how marimo embeds SQL in Python in its file format: - - ```python - output_df = mo.sql(f"SELECT * FROM my_table LIMIT {max_rows.value}") - ``` - - Notice that we have an **`output_df`** variable in the cell. This is a - resulting Polars DataFrame (if you have `polars` installed) or a Pandas - DataFrame (if you don't). One of them must be installed in order to - interact with the SQL result. - - The SQL statement itself is an formatted string (f-string), so this - means they can contain any valid Python code, such as the values of UI - elements. This means your SQL statement and results can be reactive! 🚀 - """ - ) + mo.md(r""" + ## Creating SQL cells + + Once the required dependencies are installed, you can create SQL cells + in one of the following ways: + + - right click the **Add Cell** ::lucide:circle-plus:: buttons on the left of + a cell; + - click the **Convert to SQL** ::lucide:database:: button in the cell menu ::lucide:ellipsis:: + - click the **Add SQL Cell** at the bottom of the page; + + ## Python representation + marimo is still just Python, even when using SQL. Here is an example of + how marimo embeds SQL in Python in its file format: + + ```python + output_df = mo.sql(f"SELECT * FROM my_table LIMIT {max_rows.value}") + ``` + + Notice that we have an **`output_df`** variable in the cell. This is a + resulting Polars DataFrame (if you have `polars` installed) or a Pandas + DataFrame (if you don't). One of them must be installed in order to + interact with the SQL result. + + The SQL statement itself is an formatted string (f-string), so this + means they can contain any valid Python code, such as the values of UI + elements. This means your SQL statement and results can be reactive! 🚀 + """) return @@ -142,21 +136,21 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - /// Tip | "Data sources panel" + mo.md(r""" + /// Tip | "Data sources panel" - Click the database "barrel" icon in the left toolbar to see all dataframes and in- - memory tables that your notebook has access to. - /// - """ - ) + Click the database "barrel" icon in the left toolbar to see all dataframes and in- + memory tables that your notebook has access to. + /// + """) return @app.cell(hide_code=True) def _(mo): - mo.md(r"""Let's take a look at a SQL cell. The next cell generates a dataframe called `df`.""") + mo.md( + r"""Let's take a look at a SQL cell. The next cell generates a dataframe called `df`.""" + ) return @@ -205,7 +199,9 @@ def generate_random_numbers(mean, std_dev, num_samples): @app.cell(hide_code=True) def _(mo): - mo.md(r"""Next, we create a SQL query, referencing the Python dataframe `df` directly.""") + mo.md( + r"""Next, we create a SQL query, referencing the Python dataframe `df` directly.""" + ) return @@ -231,7 +227,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md(r"""You can create SQL statements that depend on Python values, such as UI elements:""") + mo.md( + r"""You can create SQL statements that depend on Python values, such as UI elements:""" + ) return @@ -261,12 +259,10 @@ def _(mo, token_prefix): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - Since we named the output variable above **`result`**, - we can use it back in Python. - """ - ) + mo.md(r""" + Since we named the output variable above **`result`**, + we can use it back in Python. + """) return @@ -354,24 +350,22 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - We're not limited to querying dataframes. We can also query an **HTTP URL, S3 path, or a file path to a local csv or parquet file**. - - ```sql - -- or - SELECT * FROM 's3://my-bucket/file.parquet'; - -- or - SELECT * FROM read_csv('path/to/example.csv'); - -- or - SELECT * FROM read_parquet('path/to/example.parquet'); - ``` - - With a bit of boilerplate, you can even read and write to **Postgres**, and join Postgres tables with dataframes in the same query. For a full list of supported data sources, check out the [duckdb extensions](https://duckdb.org/docs/extensions/overview) and our [example notebook on duckdb connections](https://github.com/marimo-team/marimo/blob/main/examples/sql/duckdb_connections.**py**). - - For this example, we will query an HTTP endpoint of a csv. - """ - ) + mo.md(r""" + We're not limited to querying dataframes. We can also query an **HTTP URL, S3 path, or a file path to a local csv or parquet file**. + + ```sql + -- or + SELECT * FROM 's3://my-bucket/file.parquet'; + -- or + SELECT * FROM read_csv('path/to/example.csv'); + -- or + SELECT * FROM read_parquet('path/to/example.parquet'); + ``` + + With a bit of boilerplate, you can even read and write to **Postgres**, and join Postgres tables with dataframes in the same query. For a full list of supported data sources, check out the [duckdb extensions](https://duckdb.org/docs/extensions/overview) and our [example notebook on duckdb connections](https://github.com/marimo-team/marimo/blob/main/examples/sql/duckdb_connections.**py**). + + For this example, we will query an HTTP endpoint of a csv. + """) return diff --git a/marimo/_tutorials/ui.py b/marimo/_tutorials/ui.py index e1ab7cf029d..b29d2531b74 100644 --- a/marimo/_tutorials/ui.py +++ b/marimo/_tutorials/ui.py @@ -2,21 +2,19 @@ import marimo -__generated_with = "0.15.5" +__generated_with = "0.17.2" app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - """ - # UI Elements + mo.md(""" + # UI Elements - One of marimo's most powerful features is its first-class - support for interactive user interface (UI) elements: interacting - with a UI element will automatically run cells that reference it. - """ - ) + One of marimo's most powerful features is its first-class + support for interactive user interface (UI) elements: interacting + with a UI element will automatically run cells that reference it. + """) return @@ -49,19 +47,17 @@ def _(mo, slider): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### How interactions run cells + mo.md(""" + ### How interactions run cells - Whenever you interact with a UI element, its value is sent back to - Python. When this happens, all cells that reference the global variable - bound to the UI element, but don't define it, will run. + Whenever you interact with a UI element, its value is sent back to + Python. When this happens, all cells that reference the global variable + bound to the UI element, but don't define it, will run. - This simple rule lets you use UI elements to - drive the execution of your program, letting you build - interactive notebooks and tools for yourselves and others. - """ - ) + This simple rule lets you use UI elements to + drive the execution of your program, letting you build + interactive notebooks and tools for yourselves and others. + """) return @@ -102,7 +98,9 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md("""marimo has a [large library of simple UI elements](https://docs.marimo.io/api/inputs/index.html). Here are a just few examples:""") + mo.md( + """marimo has a [large library of simple UI elements](https://docs.marimo.io/api/inputs/index.html). Here are a just few examples:""" + ) return @@ -235,30 +233,26 @@ def _(basic_ui_elements, documentation): @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ### Composite elements + mo.md(""" + ### Composite elements - Composite elements are advanced elements - let you build UI elements out of other UI elements. + Composite elements are advanced elements + let you build UI elements out of other UI elements. - Use these powerful elements to logically group together related elements, - create a dynamic set of UI elements, or reduce the number of global - variables in your program. - """ - ) + Use these powerful elements to logically group together related elements, + create a dynamic set of UI elements, or reduce the number of global + variables in your program. + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - This first example shows how to create an array of UI elements using `mo.ui.array`. - When you interact with an element in the array, all cells that reference the - array are reactively run. If you instead used a regular Python list, cells referring to the list would _not_ be run. - """ - ) + mo.md(r""" + This first example shows how to create an array of UI elements using `mo.ui.array`. + When you interact with an element in the array, all cells that reference the + array are reactively run. If you instead used a regular Python list, cells referring to the list would _not_ be run. + """) return @@ -279,7 +273,9 @@ def _(array): @app.cell(hide_code=True) def _(mo): - mo.md(r"""marimo also comes with `mo.ui.dictionary`, which is analogous to `mo.ui.array`""") + mo.md( + r"""marimo also comes with `mo.ui.dictionary`, which is analogous to `mo.ui.array`""" + ) return @@ -331,29 +327,25 @@ def _(composite_elements, documentation): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" - ### Building custom elements - - marimo supports third-party UI elements through anywidget — this lets you build - your own interactive UI elements, or use widgets built by others in the - community. To learn more, [see our - docs](https://docs.marimo.io/guides/integrating_with_marimo/custom_ui_plugins.html). - """ - ) + mo.md(r""" + ### Building custom elements + + marimo supports third-party UI elements through anywidget — this lets you build + your own interactive UI elements, or use widgets built by others in the + community. To learn more, [see our + docs](https://docs.marimo.io/guides/integrating_with_marimo/custom_ui_plugins.html). + """) return @app.cell(hide_code=True) def _(mo): - mo.md( - """ - ## Appendix - The remaining cells are helper data structures and functions. - You can look at their code if you're curious how certain parts of this - tutorial were implemented. - """ - ) + mo.md(""" + ## Appendix + The remaining cells are helper data structures and functions. + You can look at their code if you're curious how certain parts of this + tutorial were implemented. + """) return diff --git a/mkdocs.yml b/mkdocs.yml index c98c6cc17a8..945d4a00754 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -107,6 +107,7 @@ nav: - Parse stdout: guides/lint_rules/rules/parse_stdout.md - Parse stderr: guides/lint_rules/rules/parse_stderr.md - Empty cells: guides/lint_rules/rules/empty_cells.md + - Markdown Indentation: guides/lint_rules/rules/markdown_indentation.md - SQL parse error: guides/lint_rules/rules/sql_parse_error.md - Misc parse log: guides/lint_rules/rules/misc_log_capture.md - SQL, dataframes, and plots: diff --git a/packages/smart-cells/src/parsers/markdown-parser.ts b/packages/smart-cells/src/parsers/markdown-parser.ts index 8be438eb2df..8b22f942df0 100644 --- a/packages/smart-cells/src/parsers/markdown-parser.ts +++ b/packages/smart-cells/src/parsers/markdown-parser.ts @@ -114,15 +114,26 @@ export class MarkdownParser implements LanguageParser { // If it's one line and not bounded by quotes, write it as single line const isOneLine = !code.includes("\n"); const boundedByQuote = code.startsWith('"') || code.endsWith('"'); + const startQuote = `${quotePrefix}"""`; if (isOneLine && !boundedByQuote) { + const markdown = `${startQuote}${escapedCode}"""`; + const prefix = "mo.md("; + if (markdown.length >= 80 - prefix.length) { + // Single lines are broken up if they exceed line length + const start = `${prefix}"\n ${startQuote}`; + return { + code: `${start}${escapedCode}"""\n)`, + offset: start.length, + }; + } const start = `mo.md(${quotePrefix}"""`; const end = `""")`; return { code: start + escapedCode + end, offset: start.length }; } // Multiline code - const start = `mo.md(\n ${quotePrefix}"""\n`; - const end = `\n"""\n)`; + const start = `mo.md(${quotePrefix}"""\n`; + const end = `\n""")`; return { code: start + escapedCode + end, offset: start.length + 1 }; } diff --git a/scripts/generate_lint_docs.py b/scripts/generate_lint_docs.py index 4cb78d2cb63..d5514ee1257 100644 --- a/scripts/generate_lint_docs.py +++ b/scripts/generate_lint_docs.py @@ -362,20 +362,7 @@ def generate_rule_page(rule_details: dict[str, Any]) -> str: """ # Add the first line of the docstring as main description - if rule['full_description'] and rule['full_description'] != rule['description']: - # Split the first line from the rest - desc_lines = rule['full_description'].split('.') - if len(desc_lines) > 1: - main_desc = desc_lines[0] + '.' - rest_desc = '.'.join(desc_lines[1:]).strip() - if rest_desc: - content += f"{main_desc}\n\n{rest_desc}\n\n" - else: - content += f"{main_desc}\n\n" - else: - content += f"{rule['full_description']}\n\n" - else: - content += f"{rule['description']}\n\n" + content += f"{rule['full_description']}\n\n" # Add structured sections from docstring sections = rule.get('sections', {}) diff --git a/tests/_cli/snapshots/markdown_to_marimo.txt b/tests/_cli/snapshots/markdown_to_marimo.txt index c2b118c4c77..d5bb28aeb69 100644 --- a/tests/_cli/snapshots/markdown_to_marimo.txt +++ b/tests/_cli/snapshots/markdown_to_marimo.txt @@ -6,13 +6,11 @@ app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" # Test Markdown print('Hello from Markdown!') - """ - ) + """) return diff --git a/tests/_cli/snapshots/remote_markdown_to_marimo.txt b/tests/_cli/snapshots/remote_markdown_to_marimo.txt index 56cd5739e93..bc669afe159 100644 --- a/tests/_cli/snapshots/remote_markdown_to_marimo.txt +++ b/tests/_cli/snapshots/remote_markdown_to_marimo.txt @@ -6,15 +6,13 @@ app = marimo.App() @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" # Remote Markdown Test ```python print('Hello from Remote Markdown!') ``` - """ - ) + """) return diff --git a/tests/_convert/snapshots/marimo_for_jupyter_users.md.txt b/tests/_convert/snapshots/marimo_for_jupyter_users.md.txt index fa2cda7a3ab..56e3dcd83af 100644 --- a/tests/_convert/snapshots/marimo_for_jupyter_users.md.txt +++ b/tests/_convert/snapshots/marimo_for_jupyter_users.md.txt @@ -73,21 +73,19 @@ cells that refer to them. In contrast, Jupyter's lack of reactivity makes IPyWidgets difficult to use. ````python {.marimo hide_code="true"} -mo.md( - r""" - ## Shareable as apps +mo.md(r""" +## Shareable as apps - marimo notebooks can be shared as read-only web apps: just serve it with +marimo notebooks can be shared as read-only web apps: just serve it with - ```marimo run your_notebook.py``` +```marimo run your_notebook.py``` - at the command-line. +at the command-line. - Not every marimo notebook needs to be shared as an app, but marimo makes it - seamless to do so if you want to. In this way, marimo works as a replacement - for both Jupyter and Streamlit. - """ -) +Not every marimo notebook needs to be shared as an app, but marimo makes it +seamless to do so if you want to. In this way, marimo works as a replacement +for both Jupyter and Streamlit. +""") ```` ## Cell order diff --git a/tests/_convert/snapshots/no-frontmatter.py.txt b/tests/_convert/snapshots/no-frontmatter.py.txt index 2aeae204c49..b4aa7cf9c8b 100644 --- a/tests/_convert/snapshots/no-frontmatter.py.txt +++ b/tests/_convert/snapshots/no-frontmatter.py.txt @@ -18,12 +18,10 @@ def _(): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" **Appendix** - This is the end of the notebook - """ - ) + """) return diff --git a/tests/_convert/snapshots/unsafe-app.md.txt b/tests/_convert/snapshots/unsafe-app.md.txt index 6027c670dbc..58807f009cb 100644 --- a/tests/_convert/snapshots/unsafe-app.md.txt +++ b/tests/_convert/snapshots/unsafe-app.md.txt @@ -9,24 +9,24 @@ import marimo as mo ````python {.marimo} mo.md(""" - # Code blocks in code blocks - Output code for Hello World! - ```python - print("Hello World") - ``` - Execute print - ```python {.marimo} - print("Hello World") - ``` +# Code blocks in code blocks +Output code for Hello World! +```python +print("Hello World") +``` +Execute print +```python {.marimo} +print("Hello World") +``` """) ```` ````python {.marimo} mo.md(f""" - with f-string too! - ```python {{.marimo}} - print("Hello World") - ``` +with f-string too! +```python {{.marimo}} +print("Hello World") +``` """) ```` @@ -53,8 +53,8 @@ The guards are ````python {.marimo} mo.md(""" - Cross cell injection - ```python +Cross cell injection +```python """) ```` diff --git a/tests/_convert/snapshots/unsafe-app.py.txt b/tests/_convert/snapshots/unsafe-app.py.txt index 3673bb15090..f7d802f6f5d 100644 --- a/tests/_convert/snapshots/unsafe-app.py.txt +++ b/tests/_convert/snapshots/unsafe-app.py.txt @@ -13,15 +13,15 @@ def _(): @app.cell def _(mo): mo.md(""" - # Code blocks in code blocks - Output code for Hello World! - ```python - print("Hello World") - ``` - Execute print - ```python {.marimo} - print("Hello World") - ``` + # Code blocks in code blocks + Output code for Hello World! + ```python + print("Hello World") + ``` + Execute print + ```python {.marimo} + print("Hello World") + ``` """) return @@ -29,10 +29,10 @@ def _(mo): @app.cell def _(mo): mo.md(f""" - with f-string too! - ```python {{.marimo}} - print("Hello World") - ``` + with f-string too! + ```python {{.marimo}} + print("Hello World") + ``` """) return @@ -50,15 +50,13 @@ def _(mo): @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" Nested fence ````text The guards are ```python {.marimo} ```` - """ - ) + """) return @@ -73,8 +71,8 @@ def _(): @app.cell def _(mo): mo.md(""" - Cross cell injection - ```python + Cross cell injection + ```python """) return diff --git a/tests/_convert/snapshots/unsafe-doc-old.md.txt b/tests/_convert/snapshots/unsafe-doc-old.md.txt index 52b396acf01..42c99eee789 100644 --- a/tests/_convert/snapshots/unsafe-doc-old.md.txt +++ b/tests/_convert/snapshots/unsafe-doc-old.md.txt @@ -15,13 +15,11 @@ print("Hello, World!") ``` ````python {.marimo hide_code="true"} -mo.md( - r""" +mo.md(r""" --> ```marimo run convert document.md``` -""" -) +""") ```` ```python {.marimo unparsable="true"} @@ -29,15 +27,13 @@ it's an unparsable cell ``` ````python {.marimo hide_code="true"} -mo.md( - r""" +mo.md(r""" ```{python} ` print("Hello, World!") -""" -) +""") ```` ```python {.marimo disabled="true"} @@ -80,9 +76,9 @@ print("Hello, World!") ````python {.marimo} mo.md(""" - This is a markdown cell with an execution block in it - ```{python} - # To ambiguous to convert - ``` - """) +This is a markdown cell with an execution block in it +```{python} +# To ambiguous to convert +``` +""") ```` \ No newline at end of file diff --git a/tests/_convert/snapshots/unsafe-doc-old.py.txt b/tests/_convert/snapshots/unsafe-doc-old.py.txt index c3564744cd3..23fa1c964f9 100644 --- a/tests/_convert/snapshots/unsafe-doc-old.py.txt +++ b/tests/_convert/snapshots/unsafe-doc-old.py.txt @@ -6,16 +6,14 @@ app = marimo.App(app_title="Casually malicious md") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" What happens if I just leave a \"\"\" " ' ! @ # $ % ^ & * ( ) + = - _ [ ] { } | \ / # Notebook ```marimo run convert document.md``` - """ - ) + """) return @@ -47,15 +43,13 @@ app._unparsable_cell( @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" ```{python} ` print("Hello, World!") - """ - ) + """) return @@ -106,8 +100,7 @@ app._unparsable_cell( @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" \"\"\" ``` @@ -121,19 +114,18 @@ def _(mo): --> - """ - ) + """) return @app.cell def _(mo): mo.md(""" - This is a markdown cell with an execution block in it - ```{python} - # To ambiguous to convert - ``` - """) + This is a markdown cell with an execution block in it + ```{python} + # To ambiguous to convert + ``` + """) return diff --git a/tests/_convert/snapshots/unsafe-doc.md.txt b/tests/_convert/snapshots/unsafe-doc.md.txt index 7757beb3333..031a8279f85 100644 --- a/tests/_convert/snapshots/unsafe-doc.md.txt +++ b/tests/_convert/snapshots/unsafe-doc.md.txt @@ -15,13 +15,11 @@ print("Hello, World!") ``` ````python {.marimo hide_code="true"} -mo.md( - r""" +mo.md(r""" --> ```marimo run convert document.md``` -""" -) +""") ```` ```python {.marimo unparsable="true"} @@ -29,15 +27,13 @@ it's an unparsable cell ``` ````python {.marimo hide_code="true"} -mo.md( - r""" +mo.md(r""" ```python {.marimo} ` print("Hello, World!") -""" -) +""") ```` ```python {.marimo disabled="true"} @@ -80,9 +76,9 @@ print("Hello, World!") ````python {.marimo} mo.md(""" - This is a markdown cell with an execution block in it - ```python {.marimo} - # To ambiguous to convert - ``` - """) +This is a markdown cell with an execution block in it +```python {.marimo} +# To ambiguous to convert +``` +""") ```` \ No newline at end of file diff --git a/tests/_convert/snapshots/unsafe-doc.py.txt b/tests/_convert/snapshots/unsafe-doc.py.txt index a3033e6817e..633638f9ac0 100644 --- a/tests/_convert/snapshots/unsafe-doc.py.txt +++ b/tests/_convert/snapshots/unsafe-doc.py.txt @@ -6,16 +6,14 @@ app = marimo.App(app_title="Casually malicious md") @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" What happens if I just leave a \"\"\" " ' ! @ # $ % ^ & * ( ) + = - _ [ ] { } | \ / # Notebook ```marimo run convert document.md``` - """ - ) + """) return @@ -47,15 +43,13 @@ app._unparsable_cell( @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" ```python {.marimo} ` print("Hello, World!") - """ - ) + """) return @@ -106,8 +100,7 @@ app._unparsable_cell( @app.cell(hide_code=True) def _(mo): - mo.md( - r""" + mo.md(r""" \"\"\" ``` @@ -121,19 +114,18 @@ def _(mo): --> - """ - ) + """) return @app.cell def _(mo): mo.md(""" - This is a markdown cell with an execution block in it - ```python {.marimo} - # To ambiguous to convert - ``` - """) + This is a markdown cell with an execution block in it + ```python {.marimo} + # To ambiguous to convert + ``` + """) return diff --git a/tests/_convert/test_convert_utils.py b/tests/_convert/test_convert_utils.py index 1f21239b65e..c26e1541222 100644 --- a/tests/_convert/test_convert_utils.py +++ b/tests/_convert/test_convert_utils.py @@ -10,16 +10,14 @@ def test_markdown_to_marimo(): markdown = "# Hello, World!\nThis is a test." - expected = 'mo.md(\n r"""\n# Hello, World!\nThis is a test.\n"""\n)' # noqa: E501 + expected = 'mo.md(r"""\n# Hello, World!\nThis is a test.\n""")' # noqa: E501 assert utils.markdown_to_marimo(markdown) == expected markdown = 'Here are some quotes: """' expected = r''' -mo.md( - r""" +mo.md(r""" Here are some quotes: \"\"\" -""" -)'''.strip() +""")'''.strip() assert utils.markdown_to_marimo(markdown) == expected @@ -32,11 +30,9 @@ def test_markdown_to_marimo_with_quotes(): markdown = '"this is markdown"' expected = ( '''\ -mo.md( - r""" +mo.md(r""" "this is markdown" -""" -)''' +""")''' ).strip() assert utils.markdown_to_marimo(markdown) == expected diff --git a/tests/_lint/snapshots/markdown_dedent_errors.txt b/tests/_lint/snapshots/markdown_dedent_errors.txt new file mode 100644 index 00000000000..f61eed81a42 --- /dev/null +++ b/tests/_lint/snapshots/markdown_dedent_errors.txt @@ -0,0 +1,41 @@ +warning[markdown-indentation]: Markdown cell should be dedented for better readability + --> tests/_lint/test_files/markdown_dedent.py:13:1 + 13 | @app.cell + 14 | def _(mo): + | ^ + 15 | mo.md( + +warning[markdown-indentation]: Markdown cell should be dedented for better readability + --> tests/_lint/test_files/markdown_dedent.py:23:1 + 23 | @app.cell + 24 | def _(mo): + | ^ + 25 | # With a comment + +warning[markdown-indentation]: Markdown cell should be dedented for better readability + --> tests/_lint/test_files/markdown_dedent.py:51:1 + 51 | @app.cell + 52 | def _(mo): + | ^ + 53 | mo.md( + +warning[markdown-indentation]: Markdown cell should be dedented for better readability + --> tests/_lint/test_files/markdown_dedent.py:63:1 + 63 | @app.cell + 64 | def _(mo): + | ^ + 65 | mo.md( + +warning[markdown-indentation]: Markdown cell should be dedented for better readability + --> tests/_lint/test_files/markdown_dedent.py:69:1 + 69 | @app.cell + 70 | def _(mo): + | ^ + 71 | mo.md( + +warning[markdown-indentation]: Markdown cell should be dedented for better readability + --> tests/_lint/test_files/markdown_dedent.py:75:1 + 75 | @app.cell + 76 | def _(mo): + | ^ + 77 | mo.md(fr"siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiingle line") diff --git a/tests/_lint/test_async_context_system.py b/tests/_lint/test_async_context_system.py index de84d807f6c..fde89935b2e 100644 --- a/tests/_lint/test_async_context_system.py +++ b/tests/_lint/test_async_context_system.py @@ -344,7 +344,7 @@ def _(): """ notebook = parse_notebook(code) - diagnostics = lint_notebook(notebook) + diagnostics = lint_notebook(notebook, code) # Should find diagnostics assert len(diagnostics) > 0 diff --git a/tests/_lint/test_files/markdown_dedent.py b/tests/_lint/test_files/markdown_dedent.py new file mode 100644 index 00000000000..f695a455618 --- /dev/null +++ b/tests/_lint/test_files/markdown_dedent.py @@ -0,0 +1,81 @@ +import marimo + +__generated_with = "0.17.0" +app = marimo.App() + + +@app.cell +def _(): + import marimo as mo + return (mo,) + + +@app.cell +def _(mo): + mo.md( + r""" + # Test Markdown + Already indented text. + """ + ) + return + +@app.cell +def _(mo): + # With a comment + # and another + mo.md( + rf""" + Has comment. No issue + """ + ) + # Suffix + return + +@app.cell +def _(mo): + # With a comment + # and another + mo.md(f"Double {{braces}}") + # Suffix + return + +@app.cell +def _(mo): + # With a comment + # and another + mo.md(rf"Single line. No issue") + # Suffix + return + +@app.cell +def _(mo): + mo.md( + rf""" + Another markdown cell with indentation. + + Some **bold** text and _italic_ text. + """ + ) + return + + +@app.cell +def _(mo): + mo.md( + rf"""single line""") + return + +@app.cell +def _(mo): + mo.md( + fr"""single line""") + return + +@app.cell +def _(mo): + mo.md(fr"siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiingle line") + return + +if __name__ == "__main__": + app.run() diff --git a/tests/_lint/test_generated_with_comparison.py b/tests/_lint/test_generated_with_comparison.py index fa6e729f1d7..fb0b66c2167 100644 --- a/tests/_lint/test_generated_with_comparison.py +++ b/tests/_lint/test_generated_with_comparison.py @@ -1,6 +1,6 @@ # Copyright 2025 Marimo. All rights reserved. -from marimo._lint.linter import _contents_differ_excluding_generated_with +from marimo._lint.linter import contents_differ_excluding_generated_with def test_contents_differ_excluding_generated_with(): @@ -34,7 +34,7 @@ def test(): """ # Should return False (no meaningful differences) - assert not _contents_differ_excluding_generated_with(original, generated) + assert not contents_differ_excluding_generated_with(original, generated) def test_contents_differ_with_real_changes(): @@ -69,7 +69,7 @@ def test(): """ # Should return True (real differences exist) - assert _contents_differ_excluding_generated_with(original, generated) + assert contents_differ_excluding_generated_with(original, generated) def test_contents_no_generated_with(): @@ -94,7 +94,7 @@ def test(): """ # Should return False (identical content) - assert not _contents_differ_excluding_generated_with(original, generated) + assert not contents_differ_excluding_generated_with(original, generated) def test_contents_mixed_generated_with(): @@ -120,4 +120,4 @@ def test(): """ # Should return True (one has __generated_with, one doesn't) - assert _contents_differ_excluding_generated_with(original, generated) + assert contents_differ_excluding_generated_with(original, generated) diff --git a/tests/_lint/test_markdown_dedent.py b/tests/_lint/test_markdown_dedent.py new file mode 100644 index 00000000000..c38fd2d5a7a --- /dev/null +++ b/tests/_lint/test_markdown_dedent.py @@ -0,0 +1,95 @@ +# Copyright 2025 Marimo. All rights reserved. +"""Tests for markdown dedent lint rule.""" + +from marimo._ast.parse import parse_notebook +from tests._lint.utils import lint_notebook + + +def test_markdown_dedent_detection(): + """Test that markdown dedent rule detects indented markdown.""" + file = "tests/_lint/test_files/markdown_dedent.py" + with open(file) as f: + code = f.read() + + notebook = parse_notebook(code, filepath=file) + errors = lint_notebook(notebook) + + # Should have MF007 errors for indented markdown cells + mf007_errors = [e for e in errors if e.code == "MF007"] + assert len(mf007_errors) > 0, "Should detect indented markdown" + + +def test_markdown_dedent_over_indent(): + """Test that correctly formatted markdown doesn't trigger the rule.""" + code = """ +import marimo + +__generated_with = "0.17.0" +app = marimo.App() + + +@app.cell +def _(): + import marimo as mo + return (mo,) + + +@app.cell +def _(mo): + mo.md(\"\"\" +# This is overly dedented + +and incorrect. +\"\"\") + return + + +if __name__ == "__main__": + app.run() +""" + notebook = parse_notebook(code, filepath="notebook.py") + errors = lint_notebook(notebook, code) + + # Should not have MF007 errors for properly dedented markdown + mf007_errors = [e for e in errors if e.code == "MF007"] + assert len(mf007_errors) == 1, ( + "Should not flag correctly dedented markdown" + ) + + +def test_markdown_dedent_no_false_positives(): + """Test that correctly formatted markdown doesn't trigger the rule.""" + code = """ +import marimo + +__generated_with = "0.17.0" +app = marimo.App() + + +@app.cell +def _(): + import marimo as mo + return (mo,) + + +@app.cell +def _(mo): + mo.md(\"\"\" + # Already dedented + + This is correct. + \"\"\") + return + + +if __name__ == "__main__": + app.run() +""" + notebook = parse_notebook(code, filepath="notebook.py") + errors = lint_notebook(notebook, code) + + # Should not have MF007 errors for properly dedented markdown + mf007_errors = [e for e in errors if e.code == "MF007"] + assert len(mf007_errors) == 0, ( + "Should not flag correctly dedented markdown" + ) diff --git a/tests/_lint/test_runtime_errors_snapshot.py b/tests/_lint/test_snapshot.py similarity index 93% rename from tests/_lint/test_runtime_errors_snapshot.py rename to tests/_lint/test_snapshot.py index 8f7cee63b6e..ed70dd32fe1 100644 --- a/tests/_lint/test_runtime_errors_snapshot.py +++ b/tests/_lint/test_snapshot.py @@ -224,3 +224,20 @@ def test_mixed_issues_snapshot(): error_output.append(error.format()) snapshot("mixed_issues_errors.txt", "\n".join(error_output)) + + +def test_markdown_dedent_snapshot(): + """Test snapshot for markdown dedent formatting.""" + file = "tests/_lint/test_files/markdown_dedent.py" + with open(file) as f: + code = f.read() + + notebook = parse_notebook(code, filepath=file) + errors = lint_notebook(notebook) + + # Format errors for snapshot + error_output = [] + for error in errors: + error_output.append(error.format()) + + snapshot("markdown_dedent_errors.txt", "\n".join(error_output)) diff --git a/tests/_lint/utils.py b/tests/_lint/utils.py index 79b6722b76a..636c91b6bba 100644 --- a/tests/_lint/utils.py +++ b/tests/_lint/utils.py @@ -1,9 +1,13 @@ """Utilities for lint tests.""" +from marimo._lint.diagnostic import Diagnostic from marimo._lint.rule_engine import RuleEngine +from marimo._schemas.serialization import NotebookSerializationV1 -def lint_notebook(notebook): +def lint_notebook( + notebook: NotebookSerializationV1, contents: str = "" +) -> list[Diagnostic]: """Lint a notebook and return all diagnostics found.""" rule_engine = RuleEngine.create_default() - return rule_engine.check_notebook_sync(notebook) + return rule_engine.check_notebook_sync(notebook, contents)