moops 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {moops-0.1.0 → moops-0.2.0}/PKG-INFO +51 -1
- {moops-0.1.0 → moops-0.2.0}/README.md +50 -0
- {moops-0.1.0 → moops-0.2.0}/pyproject.toml +2 -1
- moops-0.2.0/src/moops/__init__.py +10 -0
- moops-0.2.0/src/moops/_input_map.py +24 -0
- {moops-0.1.0 → moops-0.2.0}/src/moops/_naming.py +7 -0
- moops-0.2.0/src/moops/_options.py +593 -0
- {moops-0.1.0 → moops-0.2.0}/src/moops/_parse.py +5 -0
- moops-0.2.0/src/moops/_query_params.py +101 -0
- moops-0.2.0/src/moops/group.py +650 -0
- moops-0.2.0/src/moops/interface.py +413 -0
- moops-0.2.0/src/moops/presets.py +66 -0
- moops-0.1.0/src/moops/__init__.py +0 -6
- moops-0.1.0/src/moops/_cli_map.py +0 -28
- moops-0.1.0/src/moops/_options.py +0 -252
- moops-0.1.0/src/moops/group.py +0 -359
- moops-0.1.0/src/moops/interface.py +0 -226
- moops-0.1.0/src/moops/presets.py +0 -32
- {moops-0.1.0 → moops-0.2.0}/src/moops/_run.py +0 -0
- {moops-0.1.0 → moops-0.2.0}/src/moops/testing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: moops
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Write Marimo notebooks that also work as CLI scripts, with unified UI controls
|
|
5
5
|
Keywords: marimo,notebooks,cli,testing
|
|
6
6
|
Author: Yair Chuchem
|
|
@@ -23,6 +23,9 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
|
|
24
24
|
# moops
|
|
25
25
|
|
|
26
|
+
[](https://pypi.org/project/moops/)
|
|
27
|
+
[](https://molab.marimo.io/github/yairchu/moops/blob/main/examples/notebook.py)
|
|
28
|
+
|
|
26
29
|
Easily write Marimo notebooks that work as CLI scripts (and more!) with minimal boilerplate.
|
|
27
30
|
|
|
28
31
|
Marimo supports notebooks running as CLI scripts,
|
|
@@ -76,6 +79,52 @@ Keyword arguments override `moops.Group` inputs by their option names,
|
|
|
76
79
|
with leading dashes removed and dashes converted to underscores.
|
|
77
80
|
If no overrides are provided, `moops.run` uses the notebook defaults.
|
|
78
81
|
|
|
82
|
+
## URL query parameters
|
|
83
|
+
|
|
84
|
+
In browser notebooks, `Group()` lets URL query parameters initialize controls
|
|
85
|
+
and keeps later control changes reflected in the URL.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
args = moops.Group()
|
|
89
|
+
input_text = args.text(value="", help_text="Input text")
|
|
90
|
+
style = args.dropdown(
|
|
91
|
+
["snake_case", "camel_case"],
|
|
92
|
+
value="snake_case",
|
|
93
|
+
help_text="Output style",
|
|
94
|
+
allow_select_none=False,
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Opening the notebook with `?input_text=Hello&style=camel_case` initializes
|
|
99
|
+
those controls from the URL. Query keys use the same names as `moops.run`
|
|
100
|
+
keyword arguments. For subgroups, use dot-separated names such as
|
|
101
|
+
`?casing.style=camel_case`.
|
|
102
|
+
|
|
103
|
+
## Custom notebook controls
|
|
104
|
+
|
|
105
|
+
Use `args.custom()` when the notebook needs an interactive control that moops
|
|
106
|
+
does not wrap directly, while the CLI should use a supported fallback control.
|
|
107
|
+
The fallback supplies the CLI parser, help text, defaults, and query-parameter
|
|
108
|
+
format.
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
plot_selection = mo.ui.matplotlib(ax)
|
|
112
|
+
fallback_slider = args.range_slider(
|
|
113
|
+
start=0,
|
|
114
|
+
stop=100,
|
|
115
|
+
value=[10, 50],
|
|
116
|
+
option="--x-range",
|
|
117
|
+
help_text="X axis range",
|
|
118
|
+
)
|
|
119
|
+
x_range = args.custom(
|
|
120
|
+
plot_selection,
|
|
121
|
+
fallback_slider,
|
|
122
|
+
value=lambda plot:
|
|
123
|
+
[plot.value.x_min, plot.value.x_max]
|
|
124
|
+
if plot.value else fallback_slider.value,
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
79
128
|
## Property-based testing
|
|
80
129
|
|
|
81
130
|
`moops.testing.notebook_interface` returns the notebook's `Interface`, from which `.strategy()` generates a [Hypothesis](https://hypothesis.readthedocs.io/) strategy that produces valid `moops.run` kwargs by introspecting the notebook's interface — dropdowns yield their allowed keys, switches yield booleans, and text fields yield arbitrary strings.
|
|
@@ -99,6 +148,7 @@ From the project root:
|
|
|
99
148
|
|
|
100
149
|
```sh
|
|
101
150
|
uv run examples/notebook.py
|
|
151
|
+
uv run --with matplotlib --with numpy examples/custom_control.py --x-range 30,70
|
|
102
152
|
```
|
|
103
153
|
|
|
104
154
|
Or `uv run marimo edit` to run as notebooks.
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# moops
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/moops/)
|
|
4
|
+
[](https://molab.marimo.io/github/yairchu/moops/blob/main/examples/notebook.py)
|
|
5
|
+
|
|
3
6
|
Easily write Marimo notebooks that work as CLI scripts (and more!) with minimal boilerplate.
|
|
4
7
|
|
|
5
8
|
Marimo supports notebooks running as CLI scripts,
|
|
@@ -53,6 +56,52 @@ Keyword arguments override `moops.Group` inputs by their option names,
|
|
|
53
56
|
with leading dashes removed and dashes converted to underscores.
|
|
54
57
|
If no overrides are provided, `moops.run` uses the notebook defaults.
|
|
55
58
|
|
|
59
|
+
## URL query parameters
|
|
60
|
+
|
|
61
|
+
In browser notebooks, `Group()` lets URL query parameters initialize controls
|
|
62
|
+
and keeps later control changes reflected in the URL.
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
args = moops.Group()
|
|
66
|
+
input_text = args.text(value="", help_text="Input text")
|
|
67
|
+
style = args.dropdown(
|
|
68
|
+
["snake_case", "camel_case"],
|
|
69
|
+
value="snake_case",
|
|
70
|
+
help_text="Output style",
|
|
71
|
+
allow_select_none=False,
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Opening the notebook with `?input_text=Hello&style=camel_case` initializes
|
|
76
|
+
those controls from the URL. Query keys use the same names as `moops.run`
|
|
77
|
+
keyword arguments. For subgroups, use dot-separated names such as
|
|
78
|
+
`?casing.style=camel_case`.
|
|
79
|
+
|
|
80
|
+
## Custom notebook controls
|
|
81
|
+
|
|
82
|
+
Use `args.custom()` when the notebook needs an interactive control that moops
|
|
83
|
+
does not wrap directly, while the CLI should use a supported fallback control.
|
|
84
|
+
The fallback supplies the CLI parser, help text, defaults, and query-parameter
|
|
85
|
+
format.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
plot_selection = mo.ui.matplotlib(ax)
|
|
89
|
+
fallback_slider = args.range_slider(
|
|
90
|
+
start=0,
|
|
91
|
+
stop=100,
|
|
92
|
+
value=[10, 50],
|
|
93
|
+
option="--x-range",
|
|
94
|
+
help_text="X axis range",
|
|
95
|
+
)
|
|
96
|
+
x_range = args.custom(
|
|
97
|
+
plot_selection,
|
|
98
|
+
fallback_slider,
|
|
99
|
+
value=lambda plot:
|
|
100
|
+
[plot.value.x_min, plot.value.x_max]
|
|
101
|
+
if plot.value else fallback_slider.value,
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
56
105
|
## Property-based testing
|
|
57
106
|
|
|
58
107
|
`moops.testing.notebook_interface` returns the notebook's `Interface`, from which `.strategy()` generates a [Hypothesis](https://hypothesis.readthedocs.io/) strategy that produces valid `moops.run` kwargs by introspecting the notebook's interface — dropdowns yield their allowed keys, switches yield booleans, and text fields yield arbitrary strings.
|
|
@@ -76,6 +125,7 @@ From the project root:
|
|
|
76
125
|
|
|
77
126
|
```sh
|
|
78
127
|
uv run examples/notebook.py
|
|
128
|
+
uv run --with matplotlib --with numpy examples/custom_control.py --x-range 30,70
|
|
79
129
|
```
|
|
80
130
|
|
|
81
131
|
Or `uv run marimo edit` to run as notebooks.
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "moops"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "Write Marimo notebooks that also work as CLI scripts, with unified UI controls"
|
|
9
9
|
license = "MIT"
|
|
10
10
|
readme = "README.md"
|
|
@@ -39,6 +39,7 @@ dev-dependencies = [
|
|
|
39
39
|
"pyright>=1.1.409",
|
|
40
40
|
"pytest>=9.0.3",
|
|
41
41
|
"vulture>=2.16",
|
|
42
|
+
"pymarkdownlnt>=0.9.37",
|
|
42
43
|
]
|
|
43
44
|
|
|
44
45
|
[tool.pytest.ini_options]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from importlib.metadata import version
|
|
2
|
+
|
|
3
|
+
from ._run import run
|
|
4
|
+
from .group import Group
|
|
5
|
+
from .interface import Interface
|
|
6
|
+
from .presets import Presets
|
|
7
|
+
|
|
8
|
+
__version__ = version("moops")
|
|
9
|
+
|
|
10
|
+
__all__ = ["Group", "Interface", "Presets", "__version__", "run"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import weakref
|
|
3
|
+
|
|
4
|
+
from . import _options
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class InputMap:
|
|
8
|
+
"""Maps UI controls to their input-channel counterparts."""
|
|
9
|
+
|
|
10
|
+
def __init__(self) -> None:
|
|
11
|
+
self._registered: weakref.WeakValueDictionary[str, _options.InputControl] = (
|
|
12
|
+
weakref.WeakValueDictionary()
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
def register(self, control: typing.Any, cli: _options.InputControl) -> typing.Any:
|
|
16
|
+
self._registered[cli.option] = cli
|
|
17
|
+
control._moops_input = cli
|
|
18
|
+
return control
|
|
19
|
+
|
|
20
|
+
def get(self, control: typing.Any) -> _options.InputControl | None:
|
|
21
|
+
return getattr(control, "_moops_input", None)
|
|
22
|
+
|
|
23
|
+
def registered_options(self) -> typing.Iterator[_options.InputControl]:
|
|
24
|
+
yield from self._registered.values()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import dataclasses
|
|
2
|
+
import html
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
@dataclasses.dataclass
|
|
@@ -25,3 +26,9 @@ class OptionLabel:
|
|
|
25
26
|
if label is None:
|
|
26
27
|
label = option.lstrip("-").replace("-", " ")
|
|
27
28
|
return OptionLabel(label=label, option=option)
|
|
29
|
+
|
|
30
|
+
def label_with_tooltip(self, help_text: str) -> str:
|
|
31
|
+
return (
|
|
32
|
+
f'<span title="{html.escape(help_text, quote=True)} ({self.option})">'
|
|
33
|
+
f"{self.label}</span>"
|
|
34
|
+
)
|