holoviz-mcp 0.4.0__py3-none-any.whl

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.
Files changed (56) hide show
  1. holoviz_mcp/__init__.py +18 -0
  2. holoviz_mcp/apps/__init__.py +1 -0
  3. holoviz_mcp/apps/configuration_viewer.py +116 -0
  4. holoviz_mcp/apps/holoviz_get_best_practices.py +173 -0
  5. holoviz_mcp/apps/holoviz_search.py +319 -0
  6. holoviz_mcp/apps/hvplot_get_docstring.py +255 -0
  7. holoviz_mcp/apps/hvplot_get_signature.py +252 -0
  8. holoviz_mcp/apps/hvplot_list_plot_types.py +83 -0
  9. holoviz_mcp/apps/panel_get_component.py +496 -0
  10. holoviz_mcp/apps/panel_get_component_parameters.py +467 -0
  11. holoviz_mcp/apps/panel_list_components.py +311 -0
  12. holoviz_mcp/apps/panel_list_packages.py +71 -0
  13. holoviz_mcp/apps/panel_search_components.py +312 -0
  14. holoviz_mcp/cli.py +75 -0
  15. holoviz_mcp/client.py +94 -0
  16. holoviz_mcp/config/__init__.py +29 -0
  17. holoviz_mcp/config/config.yaml +178 -0
  18. holoviz_mcp/config/loader.py +316 -0
  19. holoviz_mcp/config/models.py +208 -0
  20. holoviz_mcp/config/resources/best-practices/holoviews.md +423 -0
  21. holoviz_mcp/config/resources/best-practices/hvplot.md +465 -0
  22. holoviz_mcp/config/resources/best-practices/panel-material-ui.md +318 -0
  23. holoviz_mcp/config/resources/best-practices/panel.md +562 -0
  24. holoviz_mcp/config/schema.json +228 -0
  25. holoviz_mcp/holoviz_mcp/__init__.py +1 -0
  26. holoviz_mcp/holoviz_mcp/data.py +970 -0
  27. holoviz_mcp/holoviz_mcp/models.py +21 -0
  28. holoviz_mcp/holoviz_mcp/pages_design.md +407 -0
  29. holoviz_mcp/holoviz_mcp/server.py +220 -0
  30. holoviz_mcp/hvplot_mcp/__init__.py +1 -0
  31. holoviz_mcp/hvplot_mcp/server.py +146 -0
  32. holoviz_mcp/panel_mcp/__init__.py +17 -0
  33. holoviz_mcp/panel_mcp/data.py +319 -0
  34. holoviz_mcp/panel_mcp/models.py +124 -0
  35. holoviz_mcp/panel_mcp/server.py +443 -0
  36. holoviz_mcp/py.typed +0 -0
  37. holoviz_mcp/serve.py +36 -0
  38. holoviz_mcp/server.py +86 -0
  39. holoviz_mcp/shared/__init__.py +1 -0
  40. holoviz_mcp/shared/extract_tools.py +74 -0
  41. holoviz_mcp/thumbnails/configuration_viewer.png +0 -0
  42. holoviz_mcp/thumbnails/holoviz_get_best_practices.png +0 -0
  43. holoviz_mcp/thumbnails/holoviz_search.png +0 -0
  44. holoviz_mcp/thumbnails/hvplot_get_docstring.png +0 -0
  45. holoviz_mcp/thumbnails/hvplot_get_signature.png +0 -0
  46. holoviz_mcp/thumbnails/hvplot_list_plot_types.png +0 -0
  47. holoviz_mcp/thumbnails/panel_get_component.png +0 -0
  48. holoviz_mcp/thumbnails/panel_get_component_parameters.png +0 -0
  49. holoviz_mcp/thumbnails/panel_list_components.png +0 -0
  50. holoviz_mcp/thumbnails/panel_list_packages.png +0 -0
  51. holoviz_mcp/thumbnails/panel_search_components.png +0 -0
  52. holoviz_mcp-0.4.0.dist-info/METADATA +216 -0
  53. holoviz_mcp-0.4.0.dist-info/RECORD +56 -0
  54. holoviz_mcp-0.4.0.dist-info/WHEEL +4 -0
  55. holoviz_mcp-0.4.0.dist-info/entry_points.txt +2 -0
  56. holoviz_mcp-0.4.0.dist-info/licenses/LICENSE.txt +30 -0
@@ -0,0 +1,318 @@
1
+ # Panel Material UI
2
+
3
+ This guide provides best practices for using Panel Material UI. Optimized for LLMs.
4
+
5
+ Please develop code, tests and documentation as an **expert Panel analytics app developer** would do when working with a **short time to market**.
6
+
7
+ **For general Panel best practices, see the Panel best practices guide. This guide focuses on Panel Material UI-specific patterns. This guide takes precedence over the Panel Best Practices guide.**
8
+
9
+ ## Best Practice Hello World App
10
+
11
+ Let's describe our best practices via a basic Hello World App:
12
+
13
+ ```python
14
+ # DO import panel as pn
15
+ import panel as pn
16
+ # DO import panel_material_ui as pmui
17
+ import panel_material_ui as pmui
18
+ import param
19
+
20
+ # DO run pn.extension
21
+ # DO remember to add any imports needed by panes, e.g. pn.extension("tabulator", "plotly", ...)
22
+ # DON'T add "bokeh" as an extension. It is not needed.
23
+ # Do use throttled=True when using slider unless you have a specific reason not to
24
+ pn.extension(throttled=True)
25
+
26
+ # DO organize functions to extract data separately as your app grows
27
+ # DO use caching to speed up the app, e.g. for expensive data loading or processing that would return the same result given same input arguments.
28
+ # DO add a ttl (time to live argument) for expensive data loading that changes over time
29
+ @pn.cache(max_items=3)
30
+ def extract(n=5):
31
+ return "Hello World" + "⭐" * n
32
+
33
+ text = extract()
34
+ text_len = len(text)
35
+
36
+ # DO organize functions to transform data separately as your app grows. Eventually in a separate transform.py file
37
+ # DO add caching to speed up expensive data transformations
38
+ def transform(data: str, count: int=5)->str:
39
+ """
40
+ Transforms the input data by truncating it to the specified count of characters.
41
+ """
42
+ count = min(count, len(data))
43
+ return data[:count]
44
+
45
+ # DO organize functions to create plots separately as your app grows. Eventually in a separate plots.py file.
46
+ # DO organize custom components and views separately as your app grows. Eventually in separate components.py or views.py file(s).
47
+
48
+ # DO use param.Parameterized, pn.viewable.Viewer or similar approach to create new components and apps with state and reactivity
49
+ class HelloWorld(pn.viewable.Viewer):
50
+ """
51
+ A simple Panel app that displays a "Hello World" message with a slider to control the length of the message.
52
+ """
53
+ # DO define parameters to hold state and drive the reactivity
54
+ characters = param.Integer(default=text_len, bounds=(0, text_len), doc="Number of characters to display")
55
+
56
+ def __init__(self, **params):
57
+ super().__init__(**params)
58
+
59
+ # DO use sizing_mode="stretch_width" for components unless "fixed" or other sizing_mode is specifically needed
60
+ with pn.config.set(sizing_mode="stretch_width"):
61
+ # DO create widgets using `.from_param` method
62
+ self._characters_input = pmui.IntSlider.from_param(self.param.characters, margin=(10,20))
63
+ # DO Collect input widgets into horizontal, columnar layout unless other layout is specifically needed
64
+ self._inputs = pmui.Column(self._characters_input, max_width=300)
65
+ # DO collect output components into some layout like Column, Row, FlexBox or Grid depending on use case
66
+ self._outputs = pmui.Column(self.model)
67
+ self._panel = pmui.Row(self._inputs, self._outputs)
68
+
69
+
70
+ # DO use caching to speed up bound methods that are expensive to compute or load data and return the same result for a given state of the class.
71
+ @pn.cache
72
+ # DO prefer .depends over .bind over .rx for reactivity methods on Parameterized classes as it can be typed and documented
73
+ # DON'T use `watch=True` or `.watch` methods to update UI. Only for updating overall app or component state.
74
+ # DO use `watch=True` or `.watch` for triggering side effect like saving file or sending email.
75
+ @param.depends("characters")
76
+ def model(self):
77
+ """
78
+ Returns the "Hello World" message truncated to the specified number of characters.
79
+ """
80
+ return transform(text, self.characters)
81
+
82
+ # DO provide a method for displaying the component in a notebook setting, i.e. without using a Template or Page element
83
+ def __panel__(self):
84
+ return self._panel
85
+
86
+ # DO provide a method to create a .servable app
87
+ @classmethod
88
+ def create_app(cls, **params):
89
+ """
90
+ Create the Panel app with the interactive model and slider.
91
+ """
92
+ instance = cls(**params)
93
+ # DO use the `Page` to layout the served app unless otherwise specified
94
+ return pmui.Page(
95
+ # DO provide a title for the app
96
+ title="Hello World App",
97
+ # DO provide optional image, optional app description, optional navigation menu, input widgets, optional documentation and optional links in the sidebar
98
+ # DO provide as list of components or a list of single horizontal layout like Column as the sidebar by default is 300 px wide
99
+ sidebar=list(instance._inputs),
100
+ # DO provide a list of layouts and output components in the main area of the app.
101
+ # DO use Grid or FlexBox layouts for complex dashboard layouts instead of combination Rows and Columns.
102
+ main=list(instance._outputs),
103
+ )
104
+
105
+ # DO provide a method to serve the app with `python`
106
+ if __name__ == "__main__":
107
+ # DO run with `python path_to_this_file.py`
108
+ HelloWorld.create_app().show(port=5007, autoreload=True, open=True)
109
+ # DO provide a method to serve the app with `panel serve`
110
+ elif pn.state.served:
111
+ # DO run with `panel serve path_to_this_file.py --port 5007 --dev` add `--show` to open the app in a browser
112
+ HelloWorld.create_app().servable() # DO mark the element(s) to serve with .servable()
113
+ ```
114
+
115
+ DO always create test in separate test files and DO run test via pytest:
116
+
117
+
118
+ ```python
119
+ import ...
120
+
121
+ # DO put tests into separate test file(s)
122
+ # DO test the reactivity of each parameter, function, method, component or app.
123
+ # DO run pytest when the code is changed. DON'T create non-pytest scripts or files to test the code.
124
+ def test_characters_reactivity():
125
+ """
126
+ Always test that the reactivity works as expected.
127
+ Put tests in a separate test file.
128
+ """
129
+ # Test to be added in separate test file
130
+ hello_world = HelloWorld()
131
+ assert hello_world.model() == text[:hello_world.characters] # DO test the default values of bound methods
132
+ hello_world.characters = 5
133
+ assert hello_world.model() == text[:5] # DO test the reactivity of bound methods when parameters change
134
+ hello_world.characters = 3
135
+ assert hello_world.model() == text[:3]
136
+ ```
137
+
138
+ ## Panel Material UI Guidelines
139
+
140
+ ### General Instructions
141
+
142
+ - DO use the new parameter names (e.g. `label`, `color`) instead of legacy aliases (e.g. `name`, `button_type`) for pmui components
143
+ - DO use `sizing_mode` parameter over `sx` css styling parameter
144
+ - DO use Material UI `sx` parameter for all css styling over `styles` and `stylesheets`
145
+ - DO use panel-material-ui components instead of panel components for projects already using panel-material-ui and for new projects
146
+
147
+ ## Component Instructions
148
+
149
+ ### Page
150
+
151
+ - DO provide the title to the `Page.title` argument. DON'T provide it in the `Page.main` area.
152
+ - DO provide an optional image, description, navigation menu to the `Page.sidebar` argument. Normally DON't put them in the `header` or `main` areas.
153
+ - DO provide the input widgets as children to the `Page.sidebar` argument
154
+ - DO not add advanced or high components to the `Page.header` as it is only 100px high by default. Normally only buttons, indicators, text and navigation links go into the header.
155
+ - DON'T include `ThemeToggle` or other widgets to toggle the theme when using the `Page`. A `ThemeToggle` is already built in.
156
+ - DO Add a little bit of `margin=10` to the outer layout component(s) in the `main` area. To make them stand out from the `sidebar` components: `Grid(..., container=True, margin=15)`.
157
+
158
+ DO provide lists of children to the `Page.sidebar`, `Page.main` or `Page.header` arguments:
159
+
160
+ ```python
161
+ pmui.Page(
162
+ header=[component1, component2], # This is correct
163
+ sidebar=[component3, component4], # This is correct
164
+ main=[a_list_like_layout, a_grid], # This is correct
165
+ )
166
+ ```
167
+
168
+ DON'T provide non-lists as children to the `Page.sidebar`, `Page.main` or `Page.header` arguments:
169
+
170
+ ```python
171
+ pmui.Page(
172
+ header=component1, # This is incorrect
173
+ sidebar=list(a_list_like_layout), # This is incorrect
174
+ main=list(a_grid), # This is incorrect
175
+ )
176
+ ```
177
+
178
+ #### Linking Dashboard Theme with Page Theme
179
+
180
+ DO synchronize component themes with Page theme:
181
+
182
+ ```python
183
+ ...
184
+
185
+ dark_theme = param.Boolean(
186
+ doc="""True if the theme is dark""",
187
+ # To enable providing parameters and bound function references
188
+ allow_refs=True
189
+ )
190
+
191
+ @classmethod
192
+ def create_app(cls, **params):
193
+ """Create app with synchronized theming."""
194
+ component = cls(**params)
195
+
196
+ page = pmui.Page(
197
+ ...,
198
+ dark_theme=component.dark_theme, # Pass theme to Page
199
+ )
200
+
201
+ # Synchronize Page theme to component theme
202
+ component.dark_theme = page.param.dark_theme
203
+ return page
204
+ ```
205
+
206
+ ### Grid
207
+
208
+ - DO set `spacing=2` or higher to separate sub components in the grid.
209
+
210
+ ### Column/ Row
211
+
212
+ - DO use `size` parameter instead of `xs`, `sm` or `md` parameters - they do not exist.
213
+ - DO use `sx` to set `spacing` instead of setting `spacing` directly. It does not exist.
214
+
215
+ ### List like layouts
216
+
217
+ For list-like layouts like `Column` and `Row` DO provide children as positional arguments:
218
+
219
+ ```python
220
+ pmui.Row(child1, child2, child3) # DO
221
+ ```
222
+
223
+ DON'T provide them as separate arguments:
224
+
225
+ ```python
226
+ pmui.Row([child1, child2, child3,]) # DON'T
227
+ ```
228
+
229
+ ### Switch
230
+
231
+ - Do add `margin=(10, 20)` when displaying in the sidebar.
232
+
233
+ ### Sliders
234
+
235
+ - DO add a little bit of margin left and right when displaying in the sidebar.
236
+
237
+ ### Cards
238
+
239
+ - DO use the `Paper` component over the `Card` unless you need the `Card`s extra features.
240
+ - DO set `collapsible=False` unless collapsible is needed.
241
+
242
+ ### Tabulator
243
+
244
+ - DO use "materialize" `theme` instead of "material". The latter does not exist.
245
+
246
+ ### Non-Existing Components
247
+
248
+ - Do use `Column` instead of `Box`. The `Box` component does not exist.
249
+
250
+ ## Material UI Examples
251
+
252
+ ### Standalone Icons
253
+
254
+ DO use `Typography` to make standalone icons without interactivity instead of `IconButton`:
255
+
256
+ ```python
257
+ # CORRECT: Typography for standalone decorative icons
258
+ pmui.Typography(
259
+ f'<span class="material-icons" style="font-size: 4rem;">lightbulb</span>',
260
+ sizing_mode="fixed", width=60, height=60, sx = {"color": "primary.main"},
261
+ )
262
+ # INCORRECT: IconButton for decorative icons
263
+ pmui.IconButton(icon=icon, disabled=True, ...)
264
+ ```
265
+
266
+ ### Static Components Pattern (Material UI)
267
+ ```python
268
+ import panel as pn
269
+ import panel_material_ui as pmui
270
+ import param
271
+
272
+ pn.extension()
273
+
274
+ class HelloWorld(pn.viewable.Viewer):
275
+ characters = param.Integer(default=10, bounds=(1, 100), doc="Number of characters to display")
276
+
277
+ def _get_kpi_card(self):
278
+ # Create a static layout once
279
+ return pmui.Paper(
280
+ pmui.Column(
281
+ pmui.Typography(
282
+ "📊 Key Performance Metrics",
283
+ variant="h6",
284
+ sx={
285
+ "color": "text.primary",
286
+ "fontWeight": 700,
287
+ "mb": 3,
288
+ "display": "flex",
289
+ "alignItems": "center",
290
+ "gap": 1
291
+ }
292
+ ),
293
+ pmui.Row(
294
+ # Use a reactive/ bound/ reference value for dynamic content
295
+ self.kpi_value
296
+ )
297
+ ),
298
+ )
299
+
300
+ @param.depends("characters")
301
+ def kpi_value(self):
302
+ return f"The kpi is {self.characters}"
303
+
304
+ def __panel__(self):
305
+ return pmui.Paper(
306
+ pmui.Column(
307
+ self.param.characters,
308
+ self._get_kpi_card(),
309
+ ),
310
+ sx={"padding": "20px", "borderRadius": "8px"},
311
+ sizing_mode="stretch_width"
312
+ )
313
+
314
+ if pn.state.served:
315
+ HelloWorld().servable()
316
+ ```
317
+
318
+ **For all other Panel patterns (parameter-driven architecture, reactive updates, serving, etc.), see the Panel Best Practices Guide.**