From 7d5f53ef8ffb8e93164795d2f6c1b41a1f75ffea Mon Sep 17 00:00:00 2001 From: Frederic COLLONVAL Date: Sat, 16 Jan 2021 16:36:19 +0100 Subject: [PATCH] Update examples --- advanced/kernel-messaging/README.md | 2 +- advanced/kernel-output/README.md | 24 +++--- advanced/kernel-output/src/panel.ts | 1 + advanced/server-extension/README.md | 75 +++++++++---------- .../jlab_ext_example/handlers.py | 6 +- basics/datagrid/README.md | 14 +++- basics/hello-world/README.md | 17 +++-- basics/signals/README.md | 10 ++- command-palette/README.md | 5 +- command-palette/src/index.ts | 3 - launcher/README.md | 6 +- settings/README.md | 2 +- state/README.md | 2 +- 13 files changed, 86 insertions(+), 81 deletions(-) diff --git a/advanced/kernel-messaging/README.md b/advanced/kernel-messaging/README.md index 607289a0..1b5c579f 100644 --- a/advanced/kernel-messaging/README.md +++ b/advanced/kernel-messaging/README.md @@ -9,7 +9,7 @@ ![Kernel Messages](preview.gif) -## Custom Kernel Interactions: Kernel Managment and Messaging +## Custom Kernel Interactions: Kernel Management and Messaging One of the main features of JupyterLab is the possibility to manage and interact with [kernels](https://jupyter-client.readthedocs.io/en/latest/kernels.html). diff --git a/advanced/kernel-output/README.md b/advanced/kernel-output/README.md index 9391a20b..aa800efe 100644 --- a/advanced/kernel-output/README.md +++ b/advanced/kernel-output/README.md @@ -41,7 +41,7 @@ object ([see the documentation](https://jupyterlab.github.io/jupyterlab/classes/ Here it is stored in the private `_sessionContext` variable: ```ts -// src/panel.ts#L94-L94 +// src/panel.ts#L95-L95 private _sessionContext: SessionContext; ``` @@ -50,7 +50,7 @@ A `SessionContext` handles a single kernel session. The session itself (not yet the kernel) is started with these lines: ```ts -// src/panel.ts#L44-L48 +// src/panel.ts#L45-L49 this._sessionContext = new SessionContext({ sessionManager: manager.sessions, @@ -63,7 +63,7 @@ The private session variable is exposed as read-only for other users through a getter method: ```ts -// src/panel.ts#L72-L74 +// src/panel.ts#L73-L75 get session(): ISessionContext { return this._sessionContext; @@ -75,7 +75,7 @@ with this line: ```ts -// src/panel.ts#L58-L69 +// src/panel.ts#L59-L70 void this._sessionContext .initialize() @@ -93,13 +93,13 @@ void this._sessionContext When a session has no predefined preferred kernel, a dialog will request the user to choose a kernel to start. Conveniently, this can -also be an already existing kernel, as you will see later. +also be an already existing kernel. The following two methods ensure the clean disposal of the session when you close the panel. ```ts -// src/panel.ts#L76-L79 +// src/panel.ts#L77-L80 dispose(): void { this._sessionContext.dispose(); @@ -108,7 +108,7 @@ dispose(): void { ``` ```ts -// src/panel.ts#L89-L92 +// src/panel.ts#L90-L93 protected onCloseRequest(msg: Message): void { super.onCloseRequest(msg); @@ -120,11 +120,11 @@ protected onCloseRequest(msg: Message): void { The `SimplifiedOutputArea` class is a `Widget`, as described in the [widget example](../../widget-tracker/widgets/README.md). It has the ability to display the results of a notebook cell execution. -You can instantiate it with a new `OutputAreaModel`; this is class containing +You can instantiate it with a new `OutputAreaModel`; this class is containing the data to show: ```ts -// src/panel.ts#L50-L54 +// src/panel.ts#L51-L55 this._outputareamodel = new OutputAreaModel(); this._outputarea = new SimplifiedOutputArea({ @@ -138,7 +138,7 @@ some code to a kernel through a `ISessionContext` ([see documentation](https://j in the specific `SimplifiedOutputArea` object you created: ```ts -// src/panel.ts#L81-L87 +// src/panel.ts#L82-L88 execute(code: string): void { SimplifiedOutputArea.execute(code, this._outputarea, this._sessionContext) @@ -158,7 +158,7 @@ To display the `SimplifiedOutputArea` Widget you need to add it to your panel with: ```ts -// src/panel.ts#L56-L56 +// src/panel.ts#L57-L57 this.addWidget(this._outputarea); ``` @@ -266,4 +266,4 @@ the variable name in the input dialog, it will be displayed in the example panel ## Where to Go Next This example makes use of input dialogs. To know which input dialogs are available -have a look at the [documentation](https://jupyterlab.readthedocs.io/en/stable/developer/ui_helpers.html). +have a look at the [documentation](https://jupyterlab.readthedocs.io/en/stable/extension/ui_helpers.html#dialogs). diff --git a/advanced/kernel-output/src/panel.ts b/advanced/kernel-output/src/panel.ts index 8494eaa1..ded4f69c 100644 --- a/advanced/kernel-output/src/panel.ts +++ b/advanced/kernel-output/src/panel.ts @@ -9,6 +9,7 @@ import { OutputAreaModel, SimplifiedOutputArea } from '@jupyterlab/outputarea'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { KernelMessage, ServiceManager } from '@jupyterlab/services'; + import { ITranslator, nullTranslator, diff --git a/advanced/server-extension/README.md b/advanced/server-extension/README.md index b88414ef..3b8ea678 100644 --- a/advanced/server-extension/README.md +++ b/advanced/server-extension/README.md @@ -28,12 +28,16 @@ like this (be careful to set _has\_server\_extension_ to _y_): ```bash author_name []: my_name -extension_name [myextension]: jlab_ext_example +python_name [myextension]: jlab_ext_example +extension_name [jlab_ext_example]: jlab-ext-example project_short_description [A JupyterLab extension.]: A minimal JupyterLab extension with backend and frontend parts. has_server_extension [n]: y -repository [https://github.com/my_name/myextension]: +has_binder [n]: y +repository [https://github.com/github_username/jlab_ext_example]: ``` +> The python name should not contain `-`. It is nice for user to test your extension online, so the `has_binder` was set to _yes_. + The cookiecutter creates the directory `jlab_ext_example` [or your extension name] that looks like this: @@ -41,25 +45,31 @@ that looks like this: jlab_ext_example/ │  # Generic Files │ .gitignore +│ install.json # Information retrieved by JupyterLab to help users │ LICENSE # License of your code │ README.md # Instructions to install and build │ ├───.github │ └───workflows │ build.yml +│ +├───binder +│ environment.yml +│ postBuild │   -│  # Backend (server) Files +│  # Python Package Files │ MANIFEST.in # Help Python to list your source files -│ pyproject.toml # Define dependencies for building the server package -│ setup.py # Information about the server package +│ pyproject.toml # Define dependencies for building the package +│ setup.py # Information about the package +│ +│ # Backend (server) Files +├───jupyter-config +│ jlab_ext_example.json # Server extension enabler │ ├───jlab_ext_example │ handlers.py # API handler (where things happen) │ _version.py # Server extension version │ __init__.py # Hook the extension in the server -│ -├───jupyter-config -│ jlab_ext_example.json # Server extension enabler │   │  # Frontend Files │ .eslintignore # Code linter configuration @@ -71,15 +81,17 @@ jlab_ext_example/ │   ├───src │ index.ts # Actual code of the extension -│ jlabextexample.ts # More code used by the extension +│ handler.ts # More code used by the extension │ └───style - index.css # CSS styling + base.css # CSS styling + index.css + index.js ``` There are two major parts in the extension: -- A Python package for the server extension +- A Python package for the server extension and the packaging - A NPM package for the frontend extension In this example, you will see that the template code have been extended @@ -312,20 +324,6 @@ an `IFrame` that will display static content fetched from the server extension. The server part of the extension is going to be presented in this section. -You first need to install the python source code. The following will install -the `jlab_ext_example` package in dev mode: - -```bash -pip install -e . -``` - -Then you need to enable the package at the Jupyter level -so that it becomes a server extension. - -```bash -jupyter serverextension enable --py jlab_ext_example -``` - JupyterLab server is built on top of the [Tornado](https://tornadoweb.org/en/stable/guide.html) Python package. To extend the server, your extension needs to be defined as a proper Python package with some hook functions: @@ -370,8 +368,8 @@ def load_jupyter_server_extension(lab_app): ``` -The `_jupyter_jlab_ext_example_paths` provides the Python package name -to the server. But the most important one is `load_jupyter_jlab_ext_example` +The `_jupyter_server_extension_paths` provides the Python package name +to the server. But the most important one is `load_jupyter_server_extension` that register new handlers. ```py @@ -389,7 +387,7 @@ example the url is _base_server_url_`/jlab-ext-example/hello` and the class hand host_pattern = ".*$" base_url = web_app.settings["base_url"] -# Prepend the base_url so that it works in a jupyterhub setting +# Prepend the base_url so that it works in a JupyterHub setting route_pattern = url_path_join(base_url, url_path, "hello") handlers = [(route_pattern, RouteHandler)] web_app.add_handlers(host_pattern, handlers) @@ -412,7 +410,7 @@ class RouteHandler(APIHandler): @tornado.web.authenticated def post(self): - # input_data is a dictionnary with a key "name" + # input_data is a dictionary with a key "name" input_data = self.get_json_body() data = {"greetings": "Hello {}, enjoy JupyterLab!".format(input_data["name"])} self.finish(json.dumps(data)) @@ -619,7 +617,7 @@ Basically it will build the frontend NPM package: install_npm(HERE, build_cmd="build:prod", npm=["jlpm"]), ``` -It will ensure one of the generated JS files is `lib/jlabextexample.js`: +It will ensure one of the generated files is `jlab_ext_example/labextension/package.json`: ```py # setup.py#L24-L27 @@ -704,11 +702,11 @@ And that server extension is available through `pip`: "pip" ``` -For more information on the `discovery` metadata, please refer to the [documentation](https://jupyterlab.readthedocs.io/en/stable/developer/extension_dev.html#ext-author-companion-packages). +For more information on the `discovery` metadata, please refer to the [documentation](https://jupyterlab.readthedocs.io/en/stable/extension/extension_dev.html#ext-author-companion-packages). ## Installing the Package -With the packaging described above, installing the extension is done in two commands once the package is published on pypi.org: +With the packaging described above, installing the extension is done in one command once the package is published on pypi.org: ```bash # Install the server extension and @@ -721,14 +719,11 @@ This will shunt the installation machinery described above. Therefore the comman to get you set are: ```bash -# Install server extension in editable mode +# Install package in development mode pip install -e . -# Build Typescript source -jlpm build -# Install your development version of the extension with JupyterLab -jupyter labextension develop . - -# Rebuild Typescript source after making changes -jlpm build +# Link your development version of the extension with JupyterLab +jupyter labextension develop . --overwrite +# Rebuild extension Typescript source after making changes +jlpm run build ``` diff --git a/advanced/server-extension/jlab_ext_example/handlers.py b/advanced/server-extension/jlab_ext_example/handlers.py index 7effc12b..c1a5144f 100644 --- a/advanced/server-extension/jlab_ext_example/handlers.py +++ b/advanced/server-extension/jlab_ext_example/handlers.py @@ -18,7 +18,7 @@ def get(self): @tornado.web.authenticated def post(self): - # input_data is a dictionnary with a key "name" + # input_data is a dictionary with a key "name" input_data = self.get_json_body() data = {"greetings": "Hello {}, enjoy JupyterLab!".format(input_data["name"])} self.finish(json.dumps(data)) @@ -28,12 +28,12 @@ def setup_handlers(web_app, url_path): host_pattern = ".*$" base_url = web_app.settings["base_url"] - # Prepend the base_url so that it works in a jupyterhub setting + # Prepend the base_url so that it works in a JupyterHub setting route_pattern = url_path_join(base_url, url_path, "hello") handlers = [(route_pattern, RouteHandler)] web_app.add_handlers(host_pattern, handlers) - # Prepend the base_url so that it works in a jupyterhub setting + # Prepend the base_url so that it works in a JupyterHub setting doc_url = url_path_join(base_url, url_path, "public") doc_dir = os.getenv( "JLAB_SERVER_EXAMPLE_STATIC_DIR", diff --git a/basics/datagrid/README.md b/basics/datagrid/README.md index 15bf8edc..b9c567d5 100644 --- a/basics/datagrid/README.md +++ b/basics/datagrid/README.md @@ -88,21 +88,27 @@ class LargeDataModel extends DataModel { The three abstract methods are `rowCount`, `columnCount` and `data`. The first two must return a number from a region argument. To know the possible values of `RowRegion` and the `ColumnRegion`, you can look at the -[Lumino code](https://github.com/jupyterlab/lumino/blob/9f5e11025b62d2c4a6fb59e2681ae1ed323dcde4/packages/datagrid/src/datamodel.ts#L112-L129): +[Lumino code](https://github.com/jupyterlab/lumino/blob/9c5f31cca3b02441850e086c1b19642a6e298493/packages/datagrid/src/datamodel.ts#L134-L155): ```ts /** * A type alias for the data model row regions. */ -type RowRegion = 'body' | 'column-header'; +export type RowRegion = 'body' | 'column-header'; + /** * A type alias for the data model column regions. */ -type ColumnRegion = 'body' | 'row-header'; +export type ColumnRegion = 'body' | 'row-header'; + /** * A type alias for the data model cell regions. */ -type CellRegion = 'body' | 'row-header' | 'column-header' | 'corner-header'; +export type CellRegion = + | 'body' + | 'row-header' + | 'column-header' + | 'corner-header'; ``` The `|` can be read as `or`. This means that the `RowRegion` type is diff --git a/basics/hello-world/README.md b/basics/hello-world/README.md index bb65a45c..a83d7a29 100644 --- a/basics/hello-world/README.md +++ b/basics/hello-world/README.md @@ -25,7 +25,7 @@ author_name []: tuto python_name [myextension]: hello_world extension_name [hello_world]: hello-world project_short_description [A JupyterLab extension.]: Minimal JupyterLab example -has_server_extension [n]: +has_server_extension [n]: has_binder [n]: y repository [https://github.com/github_username/hello_world]: ``` @@ -55,14 +55,14 @@ hello_world/ │ └───workflows │ build.yml │ -├───hello_world -│ __init__.py -│ _version.py -│ ├───binder │ environment.yml │ postBuild │ +├───hello_world +│ __init__.py +│ _version.py +│ ├───src │ index.ts │ @@ -134,6 +134,12 @@ const extension: JupyterFrontEndPlugin = { id: 'hello-world', autoStart: true, activate: (app: JupyterFrontEnd) => { + console.log('the JupyterLab main application:', app); + } +}; + +export default extension; + ``` ```ts @@ -200,7 +206,6 @@ The second command create a symbolic link to the folder `hello_world/labextensio The third command allows you to update the Javascript code each time you modify your extension code. - After all of these steps are done, running `jupyter labextension list` should show something like: diff --git a/basics/signals/README.md b/basics/signals/README.md index e5e8ccd5..6f9f32fb 100644 --- a/basics/signals/README.md +++ b/basics/signals/README.md @@ -62,7 +62,7 @@ Let's look at the implementations details. ## A simple React Button Start with a file called `src/button.tsx`. The `tsx` extension allows to use -HTML-like syntax with the tag notation `<>`to represent some visual elements +HTML-like syntax with the tag notation `<>` to represent some visual elements (note that you have to add a line: `"jsx": "react",` to the `tsconfig.json` file). This is a special syntax used by [React](https://reactjs.org/tutorial/tutorial.html). @@ -141,8 +141,9 @@ The `panel.ts` class defines an extension panel that displays the This is done in the constructor. ```ts -// src/panel.ts#L19-L30 +// src/panel.ts#L18-L30 +constructor(translator?: ITranslator) { super(); this._translator = translator || nullTranslator; this._trans = this._translator.load('jupyterlab'); @@ -188,13 +189,16 @@ In our case, that function writes `Button has been clicked ... times.` text to the browser console and in an alert when the big red button is clicked. ```ts -// src/panel.ts#L32-L36 +// src/panel.ts#L32-L39 private _logMessage(emitter: ButtonWidget, count: ICount): void { console.log('Hey, a Signal has been received from', emitter); console.log( `The big red button has been clicked ${count.clickCount} times.` ); + window.alert( + `The big red button has been clicked ${count.clickCount} times.` + ); ``` There it is. Signaling is conceptually important for building extensions. diff --git a/command-palette/README.md b/command-palette/README.md index 69062e39..de3de87e 100644 --- a/command-palette/README.md +++ b/command-palette/README.md @@ -23,7 +23,7 @@ import { ICommandPalette } from '@jupyterlab/apputils'; To see how you can add the command to the palette, let's have a look at `src/index.ts`. ```ts -// src/index.ts#L11-L37 +// src/index.ts#L11-L34 const extension: JupyterFrontEndPlugin = { id: 'command-palette', @@ -42,9 +42,6 @@ const extension: JupyterFrontEndPlugin = { console.log( `jlab-examples:command-palette has been called ${args['origin']}.` ); - // window.alert( - // `jlab-examples:command-palette has been called ${args['origin']}.` - // ); } }); diff --git a/command-palette/src/index.ts b/command-palette/src/index.ts index 16700f29..2dfdd692 100644 --- a/command-palette/src/index.ts +++ b/command-palette/src/index.ts @@ -25,9 +25,6 @@ const extension: JupyterFrontEndPlugin = { console.log( `jlab-examples:command-palette has been called ${args['origin']}.` ); - // window.alert( - // `jlab-examples:command-palette has been called ${args['origin']}.` - // ); } }); diff --git a/launcher/README.md b/launcher/README.md index c4922135..a114aa5c 100644 --- a/launcher/README.md +++ b/launcher/README.md @@ -10,7 +10,7 @@ dependencies to JupyterLab features. > Credit: This example is copied from Jeremy Tuloup [Python file extension](https://github.com/jtpio/jupyterlab-python-file). This example allows to create an empty Python file. To do so, -your extension will use two commands defined by the [documents manager](https://github.com/jupyterlab/jupyterlab/blob/master/packages/docmanager-extension/src/index.ts#L47-L75) of JupyterLab: +your extension will use two commands defined by the [documents manager](https://github.com/jupyterlab/jupyterlab/blob/master/packages/docmanager-extension/src/index.ts#L53-L86) of JupyterLab: - `'docmanager:new-untitled'`: Create new untitled document - `'docmanager:open'`: Open a document @@ -107,8 +107,8 @@ if (launcher) { This example uses a _command_. This is an essential concept of JupyterLab. To know more about it have a look at the [command example](../commands/README.md). -As seen in this example too, an user can execute a command from other UI elements than the launcher. To -know more about those other possible, you could look at the following examples: +An user can execute a command from other UI elements than the launcher. To +know more about those other possibilities, you could look at the following examples: - Add the command to the [command palette](../command-palette/README.md) - Add the command to a [menu](../main-menu/README.md) diff --git a/settings/README.md b/settings/README.md index 9df8a94c..52a2bdbc 100644 --- a/settings/README.md +++ b/settings/README.md @@ -266,7 +266,7 @@ setting.changed.connect(loadSetting); ``` Finally, to demonstrate the programmatic change of a setting, a command to toggle -the `flag` and `limit` settings are updated. +the `flag` and increment the `limit` settings is implemented. ```ts diff --git a/state/README.md b/state/README.md index e9337d50..579c3f65 100644 --- a/state/README.md +++ b/state/README.md @@ -156,4 +156,4 @@ will need another core token `ISettingRegistry` (see [that example](../settings/ for more information). This example makes use of a dialog to quickly request information from the user. JupyterLab -comes with a couple of helpful dialogs; see the [documentation](https://jupyterlab.readthedocs.io/en/stable/developer/ui_helpers.html#dialogs). +comes with a couple of helpful dialogs; see the [documentation](https://jupyterlab.readthedocs.io/en/stable/extension/ui_helpers.html#dialogs).