Skip to content

Commit a9c7563

Browse files
mscolnickakshayka
andauthored
feat: configure auto-add script metadata to notebook file, when using uv (marimo-team#2102)
* feat: configure auto-add script metadata to notebook file, when using uv * fix * snapshots * fix * improve * update * snapshots * add script metadat * fixes * 38com * name changes * Update package_management.md * Update package_management.md * add modules post installation * handle deletion * todo on using module watcher * deletion test --------- Co-authored-by: Akshay Agrawal <akshay@marimo.io>
1 parent 4c89075 commit a9c7563

20 files changed

Lines changed: 465 additions & 38 deletions

File tree

docs/guides/editor_features/configuration.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/guides/editor_features/index.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ notebooks. We've taken a batteries-included approach to designing the editor:
1515
it comes _packed_ with features to make you productive when working
1616
with code and data.
1717

18-
| Guide | Description |
19-
| :------------------- | :---------------------------------------------- |
20-
| {doc}`overview` | An overview of editor features and configuration |
21-
| {doc}`ai_completion` | Code with the help of a language model |
22-
| {doc}`hotkeys` | Our hotkeys |
18+
| Guide | Description |
19+
| :------------------------ | :----------------------------------------------- |
20+
| {doc}`overview` | An overview of editor features and configuration |
21+
| {doc}`package_management` | Using package managers in marimo |
22+
| {doc}`ai_completion` | Code with the help of a language model |
23+
| {doc}`hotkeys` | Our hotkeys |
2324

2425
Highlights include:
2526

docs/guides/editor_features/overview.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ A non-exhaustive list of settings:
2424

2525
- Outputs above or below code cells
2626
- [Disable/enable autorun](/guides/reactivity.md#runtime-configuration)
27+
- Package installation
2728
- Vim keybindings
2829
- Dark mode
2930
- Auto-save
@@ -67,14 +68,14 @@ marimo ships with the IDE panels that provide an overview of your notebook:
6768

6869
1. **file explorer**: view the file tree, open other notebooks
6970
2. **variables**: explore variable values, see where they are defined and used, with go-to-definition
70-
2. **data explorer**: see dataframe and table schemas at a glance
71-
3. **dependency graph**: view dependencies between cells, drill-down on nodes and edges
72-
4. **table of contents**: corresponding to your markdown
73-
5. **documentation** - move your text cursor over a symbol to see its documentation
74-
6. **logs**: a continuous stream of stdout and stderr
75-
7. **scratchpad**: a scratchpad cell where you can execute throwaway code
76-
8. **snippets** - searchable snippets to copy directly into your notebook
77-
9. **feedback** - share feedback!
71+
3. **data explorer**: see dataframe and table schemas at a glance
72+
4. **dependency graph**: view dependencies between cells, drill-down on nodes and edges
73+
5. **table of contents**: corresponding to your markdown
74+
6. **documentation** - move your text cursor over a symbol to see its documentation
75+
7. **logs**: a continuous stream of stdout and stderr
76+
8. **scratchpad**: a scratchpad cell where you can execute throwaway code
77+
9. **snippets** - searchable snippets to copy directly into your notebook
78+
10. **feedback** - share feedback!
7879
:::
7980

8081
::::
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Package management
2+
3+
marimo supports package management for `pip, rye, uv, poetry, pixi`. When marimo comes across a module that is not installed, you will be prompted to install it using your preferred package manager.
4+
5+
Once the module is installed, all cells that depend on the module will be rerun.
6+
7+
```{admonition} Package Installation
8+
:class: note
9+
10+
We use some heuristic for guessing the package name in your registry (e.g. PyPI) from the module name. It is possible that the package name is different from the module name. If you encounter an error, please file an issue, so we can correct the heuristic.
11+
```
12+
13+
## Auto-add inline script metadata (`uv` only)
14+
15+
When using [uv](https://docs.astral.sh/uv), marimo can automatically add the package name metadata to your script, per [PEP 723](https://peps.python.org/pep-0723/). This metadata is used to manage the script's dependencies and Python version.
16+
17+
For example, say you start marimo in a new virtual environment and spin up a new notebook. Whenever you add a new package, marimo will automatically add script metadata that looks like this:
18+
19+
```python
20+
# /// script
21+
# requires-python = ">=3.11"
22+
# dependencies = [
23+
# "pandas",
24+
# "altair",
25+
# ]
26+
# ///
27+
```

frontend/src/components/app-config/user-config-form.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,47 @@ export const UserConfigForm: React.FC = () => {
458458
</FormItem>
459459
)}
460460
/>
461+
<FormField
462+
control={form.control}
463+
disabled={isWasmRuntime}
464+
name="package_management.add_script_metadata"
465+
render={({ field }) => {
466+
if (form.getValues("package_management.manager") !== "uv") {
467+
return <div />;
468+
}
469+
470+
return (
471+
<div className="flex flex-col gap-y-1">
472+
<FormItem className={formItemClasses}>
473+
<FormLabel className="font-normal">
474+
Auto-add script metadata
475+
</FormLabel>
476+
<FormControl>
477+
<Checkbox
478+
data-testid="auto-instantiate-checkbox"
479+
disabled={field.disabled}
480+
checked={field.value}
481+
onCheckedChange={field.onChange}
482+
/>
483+
</FormControl>
484+
</FormItem>
485+
<FormDescription>
486+
Whether marimo should automatically add package metadata to
487+
scripts. See more about{" "}
488+
<a
489+
href="https://docs.marimo.io/guides/editor_features/package_management.html"
490+
target="_blank"
491+
rel="noreferrer"
492+
className="text-link hover:underline"
493+
>
494+
package metadata
495+
</a>
496+
.
497+
</FormDescription>
498+
</div>
499+
);
500+
}}
501+
/>
461502
</SettingGroup>
462503
<SettingGroup title="Runtime">
463504
<FormField

frontend/src/core/config/__tests__/config-schema.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ test("default UserConfig - empty", () => {
4949
"preset": "default",
5050
},
5151
"package_management": {
52+
"add_script_metadata": false,
5253
"manager": "pip",
5354
},
5455
"runtime": {
@@ -99,6 +100,7 @@ test("default UserConfig - one level", () => {
99100
"preset": "default",
100101
},
101102
"package_management": {
103+
"add_script_metadata": false,
102104
"manager": "pip",
103105
},
104106
"runtime": {

frontend/src/core/config/config-schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export const UserConfigSchema = z
9090
package_management: z
9191
.object({
9292
manager: z.enum(PackageManagerNames).default("pip"),
93+
add_script_metadata: z.boolean().default(false),
9394
})
9495
.default({ manager: "pip" }),
9596
ai: z

marimo/_config/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,12 @@ class PackageManagementConfig(TypedDict):
159159
**Keys.**
160160
161161
- `manager`: the package manager to use
162+
- `add_script_metadata`: if true, add script metadata to the notebook
163+
Currently only supports `uv`
162164
"""
163165

164166
manager: Literal["pip", "rye", "uv", "poetry", "pixi"]
167+
add_script_metadata: bool
165168

166169

167170
@dataclass
@@ -230,7 +233,7 @@ class MarimoConfig(TypedDict):
230233
"autosave_delay": 1000,
231234
"format_on_save": False,
232235
},
233-
"package_management": {"manager": "pip"},
236+
"package_management": {"manager": "pip", "add_script_metadata": False},
234237
"server": {
235238
"browser": "default",
236239
"follow_symlink": False,

marimo/_runtime/packages/package_manager.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import abc
55
import shutil
66
import subprocess
7+
from typing import List
78

89

910
class PackageManager(abc.ABC):
@@ -53,6 +54,21 @@ def run(self, command: list[str]) -> bool:
5354
proc = subprocess.run(command) # noqa: ASYNC101
5455
return proc.returncode == 0
5556

57+
def update_notebook_script_metadata(
58+
self,
59+
filepath: str,
60+
import_namespaces_to_add: List[str],
61+
import_namespaces_to_remove: List[str],
62+
) -> None:
63+
del filepath, import_namespaces_to_add, import_namespaces_to_remove
64+
"""
65+
Add or remove inline script metadata metadata
66+
in the marimo notebook.
67+
68+
This follows PEP 723 https://peps.python.org/pep-0723/
69+
"""
70+
return
71+
5672

5773
class CanonicalizingPackageManager(PackageManager):
5874
"""Base class for package managers.

marimo/_runtime/packages/pypi_package_manager.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright 2024 Marimo. All rights reserved.
22
from __future__ import annotations
33

4+
from typing import List
5+
46
from marimo._runtime.packages.module_name_to_pypi_name import (
57
module_name_to_pypi_name,
68
)
@@ -48,6 +50,42 @@ class UvPackageManager(PypiPackageManager):
4850
async def _install(self, package: str) -> bool:
4951
return self.run(["uv", "pip", "install", package])
5052

53+
def update_notebook_script_metadata(
54+
self,
55+
filepath: str,
56+
import_namespaces_to_add: List[str],
57+
import_namespaces_to_remove: List[str],
58+
) -> None:
59+
# Convert from module name to package name
60+
packages_to_add = [
61+
self.module_to_package(im) for im in import_namespaces_to_add
62+
]
63+
packages_to_remove = [
64+
self.module_to_package(im) for im in import_namespaces_to_remove
65+
]
66+
67+
# Filter to packages that are found by "uv pip show"
68+
packages_to_add = [
69+
im for im in packages_to_add if self._is_installed(im)
70+
]
71+
packages_to_remove = [
72+
im for im in packages_to_remove if self._is_installed(im)
73+
]
74+
75+
if packages_to_add:
76+
self.run(
77+
["uv", "--quiet", "add", "--script", filepath]
78+
+ packages_to_add
79+
)
80+
if packages_to_remove:
81+
self.run(
82+
["uv", "--quiet", "remove", "--script", filepath]
83+
+ packages_to_remove
84+
)
85+
86+
def _is_installed(self, package: str) -> bool:
87+
return self.run(["uv", "--quiet", "pip", "show", package])
88+
5189

5290
class RyePackageManager(PypiPackageManager):
5391
name = "rye"

0 commit comments

Comments
 (0)