Skip to content

Commit

Permalink
Added
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
Alan Fleming committed Feb 11, 2024
1 parent 77082c9 commit e246581
Show file tree
Hide file tree
Showing 18 changed files with 326 additions and 255 deletions.
117 changes: 65 additions & 52 deletions examples/autostart.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
"source": [
"# Autostart\n",
"\n",
"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",
"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",
"\n",
"There are no limitations to what can be done. But some possibilities include:\n",
"* Launch an app to run in its own thread;\n",
"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",
"* Create and register custom commands;\n",
"* Create launchers;\n",
"* Create new notebooks;\n",
"* Modify the appearance of Jupyterlab.\n",
"\n",
"## Entry points\n",
"\n",
Expand All @@ -32,35 +31,32 @@
"my-plugins-name = \"my_module.ipylab_plugin:ipylab_plugin\"\n",
"```\n",
"\n",
"In `my_module.autostart.py` define the plugins.\n",
"In `my_module.autostart.py` write code that will be run once.\n",
"\n",
"Example:\n",
"\n",
"```python\n",
"# @ipylab_plugin.py\n",
"\n",
"import ipylab\n",
"\n",
"app = ipylab.JupyterFrontEnd()\n",
"import asyncio\n",
"\n",
"def create_app():\n",
" Add code here to create the app\n",
"async def startup():\n",
" import ipylab\n",
" \n",
" app = ipylab.JupyterFrontEnd() \n",
" await app.read_wait()\n",
" #Do everything to startup\n",
"\n",
"class IpylabPlugins:\n",
" @ipylab.hookspecs.hookimpl()\n",
" def run_once_at_startup(self):\n",
" # May want to use a launcher instead\n",
" app.newSession(path=\"my app\", code=create_app)\n",
" # Do more stuff ...\n",
"ipylab_plugin = IpylabPlugins()\n",
"ipylab_plugin = None # Provide an empty object with the expected name.\n",
"asyncio.create_task(startup())\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example launching a small app"
"## Example creating a launcher"
]
},
{
Expand All @@ -71,50 +67,78 @@
"source": [
"# @my_module.autostart.py\n",
"\n",
"import asyncio\n",
"\n",
"import ipylab\n",
"\n",
"app = ipylab.JupyterFrontEnd()\n",
"\n",
"n = 0\n",
"\n",
"\n",
"async def create_app():\n",
" # Ensure this function provides all the imports.\n",
" # The code in this function is called in the new kernel (session).\n",
" # Ensure imports are performed inside the function.\n",
" global ma\n",
" import ipywidgets as ipw\n",
"\n",
" import ipylab\n",
"\n",
" # app = ipylab.JupyterFrontEnd()\n",
" # await app.wait_ready()\n",
" ma = ipylab.MainArea(name=\"My demo app\")\n",
" ma.content.title.label = \"Simple app\"\n",
" ma.content.title.caption = ma.kernelId\n",
" await ma.load()\n",
" console_button = ipw.Button(description=\"Toggle console\")\n",
" error_button = ipw.Button(\n",
" description=\"Do an error\",\n",
" tooltip=\"An error dialog will pop up when this is clicked.\\n\"\n",
" \"The dialog demonstrates the use of the `on_frontend_error` plugin.\",\n",
" )\n",
" console_button.on_click(\n",
" lambda b: ma.load_console() if ma.console_status == \"unloaded\" else ma.unload_console()\n",
" )\n",
" error_button.on_click(lambda b: ma.execute_command(\"Not a command\"))\n",
" ma.content.children = [\n",
" ipw.HTML(f\"<h3>My simple app</h3> Welcome to my app.<br> kernel id: {ma.kernelId}\"),\n",
" console_button,\n",
" ipw.HBox([console_button, error_button]),\n",
" ]\n",
" ma.content.label = \"This is my app\"\n",
" ma.load()\n",
" print(\"Finished creating my app\")\n",
"\n",
" # Shutdown when MainArea is unloaded.\n",
" def on_status_change(change):\n",
" if change[\"new\"] == \"unloaded\":\n",
" ma.app.shutdownKernel()\n",
"\n",
"class MyPlugins:\n",
" @ipylab.hookspecs.hookimpl()\n",
" def run_once_at_startup(self):\n",
" app.newSession(path=\"my app\", code=create_app)\n",
" ma.observe(on_status_change, \"status\")\n",
"\n",
" class IpylabPlugins:\n",
" # Define plugins (see IpylabHookspec for available hooks)\n",
" @ipylab.hookimpl\n",
" def on_frontend_error(self, obj, error, content):\n",
" ma.app.dialog.show_error_message(\"Error\", str(error))\n",
"\n",
"ipylab_plugin = MyPlugins()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Launch the app manually\n",
" # Register plugin for this kernel.\n",
" ipylab.hookspecs.pm.register(IpylabPlugins())\n",
"\n",
"We can 'launch' the app in a new kernel."
"\n",
"def start_my_app(cwd):\n",
" global n\n",
" n += 1\n",
" app.newSession(path=f\"my app {n}\", code=create_app)\n",
"\n",
"\n",
"async def register_commands():\n",
" await app.command.addPythonCommand(\n",
" \"start_my_app\",\n",
" execute=start_my_app,\n",
" label=\"Start Custom App\",\n",
" icon_class=\"jp-PythonIcon\",\n",
" )\n",
" await app.launcher.add_item(\"start_my_app\", \"Ipylab\")\n",
" return \"done\"\n",
"\n",
"\n",
"ipylab_plugin = None\n",
"t = asyncio.create_task(register_commands())"
]
},
{
Expand All @@ -123,15 +147,7 @@
"metadata": {},
"outputs": [],
"source": [
"app.newSession(path=\"my app\", code=create_app)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Auto Launch app\n",
"Simulate code launch in the as it happens in `Ipylab backend`"
"t.result()"
]
},
{
Expand All @@ -140,11 +156,8 @@
"metadata": {},
"outputs": [],
"source": [
"# Register plugin (normally via the entry point `ipylab-python-backend`)\n",
"ipylab.hookspecs.pm.register(ipylab_plugin)\n",
"\n",
"# Called when Ipylab is activated and Ipylab backend launches\n",
"app._init_python_backend()"
"# There is a new launcher called 'Start custom app'\n",
"t = app.execute_command(\"launcher:create\")"
]
}
],
Expand Down
47 changes: 29 additions & 18 deletions examples/commands.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"metadata": {},
"outputs": [],
"source": [
"len(app.commands.commands)"
"len(app.command.commands)"
]
},
{
Expand All @@ -74,7 +74,7 @@
"metadata": {},
"outputs": [],
"source": [
"t = app.commands.execute(\n",
"t = app.execute_command(\n",
" \"console:create\",\n",
" insertMode=\"split-right\",\n",
" kernelPreference={\"id\": app.kernelId},\n",
Expand Down Expand Up @@ -104,7 +104,7 @@
"metadata": {},
"outputs": [],
"source": [
"app.commands.execute(\"apputils:change-theme\", theme=\"JupyterLab Dark\")"
"app.execute_command(\"apputils:change-theme\", theme=\"JupyterLab Dark\")"
]
},
{
Expand All @@ -113,7 +113,7 @@
"metadata": {},
"outputs": [],
"source": [
"t = app.commands.execute(\"apputils:change-theme\", theme=\"JupyterLab Light\")"
"t = app.execute_command(\"apputils:change-theme\", theme=\"JupyterLab Light\")"
]
},
{
Expand All @@ -138,7 +138,7 @@
"metadata": {},
"outputs": [],
"source": [
"app.commands.execute(\"terminal:create-new\")\n",
"app.execute_command(\"terminal:create-new\")\n",
"# It can take up to 10 seconds for the terminal to show up after the cell returns."
]
},
Expand Down Expand Up @@ -208,7 +208,7 @@
"metadata": {},
"outputs": [],
"source": [
"app.commands.addPythonCommand(\n",
"app.command.addPythonCommand(\n",
" \"swap_orientation\",\n",
" execute=toggle_orientation,\n",
" label=\"Swap orientation\",\n",
Expand All @@ -229,7 +229,7 @@
"metadata": {},
"outputs": [],
"source": [
"t = app.commands.execute(\"swap_orientation\")"
"t = app.execute_command(\"swap_orientation\")"
]
},
{
Expand Down Expand Up @@ -270,7 +270,7 @@
"metadata": {},
"outputs": [],
"source": [
"assert \"swap_orientation\" in app.commands.commands"
"assert \"swap_orientation\" in app.command.commands"
]
},
{
Expand Down Expand Up @@ -312,6 +312,24 @@
"Open the command palette CTRL + SHIFT + C and the command should show now be visible. Look for `Swap orientation`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"app.launcher.add_item(\"swap_orientation\", \"Python Commands\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"t.result()"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand All @@ -327,7 +345,7 @@
"metadata": {},
"outputs": [],
"source": [
"app.commands.remove_command(\"swap_orientation\")"
"app.command.remove_command(\"swap_orientation\")"
]
},
{
Expand All @@ -336,7 +354,7 @@
"metadata": {},
"outputs": [],
"source": [
"assert \"swap_orientation\" not in app.commands.commands"
"assert \"swap_orientation\" not in app.command.commands"
]
}
],
Expand All @@ -356,14 +374,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.1"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
"version": "3.10.13"
}
},
"nbformat": 4,
Expand Down
6 changes: 3 additions & 3 deletions examples/icons.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@
},
"outputs": [],
"source": [
"panel.app.commands.addPythonCommand(\n",
"panel.app.command.addPythonCommand(\n",
" \"my-icon:randomize\",\n",
" randomize_icon,\n",
" label=\"Randomize My Icon\",\n",
Expand Down Expand Up @@ -295,7 +295,7 @@
},
"outputs": [],
"source": [
"panel.app.commands.execute(\"apputils:activate-command-palette\")"
"panel.app.execute_command(\"apputils:activate-command-palette\")"
]
},
{
Expand All @@ -313,7 +313,7 @@
"metadata": {},
"outputs": [],
"source": [
"panel.app.commands.execute(\"my-icon:randomize\", count=1)"
"panel.app.execute_command(\"my-icon:randomize\", count=1)"
]
}
],
Expand Down
13 changes: 3 additions & 10 deletions examples/ipytree.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@
"Let's also define a couple of buttons to:\n",
"\n",
"- open the selected files\n",
"- expand all nodes of the tre\n",
"- expand all nodes of the tree\n",
"- collapse all nodes of the tree"
]
},
Expand Down Expand Up @@ -315,7 +315,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"When the \"Open\" button is clicked, we call `app.commands.execute` with the path to the file to open it in the JupyterLab interface."
"When the \"Open\" button is clicked, we call `app.execute_command` with the path to the file to open it in the JupyterLab interface."
]
},
{
Expand All @@ -328,7 +328,7 @@
" for node in file_tree.selected_nodes:\n",
" filepath = node.fullpath\n",
" if filepath:\n",
" app.commands.execute(\"docmanager:open\", {\"path\": filepath})\n",
" app.execute_command(\"docmanager:open\", {\"path\": filepath})\n",
"\n",
"\n",
"open_button.on_click(on_open_clicked)"
Expand Down Expand Up @@ -413,13 +413,6 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.2"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 2,
"version_minor": 0
}
}
},
"nbformat": 4,
Expand Down
Loading

0 comments on commit e246581

Please sign in to comment.