Chapa 1)


Short hyperlinks to Python docs (eev @ EmacsConf2022)

I submitted two proposals for 5-minute talks to the EmacsConf2022.
This one corresponds to this file: eev-rstdoc.el. Its EmacsConf page is here.
The tutorial is here. The link to the video is at the bottom of the page.
My other submission is here - it corresponds to eev-kla.el.
Links to my older presentations at EmacsConfs: 2021, 2020, 2019.

Title: Short hyperlinks to Python docs
Intended duration: 5 minutes

If we have a local copy of the Python docs installed then it is easy to define the three hyperlink functions in the Python program below,

# (find-pydoc  "tutorial/classes")
# (find-pydocw "tutorial/classes")
# (find-pydocr "tutorial/classes")
class MyVector:
    def __init__(v, x, y):
        v.x = x
        v.y = y

such that each one expands its argument in the right way, and the first one opens the local URL file:///usr/share/doc/python3.9-doc/html/tutorial/classes.html in the browser, the second one opens https://docs.python.org/3/tutorial/classes.html, and the third one opens the RST source of those HTML pages in Emacs: the file /<rstsourcedir>/tutorial/classes.rst.txt.

The docs for Python are designed to be navigated in a browser. Suppose that we start on the page classes.html above, follow a couple of hyperlinks, and then we find this other page that, ahem, is very interesting and important and we need to have hyperlinks to:


The most obvious way to create elisp hyperlinks to that page is to copy its URL to Emacs, edit it by hand to produce a (find-pydoc ...) hyperlink, duplicate that hyperlink twice, and add a "w" and a "r" into the right places... but this is not very practical.

In this presentation I will show a practical way to handle that. It is a new module of eev -- eev-rstdoc.el -- that performs both the expansions needed by find-pydoc{,w,r} and the "shrinkings" that convert URLs and filenames to short hyperlinks. Eev-rstdoc.el comes with three "families" of hyperlinks, expansions, and shrinkings: one for Python docs, one for SymPy, and one for MatPlotLib. It is easy to add new families, and the parameters for expansion and shrinking in each family are easy to configure.

For more info see the comments in eev-rstdoc.el. For a translation of the Python tutorial to a format that has only executable examples and elisp hyperlinks, see this.

To watch the video on youtube, click here. That links points to the copy that is on my channel; the copy at the EmacsConf channel is here. The screenshot below is from the part of the video that explains how to create new "families"; this is explained here.

Note that youtube always converts my videos to a format that is blurry at some points. You can download a local copy of the original video, with subtitles, with the two "wget"s below:

# See:  http://anggtwu.net/eev-videos.html
#       http://anggtwu.net/eev-videos.html#mpv-keys
# Play: (find-eev2022pyvideo "0:00")
# Info: (find-1stclassvideo-links "eev2022py")
# Subs: (find-1stclassvideolsubs  "eev2022py")

wget -nc http://anggtwu.net/eev-videos/emacsconf2022-py.mp4
wget -N  http://anggtwu.net/eev-videos/emacsconf2022-py.vtt
mpv --fs --osd-level=2 emacsconf2022-py.mp4

The subtitles in Lua for this video are here.
The rest of this page contains a conversion of the subtitles in Lua
to a slightly more readable format.

00:00 Hi! My name is Eduardo Ochs. I'm the author
00:04 of an Emacs package called eev...
00:06 and eev is about taking executable notes
00:10 of everything that you do, and this
00:13 presentation is about how I use this...
00:16 how I finally found a way to take
00:18 executable notes of what the python docs
00:22 say.

00:23 Let me explain that in another way. I've
00:28 try to Learn Python many times, but
00:31 hm, my brain is wired in a weird way, so
00:34 it didn't work... and finally a few
00:37 months ago I found a way of studying
00:40 Python that finally clicked for me.

00:44 The idea is that... well, it's here in
00:47 the title - is a way to create short
00:50 hyperlinks to the
00:52 documentation of python.

00:54 Here's an example.
00:56 This file contains some some chunks
01:00 of code from the Python tutorial and
01:03 some links to the places in which
01:05 I found these chunks of code.

01:07 For example, if I run this link here
01:12 it opens a certain page of the Python
01:14 tutorial in my browser - note that it
01:18 opens the local copy of the documentation...

01:22 and if I run this link here
01:27 it opens the source in .rst
01:29 of the same page.
01:32 So the first link opens
01:34 the HTML and this one opens the RST.

01:37 This is useful because in the beginning
01:40 I was copying these chunks of code in
01:44 the obvious way - I would simply
01:46 visit the the documentation in HTML and
01:50 I would mark a snippet of code here
01:54 and I would copy it to my notes.
01:58 And then after a while I
02:01 realized that it was much easier to
02:03 simply go to the RST sources and to copy
02:07 the chunks of code from there... and
02:10 note that these links look quite similar.

02:14 There's one difference here, that is
02:17 this `r' that is prepended to the name
02:20 of the function... and the `r' means
02:23 "open the RST"...
02:26 and if I use the suffix `w' it means
02:30 use the documentation on the web instead
02:32 of using the local copy.

02:34 So this one opens a local copy
02:38 and this one...
02:42 takes a while...
02:45 and opens the page
02:49 of the documentation in the
02:52 site of Python blah blah...

02:56 and this thing here is
02:58 executable in the usual eev sense, that...
03:02 if we type f8 several times here
03:05 the f8s on the lines that start with
03:08 red stars create a target buffer here...
03:12 and in this case it creates a
03:14 target buffer running Python, and if I
03:17 type f8 on these other lines these are
03:20 the lines are sent
03:23 to that REPL.

03:25 But anyway, let me go back.

03:30 Most of the things that I'm going to
03:32 present here are in the tutorial of this...
03:35 package...
03:37 we can go to the source code
03:41 here in the eev directory - it's a file
03:44 called eev-rstdoc.el... but the best
03:50 docs are in the tutorial, here...
03:53 and the tutorial also has some
03:56 executable
03:58 chunks... some snippets of Python
04:02 code that are executable, but they
04:05 don't have those nice colors... so
04:07 apologies for that.

04:11 We need to run this thing here to make
04:13 everything work.
04:15 This thing will define some functions
04:17 with funny names that I will
04:19 explain later.

04:26 Let me explain something new.
04:30 let's compare all these
04:35 links here. They take this argument
04:38 here and they expand the the argument in
04:41 a certain way. For example, this string is
04:44 expanded to this long URL here... note that
04:49 it got a prefix here,
04:52 that's quite long... it got the .html here,
04:56 and then the hash and the anchor here...

04:59 and each one of the functions in the
05:03 pydoc family expands this
05:06 argument in a different way.
05:09 The one that that opens the doc in the
05:12 web uses another prefix -
05:16 this one - and the one that opens the rst
05:20 file ignores the part after the hash
05:24 for technical reasons... I was never
05:28 able to to find a good way to convert
05:30 this hash into a string to search for,
05:33 so to make something that goes to
05:35 the right section in the link to the rst
05:38 doc I have to convert by hand, and by
05:42 trial and error, this thing here into a
05:46 pointer to that section, like
05:48 this one...
05:50 in which the "_numeric-types:"
05:55 is here.

05:58 So all these links here are based on
06:02 expansion, and this is easy to
06:04 understand...
06:05 but suppose that I want to
06:08 create a link like this, or suppose that
06:11 I'm browsing the docs here
06:16 and I just I follow some some links...
06:21 let me do something random here...

06:31 Suppose that I decided that this
06:34 section is very interesting. How can I
06:35 create a link to that? I can
06:39 use this pilcrow symbol and the
06:44 "Copy link address",
06:45 and copy the link to
06:49 my notes...
06:51 and then the Python family...
06:55 well, we saw that the functions in the
06:58 Python family have a certain way - have
07:00 several ways of expanding these
07:03 short arguments... and they also have a
07:06 certain way of shortening URLs
07:09 like this one.

07:11 If I type `M-x pdk' the message
07:13 is this one... `pdk' is a mnemonic for
07:17 "Python doc kill", and this
07:20 "kill" means "copy to the kill ring"
07:23 so if I type `M-x pdk' here it
07:27 considers that this thing is a link
07:31 to the python Docs, and it
07:34 shortens this link in a certain way,
07:36 and it kills a short link.

07:42 I can insert the short link with C-y
07:45 (yank), and then I can test this link
07:48 to be sure that it points
07:50 to where I want, and
07:52 then I can delete this thing, and ta-da,
07:55 now I have a short link, and of course I
07:57 can modify this link by adding a suffix
08:00 here...
08:02 and in this case here
08:06 I will have to change the identifier
08:09 to something else...
08:12 but I'm not going to do that now.

08:18 This module of eev comes with three
08:20 families predefined. One is a family that
08:24 points to the the documentation of
08:26 Python itself, another one points the
08:28 documentation of SymPy, that is a program
08:30 for symbolic computation, like for doing
08:34 mathematics equations...
08:37 and the other one points to the
08:40 documentation of MatPlotLib.

08:43 How do these families work?
08:47 Each family has to be defined in two
08:51 parts. Remember that eev has lots of
08:57 families like this one... sorry, lots of
09:01 functions like this one... this one
09:03 is the most basic, and it is explained here,
09:07 in this section of the main tutorial...

09:09 and this section explains that
09:13 a sexp like this one produces lots of
09:16 functions - produces a family of
09:19 functions - and it does that by producing
09:23 a certain chunk of code and then
09:25 executing this chunk of code...
09:28 and if we add a certain prefix here...
09:30 "find-"... and if we execute this
09:32 we can... instead of executing
09:35 that chunk of code we can see what is
09:37 that chunk of code.

09:39 In the case of `code-c-d' it is this:
09:41 it is a `setq', several `defun's,
09:43 and some comments here, with
09:47 links to the documentation.

09:49 In the case of rstdoc it's the same.
09:52 We have this function here that defines
09:54 the function in the python family...
09:56 and we can run this to understand what
09:59 this `code-rstdoc' does...

10:03 it creates this temporary buffer here...
10:05 with lots of `defun's, a `code-c-d' here,
10:09 and lots of comments here... and the
10:10 comments include some tests. For example
10:13 we can use these functions here to test
10:16 how the expansion works.

10:21 And
10:23 note that in this buffer here we don't
10:26 have the paths that that this family
10:28 uses. We don't have for example
10:31 the URL that points to the site of
10:33 Python, to the directory that contains
10:36 the reference manual, or whatever... all
10:40 these things are in another part of the
10:42 definition of that family - that is a
10:44 variable.

10:46 If we execute this we go to the
10:48 source code of eev-rstdoc,
10:50 to the parts in which
10:54 this variable is defined...
10:57 and
10:59 for each family we have a variable like
11:01 this, whose value is a property list
11:05 with several fields...

11:07 these first fields are very easy to
11:09 understand - they are used in the
11:10 expansion... this one too. And these
11:16 two fields are used in the shrinking -
11:19 in the shortening - and
11:21 this field here
11:25 tells what is the name of the
11:28 killing function
11:30 so the fields of this thing here are
11:33 used to generate...

11:36 some fields are used to generate the
11:39 code that appears here, and some fields
11:41 are simply
11:44 read by functions like this one, that
11:47 consults the variable.

11:51 Now the natural question is: how can we
11:53 define new families? Or: how can we change
11:57 a family like this one to point to
11:59 another version of Python?

12:03 There are some template-based functions
12:06 for doing that. They are explained in
12:09 this section of the tutorial...
12:10 where is that?...
12:14 oh God, it's far away...
12:17 here.

12:20 Suppose that we have a package foo, that
12:23 we want to create a family that points
12:25 to the docs
12:27 of that package foo... so, we
12:31 can execute this thing here, and it
12:32 generates this
12:34 this thing from a template.

12:37 If we just want to modify a current
12:40 definition we can run something like
12:42 this - note that the family `:py'
12:44 already exists, and instead of using
12:47 placeholders in some of these
12:51 URLs it will use the current values of
12:53 the fields...
12:55 so we can also use this to modify
12:59 existing families.

13:01 Well, these are the technical details.
13:05 Now the natural question is: why do I
13:08 want this? This doesn't
13:12 any sense to me! Why should I
13:14 try this?
13:15 And the best answer: for most people
13:18 this way of using executable notes
13:22 do not make any sense
13:24 at all at first sight...

13:27 so what I'm trying to do is: I'm trying
13:30 to write to these tutorials with
13:33 many examples that are very easy to run,
13:35 and that examine data structures,
13:38 and functions, and test things,
13:40 and so on... so my main argument
13:46 for convincing people to
13:48 test this is: this is trivial to test -
13:52 simply install eev and run this thing
13:54 here, and run the examples, and probably
13:56 you're going to find that this
13:58 tutorial is fun to follow.
14:01 So... that's it! =)