mentortools/libs/: run-markdown-1.2.68107 metadata and description

Simple index

Extract and run code blocks from .md files

author Mike Orlov
author_email m.orlov@technokert.ru
classifiers
  • License :: Other/Proprietary License
  • Programming Language :: Python :: 3
  • Programming Language :: Python :: 3.11
description_content_type text/markdown
license Unpublished
requires_dist
  • mistune (>=3.0.2,<4.0.0)
requires_python >=3.11,<4.0
File Tox results History
run_markdown-1.2.68107-py3-none-any.whl
Size
13 KB
Type
Python Wheel
Python
3
run_markdown-1.2.68107.tar.gz
Size
13 KB
Type
Source

RunMarkdown

Extract and run code blocks from .md files

Пример проверки кода на python

Код, маркированный, как python, будет запущен с помощью python

print(2+3)

Следующий блок текста за исполняемым блоком будет использоваться для проверки результата

5

Пример создания и последующего импорта файла на python

Если текст перед блоком кода заканчивается жирной строкой, начинающийся с file:// и заканчивающийся на :, то код из блока будет предварительно помешён в файл(можно указывать три слеша подряд, чтобы не создавалась ссылка)
Например, создадим file:///summarize.py:

def summarize(a: int, b: int) -> int:
    return a + b

Если после блока кода нет текстового блока, то код запускается, но проверка не выполняется
Импортируем созданный файл

from summarize import summarize
print(summarize(3, 4))

Проверим, что вывелось

7

Созданные файлы в текущей версии живут до окончания всего запуска, но это может измениться в дальнейшем

Пример проверки кода, не завершающегося за 1 сек

run_markdown имеет таймаут на выполнение каждого блока кода.
По дефолту это 1 секунда. Этот параметр принимается во втором аргументе запуска.
Помимо python можно также запускать код на bash/sh.
Следующий код будет 6 секунд выводить числа подряд.

for i in {1..20}; do echo $i; sleep 0.3; done

По поскольку мы прождём только 1 секунду, то увидим первые 4 числа:

1
2
3
4

Пример проверки кода, c шаблонизированным результатом

Для текстовых результатов есть механизм, позволяющий проверять наличие только определённых строк и/или подстрок в выводе блока

Шаблонизированные строки

Для шаблонизации строки есть символ три точки подряд ....
Он интерпретируется, как любое количество любых символов, кроме переноса строки.

Пример 1

Следующий код выведет текущий год

import datetime
print(datetime.datetime.now().year)

Допустим, мы хотим проверить первые два символа года, тогда нам подойдёт следующая запись:

20...

Она обозначает, что мы ожидаем одну строку, начинающуюся с 20 и любое количество любых символов дальше.

Пример 2

Похожий пример на bash

date

мы получим примерно такую строку: Wed Feb 12 01:26:41 PM MSK 2025
Допустим, мы так же хотим проверить, что текущий год начинается с 20 Тогда напишем следующую проверку:

... 20...

Она обозначает, что мы ожидаем одну строку, начинающуюся с любого количества любых символов, потом 20 и любое количество любых символов дальше.

Пример 3

Рассмотрим пример с несколькими строками

1/0

Этот код выбросит исключение следующего вида:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ZeroDivisionError: division by zero
Допустим, нас не интересует стек, а только само исключение. Тогда мы можем написать так:

...
...
ZeroDivisionError: division by zero

Получится, что мы игнорируем дву строки, а в третьей ожидаем полного соответствия

Пропуск строк

В прошлом примере мы игнорировали ровно две строки, но бывает так, что большую часть строк мы хотим проигнорировать, а проверить наличие меньшей.
Или бывает, что мы не знаем точное количество строк, которое хоти проигнорировать.
Тогда можно использовать три звёздочки подряд: ***
Эта последовательность символов должна быть написана на отдельной строке и тогда она обозначает, что любое количество любых строк может быть проигнорировано.
Рассмотрим примеры

Пример 1

Следующий код выведет 0-5 раз строку hay(сено), один раз строку needle(иголка) и ещё 0-5 раз hay

import datetime
[print("hay") for _ in range(datetime.datetime.now().second // 10)]
print('needle')
[print("hay") for _ in range(datetime.datetime.now().minute // 10)]

Допустим, мы хотим проверить, что вывелась строка needle, тогда нам нужно написать следующее:

***
needle
***

Получается, что мы игнорируем любое количество строк до строки needle и любое количество после

Внимание

Шаблон с большим количеством тройных звёздочек, разделённых строками, при большом выводе кодового блока, который НЕ соответствует шаблону, может упереться в производительность (зависнуть), так как будет перебирать очень большое количество вариантов сопоставления большого вывода, Например, если кодовый блок вывел

0
1
2
3
4
5

А шаблон выглядит, как

***
5
***
3
***
1
***

То вычислительная сложность грубо оценивается, как количество строк вывода В СТЕПЕНИ количества тройных звёздочек. Таким образом при выводе не 5ти чисел, а 500ти вычислительная сложность вырастет 100000000 раз!

Пример проверки кода, возвращающего json

В json порядок атрибутов объектов не гарантирован, что может стать проблемой при текстовом сравнении.
Кроме того минифицированный json (без переносов строк и пробелов) эквивалентен своей полной форме.

import json
print(json.dumps({"a": 1, "b": 2}))  # напечатает строку '{"a": 1, "b": 2}'

Опишем ожидаемый результат в развёрнутом виде: Т.к. мы указали тип json, а не text, то проверка успешно прошла

{
  "b": 2,
  "a": 1
}

Пример проверки кода, возвращающего из python stderr

Кроме стандартного потока вывода(stdout) есть ещё и поток ошибок(stderr), они объединяются в единый вывод. (вызов выполняется через утилиту script)

import sys
print("something")
print('other', file=sys.stderr)
print('''third\nforth''', file=sys.stderr)

Опишем ожидаемый результат в развёрнутом виде:

something
other
third
forth
Примечание

К сожалению, из-за буфферизации может меняться порядок вывода строк из stdout и stderr друг относительно друга. Поэтому такой подход работает далеко не всегда

Пример многострочника c кавычками на bash

Расположение целевого файла

Для некоторых тестов может быть полезно обратиться к файлам рядом с целевым md файлом.
Например, выведем содержимое текущего файла и проверим, что в нём есть эта строка:

cat $ORIGIN_DIR/README.md

Проверяем:

***
...проверим, что в нём есть эта строка
***