import mistletoe
def flatten(doc, nodes=None):
nodes = nodes or []
if hasattr(doc, 'children'):
for object in doc.children:
if isinstance(object, (mistletoe.block_token.List, mistletoe.block_token.ListItem)):
nodes.extend(flatten(object))
else: nodes.append(object)
else: nodes.append(doc)
return nodes
def quote(str, punc=''):
str, leading_ws = ''.join(str), []
lines = str.splitlines(True)
_ = '"""'
if _ in str: _ = "'''"
if not str.strip(): _ = punc = ''
while lines and not lines[0]: leading_ws.append(lines.pop())
str = ''.join(lines)
end = len(str.rstrip())
str, ending_ws = str[:end], str[end:]
if str and str.endswith(_[0]): str += ' '
return F"{''.join(leading_ws)}{_}{str}{_}{punc}{ending_ws}"
import textwrap
def markdown_to_python(s):
final, buffer, min_indent = [], [], 0
original = list(str.rstrip() for str in s.splitlines())
types = mistletoe.block_token._token_types
mistletoe.block_token._token_types = [mistletoe.block_token.List, mistletoe.block_token.BlockCode, mistletoe.block_token.Paragraph]
mistletoe.block_token._token_types = types
nodes = flatten(mistletoe.Document('\n'.join(original)))
length = len(nodes)
last_token = mistletoe.block_token.BlockCode([])
if not isinstance(nodes[-1], mistletoe.block_token.BlockCode):
nodes += [last_token]
assert nodes[-1] is last_token
while nodes:
node, block = nodes.pop(0), []
for child in node.children:
for line in map(str.strip, getattr(child, 'content', '').splitlines()):
if line:
while original and (not block or (line not in block[-1])):
block.append(original.pop(0).rstrip())
if isinstance(node, mistletoe.block_token.BlockCode):
while buffer and not buffer[0]: final.append(buffer.pop(0))
body = '\n'.join(buffer)
last_line = get_first_line(reversed(final))
prior_indent = get_line_indent(last_line)
definition, returns = last_line.rstrip().endswith(':'), last_line.lstrip().startswith('return')
this_indent = get_line_indent(get_first_line(block))
if body.strip() and not min_indent: min_indent = this_indent
indent = max(min_indent, (returns and min or max)(prior_indent, this_indent))
if definition and prior_indent == indent: indent += 4
buffer = final.extend(
textwrap.indent(quote('\n'.join(buffer)) + (
';' if length > 1 and not nodes else ''), ' '*indent).splitlines() + block) or []
else: buffer.extend(block)
return textwrap.dedent('\n'.join(final))
def get_first_line(lines, line=''):
for line in lines or ['']:
if line.strip(): break
return line
def get_line_indent(line): return len(line) - len(line.lstrip())
import ast, textwrap
def is_markdown(str): return ast.literal_eval(markdown_to_python(str).strip()) == str.strip()
def is_source(str):
try: return markdown_to_python(str).strip() == textwrap.dedent(str).strip()
except: return False