back to indexnbdev tutorial
Chapters
0:0 Introduction
4:0 Creating a repo
11:25 envdev
13:10 notebook
16:40 documentation
17:30 testing
19:35 python module
22:50 index notebook
24:45 create documentation
31:30 class documentation
34:10 say hello
34:50 auto reload
36:55 running tests
38:20 installing Jekyll
40:10 console scripts
43:45 pipi
45:0 pip install
46:30 makefile
47:40 collapsible headings TOC
49:25 Notebooks
51:50 Editing Notebooks
56:5 Conventions
00:00:13.800 |
- Who you guys will know from Fast AI and Alexis. 00:00:31.260 |
You might recognize him actually briefly mentioned 00:00:49.200 |
we're just gonna step through it step by step. 00:00:51.280 |
So there won't really be much information here 00:00:59.520 |
So if you're more of a reading person than a video person, 00:01:03.760 |
So I won't go into too much detail about what NBDev is. 00:01:10.680 |
a post with a lot of information about why it exists 00:01:16.200 |
But in brief, it's a system for exploratory programming, 00:01:23.480 |
which involves or is kind of cognizant of the fact 00:01:36.280 |
So there's a lot of exploration and experimentation. 00:01:51.000 |
this is all built on is as the name suggests, 00:01:59.880 |
Jupyter Notebooks are a very nice environment 00:02:10.980 |
Silva and I both feel like we're significantly 00:02:16.080 |
as in like three to three times more productive 00:02:22.640 |
than what we're used to being kind of traditional IDEs 00:02:43.940 |
rather than trying to do everything totally top down 00:02:54.640 |
And so step one, so this thing we're looking at here, 00:02:57.520 |
nbdev tutorial, not surprisingly comes from a notebook. 00:03:02.520 |
So actually, if you click on GitHub over here, 00:03:19.340 |
So everything in nbdev itself comes from notebooks. 00:03:24.340 |
So if you ever wanna know how something is written, 00:03:33.140 |
an easy way would be just to actually have a look 00:03:40.040 |
So for example, if we look in within Jupyter, 00:03:44.300 |
here is the nbdev tutorial we're looking at right now. 00:03:48.100 |
And you'll see that some things are added automatically 00:04:03.460 |
So I'm gonna try and show the easy low fiction way 00:04:10.020 |
to do things once you learn more about how nbdev works, 00:04:22.460 |
You can certainly use other repositories as well. 00:04:29.220 |
which takes advantage of a handy thing in GitHub 00:04:47.980 |
since we had a lot of people asking the link only works 00:05:08.820 |
And I realized I didn't open that in a new window. 00:05:14.060 |
Okay, so that is going ahead and creating a new repo. 00:05:19.420 |
So here's our nbdev repo that just got created. 00:05:29.700 |
is we're gonna set up our documentation site. 00:05:32.100 |
The documentation for nbdev uses something called Jekyll, 00:05:37.900 |
which is a simple thing that builds your site 00:05:41.980 |
to allow it to be hosted on any kind of static host. 00:05:52.060 |
You can use pretty much any host you can think of. 00:05:56.260 |
But GitHub Pages is gonna be the easiest way. 00:06:00.900 |
So to enable GitHub Pages, we click Settings. 00:06:15.420 |
you'll see your site is now ready to be published 00:06:33.500 |
So we'll go back to here, click Edit, paste it here. 00:06:58.700 |
so that by the time you watch this, it will be fixed. 00:07:20.620 |
all the configuration will be created from that one place. 00:07:27.740 |
for your documentation, for your packaging, et cetera. 00:07:32.140 |
So we're gonna edit all the commented out bits. 00:07:35.140 |
So let's go ahead and find settings.ini and edit it. 00:07:40.140 |
And all these sections here which are commented 00:07:48.880 |
And we'll call this, hello, nvdev, user jphoo. 00:07:56.840 |
User jphoo, description, a tutorial project for nvdev. 00:08:13.080 |
So these are just things that are gonna end up 00:08:29.840 |
but I didn't realize how many things it drove. 00:08:34.200 |
and then also other downstream configurations 00:08:37.080 |
that let you easily share your library onto PyPy. 00:08:40.680 |
Are those the main two sort of fallouts from it 00:08:44.360 |
- Also the actual Python project that is created 00:08:55.760 |
Yeah, those are basically the artifacts we end up creating 00:08:57.800 |
an installer, a Python project, and documentation. 00:09:04.440 |
that's been in the nuisance to figure out individually 00:09:07.160 |
- Well, and also when they're in different files, 00:09:09.120 |
it's kind of like probably six or seven different files 00:09:14.360 |
from the make file through to the navigation bar 00:09:16.960 |
or through to the Jekyll config file, the setup.py file. 00:09:22.320 |
So yeah, that's make life significantly easier. 00:09:27.880 |
that know to read and write stuff in this one place. 00:09:31.760 |
So it makes it easier to kind of modify the tooling. 00:09:39.300 |
As you'll see, that's gonna be managed for us automatically. 00:09:52.180 |
The sidebar is the thing over here in your documentation, 00:10:06.780 |
PyPy expects you to say one of these seven statuses. 00:10:18.960 |
is because we're using a Python standard library module 00:10:24.340 |
And this is how Python standard library config parser 00:10:31.220 |
with the value of user automatically by Python 00:10:46.940 |
So, oh, and we did skip a step which is to clone the repo. 00:10:51.940 |
So let's go ahead and clone our repo as well. 00:11:20.560 |
Okay, so the next thing is Git and Jupyter Notebook 00:11:34.380 |
A Jupyter Notebook, if you've never looked inside one, 00:11:40.940 |
As you can see, it's basically, it's, well, it is JSON. 00:11:45.740 |
And when you move cells around or edit cells, 00:11:52.760 |
it can create a whole lot of a big def basically, 00:12:01.580 |
So one easy way to avoid those conflicts in the first place 00:12:16.080 |
And so there's a whole bunch of command line tools in NBDev. 00:12:20.580 |
If you type NBDev and hit tab, you'll see them all. 00:12:27.340 |
So if we run that, then that will install things into Git, 00:12:31.360 |
which will now automatically clean up that stuff, 00:12:42.500 |
you can run NBDev fix merge with a file name, 00:12:47.000 |
and it will try to merge them with an understanding 00:12:52.340 |
And if it can't, it'll create a new readable notebook 00:13:02.020 |
the conflict cells are actually represented directly 00:13:06.640 |
Okay, so we're now ready to edit our notebook. 00:13:11.640 |
So you can run Jupyter Notebook if it's not already running. 00:13:17.860 |
Personally, I tend to just have Jupyter Notebook 00:13:30.660 |
And you'll see there's something here called 00 core. 00:13:38.540 |
The core bit is gonna be what the HTML page will be called. 00:13:47.380 |
to have incrementing numbers as you add more notebooks, 00:13:51.560 |
'cause it kind of gives the reader a sense of it all. 00:14:01.900 |
- Are any special Jupyter extensions required 00:14:24.060 |
You'll see there's some comments which are special. 00:14:31.540 |
So the first special comment is default export comment. 00:14:46.920 |
our Python module is gonna be called Hello NBDev. 00:14:57.260 |
So this will create a sub module called Hello NBDev.core. 00:15:14.820 |
and it means when you create the documentation, 00:15:18.700 |
Otherwise, pretty much everything in the notebook 00:15:40.700 |
your notebook should be named something underscore core, 00:15:48.420 |
it should be named 001.core.utils, and so on and so forth. 00:15:53.220 |
- Yeah, well, I've never tried not doing it that way. 00:16:13.500 |
So we're gonna add a function to this notebook. 00:16:15.420 |
So let's just go ahead and copy and paste this one. 00:16:17.820 |
And it's just a perfectly normal Python function 00:16:23.600 |
with one exception, which is it says hash export at the top. 00:16:26.760 |
So hash export means please include this cell 00:16:41.180 |
oh, and the other thing it does is it's gonna include, 00:16:46.980 |
So if you have a look at the tutorial, for instance, 00:16:51.340 |
you can see that I've got this function here. 00:16:57.660 |
the function has automatically created this documentation 00:17:08.100 |
So that's what export does, it does those two things, 00:17:14.180 |
and if it's a function or a class or a variable assignment, 00:17:23.440 |
it'll put it in the documentation in that special form. 00:17:26.140 |
Okay, so the whole point of one of the key points of this 00:17:33.960 |
is to experiment and to show people that experimentation. 00:17:46.520 |
And so, and we can add some more information. 00:18:14.040 |
and it's a good idea to put in plots and images 00:18:16.920 |
and stuff like that, so here's an example of SVG. 00:18:19.520 |
And what we do a lot, and we find it works pretty well, 00:18:27.120 |
So, all right, so we've already got an error in our test, 00:18:40.920 |
So you can see what happens when you get a test failure, 00:18:45.920 |
it just appears here, and that will also appear later on 00:18:54.360 |
it can also appear in the terminal or continuous integration, 00:19:01.200 |
And this will by default appear in the documentation. 00:19:06.200 |
So I probably don't really want this import line to appear, 00:19:15.680 |
at least a few basic tests in the documentation, 00:19:35.980 |
All right, so now we can create our Python module. 00:19:44.480 |
And you can run most nbdev commands from anywhere 00:20:35.600 |
the package or the project becomes a Python package, 00:20:40.240 |
and then every notebook becomes a Python module. 00:20:44.720 |
- Exactly, and you can create sub-modules as well, 00:20:51.880 |
instead of default exp-core, it'd be default exp-blah. 00:21:04.200 |
It would be default exp-blah.blah to create a sub-module. 00:21:08.960 |
- An export means that it goes into the module and the docs. 00:21:23.240 |
then that means it goes into the docs, but not the module. 00:21:26.720 |
- You also have exports with an S for export and show, 00:21:34.040 |
and the source code will sustain the documentation 00:21:37.160 |
if you want the source code to be in your documentation 00:21:41.120 |
- Yeah, which is actually what I probably should have done 00:21:49.040 |
and also put it here so that you would see the source code 00:21:52.440 |
as well, but I probably should have just used exports, 00:21:54.880 |
would be another way to kind of do the same thing. 00:22:01.080 |
Normally you don't really want to show the source code 00:22:10.760 |
how is, how is non-markdown cell content treated at all? 00:22:16.160 |
But does it make it into the docs successfully? 00:22:31.680 |
that was effectively including an image of some kind. 00:22:34.840 |
- Yep, all that kind of markdown will work fine. 00:22:45.760 |
Okay, so now we can create or edit index notebook 00:22:53.280 |
and that's gonna be what your documentation homepage 00:23:12.280 |
So we should import, change that to hello nvdev.core 00:23:21.040 |
It did, so we have successfully imported something. 00:23:35.120 |
This is used to create the HTML documentation title 00:23:58.800 |
- Just to learn nvdev but you can put world if you want. 00:25:24.760 |
We'll see there's a whole bunch of extra stuff here. 00:25:29.600 |
And so you can see the things that it's modified for us 00:25:50.000 |
is the init.py that's created for you is by default empty. 00:26:41.440 |
Okay, so GitHub is gonna go ahead and process that commit. 00:26:46.440 |
And so if we go back to the main GitHub page, 00:27:34.560 |
So when you first clone the repo by definition, 00:27:45.720 |
with the help of GitHub actions automatically checks 00:27:50.400 |
that all of your bits and pieces work, as you can see. 00:28:12.400 |
Okay, so this one's now finished, and we still have an X. 00:28:23.280 |
Ah, so in this case, I tried to use tests from FastCore, 00:28:37.880 |
So to fix that, the best way to do it is to tell nvdev, 00:28:42.880 |
or which it really talks to Python's setup tools, 00:28:49.040 |
So to do that, as you would hopefully expect, 00:28:59.120 |
and we can just add space separated any requirements we have. 00:29:31.840 |
And so if you want to see how those requirements 00:29:36.480 |
you can see it's just grabbing the requirements thing, 00:30:08.240 |
because it did say that the page built correctly. 00:30:27.920 |
has automatically been grabbed from over here. 00:30:32.280 |
So while we're here, let's go ahead and fix that. 00:30:34.880 |
Hello, nbdev, I guess it should be this really. 00:30:40.680 |
And you can see the title's been set over here. 00:30:50.440 |
And here is the automatically generated documentation, 00:31:26.000 |
get started, the basics are now all in place. 00:32:04.400 |
The methods are not documented automatically. 00:32:12.420 |
you have to add a call to the special showdoc, 00:32:29.560 |
And so it might be nice to include a docstring. 00:32:31.960 |
You don't have to, but now it'll appear here. 00:32:39.440 |
And in the documentation, the showdoc input would appear, 00:32:50.960 |
intersperse markdown comments and images and plots 00:32:55.480 |
and whatever in amongst your documentation of your class 00:33:00.600 |
And I should mention, it's a really good idea 00:33:18.640 |
And then classes will automatically add their own heading. 00:33:23.520 |
And so this method will already sit underneath 00:33:46.920 |
So we have a bug, which is now that should return. 00:33:51.920 |
Great, and we could have used a test of course. 00:34:03.760 |
So here's something neat, which is, see here, 00:34:29.240 |
So nbdev will look for anything in backticks, 00:34:33.460 |
whether it be in markdown or docstrings or whatever. 00:34:37.040 |
And it will attempt to see if it can resolve it 00:34:46.080 |
So you can see not only do we have it in the docstring here, 00:34:52.120 |
but you can also see here that I've got hyperlinks 00:34:57.840 |
Again, they were just created using backticks. 00:35:05.640 |
- And does it look through all things in backticks 00:35:38.080 |
These two lines will set up what's called auto reload, 00:35:51.360 |
if we have these two lines as the first two lines, 00:35:54.660 |
then every time we update hello world nb.core, 00:35:59.660 |
we don't have to manually restart this kernel. 00:36:19.900 |
of your exported notebook along with a hash hide. 00:36:27.780 |
And this is exactly the same as running nbdev buildlib. 00:37:16.780 |
like we do for fast.aiv2, it just takes a few seconds. 00:37:25.500 |
it would pop them up and show you the stack trace 00:37:29.520 |
- One thing to add about the tests documentation 00:37:34.060 |
and building the library is that if you're working 00:37:38.460 |
you can put an underscore at the beginning of its name 00:37:41.500 |
and it won't be considered by all of those commands. 00:38:24.480 |
Sometimes your documentation will fail to build. 00:38:28.640 |
GitHub pages will give you a red cross next to the bit 00:38:33.660 |
But it tends not to give you any information about why. 00:38:42.660 |
Also, it's sometimes nice just to look at your docs locally 00:38:56.380 |
the easiest way is the official on Jekyll installation. 00:39:11.460 |
the next step is to CD into the docs directory 00:39:23.840 |
Then CD back to your repo root and type make docs serve. 00:39:47.300 |
I'm actually not running this locally, it's remote. 00:39:51.460 |
So I need to do something slightly different, 00:40:10.580 |
The next thing to mention is console scripts. 00:40:16.260 |
So maybe you want to create a console script. 00:40:21.260 |
There's actually a very nice system in setup tools 00:40:28.460 |
for creating console scripts that will actually work 00:40:30.540 |
on Windows or Mac or Linux automatically and the trick. 00:40:35.540 |
And that's a surface through again, settings.any. 00:40:59.420 |
And we use our fast script library for creating these. 00:41:12.740 |
In fact, you don't actually need that for console scripts. 00:41:14.500 |
You can just create a function that looks at sys.argv. 00:41:27.500 |
This is going to be the name of the script that you want. 00:41:33.540 |
This is the name of your module where you defined it. 00:41:48.940 |
Now, just putting it in the settings.any doesn't do anything. 00:41:56.980 |
the easiest way is to type pip install minus e dot 00:42:03.940 |
And that does something called an editable install. 00:42:07.740 |
And that will install the console scripts in such a way 00:42:14.100 |
that it's actually linking back to the live code. 00:42:16.420 |
So you can change things without having to reinstall. 00:42:19.380 |
And so that's a nice, easy way to test your module 00:42:23.260 |
in other projects and to test your console scripts 00:42:43.540 |
- This is the name of the function that is being called. 00:42:53.260 |
And then nbdev build lib is the function within that module. 00:42:56.940 |
- Yeah, in fact, maybe rather than looking at the notebook, 00:43:02.900 |
So if you look at nbdev, cli, here is nbdev build lib. 00:43:23.780 |
to define a script that had a slightly different name 00:43:31.660 |
click on this little cross-platform console scripts link 00:43:36.860 |
'cause it's all just passing it through to setup tools, 00:43:39.620 |
which is the standard library thing in Python. 00:43:47.820 |
All right, so since this is such a great module, 00:43:50.640 |
and probably everybody on the internet will want to use it, 00:43:53.220 |
we should make it easier for everybody to use 00:43:57.500 |
so that people can then go pip install hello nbdev. 00:44:02.420 |
So, first of all, click where it says PyPy here, 00:44:18.740 |
create this file called .pypyrc in your home directory, 00:44:35.680 |
And what that will do is it will bump the version, 00:44:41.920 |
with the same version number, and then upload it. 00:44:50.180 |
and you'll see that it has uploaded it to PyPy. 00:45:04.640 |
And so you can see everything's gonna happen for you. 00:45:10.620 |
Your index has automatically been put into here. 00:45:31.340 |
Yes, so the GitHub repo actually set a different name 00:45:42.380 |
All right, so let's go ahead and commit that. 00:46:32.820 |
- So just, sorry, this may be the basic question, 00:46:35.180 |
but make release, does that just call the same scripts 00:46:39.180 |
that you were showing individually before, like nbdev? 00:47:15.180 |
So pip install twine if you don't already have it. 00:47:18.900 |
when you go docs-serve, it calls nbdev-build-docs 00:47:29.220 |
And you don't have to use the makefile at all. 00:47:36.260 |
you can just run any of those things manually. 00:47:50.860 |
But there are two extensions that we do recommend, 00:48:11.700 |
these little arrows here, I can collapse them. 00:48:23.460 |
Left again to go to the start of the super section. 00:48:28.700 |
So that's collapsible headings, which is super handy. 00:48:31.780 |
And the other one that's super handy is TOC2. 00:48:39.020 |
And you can configure that in various different ways, 00:49:31.100 |
how things have already been written in another context. 00:49:36.100 |
And so going and having a look at the nbdev notebooks, 00:49:40.140 |
all that functionality you've seen is just in 00:49:42.580 |
one, two, three, four, five, six, seven, eight notebooks. 00:50:07.100 |
So here's something like starts right at step one. 00:50:09.820 |
So like, if you're trying to understand all the detail 00:50:16.620 |
which is where we actually read the JSON of a notebook. 00:50:24.060 |
And here's an example of the metadata and so forth. 00:50:39.220 |
So as we started building the functions to read it 00:50:41.500 |
and explore it, that became part of the documentation 00:50:49.900 |
that we did along the way as we tried to build something 00:51:04.120 |
which we haven't described like default class level. 00:51:06.380 |
And then you can go and search the documentation 00:51:25.500 |
and then using these compile tools essentially, 00:51:29.900 |
It's like what you would have if you'd worked 00:51:37.520 |
Let's say you do that and then you want to go in 00:51:39.780 |
and make a change directly to the Python code 00:51:43.740 |
How do you get the change back into the notebook? 00:51:56.540 |
where appropriate to edit things in the notebook. 00:52:01.600 |
And the reason for that is that in the notebook, 00:52:10.660 |
You can explore to make sure the change you made 00:52:13.220 |
really is working the way you thought it was. 00:52:32.880 |
when you're kind of starting to find your way 00:52:40.500 |
it can be really helpful to use kind of the tags features, 00:52:51.600 |
And so I'd like in VMI hit control right square bracket 00:52:54.180 |
to jump straight to the definition of say hello. 00:53:01.780 |
by like adding the print statement somewhere, 00:53:05.660 |
or maybe you find like a typo in a doc string. 00:53:21.780 |
All right, so I've only changed the doc string. 00:53:23.180 |
So there's no particular point to go back to the notebook, 00:53:26.860 |
but I would like to now have that be modified 00:53:31.260 |
So to do that, I just type nb dev update lib instead 00:53:51.100 |
Now, this is not for doing like major refactorings and stuff. 00:54:08.500 |
and to be able to find the right place to change. 00:54:11.100 |
But for little changes like that, it'll work fine. 00:54:14.660 |
Yes, the main thing is, as long as you don't want 00:54:32.480 |
there is a command for that, which is nb dev diff 00:54:44.360 |
So let's say we want to go back to what we had before. 00:55:08.140 |
And so if there's a difference, it'll tell you so. 00:55:12.760 |
And so one obvious way to fix that is just to run 00:55:19.800 |
And then there won't be a difference anymore. 00:55:45.760 |
I said nb dev build lib when I was inside the lib. 00:55:48.960 |
So the directory I was in had just got replaced 00:55:54.280 |
I don't quite know what that's got to do with the MKL, 00:56:04.320 |
- I think I just want to pull things together 00:56:16.060 |
Basic one is that the project becomes a package, 00:56:21.540 |
It's advisable, maybe necessary, I'm not sure about that, 00:56:28.960 |
- I'm not sure the number prefixing is necessary. 00:56:33.040 |
with the modules and documentations is necessary. 00:56:38.040 |
The numbers is just a recommendation, I think. 00:56:46.760 |
could be, are specified in the settings on any file. 00:56:50.440 |
And then there's also a special markdown cell 00:57:01.080 |
it'll just mean that you'll have some default 00:57:07.280 |
- All right, so that just affects how the docs look. 00:57:13.360 |
Now that I think about it, I don't know why it's necessary 00:57:15.480 |
because we should be able to just grab it from the name. 00:57:21.760 |
- It's just because sometimes you have notebooks 00:57:29.720 |
around underscore notebooks not being exported. 00:57:32.280 |
And in terms of what someone would need to use this, 00:57:36.320 |
you need to have stuff like Python assault, obviously, 00:57:45.240 |
This thing called Twine, it's also part of the-- 00:57:50.000 |
- You can store Twine in order to push to PayPal. 00:57:53.280 |
Other than those, everything is automatically installed 00:58:11.440 |
- And in terms of the key mechanics of interaction, 00:58:13.920 |
there's a set of build tools for building the load, 00:58:17.480 |
There's a make file for like bumping versions 00:58:24.980 |
there's hide, which means don't put it in the module 00:58:28.000 |
There's export, which means put it in the module 00:58:40.040 |
- As well as the export in the docs in the module. 00:58:45.320 |
- Just wanna make sure I had the essentials right. 00:58:54.680 |
See you next time we do a thrilling tutorial.