misaka
misaka copied to clipboard
Unable to call HtmlRenderer's paragraph method
I am creating a customer renderer to adds admonition tags to Markdown.
import misaka as m
import re
import houdini as h
class CustomHTMLRenderer(m.HtmlRenderer):
def paragraph(self, content):
_prefix_re = re.compile(r'^\s*(!{1,4})\s+')
CLASSES = {
1: 'note',
2: 'info',
3: 'tip',
4: 'warning',
}
match = _prefix_re.match(content)
if match is None:
return super(CustomHTMLRenderer, self).paragraph(content) ## this call is the problem
else:
# do something
pass
When paragraph() method is called I get this error:
AttributeError: 'super' object has no attribute 'paragraph'
From cffi callback <function cb_paragraph at 0x7f4fb4108b70>:
Traceback (most recent call last):
File "/home/x/project/env/lib/python3.6/site-packages/misaka/callbacks.py", line 82, in cb_paragraph
result = renderer.paragraph(content)
File "/home/x/project/django_project/wiki/utils.py", line 99, in paragraph
return super(CustomHTMLRenderer, self).paragraph(content)
AttributeError: 'super' object has no attribute 'paragraph'
Unfortunately the current design doesn't support overriding parent methods, because HtmlRenderer doesn't have any methods. It just fills a struct with function pointers on init (which are not accessible from Python).
I'm planning to address this in the next major version.
For now you have to re-implement the paragraph rendering method yourself. See code below for an example.
import misaka as m
import re
import houdini as h
class CustomHTMLRenderer(m.HtmlRenderer):
def paragraph(self, content):
_prefix_re = re.compile(r'^\s*(!{1,4})\s+')
CLASSES = {
1: 'note',
2: 'info',
3: 'tip',
4: 'warning',
}
match = _prefix_re.match(content)
if match is None:
return '<p>' + content + '</p>\n'
else:
length = len(match.group(1))
value = CLASSES[length]
return '<p class="' + value + '">' + content[length+1:] + '</p>\n'
if __name__ == '__main__':
rndr = CustomHTMLRenderer(flags=('escape',))
md = m.Markdown(rndr)
print(md("""
some <b>text</b>
!!!! some more text
"""))
Thanks that would work.
BTW, how can I add Table of contents. The docs mention the HtmlTocRenderer class but doesn't give a clue about how to use it?
You can add nesting_level=6 to CustomHTMLRenderer to add id attributes to the HTML headers. And HtmlTocRenderer can be used to render the input text to a nested list of header contents.
Here's your code updated with a toc:
import misaka as m
import re
import houdini as h
class CustomHTMLRenderer(m.HtmlRenderer):
def paragraph(self, content):
_prefix_re = re.compile(r'^\s*(!{1,4})\s+')
CLASSES = {
1: 'note',
2: 'info',
3: 'tip',
4: 'warning',
}
match = _prefix_re.match(content)
if match is None:
return '<p>' + content + '</p>\n'
else:
length = len(match.group(1))
value = CLASSES[length]
return '<p class="' + value + '">' + content[length+1:] + '</p>\n'
def render_table_of_contents(text):
rndr = m.HtmlTocRenderer()
md = m.Markdown(rndr)
return md(text)
def render_contents(text, flags):
rndr = CustomHTMLRenderer(nesting_level=6, flags=('escape',))
md = m.Markdown(rndr)
return md(text)
if __name__ == '__main__':
flags = ('escape',)
text = """
# H1
some <b>text</b>
## H2
!!!! some more text
"""
print(
render_table_of_contents(text) +
render_contents(text, flags)
)
Unfortunately the current design doesn't support overriding parent methods, because
HtmlRendererdoesn't have any methods. It just fills a struct with function pointers on init (which are not accessible from Python).I'm planning to address this in the next major version.
For now you have to re-implement the paragraph rendering method yourself. See code below for an example.
import misaka as m import re import houdini as h class CustomHTMLRenderer(m.HtmlRenderer): def paragraph(self, content): _prefix_re = re.compile(r'^\s*(!{1,4})\s+') CLASSES = { 1: 'note', 2: 'info', 3: 'tip', 4: 'warning', } match = _prefix_re.match(content) if match is None: return '<p>' + content + '</p>\n' else: length = len(match.group(1)) value = CLASSES[length] return '<p class="' + value + '">' + content[length+1:] + '</p>\n' if __name__ == '__main__': rndr = CustomHTMLRenderer(flags=('escape',)) md = m.Markdown(rndr) print(md(""" some <b>text</b> !!!! some more text """))
This code renders the HTML_HARD_WRAP flag useless.
You can add
nesting_level=6toCustomHTMLRendererto add id attributes to the HTML headers. AndHtmlTocRenderercan be used to render the input text to a nested list of header contents.Here's your code updated with a toc:
import misaka as m import re import houdini as h class CustomHTMLRenderer(m.HtmlRenderer): def paragraph(self, content): _prefix_re = re.compile(r'^\s*(!{1,4})\s+') CLASSES = { 1: 'note', 2: 'info', 3: 'tip', 4: 'warning', } match = _prefix_re.match(content) if match is None: return '<p>' + content + '</p>\n' else: length = len(match.group(1)) value = CLASSES[length] return '<p class="' + value + '">' + content[length+1:] + '</p>\n' def render_table_of_contents(text): rndr = m.HtmlTocRenderer() md = m.Markdown(rndr) return md(text) def render_contents(text, flags): rndr = CustomHTMLRenderer(nesting_level=6, flags=('escape',)) md = m.Markdown(rndr) return md(text) if __name__ == '__main__': flags = ('escape',) text = """ # H1 some <b>text</b> ## H2 !!!! some more text """ print( render_table_of_contents(text) + render_contents(text, flags) )
There is one problem with this code. Consider the following:
# from PIL import Image
# import webp
#
# img = Image.open('/home/x/Downloads/img1.png')
# webp.save_image(img, '/home/x/Downloads/error.webp', quality=80)
import misaka as m
import re
import houdini as h
class CustomHTMLRenderer(m.HtmlRenderer):
def paragraph(self, content):
_prefix_re = re.compile(r'^\s*(!{1,4})\s+')
CLASSES = {
1: 'note',
2: 'info',
3: 'tip',
4: 'warning',
}
match = _prefix_re.match(content)
if match is None:
return '<p>' + content + '</p>\n'
else:
length = len(match.group(1))
value = CLASSES[length]
return '<p class="' + value + '">' + content[length+1:] + '</p>\n'
def render_table_of_contents(text):
rndr = m.HtmlTocRenderer()
md = m.Markdown(rndr)
return md(text)
def render_contents(text, flags):
rndr = CustomHTMLRenderer(nesting_level=6, flags=('escape',))
md = m.Markdown(rndr)
return md(text)
if __name__ == '__main__':
flags = ('escape',)
text = """
# H1
some <b>text</b>
## H2
!!!! some more text
```python
# comment
print("hello")
print(
render_table_of_contents(text) +
render_contents(text, flags)
)
Here the line `# comment` is part of python code, but it is still being rendered in toc.