Сообщить об ошибке.

Модуль misaka в Python, быстрый парсер Мarkdown

Быстрая обработка документов Мarkdown

Модуль misaka - это привязка на основе CFFI для библиотеки Hoedown, написанной на языке C. В ней есть быстрое средство визуализации HTML и функциональность для создания настраиваемых средств визуализации (например, страниц руководства или LaTeX).

Установка модуля misaka в виртуальное окружение:

# создаем виртуальное окружение, если нет
$ python3 -m venv .venv --prompt VirtualEnv
# активируем виртуальное окружение 
$ source .venv/bin/activate
# ставим модуль misaka
(VirtualEnv) Idea@Centre:~$ python -m pip install -U misaka

Модуль misaka тестировался на CPython 3.3, 3.4, 3.5, 3.6, 3.8 и PyPy 3.7.

Содержание:


Поддерживаемые расширения.

Внимание! Некоторые встроенные в модуль misaka расширения, поддерживают не всю функциональность, описанную в одноименных расширениях модуля Python-Мarkdown.

НазваниеКонстанта
tablesEXT_TABLES
fenced-codeEXT_FENCED_CODE
footnotesEXT_FOOTNOTES
autolinkEXT_AUTOLINK
strikethroughEXT_STRIKETHROUGH
underlineEXT_UNDERLINE
highlightEXT_HIGHLIGHT
quoteEXT_QUOTE
superscriptEXT_SUPERSCRIPT
mathEXT_MATH
no-intra-emphasisEXT_NO_INTRA_EMPHASIS
space-headersEXT_SPACE_HEADERS
math-explicitEXT_MATH_EXPLICIT
disable-indented-codeEXT_DISABLE_INDENTED_CODE

Флаги рендеринга HTML.

НазваниеКонстанта
skip-htmlHTML_SKIP_HTML
escapeHTML_ESCAPE
hard-wrapHTML_HARD_WRAP
use-xhtmlHTML_USE_XHTML

Функции, определяемые модулем misaka

misaka.html(text, extensions=0, render_flags=0):

Метод misaka.html() преобразует текст Markdown в HTML.

Аргумент extensions может быть списком или кортежем расширений, например ('fenced-code', 'footnotes', 'strikethrough') или целое число (константа), например EXT_FENCED_CODE | EXT_FOOTNOTES | EXT_STRIKETHROUGH.

Аргумент render_flags может быть списком или кортежем флагов, например ('skip-html', 'hard-wrap') или целое число (константа), например HTML_SKIP_HTML | HTML_HARD_WRAP.

misaka.smartypants(text):

Метод misaka.smartypants() преобразует последовательности символов в HTML-сущности.

MarkdownHTML
's (s, t, m, d, re, ll, ve)’s
"Quotes"“Quotes”
---
--
...
. . .
(c)©
(r)®
(tm)
3/4¾
1/2½
1/4¼

misaka.escape_html(text, escape_slash=False):

Метод misaka.escape_html() привязка для функции экранирования HTML Hoedown.

Реализация основана на рекомендациях OWASP XSS Prevention:

  • & --> &
  • < --> &lt;
  • > --> &gt;
  • " --> &quot;
  • ' --> &#x27;
  • / --> &#x2F; когда аргумент escape_slash=True

Классы, определяемые модулем misaka.

misaka.Markdown(renderer, extensions=0):

Класс misaka.Markdown() разбирает разметку документа Мarkdown и отображает его с помощью данного средства визуализации.

Аргумент extensions может быть списком или кортежем расширений, например ('fenced-code', 'footnotes', 'strikethrough') или целое число (константа), например EXT_FENCED_CODE | EXT_FOOTNOTES | EXT_STRIKETHROUGH.

Аргумент renderer это экземпляр класса HtmlRenderer().

misaka.HtmlRenderer(flags=0, nesting_level=0):

Класс misaka.HtmlRenderer() представляет собой обертку для средства визуализации HTML, включенного в Hoedown.

Аргумент flags может быть списком или кортежем флагов, например ('skip-html', 'hard-wrap') или целое число (константа), например HTML_SKIP_HTML | HTML_HARD_WRAP.

Аргумент nesting_level ограничивает то, что включено в оглавление. Значение по умолчанию - 0, заголовков нет.

Экземпляр HtmlRenderer() нельзя использовать совместно с несколькими экземплярами Markdown, поскольку он содержит состояние, измененное экземпляром Markdown.

misaka.SaferHtmlRenderer(flags=(), sanitization_mode='skip-html', nesting_level=0, link_rewrite=None, img_src_rewrite=None):

Класс misaka.SaferHtmlRenderer() представляет собой подкласс HtmlRenderer, который добавляет защиту от межсайтового скриптинга (XSS):

Флаг skip-html включен по умолчанию, предотвращая внедрение HTML-элементов. Если необходимо оставить HTML-код вместо его полного удаления, измените на sanitization_mode=escape.

URL-адреса ссылок и изображений фильтруются, чтобы предотвратить внедрение JavaScript. Это также блокирует преобразование адресов электронной почты в ссылки. Смотрите метод check_url() ниже.

При желании URL-адреса также могут быть переписаны для противодействия другим атакам, например фишингу.

Для включения перезаписи URL требуются дополнительные аргументы:

Параметры:

  • link_rewrite - URL страницы редиректа, необходим для перезаписи атрибута ссылки href;
  • img_src_rewrite - URL-адрес прокси изображения, необходимый для перезаписи атрибута изображения src.

Обе строки должны включать заполнитель {url} для цели с кодировкой URL. Примеры:

link_rewrite='https://example.com/redirect?url={url}',
img_src_rewrite='https://img-proxy-domain/{url}'

Методы объекта SaferHtmlRenderer:

  • autolink(raw_url, is_email) - фильтрует ссылки, созданные расширением autolink.

  • check_url(url, is_image_src=False) - этот метод используется для проверки URL. Возвращает True, если URL является безопасным, в противном случае - False.

    Реализация по умолчанию разрешает только ссылки HTTP и HTTPS. Это означает, что не будут обрабатываться mailto:, xmpp:, ftp: и т. д.

    Этот метод существует специально для того, чтобы упростить настройку фильтрации ссылок через подклассы, поэтому не стесняйтесь писать свои собственные.

    Если думаете о внедрении подхода с использованием черного списка, прочтите о том какие схемы URL-адресов опасны (можно использовать XSS)?.

  • image(raw_url, title='', alt='') - фильтрует атрибут src изображения.

    Обратите внимание, что фильтрация исходного URL-адреса тега <img> - это только самая базовая защита и в большинстве случаев бесполезна в современных браузерах (по умолчанию они блокируют JavaScript). Примером атаки, которую не предотвращает фильтрация, является фишинг на основе HTTP-аутентификации.

    Чтобы смягчить эту проблему, необходимо разрешать изображения только из доверенных источников, например вашего собственного хранилища изображений или прокси (смотрите метод .rewrite_url()).

  • link(content, raw_url, title='') - фильтрует ссылки.

  • rewrite_url(url, is_image_src=False) - этот метод вызывается для перезаписи URL-адресов.

    Он использует self.link_rewrite или self.img_src_rewrite в зависимости от значения is_image_src. URL-адрес возвращается без изменений, если соответствующий атрибут равен None.

misaka.HtmlTocRenderer(nesting_level=6):

Метод misaka.HtmlTocRenderer() представляет собой обертку для средства визуализации Оглавления, включенного в Hoedown.

Аргумент nesting_level ограничивает то, что включается в оглавление. Значение по умолчанию - 6, все заголовки.

Экземпляр HtmlTocRenderer нельзя использовать совместно с несколькими экземплярами Markdown, поскольку он несет состояние, измененное экземпляром Markdown.

misaka.BaseRenderer:

Класс misaka.BaseRenderer определяет следующие атрибуты и методы:

  • blockcode(text, lang=''), аргумент lang содержит язык по умолчанию, если включено расширение изолированные блоки кода, а язык определен в блоке кода.

  • blockquote(content);

  • header(content, level) - уровень, может быть числом от 1 до 6.

  • hrule();

  • list(content, is_ordered, is_block);

  • listitem(content, is_ordered, is_block);

  • paragraph(content);

  • table(content) - зависит от расширенияtables`.

  • table_header(content) - зависит от расширения tables.

  • table_body(content) - зависит от расширения tables.

  • table_row(content) - зависит от расширения tables.

  • table_cell(content, align, is_header) - зависит от расширения tables, аргумент align может быть пустым, center, left или right.

  • footnotes(content) - зависит от расширения footnotes.

  • footnote_def(content, num) - зависит от расширения footnotes.

  • footnote_ref(num) - зависит от расширения footnotes.

  • blockhtml(text);

  • autolink(link, is_email) - зависит от расширения autolink.

  • codespan(text);

  • double_emphasis(content);

  • emphasis(content);

  • underline(content) - Depends on the underline extension.

  • highlight(content) - зависит от расширенияhighlight`.

  • quote(content) - зависит от расширенияquote`.

  • image(link, title='', alt='');

  • linebreak();

  • link(content, link, title='');

  • triple_emphasis(content);

  • strikethrough(content) - зависит от расширения strikethrough.

  • superscript(content) - зависит от расширения superscript.

  • math(text, displaymode) - зависит от расширения math. Аргумент displaymode может быть 0 или 1. HtmlRenderer обрабатывает это следующим образом:

    if displaymode == 1:
        return f'\\[{text}\\]'
    else:  # displaymode == 0
        return f'\\({text}\\)'
    
  • raw_html(text);

  • entity(text);

  • normal_text(text);

  • doc_header(inline_render);

  • doc_footer(inline_render).

Примеры использования модуля misaka:

Очень простой пример:

import misaka
text = """
# Some text

* list
* list
* list

### Some other text
"""
html = misaka.html(text)
print(html)
# <h1>Some text</h1>
# <ul>
# <li>list</li>
# <li>list</li>
# <li>list</li>
# </ul>
# <h3>Some other text</h3>

или

>>> from misaka import Markdown, HtmlRenderer
text = """
Here is some code:

```python
print(123)
```

More code:

    print(123)
"""
>>> render = HtmlRenderer()
>>> md = Markdown(render)
>>> html = md(text)
>>> print(html)
# <p>Here is some code:</p>
# <p><code>python
# print(123)
# </code></p>
# <p>More code:</p>
# <pre><code>print(123)
# </code></pre>

Пример использования подсветки кода в модуле misaka.

Вот простой пример, который использует модуль pygments для подсветки кода. Для воспроизведения этого примера модуль pygments должен быть так же установлены в виртуальном окружении.

Приведенный ниже код содержит подклассы HtmlRenderer и реализует метод BaseRenderer.blockcode().

import misaka as m
from pygments import highlight
from pygments.formatters import HtmlFormatter, ClassNotFound
from pygments.lexers import get_lexer_by_name

class HighlighterRenderer(m.HtmlRenderer):
    def blockcode(self, text, lang):
        try:
            lexer = get_lexer_by_name(lang, stripall=True)
        except ClassNotFound:
            lexer = None
        if lexer:
            formatter = HtmlFormatter()
            return highlight(text, lexer, formatter)
        
        # default
        t = m.escape_html(text.strip())
        return f'\n<pre><code>{t}</code></pre>\n'

renderer = HighlighterRenderer()
md = m.Markdown(renderer, extensions=('fenced-code',))

text = """
Here is some code:

```python
print(123)
```

More code:

    print(123)
"""

html = md(text)
print(html)
# <p>Here is some code:</p>
# <div class="highlight"><pre><span></span>
# <span class="nb">print</span><span class="p">(</span>
# <span class="mi">123</span><span class="p">)</span>
# </pre></div>
# <p>More code:</p>
# <pre><code>print(123)</code></pre>