Sphinx: button inside literalinclude blocks - python

I have a desktop application and a user guide written in Sphinx. The API is explained with the use of code blocks that are imported with literalinclude blocks.
What I would like to have is a button inside or close to each code block. The button is intended for opening the respective example in our application.
What I have achieved so far (see below) is a button above the code block, that I have to include manually every time I use a literalinclude statement.
How can I put the button inside the code block rather than above?
A particularly beautiful result would be a transparent button like Chris Holdgraf's Sphinx copybutton. But at the moment I would already be happy to have the button as it is located in the top right corner of the code block.
Minimal example of how things are right now
The button is rendered above the code block. But I want to have it inside (at the top right corner).
Folder structure:
conf.py
index.rst
source_file.py
load_source.py
Content of index.rst:
:load_example:`source_file.py`
.. literalinclude:: source_file.py
Content of source_file.py:
import numpy as np
print "hello extension"
for i in range(3):
print np.sin(i)
Content of load_souce.py extension file:
from docutils import nodes
# HTML code to generate button
button_raw = """
<script>
function openScriptFunction() {
callBackHandler.openScript("%s");
}
</script>
<button onclick="openScriptFunction()">Load %s</button>
"""
def setup(app):
app.add_role('load_example', load_example_script)
def load_example_script(name, rawtext, text, lineno, inliner, options={}, content=[]):
node = nodes.raw(rawsource = button_raw%(text, text), text = button_raw%(text, text), format="html")
return [node], []
This extension is included in the conf.py by extensions = ['load_source']

Related

Convert XML document (describing a markdown file) to markdown file

Have been using Ulysses App (a markdown writing app for Mac) for a while and created hundreds of notes. Ulysses App will let you write in markdown, but internally it saves the notes in XML format.
Now I'd like to move my notes out of it, but it does not offer an easy way to do so. (At least in some edge cases where you have embedded images.)
Here is an example note in XML format:
<sheet version="5" app_version="19.2">
<string xml:space="preserve">
<p><tags><tag kind="heading1"># </tag></tags>Ulysses App - Example note</p>
<p></p>
<p><tags><tag kind="heading2">## </tag></tags>This is a header 2</p>
<p></p>
<p>And here is some text under headar 2.</p>
<p></p>
<p><tags><tag kind="heading2">## </tag></tags>Now some more</p>
<p></p>
<p><tags><tag kind="orderedList">1. </tag></tags>Item one</p>
<p><tags><tag kind="orderedList">2. </tag></tags>Item two</p>
<p></p>
<p><tags><tag kind="heading2">## </tag></tags>Finally some code</p>
<p></p>
<p><tags><tag kind="codeblock"></tag></tags><attribute identifier="syntax">python</attribute>for j in range(10):</p>
<p><tags><tag kind="codeblock"></tag></tags> print(j)</p>
<p></p>
<p></p>
<p></p></string>
</sheet>
It will be rendered as:
# Ulysses App - Example note
## This is a header 2
And here is some text under headar 2.
## Now some more
1. Item one
2. Item two
## Finally some code
```python
for j in range(10):
print(j)
``
In doing some research about how I can convert these XML files to markdown files I came across XSLT. Did some research about XSLT, but I am overwhelmed because I don't have a clue where to start.
Can someone point me to the right direction? Is trying to do an XML transformation via XSLT the right way to doing the task? Or is it too heavyweight?
I am fluent in Python. Does it make more sense to parse the XML in Python and try to convert it via Python?
All tips are welcome and appreciated.
Transformation rules
The way I see it, the transformation rules are like so:
A document consists of paragraphs. Even a headar is (in a) paragraph
Each paragraph can have one or more "qualifiers".
So a paragraph can contain only plain text like <p>And here is some text under headar 2.</p> or it can have a qualifier before or after the text like here: <p><tags><tag kind="orderedList">1. </tag></tags>Item one</p>.
In a first attempt I can parse the XML in Python to get the paragrapth texts. That would get me the bare bones of my note.
In a second iteration I can focus on parsing the "tags" (or qualifiers).
Will post my results here once done.
Question: Can this "easily" be done in XSLT?
Update: Naive solution in Python
I came up with a solution in Python3 that gets all inner texts of the paragraphs and their children. That pretty closely resembles my markdown file:
#!/usr/bin/env python3
import argparse
import xml.etree.ElementTree as ET
def load_xml(filename):
tree = ET.parse(filename)
root = tree.getroot()
# Traverse second child!
# First: "markdown", second: "string" (contains the content of the doc)
content = root[1]
return content
def main():
# get filename from command line
parser = argparse.ArgumentParser()
parser.add_argument("--file", "-f", type=str, required=True)
args = parser.parse_args()
filename = args.file
# load xml content
content = load_xml(filename)
# get all text from all children
# https://stackoverflow.com/a/34240893/5115219
para = list(content.itertext())
# join text list
text = "".join(para)
print(text)
if __name__ == "__main__":
main()
Test run
➜ (venv:ulysses_xml) ulysses_xml ./process_xml.py -f Content.xml
# Ulysses App - Example note
## This is a header 2
And here is some text under headar 2.
## Now some more
1. Item one
2. Item two
## Finally some code
pythonfor j in range(10):
 print(j)
Of course some things are missing. For instance the code block markup at the bottom. And some other fine details. But a first start at least.

How to make multi-line pop-up in Sublime Text 3 plugin

I am making a plugin for Sublime Text 3. It contacts my server in Java and receives a response in the form of a list of strings. I want a pop-up window to appear when you press a key combination, in which you can view all the line options and copy the desired one. I found an example of how to do this for one line (Github), but I don’t understand how to modify this for several lines (and several “copy” buttons, of course). It should be like:
TEXT1 - Copy
TEXT2 - Copy
TEXT3 - Copy
...
Below is the code of plugin that shows scope name in pop-up:
import sublime
import sublime_plugin
def copy(view, text):
sublime.set_clipboard(text)
view.hide_popup()
sublime.status_message('Scope name copied to clipboard')
class ShowScopeNameCommand(sublime_plugin.TextCommand):
def run(self, edit):
scope = self.view.scope_name(self.view.sel()[-1].b)
html = """
<body id=show-scope>
<style>
p {
margin-top: 0;
}
a {
font-family: system;
font-size: 1.05rem;
}
</style>
<p>%s</p>
Copy
</body>
""" % (scope.replace(' ', '<br>'), scope.rstrip())
self.view.show_popup(html, max_width=512, on_navigate=lambda x: copy(self.view, x))
It's actually quite simple once you know what get's copied when you click on the link that says Copy.
As per the official api reference, we have :-
on_navigate is a callback that should accept a string contents of the href attribute on the link the user clicked.
So whatever is in the href attribute gets copied to clipboard for the show_scope_name command (or to put in more correct terms, the href contents is passed on as an argument to the on_navigate callback). Armed with this information, here is a simple plugin that fetches some todos from Jsonplaceholder (which is a fake REST API for demo purposes), displays it as a list with each one having it's own Copy for you to select what to copy. Instead of Jsonplaceholder, you'll have to send a request to your Java server to get the list of strings and modify the example accordingly.
import json
import sublime
import urllib.parse
import urllib.request
import sublime_plugin
def get_data(num_of_todos):
""" Fetches some todos from the Jsonplaceholder API (for the purposes of getting fake data).
Args:
num_of_todos (int) : The number of todos to be fetched.
Returns:
final_data (list) : The number of todos as a list.
"""
try:
url = "https://jsonplaceholder.typicode.com/todos"
req = urllib.request.Request(url)
req.add_header('User-agent', 'Mozilla/5.0')
with urllib.request.urlopen(req) as response:
fake_data = json.loads(response.read().decode("utf-8"))
final_data = []
for todo in fake_data:
final_data.append(todo["title"])
return final_data[:num_of_todos]
except urllib.error.HTTPError as error:
return json.loads(error.read().decode("utf-8"))
class MultilinePopUpCopyCommand(sublime_plugin.TextCommand):
""" Command for fetching some todos & displaying a Copy link for each one of them,
which upon being pressed copies the specified todo
"""
def run(self, edit):
""" This method is invoked when the command is run.
Args:
edit (sublime.Edit) : The edit object necessary for making buffer modifications
in the current view.
Returns:
None.
"""
# Construct an li tree to be injected later in the ul tag.
li_tree = ""
final_data = get_data(5)
for i in range(len(final_data)):
li_tree += "<li>%s <a href='%s'>Copy</a></li>\n" %(final_data[i], final_data[i])
# The html to be shown.
html = """
<body id=copy-multiline>
<style>
ul {
margin: 0;
}
a {
font-family: system;
font-size: 1.05rem;
}
</style>
<ul>
%s
</ul>
</body>
""" %(li_tree)
self.view.show_popup(html, max_width=512, on_navigate=lambda todo: self.copy_todo(todo))
def copy_todo(self, todo):
""" Copies the todo to the clipboard.
Args:
todo (str) : The selected todo.
Returns:
None.
"""
sublime.set_clipboard(todo)
self.view.hide_popup()
sublime.status_message('Todo copied to clipboard !')
Here is a demo of the plugin (Here I have bound the command to a key binding) :-
Hope this meets your requirements.

How can I hide code and rerun all cells in a jupyter notebook?

I'd like to add some sort of functionality at the beginning of a Jupyter Notebook that hides / shows all cells and reruns all cells. What I'd like to end up with is a set of charts that are refreshed when all cells are re-run.
The details and what I've tried:
The post IPython - Run all cells below from a widget shows how you can add a button to rerun all cells below. And the post How to hide code from cells in ipython notebook visualized with nbviewer?. With this setup in two different cells I end up with this:
When the cells are collapsed it looks like this:
And this works pretty well, but I'm just really curious if it's possible to format the buttons so that they look the same. And maybe it's possible to align them as output from the same cell? I've tried to do just that by having the two snippets in the same cell, but now it seems that the Hide button is overwritten by the Refresh button:
Snippet 1:
from IPython.display import HTML
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show code"></form>''')
from IPython.display import Javascript, display
from ipywidgets import widgets
def run_all(ev):
display(Javascript('IPython.notebook.execute_cells_below()'))
button = widgets.Button(description="Refresh")
button.on_click(run_all)
display(button)
And now I end up with this:
Output 1:
Does anyone know how to make this a bit more elegant?
I really hope someone is able to provide a better answer, but having tried and failed for a couple of hours, I've found this:
By simply mixing a few parts of the two snippets in the question, I'm able to set up a Refresh button in the same format as the Hide Code buttion:
Ouptput / Notebook View:
But this still requiers two code snippets in two different cells, as well as some test code in a third cell:
Cell / snippet 1:
from IPython.display import HTML
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Display code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Display code"></form>''')
Cell / snippet 2:
HTML('''<script>
</script>
<form action="javascript:IPython.notebook.execute_cells_below()"><input type="submit" id="toggleButton" value="Refresh"></form>''')
Cell / snippet 3:
try: x
except NameError: x = None
if x is None:
x = 0
print(x)
else:
x = x + 1
print(x)
However, I'm still not able to display the two buttons beautifully side by side, and the display flickers when I hit Refresh.

Modifying a clipboard content to be treated as HTML

When I “copy an image” on the web (by highlighting the image and ctrl+C) and then passed it into the text view of the HTML WYSIWYG editor (not the source code editor) the picture is displayed. Even though I paste in the text editor ( source code editor), the content of the clipboard is understood by the editor as an html code.
For example, if I simply paste “<img src="someURL" />in the text editor, it will be added in the source code as “<p><img src="someURL" /></p>” so this clipboard isn’t understood by the editor as an html code.
So how should I modify the content of my clipboard so that an HTML WYSIWYG editor understand it as an html code even though I am pasting it in the text view (not source code editor)?
What I want to do in more details:
when I have the URL of an image stored in my clipboard, I want to be able to add the image to the HTML WYSIWYG editor without having to switch to the source code editor. So I would like to transform the content of my clipboard (by adding some code before and after the URL) so it is understood as HTML code (just like the example mentioned above) by my HTML WYSIWYG editor.
Edit: to better target the answer here is what I try to achieve. When I use shareX to upload a picture, ShareX store automatically this (private) shareable URL in the clipboard. https://drive.google.com/open?id=XXXX
This code convert it in an embedded format. But I'm still looking for a way to store that as html format.
#URL_to_Picture.py
#
#(xxx=FileID)
#
#You need that kind of URL to be able to embed the picture in an editor: https://drive.google.com/uc?export=view&id=XXXX
#
#This script does a part of the job by converting Google drive URL into an embedded (and permanent) link:
from jaraco import clipboard
UrlShareX = clipboard.paste_text()
UrlShareX=UrlShareX.replace("https://drive.google.com/file/d/", "")
UrlShareX=UrlShareX.replace("/view?usp=drivesdk", "")
UrlShareX=UrlShareX.replace("/view?usp=sharing", "")
UrlShareX=UrlShareX.replace("https://drive.google.com/open?id=", "")
URL= '<img src="https://drive.google.com/uc?export=view&id={}" />'.format(UrlShareX)
clipboard.copy_html(URL)
To try on ShareX:
You must set the access to Google drive in ShareX menu:
destination/destination settings/google drive.
You must set the ShareX menu: “after upload task” to “copy URL to
clipboard”
I want to be able to add the image to the HTML WYSIWYG editor without having to switch to the source code editor
AHK solution: use a hotkey like ctrl+shift+v
you have plain text in clipboard: https://cdn.sstatic.net/Img/teams/teams-illo-free-sidebar-promo.svg?v=47faa659a05e
go in WYSIWYG editor and press ctrl+shift+v, it will be pasted in HTML format
HTML format is a clipboard format, so an image will be shown.
what you need is here: WinClipv2\imgSrc to HTML Format\src in clip.ah2
I put the code in a repo because there's a library to include:
https://github.com/FuPeiJiang/WinClipv2
READ the README.md
You can do this:
Install HtmlClipboard : copy the script, save it as HtmlClipboard.py in C:\Python##\Lib\site-packages\
Save the script below as image_link_as_html.py(I used some of your code in your question):
Create a shorcut for the script in step to (right click on the file image_link_as_html.py, and select create a shorcut)
Right click on the shorcut, select Properties, and and add a keyboard shorcut in Shorcut key.
That's it. When you have an image url in our clipboard, you can just press your keyboard shorcut and you can paste your image directly in the html mode of you editor.
image_link_as_html.py (Python34):
from tkinter import Tk
root = Tk()
root.withdraw()
image_url = root.clipboard_get()
# send <img src="https://image_url" alt="" /> to an "HTML format clipboard"
import HtmlClipboard
HtmlClipboard.PutHtml("<img src=\"http://"+image_url+" \" alt=\"\"/>")
To address the part about ShareX, you could use this scrip instead:
from tkinter import Tk
root = Tk()
root.withdraw()
UrlShareX = root.clipboard_get()
# remove everything except the file google ID: this part is not needed
UrlShareX=UrlShareX.replace("https://drive.google.com/file/d/", "")
UrlShareX=UrlShareX.replace("/view?usp=drivesdk", "")
UrlShareX=UrlShareX.replace("/view?usp=sharing", "")
UrlShareX=UrlShareX.replace("https://drive.google.com/open?id=", "")
UrlShareX=UrlShareX.replace("/view", "")
# send <img src="https://drive.google.com/uc?export=view&id=xxx " alt="" /> to an "HTML format clipboard"
import HtmlClipboard
HtmlClipboard.PutHtml("<img src=\"https://drive.google.com/uc?export=view&id="+UrlShareX+" \" alt=\"\"/>")

Generating HTML documents in python

In python, what is the most elegant way to generate HTML documents. I currently manually append all of the tags to a giant string, and write that to a file. Is there a more elegant way of doing this?
You can use yattag to do this in an elegant way. FYI I'm the author of the library.
from yattag import Doc
doc, tag, text = Doc().tagtext()
with tag('html'):
with tag('body'):
with tag('p', id = 'main'):
text('some text')
with tag('a', href='/my-url'):
text('some link')
result = doc.getvalue()
It reads like html, with the added benefit that you don't have to close tags.
I would suggest using one of the many template languages available for python, for example the one built into Django (you don't have to use the rest of Django to use its templating engine) - a google query should give you plenty of other alternative template implementations.
I find that learning a template library helps in so many ways - whenever you need to generate an e-mail, HTML page, text file or similar, you just write a template, load it with your template library, then let the template code create the finished product.
Here's some simple code to get you started:
#!/usr/bin/env python
from django.template import Template, Context
from django.conf import settings
settings.configure() # We have to do this to use django templates standalone - see
# http://stackoverflow.com/questions/98135/how-do-i-use-django-templates-without-the-rest-of-django
# Our template. Could just as easily be stored in a separate file
template = """
<html>
<head>
<title>Template {{ title }}</title>
</head>
<body>
Body with {{ mystring }}.
</body>
</html>
"""
t = Template(template)
c = Context({"title": "title from code",
"mystring":"string from code"})
print t.render(c)
It's even simpler if you have templates on disk - check out the render_to_string function for django 1.7 that can load templates from disk from a predefined list of search paths, fill with data from a dictory and render to a string - all in one function call. (removed from django 1.8 on, see Engine.from_string for comparable action)
If you're building HTML documents than I highly suggest using a template system (like jinja2) as others have suggested. If you're in need of some low level generation of html bits (perhaps as an input to one of your templates), then the xml.etree package is a standard python package and might fit the bill nicely.
import sys
from xml.etree import ElementTree as ET
html = ET.Element('html')
body = ET.Element('body')
html.append(body)
div = ET.Element('div', attrib={'class': 'foo'})
body.append(div)
span = ET.Element('span', attrib={'class': 'bar'})
div.append(span)
span.text = "Hello World"
if sys.version_info < (3, 0, 0):
# python 2
ET.ElementTree(html).write(sys.stdout, encoding='utf-8',
method='html')
else:
# python 3
ET.ElementTree(html).write(sys.stdout, encoding='unicode',
method='html')
Prints the following:
<html><body><div class="foo"><span class="bar">Hello World</span></div></body></html>
There is also a nice, modern alternative: airium: https://pypi.org/project/airium/
from airium import Airium
a = Airium()
a('<!DOCTYPE html>')
with a.html(lang="pl"):
with a.head():
a.meta(charset="utf-8")
a.title(_t="Airium example")
with a.body():
with a.h3(id="id23409231", klass='main_header'):
a("Hello World.")
html = str(a) # casting to string extracts the value
print(html)
Prints such a string:
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8" />
<title>Airium example</title>
</head>
<body>
<h3 id="id23409231" class="main_header">
Hello World.
</h3>
</body>
</html>
The greatest advantage of airium is - it has also a reverse translator, that builds python code out of html string. If you wonder how to implement a given html snippet - the translator gives you the answer right away.
Its repository contains tests with example pages translated automatically with airium in: tests/documents. A good starting point (any existing tutorial) - is this one: tests/documents/w3_architects_example_original.html.py
I would recommend using xml.dom to do this.
http://docs.python.org/library/xml.dom.html
Read this manual page, it has methods for building up XML (and therefore XHTML). It makes all XML tasks far easier, including adding child nodes, document types, adding attributes, creating texts nodes. This should be able to assist you in the vast majority of things you will do to create HTML.
It is also very useful for analysing and processing existing xml documents.
Here is a tutorial that should help you with applying the syntax:
http://www.postneo.com/projects/pyxml/
I am using the code snippet known as throw_out_your_templates for some of my own projects:
https://github.com/tavisrudd/throw_out_your_templates
https://bitbucket.org/tavisrudd/throw-out-your-templates/src
Unfortunately, there is no pypi package for it and it's not part of any distribution as this is only meant as a proof-of-concept. I was also not able to find somebody who took the code and started maintaining it as an actual project. Nevertheless, I think it is worth a try even if it means that you have to ship your own copy of throw_out_your_templates.py with your code.
Similar to the suggestion to use yattag by John Smith Optional, this module does not require you to learn any templating language and also makes sure that you never forget to close tags or quote special characters. Everything stays written in Python. Here is an example of how to use it:
html(lang='en')[
head[title['An example'], meta(charset='UTF-8')],
body(onload='func_with_esc_args(1, "bar")')[
div['Escaped chars: ', '< ', u'>', '&'],
script(type='text/javascript')[
'var lt_not_escaped = (1 < 2);',
'\nvar escaped_cdata_close = "]]>";',
'\nvar unescaped_ampersand = "&";'
],
Comment('''
not escaped "< & >"
escaped: "-->"
'''),
div['some encoded bytes and the equivalent unicode:',
'你好', unicode('你好', 'utf-8')],
safe_unicode('<b>My surrounding b tags are not escaped</b>'),
]
]
I am attempting to make an easier solution called
PyperText
In Which you can do stuff like this:
from PyperText.html import Script
from PyperText.htmlButton import Button
#from PyperText.html{WIDGET} import WIDGET; ex from PyperText.htmlEntry import Entry; variations shared in file
myScript=Script("myfile.html")
myButton=Button()
myButton.setText("This is a button")
myScript.addWidget(myButton)
myScript.createAndWrite()
I wrote a simple wrapper for the lxml module (should work fine with xml as well) that makes tags for HTML/XML -esq documents.
Really, I liked the format of the answer by John Smith but I didn't want to install yet another module to accomplishing something that seemed so simple.
Example first, then the wrapper.
Example
from Tag import Tag
with Tag('html') as html:
with Tag('body'):
with Tag('div'):
with Tag('span', attrib={'id': 'foo'}) as span:
span.text = 'Hello, world!'
with Tag('span', attrib={'id': 'bar'}) as span:
span.text = 'This was an example!'
html.write('test_html.html')
Output:
<html><body><div><span id="foo">Hello, world!</span><span id="bar">This was an example!</span></div></body></html>
Output after some manual formatting:
<html>
<body>
<div>
<span id="foo">Hello, world!</span>
<span id="bar">This was an example!</span>
</div>
</body>
</html>
Wrapper
from dataclasses import dataclass, field
from lxml import etree
PARENT_TAG = None
#dataclass
class Tag:
tag: str
attrib: dict = field(default_factory=dict)
parent: object = None
_text: str = None
#property
def text(self):
return self._text
#text.setter
def text(self, value):
self._text = value
self.element.text = value
def __post_init__(self):
self._make_element()
self._append_to_parent()
def write(self, filename):
etree.ElementTree(self.element).write(filename)
def _make_element(self):
self.element = etree.Element(self.tag, attrib=self.attrib)
def _append_to_parent(self):
if self.parent is not None:
self.parent.element.append(self.element)
def __enter__(self):
global PARENT_TAG
if PARENT_TAG is not None:
self.parent = PARENT_TAG
self._append_to_parent()
PARENT_TAG = self
return self
def __exit__(self, typ, value, traceback):
global PARENT_TAG
if PARENT_TAG is self:
PARENT_TAG = self.parent

Categories