Skip to content

Commit e246581

Browse files
author
Alan Fleming
committed
Added
- launcher - kerenel status watcher and onKernelLost to dispose instead of using 'comm_live_update'. - execute_command on AsyncWidgetBase instead of execute on CommandRegistry. Renamed - JupyterFrontEnd.commands to JupyterFrontEnd.command Removed - Hookspec: get_ipylab_backend_class & run_once_at_startup
1 parent 77082c9 commit e246581

18 files changed

+326
-255
lines changed

examples/autostart.ipynb

Lines changed: 65 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@
1515
"source": [
1616
"# Autostart\n",
1717
"\n",
18-
"Autostart is a feature implemented using the [`pluggy`](https://pluggy.readthedocs.io/en/stable/index.html#pluggy) plugin system. Plugins registered under the entry point `ipylab-python-backend` will be called once when `ipylab` is activated. Normally activation of `ipylab` will occur when Jupyterlab is started (assuming `ipylab` is installed and enabled). \n",
18+
"Autostart is a feature implemented using the [`pluggy`](https://pluggy.readthedocs.io/en/stable/index.html#pluggy) plugin system. The code associated with the entry point `ipylab-python-backend` will be called (imported) when `ipylab` is activated. `ipylab` will activate when Jupyterlab is started (provided `ipylab` is installed and enabled). \n",
1919
"\n",
20-
"There are no limitations to what can be done. But some possibilities include:\n",
21-
"* Launch an app to run in its own thread;\n",
20+
"There are no limitations to what can be done. But it is recommended to import on demand to minimise the time required to launch. Some possibilities include:\n",
2221
"* Create and register custom commands;\n",
2322
"* Create launchers;\n",
24-
"* Create new notebooks;\n",
23+
"* Modify the appearance of Jupyterlab.\n",
2524
"\n",
2625
"## Entry points\n",
2726
"\n",
@@ -32,35 +31,32 @@
3231
"my-plugins-name = \"my_module.ipylab_plugin:ipylab_plugin\"\n",
3332
"```\n",
3433
"\n",
35-
"In `my_module.autostart.py` define the plugins.\n",
34+
"In `my_module.autostart.py` write code that will be run once.\n",
3635
"\n",
3736
"Example:\n",
3837
"\n",
3938
"```python\n",
4039
"# @ipylab_plugin.py\n",
4140
"\n",
42-
"import ipylab\n",
43-
"\n",
44-
"app = ipylab.JupyterFrontEnd()\n",
41+
"import asyncio\n",
4542
"\n",
46-
"def create_app():\n",
47-
" Add code here to create the app\n",
43+
"async def startup():\n",
44+
" import ipylab\n",
45+
" \n",
46+
" app = ipylab.JupyterFrontEnd() \n",
47+
" await app.read_wait()\n",
48+
" #Do everything to startup\n",
4849
"\n",
49-
"class IpylabPlugins:\n",
50-
" @ipylab.hookspecs.hookimpl()\n",
51-
" def run_once_at_startup(self):\n",
52-
" # May want to use a launcher instead\n",
53-
" app.newSession(path=\"my app\", code=create_app)\n",
54-
" # Do more stuff ...\n",
55-
"ipylab_plugin = IpylabPlugins()\n",
50+
"ipylab_plugin = None # Provide an empty object with the expected name.\n",
51+
"asyncio.create_task(startup())\n",
5652
"```"
5753
]
5854
},
5955
{
6056
"cell_type": "markdown",
6157
"metadata": {},
6258
"source": [
63-
"## Example launching a small app"
59+
"## Example creating a launcher"
6460
]
6561
},
6662
{
@@ -71,50 +67,78 @@
7167
"source": [
7268
"# @my_module.autostart.py\n",
7369
"\n",
70+
"import asyncio\n",
71+
"\n",
7472
"import ipylab\n",
7573
"\n",
7674
"app = ipylab.JupyterFrontEnd()\n",
7775
"\n",
76+
"n = 0\n",
77+
"\n",
7878
"\n",
7979
"async def create_app():\n",
80-
" # Ensure this function provides all the imports.\n",
80+
" # The code in this function is called in the new kernel (session).\n",
81+
" # Ensure imports are performed inside the function.\n",
8182
" global ma\n",
8283
" import ipywidgets as ipw\n",
8384
"\n",
8485
" import ipylab\n",
8586
"\n",
86-
" # app = ipylab.JupyterFrontEnd()\n",
87-
" # await app.wait_ready()\n",
8887
" ma = ipylab.MainArea(name=\"My demo app\")\n",
88+
" ma.content.title.label = \"Simple app\"\n",
89+
" ma.content.title.caption = ma.kernelId\n",
90+
" await ma.load()\n",
8991
" console_button = ipw.Button(description=\"Toggle console\")\n",
92+
" error_button = ipw.Button(\n",
93+
" description=\"Do an error\",\n",
94+
" tooltip=\"An error dialog will pop up when this is clicked.\\n\"\n",
95+
" \"The dialog demonstrates the use of the `on_frontend_error` plugin.\",\n",
96+
" )\n",
9097
" console_button.on_click(\n",
9198
" lambda b: ma.load_console() if ma.console_status == \"unloaded\" else ma.unload_console()\n",
9299
" )\n",
100+
" error_button.on_click(lambda b: ma.execute_command(\"Not a command\"))\n",
93101
" ma.content.children = [\n",
94102
" ipw.HTML(f\"<h3>My simple app</h3> Welcome to my app.<br> kernel id: {ma.kernelId}\"),\n",
95-
" console_button,\n",
103+
" ipw.HBox([console_button, error_button]),\n",
96104
" ]\n",
97-
" ma.content.label = \"This is my app\"\n",
98-
" ma.load()\n",
99-
" print(\"Finished creating my app\")\n",
100105
"\n",
106+
" # Shutdown when MainArea is unloaded.\n",
107+
" def on_status_change(change):\n",
108+
" if change[\"new\"] == \"unloaded\":\n",
109+
" ma.app.shutdownKernel()\n",
101110
"\n",
102-
"class MyPlugins:\n",
103-
" @ipylab.hookspecs.hookimpl()\n",
104-
" def run_once_at_startup(self):\n",
105-
" app.newSession(path=\"my app\", code=create_app)\n",
111+
" ma.observe(on_status_change, \"status\")\n",
106112
"\n",
113+
" class IpylabPlugins:\n",
114+
" # Define plugins (see IpylabHookspec for available hooks)\n",
115+
" @ipylab.hookimpl\n",
116+
" def on_frontend_error(self, obj, error, content):\n",
117+
" ma.app.dialog.show_error_message(\"Error\", str(error))\n",
107118
"\n",
108-
"ipylab_plugin = MyPlugins()"
109-
]
110-
},
111-
{
112-
"cell_type": "markdown",
113-
"metadata": {},
114-
"source": [
115-
"### Launch the app manually\n",
119+
" # Register plugin for this kernel.\n",
120+
" ipylab.hookspecs.pm.register(IpylabPlugins())\n",
116121
"\n",
117-
"We can 'launch' the app in a new kernel."
122+
"\n",
123+
"def start_my_app(cwd):\n",
124+
" global n\n",
125+
" n += 1\n",
126+
" app.newSession(path=f\"my app {n}\", code=create_app)\n",
127+
"\n",
128+
"\n",
129+
"async def register_commands():\n",
130+
" await app.command.addPythonCommand(\n",
131+
" \"start_my_app\",\n",
132+
" execute=start_my_app,\n",
133+
" label=\"Start Custom App\",\n",
134+
" icon_class=\"jp-PythonIcon\",\n",
135+
" )\n",
136+
" await app.launcher.add_item(\"start_my_app\", \"Ipylab\")\n",
137+
" return \"done\"\n",
138+
"\n",
139+
"\n",
140+
"ipylab_plugin = None\n",
141+
"t = asyncio.create_task(register_commands())"
118142
]
119143
},
120144
{
@@ -123,15 +147,7 @@
123147
"metadata": {},
124148
"outputs": [],
125149
"source": [
126-
"app.newSession(path=\"my app\", code=create_app)"
127-
]
128-
},
129-
{
130-
"cell_type": "markdown",
131-
"metadata": {},
132-
"source": [
133-
"### Auto Launch app\n",
134-
"Simulate code launch in the as it happens in `Ipylab backend`"
150+
"t.result()"
135151
]
136152
},
137153
{
@@ -140,11 +156,8 @@
140156
"metadata": {},
141157
"outputs": [],
142158
"source": [
143-
"# Register plugin (normally via the entry point `ipylab-python-backend`)\n",
144-
"ipylab.hookspecs.pm.register(ipylab_plugin)\n",
145-
"\n",
146-
"# Called when Ipylab is activated and Ipylab backend launches\n",
147-
"app._init_python_backend()"
159+
"# There is a new launcher called 'Start custom app'\n",
160+
"t = app.execute_command(\"launcher:create\")"
148161
]
149162
}
150163
],

examples/commands.ipynb

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"metadata": {},
5959
"outputs": [],
6060
"source": [
61-
"len(app.commands.commands)"
61+
"len(app.command.commands)"
6262
]
6363
},
6464
{
@@ -74,7 +74,7 @@
7474
"metadata": {},
7575
"outputs": [],
7676
"source": [
77-
"t = app.commands.execute(\n",
77+
"t = app.execute_command(\n",
7878
" \"console:create\",\n",
7979
" insertMode=\"split-right\",\n",
8080
" kernelPreference={\"id\": app.kernelId},\n",
@@ -104,7 +104,7 @@
104104
"metadata": {},
105105
"outputs": [],
106106
"source": [
107-
"app.commands.execute(\"apputils:change-theme\", theme=\"JupyterLab Dark\")"
107+
"app.execute_command(\"apputils:change-theme\", theme=\"JupyterLab Dark\")"
108108
]
109109
},
110110
{
@@ -113,7 +113,7 @@
113113
"metadata": {},
114114
"outputs": [],
115115
"source": [
116-
"t = app.commands.execute(\"apputils:change-theme\", theme=\"JupyterLab Light\")"
116+
"t = app.execute_command(\"apputils:change-theme\", theme=\"JupyterLab Light\")"
117117
]
118118
},
119119
{
@@ -138,7 +138,7 @@
138138
"metadata": {},
139139
"outputs": [],
140140
"source": [
141-
"app.commands.execute(\"terminal:create-new\")\n",
141+
"app.execute_command(\"terminal:create-new\")\n",
142142
"# It can take up to 10 seconds for the terminal to show up after the cell returns."
143143
]
144144
},
@@ -208,7 +208,7 @@
208208
"metadata": {},
209209
"outputs": [],
210210
"source": [
211-
"app.commands.addPythonCommand(\n",
211+
"app.command.addPythonCommand(\n",
212212
" \"swap_orientation\",\n",
213213
" execute=toggle_orientation,\n",
214214
" label=\"Swap orientation\",\n",
@@ -229,7 +229,7 @@
229229
"metadata": {},
230230
"outputs": [],
231231
"source": [
232-
"t = app.commands.execute(\"swap_orientation\")"
232+
"t = app.execute_command(\"swap_orientation\")"
233233
]
234234
},
235235
{
@@ -270,7 +270,7 @@
270270
"metadata": {},
271271
"outputs": [],
272272
"source": [
273-
"assert \"swap_orientation\" in app.commands.commands"
273+
"assert \"swap_orientation\" in app.command.commands"
274274
]
275275
},
276276
{
@@ -312,6 +312,24 @@
312312
"Open the command palette CTRL + SHIFT + C and the command should show now be visible. Look for `Swap orientation`"
313313
]
314314
},
315+
{
316+
"cell_type": "code",
317+
"execution_count": null,
318+
"metadata": {},
319+
"outputs": [],
320+
"source": [
321+
"app.launcher.add_item(\"swap_orientation\", \"Python Commands\")"
322+
]
323+
},
324+
{
325+
"cell_type": "code",
326+
"execution_count": null,
327+
"metadata": {},
328+
"outputs": [],
329+
"source": [
330+
"t.result()"
331+
]
332+
},
315333
{
316334
"cell_type": "markdown",
317335
"metadata": {},
@@ -327,7 +345,7 @@
327345
"metadata": {},
328346
"outputs": [],
329347
"source": [
330-
"app.commands.remove_command(\"swap_orientation\")"
348+
"app.command.remove_command(\"swap_orientation\")"
331349
]
332350
},
333351
{
@@ -336,7 +354,7 @@
336354
"metadata": {},
337355
"outputs": [],
338356
"source": [
339-
"assert \"swap_orientation\" not in app.commands.commands"
357+
"assert \"swap_orientation\" not in app.command.commands"
340358
]
341359
}
342360
],
@@ -356,14 +374,7 @@
356374
"name": "python",
357375
"nbconvert_exporter": "python",
358376
"pygments_lexer": "ipython3",
359-
"version": "3.12.1"
360-
},
361-
"widgets": {
362-
"application/vnd.jupyter.widget-state+json": {
363-
"state": {},
364-
"version_major": 2,
365-
"version_minor": 0
366-
}
377+
"version": "3.10.13"
367378
}
368379
},
369380
"nbformat": 4,

examples/icons.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@
240240
},
241241
"outputs": [],
242242
"source": [
243-
"panel.app.commands.addPythonCommand(\n",
243+
"panel.app.command.addPythonCommand(\n",
244244
" \"my-icon:randomize\",\n",
245245
" randomize_icon,\n",
246246
" label=\"Randomize My Icon\",\n",
@@ -295,7 +295,7 @@
295295
},
296296
"outputs": [],
297297
"source": [
298-
"panel.app.commands.execute(\"apputils:activate-command-palette\")"
298+
"panel.app.execute_command(\"apputils:activate-command-palette\")"
299299
]
300300
},
301301
{
@@ -313,7 +313,7 @@
313313
"metadata": {},
314314
"outputs": [],
315315
"source": [
316-
"panel.app.commands.execute(\"my-icon:randomize\", count=1)"
316+
"panel.app.execute_command(\"my-icon:randomize\", count=1)"
317317
]
318318
}
319319
],

examples/ipytree.ipynb

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@
262262
"Let's also define a couple of buttons to:\n",
263263
"\n",
264264
"- open the selected files\n",
265-
"- expand all nodes of the tre\n",
265+
"- expand all nodes of the tree\n",
266266
"- collapse all nodes of the tree"
267267
]
268268
},
@@ -315,7 +315,7 @@
315315
"cell_type": "markdown",
316316
"metadata": {},
317317
"source": [
318-
"When the \"Open\" button is clicked, we call `app.commands.execute` with the path to the file to open it in the JupyterLab interface."
318+
"When the \"Open\" button is clicked, we call `app.execute_command` with the path to the file to open it in the JupyterLab interface."
319319
]
320320
},
321321
{
@@ -328,7 +328,7 @@
328328
" for node in file_tree.selected_nodes:\n",
329329
" filepath = node.fullpath\n",
330330
" if filepath:\n",
331-
" app.commands.execute(\"docmanager:open\", {\"path\": filepath})\n",
331+
" app.execute_command(\"docmanager:open\", {\"path\": filepath})\n",
332332
"\n",
333333
"\n",
334334
"open_button.on_click(on_open_clicked)"
@@ -413,13 +413,6 @@
413413
"nbconvert_exporter": "python",
414414
"pygments_lexer": "ipython3",
415415
"version": "3.8.2"
416-
},
417-
"widgets": {
418-
"application/vnd.jupyter.widget-state+json": {
419-
"state": {},
420-
"version_major": 2,
421-
"version_minor": 0
422-
}
423416
}
424417
},
425418
"nbformat": 4,

0 commit comments

Comments
 (0)