Back to the talks Previous by track: Fanfare for the Common Emacs User Next by track: Sunday closing remarks Track: Development

Short hyperlinks to Python docs

Eduardo Ochs

The following image shows where the talk is in the schedule for Sun 2022-12-04. Solid lines show talks with Q&A via BigBlueButton. Dashed lines show talks with Q&A via IRC or Etherpad.

Format: 15-min talk followed by IRC Q&A (#emacsconf-dev)
Discuss on IRC: #emacsconf-dev
Status: Q&A finished, IRC and pad will be archived on this page


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, 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 this page. For a translation of the Python tutorial to a format that has only executable examples and elisp hyperlinks, see this.


Hi! My name is Eduardo Ochs. I'm the author of an Emacs package called eev... and eev is about taking executable notes of everything that you do, and this presentation is about how I use this... how I finally found a way to take executable notes of what the python docs say. Let me explain that in another way. I've try to Learn Python many times, but hm, my brain is wired in a weird way, so it didn't work... and finally a few months ago I found a way of studying Python that finally clicked for me. The idea is that... well, it's here in the title - is a way to create short hyperlinks to the documentation of python. Here's an example. This file contains some some chunks of code from the Python tutorial and some links to the places in which I found these chunks of code. for example, if I run this link here it opens a certain page of the Python tutorial in my browser - note that it opens the local copy of the documentation - and if I run this link here it opens the source in .rst of the same page. So the first link opens the HTML and this one opens the RST. This is useful because in the beginning I was copying these chunks of code in the obvious way - I would simply visit the the documentation in HTML and I would mark a chunk... a snippet of code here and I would copy it to my notes. And then after a while I realized that it was much easier to simply go to the RST sources and to copy the chunks of code from there... and note that these links look quite similar. There's one difference here, that is this r that is prepended to the name of the function... the r means "open the RST"... and if I use the suffix w it means use the documentation on the web instead of using the local copy. So this one opens a local copy and this one takes a while and opens the the page of the documentation in the site of Python blah blah... and this thing here is executable in the usual eev sense, that we ca... if we type f8 several times here the f8s on the lines that start with red stars create a target buffer here... and in this case it creates a target buffer running Python, and if I type f8 on these other lines these are the lines are sent to that REPL. But anyway, let me go back. Most of the things that I'm going to present here are in the tutorial of this... package... we can go to the source code here in the eev directory - it's a file called eev-rstdoc.el but the best docs are in the tutorial, here... and the tutorial also has some executable chunks... some snippets of python code that are executable, but they don't have those nice colors... so apologies for that. We need to run this thing here to make everything work. This thing will define some functions with funny names that I will explain later. Let me explain something new. let's compare all these links here. They take this argument here and they expand the the argument in a certain way. For example this string is expanded to this long URL here... note that it got a prefix here, that's quite long... it got the .html here, and then the hash and the anchor here... and each one of the functions in the pydoc family expands this argument in a different way. The one that that opens the doc in the web uses another prefix - this one - and the one that opens the rst file ignores the part after the hash for technical reasons... I was never able to to find a good way to convert this hash into a string to search for, so to make something that goes to the right section in the link to the rst doc I have to convert by hand, and by trial and error, this thing here into a pointer to that section, like this one... in which the "_numeric-types:" is here. So all these links here are based on expansion, and this is easy to understand... but suppose that I want to create a link like this, or suppose that I'm browsing the docs here and I just I follow some some links... let me do something random here... suppose that I decide that this section is very interesting. How can I create a link to that? I can use this pilcrow symbol and the "Copy link address", and copy the link to my notes... and then the Python family... well, we saw the the functions in the Python family have a certain way - have several ways of expanding these short arguments... and they also have a certain way of shortening URLs like this one. If I type M-x pdk the message is this one. pdk is a mnemonic for "Python doc kill", and this "kill" means "copy to the kill ring" so if I type M-x pdk here it considers that this thing is a link to the python Docs, and it shortens this link in a certain way, and it kills a short link. I can insert the short link with C-y (yank) and then I can test this link to be sure that it points to where I want, and then I can delete this thing, and ta-da, now I have a short link, and of course I can modify this link by adding a suffix here... and in this case here I will have to change the identifier to something else... but I'm not going to do that now. This module of eev comes with three families predefined. One is a family that points to the the documentation of Python itself, another one points the documentation of SymPy, that is a program for symbolic computation, like for doing mathematics equations... and the other one points to the documentation of MatPlotLib. How do these families work? Each family has to be defined in two parts. Remember that eev has lots of functions like this one... this one is the most basic, and it is explained here, in this section of the main tutorial. This section explains that a sexp like this one produces lots of functions - produces a family of functions - and it does that by producing a certain chunk of code and then executing this chunk of code... and if we add a certain prefix here... find- and we execute this we can... instead of executing that chunk of code we can see what is that chunk of code. In the case of code-c-d it is this. It is a setq, several defuns, and some comments here, with links to the documentation. In the case of rstdoc it's the same. We have this function here that defines the function in the python family... and we can run this to understand what this code-rstdoc does. It creates this temporary buffer here... with lots of defuns, a code-c-d here, and lots of comments here... and the comments include some tests. For example we can use these functions here to test how the expansion works. And note that in this buffer here we don't have the paths that that this family uses. We don't have for example the URL that points to the site of Python, to the directory that contains the reference manual, or whatever... all these things are in another part of the definition of that family - that is a variable. If we execute this we go to the source code of eev-rstdoc, to the parts in which this variable is defined... and for each family we have a variable like this, whose value is a property list with several fields... these first fields are very easy to understand - they are used in the expansion... this one too. And these two fields are used in the shrinking - in the shortening - and this field here tells what is the name of the killing function so the fields of this thing here are used to generate... some fields are used to generate the code that appears here, and some fields are simply read by functions like this one, that consults the variable. Now the natural question is: how can we define new families? Or: how can we change a family like this one to point to another version of Python? There are some template-based functions for doing that. They are explained in this section of the tutorial... where is that?... oh God, it's far away... here. Suppose that we have a package foo, that we want to create a family that points to the docs of that package foo... so, we can execute this thing here, and it generates this this thing from a template. If we just want to modify a current definition we can run something like this - note that the family :py already exists, and instead of using placeholders in some of these URLs it will use the current values of the fields... so we can also use this modify existing families. Well these are the technical details. Now the natural question is: why do I want this? This doesn't any sense to me! Why should I try this? And the best answer: is for most people this way of using executable notes do not make any sense at all at first sight... so what I'm trying to do is: I'm trying to write to these tutorials with many examples that are very easy to run, and that examine data structures, and functions, and test things, and so on... so my main argument for convincing people to test this is: this is trivial to test - simply install eev and run this thing here, and run the examples, and probably you're going to find that this tutorial is fun to follow. So that's it! =)

Captioner: eduardo

Questions or comments? Please e-mail

Back to the talks Previous by track: Fanfare for the Common Emacs User Next by track: Sunday closing remarks Track: Development