Creating Your Own Extensions for JupyterLab
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 131 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/69416 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
00:00
Field extensionReceiver operating characteristicOptical character recognitionLaptopMagneto-optical driveLink (knot theory)Repository (publishing)CodeDemo (music)Inheritance (object-oriented programming)Social classCoding theoryPole (complex analysis)Enterprise architectureProduct (business)Data managementOpen sourceSoftwareMathematical analysis1 (number)Kummer-TheorieInheritance (object-oriented programming)Multiplication signSelf-organizationEmailLink (knot theory)Revision controlLaptopOpen sourceSoftware engineeringBasis <Mathematik>Social classWeb pageRepository (publishing)Computer animationLecture/Conference
01:44
CodeVideo game consoleOnline helpKummer-TheorieKernel (computing)Cellular automatonControl flowComputer fileRadical (chemistry)LaptopAreaRight angleCASE <Informatik>
02:18
CodeElectronic visual displayForceInterrupt <Informatik>Online helpComa BerenicesComputer fileDot productKummer-TheorieKernel (computing)Plot (narrative)Inversion (music)Enterprise resource planningDesign of experimentsDebuggerAreaWeb browserComputer fileCategory of beingVideo game consoleKummer-TheoriePoint (geometry)LaptopOpen setComputer animation
02:49
Remote Access ServicePlot (narrative)Demo (music)CodeOffice suiteKummer-TheorieLine (geometry)Control flowVideo GenieElectronic visual displayKernel (computing)Video game consoleCellular automatonException handlingComputer fileBitNetwork topologyForestProduct (business)Computer animation
03:29
Interrupt <Informatik>Control flowCellular automatonVideo game consoleCodeGUI widgetPoint (geometry)Different (Kate Ryan album)Programming languageSymbol tableComputer animation
04:08
Kummer-TheorieLaptopPlug-in (computing)Function (mathematics)Social classToken ringInstance (computer science)GUI widgetCategory of beingTouchscreenTemplate (C++)Windows RegistryAreaComputer configurationDefault (computer science)Virtual realityWindows RegistryLaptopDebuggerVirtual realityGUI widgetFunctional (mathematics)Type theoryKummer-TheorieCodeDifferent (Kate Ryan album)Data managementTouchscreenParameter (computer programming)Function (mathematics)Revision controlSet (mathematics)Multiplication signTerm (mathematics)Social classMathematical analysisPlug-in (computing)Integrated development environmentIdentifiabilityToken ringService (economics)Instance (computer science)MappingCondition numberClassical physicsDivergenceAverageInstallation artComputer animation
07:23
Integrated development environmentSuccessive over-relaxationKummer-TheorieTemplate (C++)Integrated development environmentCondition numberType theoryArithmetic progressionKummer-TheorieHTTP cookieTemplate (C++)Projective planeSoftware developerComputer animation
08:14
Codierung <Programmierung>Kummer-TheorieArrow of timeKummer-TheorieTemplate (C++)User interfaceWeb browserServer (computing)MereologyType theoryMultiplication signDebuggerComputer animation
08:47
Kummer-TheorieDistribution (mathematics)Kummer-TheorieAuthorizationType theoryUniform resource locatorSet (mathematics)Multiplication signSoftware testingLinear regressionDescriptive statisticsComputer animation
09:39
StatisticsMathematicsLogarithmCodeAreaCase moddingOvalElectronic mailing listComputer fileMathematicsKummer-TheorieDirectory serviceComputer animation
10:17
CodeLogarithmMathematicsExact sequenceKummer-TheorieKey (cryptography)Sima (architecture)Maxima and minimaComputer fileData managementPoint (geometry)AuthorizationHome pageDescriptive statisticsRevision controlFile formatSheaf (mathematics)Scripting languageComputer animationSource code
10:56
Manufacturing execution systemWeb pageTrigonometric functionsRevision controlBuildingScripting languageComputer fileSource codeLevel (video gaming)Type theoryKummer-Theorie2 (number)Software developerAsynchronous Transfer ModeProduct (business)Source codeComputer animation
11:36
CASE <Informatik>Macro (computer science)Simultaneous localization and mappingCodeBit rateLogarithmMathematicsStaff (military)Codierung <Programmierung>Reading (process)Price indexComa BerenicesScripting languageSheaf (mathematics)Computer fileCartesian coordinate systemDirectory serviceSource codeSubject indexingKummer-TheorieSource codeComputer animation
12:13
Kummer-TheorieIntrusion detection systemSocial classDescriptive statisticsKummer-TheorieAttribute grammarFunctional (mathematics)String (computer science)Plug-in (computing)DebuggerCartesian coordinate systemPoint (geometry)Interactive televisionFront and back endsType theoryArithmetic meanMobile appRight angleComputer animation
13:32
Repository (publishing)CodeKummer-TheorieMathematicsInstallation artProjective planeCodeRepository (publishing)Multiplication signLink (knot theory)Data managementComputer animation
14:05
FingerprintLogic gateEvolutionarily stable strategyRevision controlCAN busCache (computing)Bit rateEstimationSystem of linear equationsStatisticsMathematicsLogarithmTouchscreenMultiplication sign2 (number)Data miningMessage passingTrailDirectory serviceComputer fileInstallation artData managementSource codeComputer animation
14:41
StatisticsModule (mathematics)Vertex (graph theory)Thomas BayesValue-added networkAsynchronous Transfer ModeOrder of magnitudeSystem of linear equationsMultiplication signNumberCartesian coordinate systemMobile appUtility softwareComputer animation
15:16
Kummer-TheorieInstallation artConservation of energyGEDCOMOrdinary differential equationVertex (graph theory)BootingElectronic mailing listComputer fileScripting languageBuildingData mining2 (number)Message passingKummer-TheorieElectronic mailing listSoftware developerMultiplication signMathematicsCodeArithmetic meanAsynchronous Transfer ModeInstallation artComputer animation
16:24
Exact sequence40 (number)LaceCodeInstallation artKummer-TheorieElectronic mailing listKummer-TheorieElectronic mailing listDirectory serviceDifferent (Kate Ryan album)Flow separationSoftware developerComputer animation
16:56
AngleGodPseudodifferentialoperatorDesign of experimentsCommercial Orbital Transportation ServicesMessage passingRevision controlProjective planeKummer-TheorieElectronic mailing listInstallation artDirectory serviceMathematicsLink (knot theory)WindowIntegrated development environment2 (number)CodeSource codeComputer animation
17:42
Cellular automatonVideo game consoleKummer-TheorieKernel (computing)Computer fileInformationPrice indexDigital filterCodeGUI widgetAreaTemplate (C++)Computer virusDefault (computer science)Function (mathematics)Web browserVideo game consoleKummer-TheorieRight angleGraphical user interfaceSoftware developerWritingMessage passingKey (cryptography)Programmer (hardware)Attribute grammarWeb browserSoftware testingFunctional (mathematics)Cartesian coordinate systemWindows RegistryMobile appCodeComputer virusString (computer science)Computer animation
19:40
Set-top boxPC CardDefault (computer science)Modul <Datentyp>BootingVertex (graph theory)Run time (program lifecycle phase)Video game consoleKummer-TheorieCellular automatonLaptopPrice indexKernel (computing)Exception handlingGUI widgetTemplate (C++)AreaAbelian categoryWeb browserBuildingMessage passingMereologyCartesian coordinate systemCategory of beingAttribute grammarService (economics)Token ringElectronic mailing listMobile appTouchscreenWindows RegistryFunctional (mathematics)CodeLine (geometry)System callPlug-in (computing)Source codeComputer animation
21:05
Run time (program lifecycle phase)Computer engineeringPlastikkarteWebsitePrice indexKernel (computing)Video game consoleDebuggerException handlingKummer-TheorieElectronic visual displayMagneto-optical driveTemplate (C++)GUI widgetAreaConservation of energyAsynchronous Transfer ModeInterrupt <Informatik>Cellular automatonBuildingVideo game consoleWeb browserFunctional (mathematics)GUI widgetTouchscreenAreaSource codeComputer animation
21:38
Data acquisitionAreaGUI widgetKummer-TheorieConstructor (object-oriented programming)Inheritance (object-oriented programming)Computer virusGastropod shellFunction (mathematics)Content (media)Inheritance (object-oriented programming)Cartesian coordinate systemSocial classMessage passingConstructor (object-oriented programming)GUI widgetMenu (computing)Multiplication signFunctional (mathematics)Element (mathematics)Parameter (computer programming)String (computer science)Type theoryElectronic signatureAreaWindows RegistryGreatest elementGastropod shellEmailTouchscreenAttribute grammarContent (media)System callTesselationIdentifiabilityVariable (mathematics)Video game consoleWeb browserDisk read-and-write headMobile appComputer animation
24:28
CodeKernel (computing)Electronic visual displayKummer-TheorieError messageComputer virusMathematicsCellular automatonGUI widgetComputer configurationState diagramDefault (computer science)Electronic program guideGUI widgetWeb browserGreatest elementComputer fileDirectory serviceComputer animationLecture/Conference
25:00
GUI widgetType theoryKummer-TheorieMultiplication signPosition operatorGraph coloringLatent heatEmailSocial classComputer animation
25:35
Inheritance (object-oriented programming)Constructor (object-oriented programming)GUI widgetLine (geometry)Cellular automatonException handlingVideo game consoleDebuggerCodeLine (geometry)Social classMessage passingGUI widgetDot productConstructor (object-oriented programming)Web browserMenu (computing)Computer animationSource code
26:09
GUI widgetComputer configurationComputer iconState transition systemKummer-TheorieFunction (mathematics)Video game consoleLogarithmAbelian categoryLaptopSheaf (mathematics)LaptopKummer-TheorieVideo game consoleFunctional (mathematics)Mobile appWeb browserSystem callMereologyMessage passingComputer configurationCategory of beingAttribute grammarComputer animation
27:32
Algorithmic information theoryModule (mathematics)CodeOctahedronComponent-based software engineeringService (economics)Magneto-optical drivePrinciple of relativityModule (mathematics)Windows RegistryData managementSystem callComputer animation
28:10
BootingOperations support systemRippingCommon Information Model (computing)Computer fileLocal ringDirectory serviceKummer-Theorie2 (number)Sheaf (mathematics)Installation artFunction (mathematics)File formatWindows RegistryDirectory serviceComputer fileSheaf (mathematics)Cartesian coordinate systemComputer animation
28:50
ForceKernel (computing)Cellular automatonVideo game consoleAbelian categoryLaptopLogarithmContent (media)Gastropod shellGUI widgetFunction (mathematics)Open setComputer virusInheritance (object-oriented programming)Web browserToken ringWeb browserAdditionRight angleParameter (computer programming)String (computer science)Object-oriented programmingConstructor (object-oriented programming)Logical constantGUI widgetDifferent (Kate Ryan album)Functional (mathematics)Type theoryKey (cryptography)Cartesian coordinate systemDefault (computer science)WordAttribute grammarCategory of beingSource codeComputer animation
30:38
Kernel (computing)View (database)MathematicsVideo game consoleCellular automatonSingle sign-onException handling2 (number)Electronic visual displayGUI widgetComputer configurationEvent horizonAreaParameter (computer programming)Event horizonGUI widgetSocial classSet (mathematics)Constructor (object-oriented programming)Computer animation
31:33
Gastropod shellFunction (mathematics)Kummer-TheorieVideo game consoleLogarithmAbelian categoryLaptop2 (number)Web browserMathematicsKernel (computing)Exception handlingCodeCellular automatonFunctional (mathematics)Web browserAreaGUI widgetRight angleComputer iconComputer animation
32:16
Video game consoleComputer fileGUI widgetEvent horizonComputer configurationAreaMagneto-optical driveOptical character recognitionPersonal area networkConstructor (object-oriented programming)Inheritance (object-oriented programming)Interior (topology)String (computer science)Element (mathematics)Gastropod shellLogarithmAbelian categoryLaptopWeb browserGUI widgetRight angleEvent horizonWeb browserWindows RegistryInformationMobile appRow (database)Field (computer science)Key (cryptography)Electronic signatureDebuggerDifferent (Kate Ryan album)Constructor (object-oriented programming)Functional (mathematics)Programming languageSystem callComputer animation
33:41
Successive over-relaxationTrigonometric functionsThermische ZustandsgleichungImplicit function theoremToken ringCore dumpKummer-TheorieLink (knot theory)Software developerElectronic program guideRepository (publishing)Gastropod shellRandom numberProgramming languageDifferent (Kate Ryan album)LaptopCore dumpText editorRepository (publishing)Link (knot theory)MereologySound effectSet (mathematics)Presentation of a groupMultiplication signKummer-TheorieCodeToken ringBitTouchscreenGastropod shellWindows RegistryElectronic program guideSoftware developerMathematicsGUI widgetDebuggerMenu (computing)Slide ruleComputer animation
36:28
Successive over-relaxationCorrelation and dependenceDesign of experimentsArc (geometry)Optical character recognitionUser interfaceDifferent (Kate Ryan album)Type theoryPresentation of a groupLaptopSoftware frameworkInterface (computing)Revision controlKummer-TheorieGoodness of fitGUI widgetMultiplication signFront and back endsInstallation artControl flowToken ringService (economics)Roundness (object)DebuggerResultantMoment (mathematics)Key (cryptography)Disk read-and-write headCodeComputer iconGreatest elementComputer clusterLecture/ConferenceComputer animation
Transcript: English(auto-generated)
00:04
Thank you. So we're talking about Jupyter extensions, which ones in particular, extensions for JupyterLab or Jupyter Notebook version 7 and higher. I designed this talk as a tutorial.
00:20
It can be given either as a talk or a tutorial. Basically I'm going to do the tutorial in front of you and explain what I'm doing and then you can, you know, I'll give you some links to the repository and step-by-step documentation. You can go do the tutorial. If you have questions, my email is on my GitHub page.
00:42
So prerequisites, obviously you need to be familiar with either Jupyter Notebook or JupyterLab and you'll need to have some experience coding classes and inheritance. I'd like to start saying thank you. Thank you to all of you for coming. Thank you. We were just discussing with Mark all the volunteers and organizers.
01:03
This is one of the best conferences I've been to. It is amazing. And of course the conference sponsors and my employer Bloomberg for also being a sponsor and for sponsoring me to come to this conference. I'm going to try to save some time.
01:20
I'll just tell you Bloomberg does a lot of heavy-duty software engineering for high-level professionals in the financial industry. We're a relatively big company, 21,000 employees. About 43% of our employees are software engineers and a little less than half of them work with Python on a daily basis.
01:41
And we do a lot with open source as well. We can skip about me. You can read my bio if you're interested. I'm going to give a quick little tour of JupyterLab in case some of you are like I was when I started this and I was very familiar with Jupyter Notebooks but not so familiar with JupyterLab. So this is JupyterLab. This is the main area right here where we can open up notebooks.
02:03
We can open up a terminal, edit files, text files, markdown files, Python files. And then we have an area over here. We call this the side panel. This is the left side panel and there are multiple panels over here. We can also open up a right side panel. There's the debugger over here.
02:21
Both panels can be closed. Then you have a larger central area. And this particular panel that we're looking at is called the command palette. There are various commands here that we can run in different categories. We can run console commands, debugger commands, extension commands. Another side panel over here I just want to point out is the file browser where we
02:44
can click on files, open up a notebook for example, open up a Python file for editing, open up another Python file. These tabs can be dragged around. So you can put your files side by side and compare them and close the side panel and get a little bit more room. That's JupyterLab for those of you who may not have been all that familiar with it.
03:04
Now let me show you kind of the end product of this tutorial before we get into the step by step so you can kind of see the forest for the trees. We're going to create over here on the side panel a command in the command palette, hello world, and we're also going to see how we can create one
03:22
over here in the launcher. Obviously, you can create these commands. I can put it in the menus. I can put it down here in the little icons, and when you click on it, it's going to say hello world. We've got a nice widget there that says hello world. At this point, you can code whatever you want to put in there. The last step of the tutorial is we're going
03:42
to create our own side panel here with different buttons, and when you click on them, you'll be able to get the whole hello world in different languages. Just to give an example of where you might go with something like this, here I've created a side panel where you can put in the ticker symbol
04:03
of a stock, and it comes back and it tells you the name of the stock, and then I could click the button that says candle chart, for example, and I get a candle chart over here, historical prices for the stock. I could click this and do a technical analysis of the stock, moving average, convergence, divergence, and maybe I could add another button here
04:21
and it would take all this calculated data and throw it into a notebook for me so that I can do further analysis. So that's just to give you an idea of where you can go with these types of things. Some vocabulary to help us with the tutorial, if you hear the term NB extension, notebook extension, these are the classic Jupyter notebook extensions.
04:41
They are being deprecated. That's not what we're going to learn today. They're being replaced with lab extensions, which as I mentioned before, work with JupyterLab or notebook 7 and higher. At Lumino and at JupyterLab are NPM package scopes for TypeScript and JavaScript packages. We'll be using them in the tutorial.
05:02
A plug-in is, this is the basic class that provides the extension functionality. And now we can define an extension as a package that you can build and distribute that contains one or more of these plug-in extension classes. A token is an identifier for a service. It's an instance of the Lumino token class.
05:24
There is a concept that comes from the Lumino package in the Jupyter front end called the command registry. It's a place where you can register commands and then it's basically a mapping from a command identifier to a function and then these commands can be executed
05:40
from anywhere within JupyterLab. So we'll be doing that. A widget is basically anything on the screen and JLPM stands for the JupyterLab packaging manager. That's Jupyter's own version of the yarn packaging manager. We'll be using that as well. So now just quickly to go through the steps that I broke up the tutorial.
06:00
In step zero we're going to create a basic do nothing extension from a template. Then we'll modify the extension to actually put a command in the command registry. Then we'll see how we can execute that command from the command palette. Modify the command to create a widget on the screen. Style that widget. Execute the command from somewhere else in JupyterLab.
06:22
And then we'll see how we can pass arguments to our command so we can make it behave differently in different situations. Perhaps for different users you want it to behave differently if they have different preferences and things like that. And then finally we'll create that sidebar widget, another widget that has buttons in it to execute our command in different ways.
06:42
So to start the tutorial you want to create a virtual environment. I like using mini conda. You can use conda or mamba or micro mamba. Either of them work. So we're going to call conda create and name our extension, name our environment JLX. I chose that name, JupyterLab extension.
07:02
We want to override channels and set strict channel priority. We're going to use channel conda forge and set no defaults so that if the code isn't found in conda forge it's not going to fall back to anything else. We're going to install JupyterLab 4, Node.js 18, Git, Copier 7, and Jinja 2 time is something that Copier needs.
07:24
When you create your conda environment, if you haven't done it before it kind of looks like this. It shows you the packages you requested and all the dependent packages that it's going to install. And after it lists that it asks you do you want to proceed. And then you'll see a progress bar when it hits 100%. It'll tell you that it's done.
07:41
And then it'll tell you to activate your environment. You type in conda activate JLX. And so we do that and we have our environment to do our development. Next we're going to run Copier. Copier is a project templating tool similar to cookie cutter or yeoman or hygiene. So we run the copy command on Copier.
08:02
We're going to take our template from github.com slash JupyterLab slash extension dash template. And we're going to name our template EPJLX for EuroPython JupyterLab extension. These templating tools, as you may know, the first thing they do is they ask you a bunch of
08:20
questions so they can configure your template. It's going to ask us what type of extensions you want to create. We're going to create a front end extension. This is an extension for the part of JupyterLab that you see running in your browser, the user interface, we could write a server extension. The server extensions are written in Python. Maybe I'll come back next year and talk about how to write a server extension.
08:40
But today we're talking about front end extensions, which are written actually in JavaScript. We'll talk about these others some other time. Here's all the questions it asks you. Extension type, your name, author's email, package name. Again, EPJLX we're calling it. It will create both a Python package for distribution
09:01
and a JavaScript package for distribution. You can use both or whichever one you want to distribute your extension. Give a description. These next three questions for the tutorial we're going to say no to keep things simple. But these are important questions. The first one is does your extension have user settings? You can set it up so that each user can have certain
09:21
preferences for your extension. Do you want to create a binder example so that people can play with your extension without actually installing it? And do you want to set up regression tests for your extension, which obviously we would all want to do if you're going to distribute it publicly? And finally, a URL for your extension. After you've answered all the questions,
09:42
it'll list out the files that it created. And if you look on disk, what you're going to see is it created the directory of the name of your extension, EPJLX, and it has all the typical things you see in a package, a changelog, a license, a readme file. I'm going to focus on a couple of files here and explain what they're doing.
10:02
So notice in the EPJLX directory, there's a subdirectory of the same name, EPJLX. This directory is currently empty. When you build your extension, that's where it's going to go, and that's what's going to get distributed, is all the artifacts in that directory. I'd like to also point out this file, package.json file.
10:20
This is a JSON file that the package manager looks at to know what to do with how to build your package. Let's take a look inside that file. You'll see a bunch of descriptive things, the name, the version, keywords, description, your home page, the license, the author, the file types that
10:41
are valid for this package. And if you scroll down, there's another section here in the file called scripts. The package manager, jlpm, has a command called run, which takes as a subcommand any of the scripts that are defined in this file. And we're going to be using this script here a lot, jlpm run build.
11:01
And the build script you can see is actually two scripts. The first script is it runs jlpm build live, which is actually another script in this file. So you can see the scripts that are defined here can call each other. The build live script simply does a type script compile with a source map for debugging purposes. And the second command, build lab extension dev,
11:22
also a script in this file, is going to run Jupyter's lab extension command with a subcommand of build with development set to true. So we're going to build in development mode. There is a way. You can see the script above that for building for production. And if you scroll down, there's a lot more scripts
11:42
defined here. When you do this tutorial yourself, I suggest you read through them and see what's in there. Another section of this file I want to focus on is this dependency section. This do nothing template depends only on at Jupyter lab slash application package. We'll see later how we can add other packages here to the dependencies.
12:02
There's a source code directory in the directory that was built. And in there is a file index.ts. This is the source code for our extension. Let's take a look at this do nothing extension that it wrote for us. So the first thing it does is it imports the Jupyter front end. That's the application itself that we're writing an extension for.
12:21
And it imports Jupyter front end plug-in. This is the plug-in class we're going to use to create our extension. Both of those are imported from Jupyter lab slash application package. So here's our extension. We're going to declare a const variable called plug-in of type Jupyter front end plug-in. And we're going to set a couple of attributes on it. We'll give it an ID. This is just a string.
12:40
There is a convention within Jupyter lab often to put a colon in the middle of an ID so that you can kind of scope it out with a scope on the left side and something more specific on the right. We'll give it a description. Auto start equals true means when the user starts Jupyter lab, I want my extension to be initialized.
13:00
So how does it get initialized? Well, the Jupyter lab front end will call your activate function. So here we define an activate function. Right here it's an anonymous function. We're going to accept the Jupyter front end application Excel as a variable called app so that we can interact with it. But this extension doesn't interact with it yet. All it does is it writes to console.log.
13:23
Jupyter lab extension EPJLX is activated so we can know it's working. At the very end, we're going to export the plug-in that we declared so that the rest of Jupyter app can see it. At this point, if you want, you can create a good get repository out of it. When I give you the link to my repository where I did this,
13:42
each step of the tutorial, I did another commit. So if you look at the commit diffs, you'll see the code changes that we're going to see here. Now we need to build our project. The first time you build, you have to install all your dependencies. So we're going to run the packaging manager JLPM install. Again, this installs our dependencies
14:01
where we're working. This is not installing the extension itself. So when you run that, you'll see the screen repainting several times with all kinds of warning messages and stuff. But in the end, it'll tell you it's done. Mine took about 20 seconds to run. And if you look at your directory, after that, you're going to see two new files. Yarn.log is a text file.
14:21
You don't need to worry about it, but this is something that the packaging manager uses to keep track of all the interdependencies between the various packages. The node underbar modules directory is where all your packages just got installed. If you look in that directory, we're just looking at the top 18 package scopes here.
14:41
Here is the at Jupyter package scope we talked about, at JupyterLab package scope, at Lumenu package scope. Each of these package scopes contains anywhere from one to a couple dozen packages altogether. I got 429 packages installed. This number might change slightly from time to time as these packages change.
15:00
If you look at one of the package scopes, let's look at JupyterLab, there's 16 packages in there. Two of them we'll be using to start out. The at JupyterLab application we already saw we imported from there, and we'll also use at JupyterLab app utils. So now we have our dependencies installed. We can run JLPM run build.
15:22
Again, this is the script that we saw in the JSON file. So if you run the build, you get some messages about the assets being created, and in the end you should see a message saying that compiled successfully. Mine took about a half a second. Now we have a build extension. We need to install it.
15:41
Before we install it, I'm going to show you a couple of commands. JupyterLab extension has a subcommand called list, which will list all of the extensions that are currently installed. So we'll run that once, see what's installed, and then we'll install our extension, and then we'll run it again and see that it actually got installed. Now notice we could install our extension with pip install.
16:02
The problem with that is every time we make a code change, we're going to have to do the install all over again. So instead, for the tutorial, we're going to install it with the lab extension develop command. Dash dash overwrite means get rid of anything that was previously installed, and this will install in development mode, in an editable mode, so that any changes we make
16:21
to the code will not require a reinstall. So if we run JupyterLab extension list, we see there is one extension already there. JupyterLab underbar pigments comes with JupyterLab. And notice it also tells me the directory where it found it. It actually looks in several different places for extensions. And if I LS that directory,
16:41
I'll see the JupyterLab pigments directory there. This is like that EPJLX subdirectory where I said everything is going to get built, and that's what gets installed. So this is the extension itself. So now we run the lab extension develop overwrite command, and we'll see various messages about building an editable version of the project, and symlinking it.
17:05
And now if we run lab extension list, we see two extensions. So we see our extension did get installed. And if you LS the directory, notice that our extension is installed as a symbolic link back to the directory where we're working, so that any changes we make are automatically reflected
17:21
in the installed version. Now we need to test it, see if our extension works. I recommend opening another window so you have one window for working on your code, another window where you're going to run JupyterLab, but make sure you activate your environment over in the second window so that it's looking at the same things. So we're going to activate the environment,
17:42
run JupyterLab, and here's the JupyterLab. Now where's our extension? Anyone know? Where's our extension? It's just writing to the console. So we need to open up the console to see if it actually worked. So I'm running Chrome here so that it's down here in more tools, development tools. Open up the console and there it tells me my extension is activated.
18:01
So I see that it actually worked. Great, that was wonderful. That was step zero. That's the biggest and longest step. Once you get there, you have an extension. Now it's just a matter of enhancing it. So the next thing we're going to do is have our extension create a command to actually do something. The rest of the steps in the tutorial are very simple. We're going to change the code, run the build,
18:22
and refresh the browser. We don't need to install anymore, but you do need to refresh the browser to pull the code back in. So here was our activate function just writing. We're going to add some more code to it. Let's take a closer look. I'm going to leave the console.log message in there just so that I can make sure if something goes wrong that it's actually working.
18:41
We're going to define a command ID, again, a string. This is just the convention many Jupyter programmers use to scope things out. Now we're interacting with the app that's getting passed in. So I'm going to call app.commands. The commands attribute is the command registry in the application. I'm going to call add command on the command registry,
19:01
passing in the command ID, and setting a couple of attributes. We'll give it a label, hello world, so that if the command gets displayed anywhere, that's what it'll look like. And this is the key to the command registry. We provide an execute function. We're going to say the execute function is say hello. Call say hello if this command gets executed.
19:21
Say hello is down here. Right now, say hello is just writing hello world to console.log. Now this is not something normal to do, but for testing purposes, the command registry also has an execute function. And I'm going to say here, right in my activate function, I want to execute the command, just for testing purposes. Run the build, refresh the browser.
19:40
Here's the build. It was successful. Here's refreshing the browser. Now when I refresh the browser, now I get both the activated message and the hello world message. Okay, so that's great. We have a command in the registry, but we want to run that command from somewhere in JupyterLab. So now let's add a command to the command palette so we can run it there.
20:00
So again, we're going to delete this line of code, executing it from the activate function. That's not where we would normally execute it. And over here, we're going to import iCommandPalette from addJupyterLab app.util. This is one of those tokens, the services that you can import and use. And we're going to add an attribute to the plugin.
20:21
We're going to specify the requires attribute. This is a list of these tokens or services that we want passed into our activate function so we can interact with them. So we're going to say requires iCommandPalette, and that means that the JupyterLab application is not only going to pass itself into our activate function, but also pass in the command palette, which we will accept as a variable called palette.
20:42
The next part, the top part of the activate function is the same as it was. We're putting the command in the command registry. And now we're going to call palette add item, pass in the command ID, that's all it knows. The palette knows how to access the command registry. And we're going to specify category of anything because the categories are alphabetical on the screen
21:01
and I just want it to pop up near the top. So we run the build, refresh the browser. Here's the build. It says it was successful. Now when I refresh the browser, it disappears from console because we're not doing it in the activate function anymore. But now suddenly I have hello world over here in the command palette. And then when I click it,
21:22
then it shows up in the console. Wonderful. But that's not very interesting. So now let's modify our command to actually do something, to create a widget on the screen. So we're going to put the widget in the main area. Again, this is the main area of JupyterLab. I'm going to skip step 3a
21:41
that's just getting rid of the anonymous activate. Anonymous functions are great when they're small, but when they start getting big, it's time to split them out. So step 3b, we're going to create a main area widget. We need to import widget from atlumina-widgets. And we're going to import main area widget
22:00
from atjupyter-lab-app-utils. We'll come back to why we're changing the signature on our say hello function here in a minute. Here's the modifications. We're going to create, whoops, create class hello world widget, extends widget. And all we have to do for now is create a constructor for our class.
22:20
We're going to call super to instantiate the parent. We're going to set a few variables. This.id, we'll give it a string for an identifier. This.title.label, so the title bar has a label that says hello world. This.title.closable equals true so that the user can click the X and close our widget if he wants. And then we'll create some HTML elements.
22:42
We'll call document.createElement for a body. Document.createElement for a header, heading. And we'll set the heading inner text to hello world from your Python. And then we have to call append child on the body to append the header to the body. And then we'll call append child to append the body to this widget. This.node is our widget itself.
23:04
So now we have our widget. So our say hello function, we're not going to write to the console anymore. Instead, what we're going to do, we're going to call new hello world widget and instantiate the widget, put it in a variable called content, and then new main area widget and pass in that content. Now the reason we're doing this,
23:21
this way we'll inherit everything that the main area widget can do. Like we saw we dragged it around on the screen and all that kind of stuff. And now we have to add the widget to the screen. So the application we saw, the command registry, it also has an attribute called shell, which is the thing that ties together all the widgets on the screen. So we're going to call app.shell.add to add a widget to it.
23:42
We'll pass in our widget. And as the second argument, we're going to specify main. We could say over here, we could say left. There's about six or seven different areas that you can add it to that are in the documentation. I could say left, right, top, bottom, the menu. And then we have to activate our widget. So we're going to call activate by ID and pass in the widgets identifier.
24:02
Now the say hello function now needs to interact with the JupyterLab application. The execute function of the command registry can only accept one type of argument. And we'll see later what that is. But for now, to get around that and pass in the application, we're going to change execute
24:22
to an anonymous function that simply calls say hello and passes in the application. Run the build, refresh the browser. And now when we click Hello World, we get a nice little widget there. I can take this widget. I can drag it over to the side. I can drag it to the bottom. I could click Hello World again and get a second widget.
24:42
So it's all quite functional now. So now let's see how we can style the widget. The directory has a subdirectory called style. In there is a file called base.css. These other files simply include base.css, so you don't have to worry about them. And that's basically an empty file with a comment in it.
25:01
We're going to style the body, give it a background color, center the text, style the header, position it maybe a third of the way down, stretch it from left to right, increase the font size. Now notice we are styling only for a specific CSS class. So I made up this name, hww, for Hello World widget. If we didn't do this, we would end
25:22
up styling all of JupyterLab. And we don't want to do that. There's actually a type of extension that you can create called a theme where you can create your own themes for JupyterLab. Maybe we'll talk about that another time. So we have to add one line of code to our constructor for our Hello World widget.
25:41
We're going to call this dot add class and pass in hww so that our Hello World widget now has the CSS class associated with it. Run the build, refresh the browser, and now instead of this boring little gray Hello World from EuroPython, we get a nice colorful Hello World from EuroPython.
26:01
OK, so that's very interesting. We saw how we can run the command from here. What if we run a command from somewhere else? We want to run it from the menu or something like that. We're going to run a command from the launcher. This is the launcher over here. Notice the notebook section is near the top. So we're going to choose that so we can see it nice and clear.
26:21
So we're going to import ilauncher from add JupyterLab launcher. And now I could, where the requires attribute is, I could say I command palette comma ilauncher, and that would work. It would pass in the ilauncher to our activate function. But ilauncher potentially, it itself is an extension and could be disabled by a user.
26:43
So what we're going to do is we're going to accept it as optional, pass in the ilauncher because maybe we want our extension to work even if the ilauncher is not there. We don't want our extension to fail. So we're going to say it's optional. And then, so when JupyterLab passes it in, it's going to pass in. We have the app here, the palette.
27:01
And now we're going to accept launcher as either an ilauncher or a null. It could be either one. If it's not there, if it's not activated, we'll get a null. So the rest of the activate function is the same. But now here down at the bottom, we're going to call launcher.add. Pass in the command ID. I'm going to set the category to notebook so it shows up in that part of the launcher.
27:20
But because it could be null, I have to wrap this and say if launcher, then call launcher.add. Otherwise, I'm just going to write to the console, our launcher is not available. So run the build, refresh the browser, and the build fails. Why did the build fail? It's failing here on an import and saying I can't find this module at JupyterLab launcher.
27:43
So if you look in the JupyterLab scope, we see these 16 packages, but the launcher's not here. This is alphabetical. Launcher should be between doc registry and MB format, it's not here. So how do we add a package that we now want to use that didn't get installed
28:00
with our original dependencies installed? So we can call jlpm add, the JupyterLab packaging manager add command, and tell it we want to add the launcher package. So when we do that, you'll see the output looks similar to the original install. And now, if we look in that directory, now we do see the launcher in between doc registry
28:21
and MB format, so it got installed. One other thing I want to point out, if we now run git status, notice the package.json file changed. Let's see what changed there. On our dependencies section, where we originally had only at JupyterLab application, we now have the application and the launcher. So to summarize, jlpm add does two things.
28:41
It installs the package into the node modules directory, and it also edits the dependencies section automatically for us. Now we can run the build, refresh the browser, and now we have our hello world token right here inside the launcher, in addition to in the command palette. We can click that, we get hello world from your Python, click that, we get the same thing.
29:03
So it's working, but maybe I want it to behave differently if it's launched from the launcher versus if it's launched from the command palette. Or maybe, as I said before, maybe users have different preferences. So we do that by passing arguments to our command. We can do that by adding the arguments,
29:22
this is what I mentioned before, the execute function only accepts one type of argument, and that is a constant JSON object. So I'm gonna say args, there is no constant JSON object in TypeScript, so I'm just gonna say it could be anything. And then I'll pass the application and the args into our say hello function.
29:40
Then down here in the command palette, I'm gonna say in addition to specifying the ID and the category, I'm gonna say args, and I'm gonna pass in a constant JSON object where the key is greeting, and the value is hello from the command palette. Now I could do the same thing down here in the launcher, I could pass arguments and say hello from the launcher, but I want you to see what's the difference
30:00
between having arguments and not having arguments. It's pretty easy to handle, we're just gonna get a null. So our say hello is gonna accept the arguments. If there are no arguments, we're gonna get a null here. I'm gonna grab the greeting attribute out of the arguments. If there are no arguments, again it's null. If there are arguments but there's no greeting attribute, again it's null, and we're passing that
30:20
into the hello world widget constructor. So here in the constructor, we're gonna accept a greeting as either a string or a null. And then down here where we were setting the inner text to hello world from your Python, if we have a greeting, we'll set it to the greeting, otherwise we'll default to hello from your Python. Run the build, refresh the browser, and now when we click in the launcher,
30:42
we get hello world from your Python, but if we click from the command palette, we get hello from the command palette. So that's how an argument can be passed to your command. Okay, so now let's see how we can create our own sidebar widget to run various commands, and we're just gonna run them with a few buttons. You could make it much more fancy than that, obviously.
31:02
I broke this step down into three steps. We'll create the sidebar widget with some buttons, we'll style it, and then we'll add event listeners. So here's the sidebar widget, similar to the other widget we created, class sidebar widget, extents widget. We just created a constructor. We're gonna call the superset, the ID, the label, closable equals true. We're gonna add a different class,
31:21
because maybe we wanna style this one differently, and then I'm just gonna create four buttons and set the inner text to the letter C, D, E, and F on the buttons. Pen the buttons to the body, and pen the body to this dot node. Now, our activate function is identical to what it was before, except at the very bottom, we're gonna instantiate our sidebar hello widget.
31:43
Now we're gonna call app.shell add, give it the sidebar widget, but now we're saying add it to the left, not the main area, to the left. And activate it, run the build, refresh the browser, and now, where's our sidebar widget? Why don't we have a sidebar widget?
32:01
Anyone see it? It's right here. So you see we have an icon for the sidebar widget, but the sidebar widget is not active. We have JupyterLab, when you run it, it remembers what was the last thing that was active. So our command palette was active, but if I clicked here where it says hello world, now I have my sidebar widget active.
32:20
And buttons are up here, they're kind of small, so let's style it. I'm gonna skip styling, you saw how styling works. Go through, we style it, run the build, refresh the browser, and now I have some nice big buttons. But these buttons don't do anything. So now let's add some event listeners to our buttons. So to do that, I modified the sidebar widget constructor,
32:45
and I created a record here, key value pairs, of those four letters, C, D, E, and F. And just to say hello world in different languages, and then I'm looping through this button info record, and for each item in the record, I'm gonna create a button, set the inner text to the key,
33:01
and then I'm gonna call add event listener on the button for click, give it an anonymous function, and now I'm calling that command registry execute function again, and I'm executing the command ID, and I'm passing in as a greeting whatever was the value in the button info field. Now of course, now my constructor needs the JupyterLab app front end
33:20
to be able to access the command registry, and it will also need to know the command ID that we wanna run. So that's why we changed the signature on that. So over here, where we are instantiating the sidebar hello widget, I'm gonna pass in the app and the command ID, run the build, refresh the browser,
33:42
and now when I click each of the buttons, I get hello world in a different language. So that's the end of the tutorial. Let's talk a little bit about the documentation that's available. There are some links in this presentation.
34:02
The presentation is on the GitHub repository for this, which I'll give you the address for in a minute. This is an important part of the documentation. The core tokens, we saw I command palette, and we saw I launcher. There were actually 82 different tokens there last time I counted.
34:21
I'm gonna just highlight a couple of them that are interesting. There's I main menu, obviously. If you want to do stuff with the menu, put things in the menu. There's a layout restorer. As I said before, JupyterLab generally remembers what was up. If you had a notebook up and you closed JupyterLab and you open it up, the same notebook is up.
34:40
You might want to do that with our widget that we created. Every time you run JupyterLab, it's gone. You have to click it again to make it appear, but maybe you want it to stay there. So you can use I layout restore to do that. There's a settings registry we talked about if you want to have user settings. Trackers are very interesting. These are just two of them. There's a notebook tracker and a setting editor tracker.
35:02
So for example, if the user changes his settings and you want it to take effect immediately, maybe you want to track and have your extension be notified every time a setting changes. Or similarly with the notebook, maybe I wrote a spell checker for a notebook and I want to know every time the notebook has changed so that I can spell check it again.
35:21
So that's what trackers are good for. Again, there's like 82 of these. And if you click here, you'll get that. This is where the repository is, github.com slash my name slash epjlx. If you remember anything, just remember this. You go there, it's got the slides, it's got all the instructions, everything else.
35:42
JupyterLab extension developer guide, there's a general developer guide for these extensions. The front end shell, that's where we did the, we accessed, we added the tokens to the shell. It tells you a little bit more about the things you can do with the shell. Jupyter has their own extension tutorial where you put up a random astronomy picture
36:01
on the screen. You learn certain things in my tutorial that you don't in theirs and vice versa, certain things in their tutorial that you don't in mine, so you might want to do that. And then there's a whole github repository of extensions with example code. Not documented very well, but the code is there. Code is the documentation. You can play with those and see how well they work.
36:23
And that's it. I guess we have time for questions. We do have time for questions. So if anybody has a question, could they come up to one of the microphones? Well, the microphone in the center. Great.
36:45
Hi, thanks. Very interesting talk that you gave. I was curious now that you have developed your extension, how would you distribute it to your users? Or that they don't have to go through the build phases, but also perhaps you don't want to publish it to the public Jupyter extension installer?
37:05
Right, so normally you would publish it. Well, my preference is to lean towards Python packages. So I would simply put the Python package on PyPy and people could run pip install and get your extension that way. Already pre-built, Jupyter as a whole, they encourage you
37:24
to create pre-built extensions so that your users don't have to build them themselves, but you can also make them so that the user downloads it and then builds it themselves as well. Any more questions?
37:41
Great talk. Do these extensions run in Jupyter Lite or is there a difference? I'm sorry, say that again. Jupyter Lite, you know, does this, does. Oh, does it work with Jupyter Lite? I don't know, that's a good question. Possibly, basically, the new versions of JupyterLab, I don't know when it started. A couple of versions ago, maybe at least JupyterLab 3
38:02
uses the basic TypeScript technology and that's why Jupyter Notebook version 7 and higher also uses that technology. Once you're using that, you can do these type of extensions. In fact, as you get to know JupyterLab, pretty much JupyterLab itself, the whole thing is all just a bunch
38:21
of extensions glued together, which is really nice the way they design the code that way. So I'm not familiar with Jupyter Lite if it uses the same technology. If it doesn't yet, I'm sure someone's gonna eventually convert it to using that.
38:45
Hi, very, very nice presentation. I was curious about how will one connect or interact between a notebook and this, maybe this is room, this will be another full talk.
39:00
Another talk, yeah, it could be another talk. So I realize I didn't go into any of how, obviously those tokens, the various services that you can interact with, there are services to interact with notebooks themselves. I didn't go into that, it's a little more complicated. Maybe that's the next talk, if not the backend.
39:23
But yeah, you can definitely do things with notebooks and stuff like that. Okay, thank you. By the way, the debugger that comes with JupyterLab is itself an extension. It was originally written as an extension that you had to install and then so many people were using it, they just said, you know what, we're gonna package that extension with JupyterLab. It doesn't show up as an extension when you run,
39:43
but it is actually an extension that's packaged with JupyterLab. I have a question. Yes. So I imagine if I was building an extension with quite a rich user interface, I might want to use one of the many JavaScript frameworks that are out there. Yeah, once you have that widget,
40:02
you can use any web-based technology that you want. You can use React, all those things. And build whatever rich interface you want to. You can also not use, your extension could have nothing to do with widgets. It could just do stuff like I mentioned, a spell checker for notebooks. Maybe you get a little icon at the bottom of the notebook
40:22
and every time you click it, it spell checks the, or it turns the spell checker on or off. And then you're not actually seeing a widget on the screen, but you're seeing the results of the spell check. Yeah, lots of possibilities. Thank you. Yeah, lots of possibilities. One more question. We can have more than one question. So if anybody has a question,
40:40
feel free to line up at the mic. Thank you for the talk. Thank you. I'm wondering, how do you manage secrets? Let's imagine my extension needs some API key or something like this. How would I include this probably? Is this like- That's a good question. I'm not 100% sure. I faintly, I might be wrong, but I faintly recall there was something in JupyterLab
41:03
for managing secrets. I'll have to look it up. But yeah, no, that's a good, definitely a good question. I don't remember off the top of my head, but I faintly recall seeing something that you can use, maybe one of those tokens where you can manage your secrets. Thank you.
41:21
Okay, if we don't have any more questions, can we give Daniel a big round of applause, please? Thank you. Thank you very much. I think it's a break now.