aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--markdown.py600
1 files changed, 300 insertions, 300 deletions
diff --git a/markdown.py b/markdown.py
index 42a50f9..99f76b8 100644
--- a/markdown.py
+++ b/markdown.py
@@ -48,7 +48,7 @@ console_hndlr.setLevel(MESSAGE_THRESHOLD)
logger.addHandler(console_hndlr)
-def message(level, text) :
+def message(level, text):
''' A wrapper method for logging debug messages. '''
logger.log(level, text)
@@ -74,9 +74,9 @@ RTL_BIDI_RANGES = ( (u'\u0590', u'\u07FF'),
# 0780-07BF - Thaana
# 07C0-07FF - Nko
-BOMS = { 'utf-8' : (codecs.BOM_UTF8, ),
- 'utf-16' : (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE),
- #'utf-32' : (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)
+BOMS = { 'utf-8': (codecs.BOM_UTF8, ),
+ 'utf-16': (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE),
+ #'utf-32': (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE)
}
def removeBOM(text, encoding):
@@ -106,7 +106,7 @@ BLOCK_LEVEL_ELEMENTS = ['p', 'div', 'blockquote', 'pre', 'table',
'form', 'fieldset', 'iframe', 'math', 'ins',
'del', 'hr', 'hr/', 'style']
-def is_block_level (tag) :
+def is_block_level (tag):
return ( (tag in BLOCK_LEVEL_ELEMENTS) or
(tag[0] == 'h' and tag[1] in "0123456789") )
@@ -134,47 +134,47 @@ ENTITY_NORMALIZATION_EXPRESSIONS_SOFT = [ (re.compile("&(?!\#)"), "&"),
(re.compile("\""), """)]
-def getBidiType(text) :
+def getBidiType(text):
- if not text : return None
+ if not text: return None
ch = text[0]
if not isinstance(ch, unicode) or not ch.isalpha():
return None
- else :
+ else:
- for min, max in RTL_BIDI_RANGES :
- if ( ch >= min and ch <= max ) :
+ for min, max in RTL_BIDI_RANGES:
+ if ( ch >= min and ch <= max ):
return "rtl"
- else :
+ else:
return "ltr"
-class Document :
+class Document:
- def __init__ (self) :
+ def __init__ (self):
self.bidi = "ltr"
- def appendChild(self, child) :
+ def appendChild(self, child):
self.documentElement = child
child.isDocumentElement = True
child.parent = self
self.entities = {}
- def setBidi(self, bidi) :
- if bidi :
+ def setBidi(self, bidi):
+ if bidi:
self.bidi = bidi
- def createElement(self, tag, textNode=None) :
+ def createElement(self, tag, textNode=None):
el = Element(tag)
el.doc = self
- if textNode :
+ if textNode:
el.appendChild(self.createTextNode(textNode))
return el
- def createTextNode(self, text) :
+ def createTextNode(self, text):
node = TextNode(text)
node.doc = self
return node
@@ -184,51 +184,51 @@ class Document :
self.entities[entity] = EntityReference(entity)
return self.entities[entity]
- def createCDATA(self, text) :
+ def createCDATA(self, text):
node = CDATA(text)
node.doc = self
return node
- def toxml (self) :
+ def toxml (self):
return self.documentElement.toxml()
- def normalizeEntities(self, text, avoidDoubleNormalizing=False) :
+ def normalizeEntities(self, text, avoidDoubleNormalizing=False):
- if avoidDoubleNormalizing :
+ if avoidDoubleNormalizing:
regexps = ENTITY_NORMALIZATION_EXPRESSIONS_SOFT
- else :
+ else:
regexps = ENTITY_NORMALIZATION_EXPRESSIONS
- for regexp, substitution in regexps :
+ for regexp, substitution in regexps:
text = regexp.sub(substitution, text)
return text
- def find(self, test) :
+ def find(self, test):
return self.documentElement.find(test)
- def unlink(self) :
+ def unlink(self):
self.documentElement.unlink()
self.documentElement = None
-class CDATA :
+class CDATA:
type = "cdata"
- def __init__ (self, text) :
+ def __init__ (self, text):
self.text = text
- def handleAttributes(self) :
+ def handleAttributes(self):
pass
- def toxml (self) :
+ def toxml (self):
return "<![CDATA[" + self.text + "]]>"
-class Element :
+class Element:
type = "element"
- def __init__ (self, tag) :
+ def __init__ (self, tag):
self.nodeName = tag
self.attributes = []
@@ -237,9 +237,9 @@ class Element :
self.bidi = None
self.isDocumentElement = False
- def setBidi(self, bidi) :
+ def setBidi(self, bidi):
- if bidi :
+ if bidi:
orig_bidi = self.bidi
@@ -249,56 +249,56 @@ class Element :
self.parent.setBidi(bidi)
- def unlink(self) :
- for child in self.childNodes :
- if child.type == "element" :
+ def unlink(self):
+ for child in self.childNodes:
+ if child.type == "element":
child.unlink()
self.childNodes = None
- def setAttribute(self, attr, value) :
- if not attr in self.attributes :
+ def setAttribute(self, attr, value):
+ if not attr in self.attributes:
self.attributes.append(attr)
self.attribute_values[attr] = value
- def insertChild(self, position, child) :
+ def insertChild(self, position, child):
self.childNodes.insert(position, child)
child.parent = self
- def removeChild(self, child) :
+ def removeChild(self, child):
self.childNodes.remove(child)
- def replaceChild(self, oldChild, newChild) :
+ def replaceChild(self, oldChild, newChild):
position = self.childNodes.index(oldChild)
self.removeChild(oldChild)
self.insertChild(position, newChild)
- def appendChild(self, child) :
+ def appendChild(self, child):
self.childNodes.append(child)
child.parent = self
- def handleAttributes(self) :
+ def handleAttributes(self):
pass
- def find(self, test, depth=0) :
+ def find(self, test, depth=0):
""" Returns a list of descendants that pass the test function """
matched_nodes = []
- for child in self.childNodes :
- if test(child) :
+ for child in self.childNodes:
+ if test(child):
matched_nodes.append(child)
- if child.type == "element" :
+ if child.type == "element":
matched_nodes += child.find(test, depth+1)
return matched_nodes
def toxml(self):
- if ENABLE_ATTRIBUTES :
+ if ENABLE_ATTRIBUTES:
for child in self.childNodes:
child.handleAttributes()
buffer = ""
- if self.nodeName in ['h1', 'h2', 'h3', 'h4'] :
+ if self.nodeName in ['h1', 'h2', 'h3', 'h4']:
buffer += "\n"
- elif self.nodeName in ['li'] :
+ elif self.nodeName in ['li']:
buffer += "\n "
# Process children FIRST, then do the attributes
@@ -307,14 +307,14 @@ class Element :
if self.childNodes or self.nodeName in ['blockquote']:
childBuffer += ">"
- for child in self.childNodes :
+ for child in self.childNodes:
childBuffer += child.toxml()
- if self.nodeName == 'p' :
+ if self.nodeName == 'p':
childBuffer += "\n"
- elif self.nodeName == 'li' :
+ elif self.nodeName == 'li':
childBuffer += "\n "
childBuffer += "</%s>" % self.nodeName
- else :
+ else:
childBuffer += "/>"
@@ -322,18 +322,18 @@ class Element :
buffer += "<" + self.nodeName
if self.nodeName in ['p', 'li', 'ul', 'ol',
- 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'] :
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
if not self.attribute_values.has_key("dir"):
- if self.bidi :
+ if self.bidi:
bidi = self.bidi
- else :
+ else:
bidi = self.doc.bidi
- if bidi=="rtl" :
+ if bidi=="rtl":
self.setAttribute("dir", "rtl")
- for attr in self.attributes :
+ for attr in self.attributes:
value = self.attribute_values[attr]
value = self.doc.normalizeEntities(value,
avoidDoubleNormalizing=True)
@@ -351,29 +351,29 @@ class Element :
return buffer
-class TextNode :
+class TextNode:
type = "text"
attrRegExp = re.compile(r'\{@([^\}]*)=([^\}]*)}') # {@id=123}
- def __init__ (self, text) :
+ def __init__ (self, text):
self.value = text
- def attributeCallback(self, match) :
+ def attributeCallback(self, match):
self.parent.setAttribute(match.group(1), match.group(2))
- def handleAttributes(self) :
+ def handleAttributes(self):
self.value = self.attrRegExp.sub(self.attributeCallback, self.value)
- def toxml(self) :
+ def toxml(self):
text = self.value
self.parent.setBidi(getBidiType(text))
if not text.startswith(HTML_PLACEHOLDER_PREFIX):
- if self.parent.nodeName == "p" :
+ if self.parent.nodeName == "p":
text = text.replace("\n", "\n ")
elif (self.parent.nodeName == "li"
and self.parent.childNodes[0]==self):
@@ -412,7 +412,7 @@ must extend markdown.Preprocessor.
"""
-class Preprocessor :
+class Preprocessor:
pass
@@ -423,27 +423,27 @@ class HeaderPreprocessor (Preprocessor):
the nead for lookahead later.
"""
- def run (self, lines) :
+ def run (self, lines):
i = -1
- while i+1 < len(lines) :
+ while i+1 < len(lines):
i = i+1
- if not lines[i].strip() :
+ if not lines[i].strip():
continue
- if lines[i].startswith("#") :
+ if lines[i].startswith("#"):
lines.insert(i+1, "\n")
if (i+1 <= len(lines)
and lines[i+1]
- and lines[i+1][0] in ['-', '=']) :
+ and lines[i+1][0] in ['-', '=']):
underline = lines[i+1].strip()
- if underline == "="*len(underline) :
+ if underline == "="*len(underline):
lines[i] = "# " + lines[i].strip()
lines[i+1] = ""
- elif underline == "-"*len(underline) :
+ elif underline == "-"*len(underline):
lines[i] = "## " + lines[i].strip()
lines[i+1] = ""
@@ -456,24 +456,24 @@ class LinePreprocessor (Preprocessor):
blockquote_re = re.compile(r'^(> )+')
- def run (self, lines) :
- for i in range(len(lines)) :
+ def run (self, lines):
+ for i in range(len(lines)):
prefix = ''
m = self.blockquote_re.search(lines[i])
if m : prefix = m.group(0)
- if self._isLine(lines[i][len(prefix):]) :
+ if self._isLine(lines[i][len(prefix):]):
lines[i] = prefix + self.stash.store("<hr />", safe=True)
return lines
- def _isLine(self, block) :
+ def _isLine(self, block):
"""Determines if a block should be replaced with an <:wHR>"""
- if block.startswith(" ") : return 0 # a code block
+ if block.startswith(" "): return 0 # a code block
text = "".join([x for x in block if not x.isspace()])
- if len(text) <= 2 :
+ if len(text) <= 2:
return 0
- for pattern in ['isline1', 'isline2', 'isline3'] :
+ for pattern in ['isline1', 'isline2', 'isline3']:
m = RE.regExp[pattern].match(text)
- if (m and m.group(1)) :
+ if (m and m.group(1)):
return 1
else:
return 0
@@ -493,11 +493,11 @@ class HtmlBlockPreprocessor (Preprocessor):
def _equal_tags(self, left_tag, right_tag):
- if left_tag in ['?', '?php', 'div'] : # handle PHP, etc.
+ if left_tag in ['?', '?php', 'div']: # handle PHP, etc.
return True
if ("/" + left_tag) == right_tag:
return True
- if (right_tag == "--" and left_tag == "--") :
+ if (right_tag == "--" and left_tag == "--"):
return True
elif left_tag == right_tag[1:] \
and right_tag[0] != "<":
@@ -509,7 +509,7 @@ class HtmlBlockPreprocessor (Preprocessor):
return (tag in ['hr', 'hr/'])
- def run (self, text) :
+ def run (self, text):
new_blocks = []
text = text.split("\n\n")
@@ -520,7 +520,7 @@ class HtmlBlockPreprocessor (Preprocessor):
in_tag = False # flag
for block in text:
- if block.startswith("\n") :
+ if block.startswith("\n"):
block = block[1:]
if not in_tag:
@@ -570,7 +570,7 @@ class HtmlBlockPreprocessor (Preprocessor):
self.stash.store('\n\n'.join(items)))
items = []
- if items :
+ if items:
new_blocks.append(self.stash.store('\n\n'.join(items)))
new_blocks.append('\n')
@@ -581,7 +581,7 @@ HTML_BLOCK_PREPROCESSOR = HtmlBlockPreprocessor()
class ReferencePreprocessor (Preprocessor):
- def run (self, lines) :
+ def run (self, lines):
new_text = [];
for line in lines:
@@ -589,14 +589,14 @@ class ReferencePreprocessor (Preprocessor):
if m:
id = m.group(2).strip().lower()
t = m.group(4).strip() # potential title
- if not t :
+ if not t:
self.references[id] = (m.group(3), t)
elif (len(t) >= 2
and (t[0] == t[-1] == "\""
or t[0] == t[-1] == "\'"
- or (t[0] == "(" and t[-1] == ")") ) ) :
+ or (t[0] == "(" and t[-1] == ")") ) ):
self.references[id] = (m.group(3), t[1:-1])
- else :
+ else:
new_text.append(line)
else:
new_text.append(line)
@@ -665,7 +665,7 @@ STRONG_EM_RE = r'\*\*\*([^_]*)\*\*\*' # ***strong***
if SMART_EMPHASIS:
EMPHASIS_2_RE = r'(?<!\S)_(\S[^_]*)_' # _emphasis_
-else :
+else:
EMPHASIS_2_RE = r'_([^_]*)_' # _emphasis_
STRONG_2_RE = r'__([^_]*)__' # __strong__
@@ -687,34 +687,34 @@ LINE_BREAK_2_RE = r' $' # two spaces at end of text
class Pattern:
- def __init__ (self, pattern) :
+ def __init__ (self, pattern):
self.pattern = pattern
self.compiled_re = re.compile("^(.*)%s(.*)$" % pattern, re.DOTALL)
- def getCompiledRegExp (self) :
+ def getCompiledRegExp (self):
return self.compiled_re
BasePattern = Pattern # for backward compatibility
-class SimpleTextPattern (Pattern) :
+class SimpleTextPattern (Pattern):
- def handleMatch(self, m, doc) :
+ def handleMatch(self, m, doc):
return doc.createTextNode(m.group(2))
class SimpleTagPattern (Pattern):
- def __init__ (self, pattern, tag) :
+ def __init__ (self, pattern, tag):
Pattern.__init__(self, pattern)
self.tag = tag
- def handleMatch(self, m, doc) :
+ def handleMatch(self, m, doc):
el = doc.createElement(self.tag)
el.appendChild(doc.createTextNode(m.group(2)))
return el
class SubstituteTagPattern (SimpleTagPattern):
- def handleMatch (self, m, doc) :
+ def handleMatch (self, m, doc):
return doc.createElement(self.tag)
class BacktickPattern (Pattern):
@@ -723,7 +723,7 @@ class BacktickPattern (Pattern):
Pattern.__init__(self, pattern)
self.tag = "code"
- def handleMatch(self, m, doc) :
+ def handleMatch(self, m, doc):
el = doc.createElement(self.tag)
text = m.group(2).strip()
#text = text.replace("&", "&amp;")
@@ -731,9 +731,9 @@ class BacktickPattern (Pattern):
return el
-class DoubleTagPattern (SimpleTagPattern) :
+class DoubleTagPattern (SimpleTagPattern):
- def handleMatch(self, m, doc) :
+ def handleMatch(self, m, doc):
tag1, tag2 = self.tag.split(",")
el1 = doc.createElement(tag1)
el2 = doc.createElement(tag2)
@@ -744,7 +744,7 @@ class DoubleTagPattern (SimpleTagPattern) :
class HtmlPattern (Pattern):
- def handleMatch (self, m, doc) :
+ def handleMatch (self, m, doc):
rawhtml = m.group(2)
inline = True
place_holder = self.stash.store(rawhtml)
@@ -753,16 +753,16 @@ class HtmlPattern (Pattern):
class LinkPattern (Pattern):
- def handleMatch(self, m, doc) :
+ def handleMatch(self, m, doc):
el = doc.createElement('a')
el.appendChild(doc.createTextNode(m.group(2)))
parts = m.group(9).split('"')
# We should now have [], [href], or [href, title]
- if parts :
+ if parts:
el.setAttribute('href', parts[0].strip())
- else :
+ else:
el.setAttribute('href', "")
- if len(parts) > 1 :
+ if len(parts) > 1:
# we also got a title
title = '"' + '"'.join(parts[1:]).strip()
title = dequote(title) #.replace('"', "&quot;")
@@ -775,13 +775,13 @@ class ImagePattern (Pattern):
def handleMatch(self, m, doc):
el = doc.createElement('img')
src_parts = m.group(9).split()
- if src_parts :
+ if src_parts:
el.setAttribute('src', src_parts[0])
else:
el.setAttribute('src', "")
- if len(src_parts) > 1 :
+ if len(src_parts) > 1:
el.setAttribute('title', dequote(" ".join(src_parts[1:])))
- if ENABLE_ATTRIBUTES :
+ if ENABLE_ATTRIBUTES:
text = doc.createTextNode(m.group(2))
el.appendChild(text)
text.handleAttributes()
@@ -796,14 +796,14 @@ class ReferencePattern (Pattern):
def handleMatch(self, m, doc):
- if m.group(9) :
+ if m.group(9):
id = m.group(9).lower()
- else :
+ else:
# if we got something like "[Google][]"
# we'll use "google" as the id
id = m.group(2).lower()
- if not self.references.has_key(id) : # ignore undefined refs
+ if not self.references.has_key(id): # ignore undefined refs
return None
href, title = self.references[id]
text = m.group(2)
@@ -812,7 +812,7 @@ class ReferencePattern (Pattern):
def makeTag(self, href, title, text, doc):
el = doc.createElement('a')
el.setAttribute('href', href)
- if title :
+ if title:
el.setAttribute('title', title)
el.appendChild(doc.createTextNode(text))
return el
@@ -823,7 +823,7 @@ class ImageReferencePattern (ReferencePattern):
def makeTag(self, href, title, text, doc):
el = doc.createElement('img')
el.setAttribute('src', href)
- if title :
+ if title:
el.setAttribute('title', title)
el.setAttribute('alt', text)
return el
@@ -839,7 +839,7 @@ class AutolinkPattern (Pattern):
class AutomailPattern (Pattern):
- def handleMatch(self, m, doc) :
+ def handleMatch(self, m, doc):
el = doc.createElement('a')
email = m.group(2)
if email.startswith("mailto:"):
@@ -897,7 +897,7 @@ There are currently no standard post-processors, but the footnote
extension below uses one.
"""
-class Postprocessor :
+class Postprocessor:
pass
@@ -916,20 +916,20 @@ Text-Post-Processors should extend markdown.Postprocessor.
"""
-class RawHtmlTextPostprocessor(Postprocessor) :
+class RawHtmlTextPostprocessor(Postprocessor):
def __init__(self):
pass
def run(self, text):
- for i in range(self.stash.html_counter) :
+ for i in range(self.stash.html_counter):
html, safe = self.stash.rawHtmlBlocks[i]
- if self.safeMode and not safe :
- if str(self.safeMode).lower() == 'escape' :
+ if self.safeMode and not safe:
+ if str(self.safeMode).lower() == 'escape':
html = self.escape(html)
- elif str(self.safeMode).lower() == 'remove' :
+ elif str(self.safeMode).lower() == 'remove':
html = ''
- else :
+ else:
html = HTML_REMOVED_TEXT
text = text.replace("<p>%s\n</p>" % (HTML_PLACEHOLDER % i),
@@ -952,15 +952,15 @@ RAWHTMLTEXTPOSTPROCESSOR = RawHtmlTextPostprocessor()
======================================================================
"""
-class HtmlStash :
+class HtmlStash:
"""This class is used for stashing HTML objects that we extract
in the beginning and replace with place-holders."""
- def __init__ (self) :
+ def __init__ (self):
self.html_counter = 0 # for counting inline html segments
self.rawHtmlBlocks=[]
- def store(self, html, safe=False) :
+ def store(self, html, safe=False):
"""Saves an HTML segment for later reinsertion. Returns a
placeholder string that needs to be inserted into the
document.
@@ -975,9 +975,9 @@ class HtmlStash :
return placeholder
-class BlockGuru :
+class BlockGuru:
- def _findHead(self, lines, fn, allowBlank=0) :
+ def _findHead(self, lines, fn, allowBlank=0):
"""Functional magic to help determine boundaries of indented
blocks.
@@ -995,7 +995,7 @@ class BlockGuru :
i = 0 # to keep track of where we are
- for line in lines :
+ for line in lines:
if not line.strip() and not allowBlank:
return items, lines[i:]
@@ -1005,11 +1005,11 @@ class BlockGuru :
i += 1
# Find the next non-blank line
- for j in range(i, len(lines)) :
- if lines[j].strip() :
+ for j in range(i, len(lines)):
+ if lines[j].strip():
next = lines[j]
break
- else :
+ else:
# There is no more text => this is the end
break
@@ -1017,36 +1017,36 @@ class BlockGuru :
part = fn(next)
- if part :
+ if part:
items.append("")
continue
- else :
+ else:
break # found end of the list
part = fn(line)
- if part :
+ if part:
items.append(part)
i += 1
continue
- else :
+ else:
return items, lines[i:]
- else :
+ else:
i += 1
return items, lines[i:]
- def detabbed_fn(self, line) :
+ def detabbed_fn(self, line):
""" An auxiliary method to be passed to _findHead """
m = RE.regExp['tabbed'].match(line)
if m:
return m.group(4)
- else :
+ else:
return None
- def detectTabbed(self, lines) :
+ def detectTabbed(self, lines):
return self._findHead(lines, self.detabbed_fn,
allowBlank = 1)
@@ -1057,12 +1057,12 @@ def print_error(string):
sys.stderr.write(string +'\n')
-def dequote(string) :
+def dequote(string):
""" Removes quotes from around a string """
if ( ( string.startswith('"') and string.endswith('"'))
- or (string.startswith("'") and string.endswith("'")) ) :
+ or (string.startswith("'") and string.endswith("'")) ):
return string[1:-1]
- else :
+ else:
return string
"""
@@ -1075,13 +1075,13 @@ see first if you can do it via pre-processors, post-processors,
inline patterns or a combination of the three.
"""
-class CorePatterns :
+class CorePatterns:
"""This class is scheduled for removal as part of a refactoring
effort."""
patterns = {
'header': r'(#*)([^#]*)(#*)', # # A title
- 'reference-def' : r'(\ ?\ ?\ ?)\[([^\]]*)\]:\s*([^ ]*)(.*)',
+ 'reference-def': r'(\ ?\ ?\ ?)\[([^\]]*)\]:\s*([^ ]*)(.*)',
# [Google]: http://www.google.com/
'containsline': r'([-]*)$|^([=]*)', # -----, =====, etc.
'ol': r'[ ]{0,3}[\d]*\.\s+(.*)', # 1. text
@@ -1090,13 +1090,13 @@ class CorePatterns :
'isline2': r'(\-*)', # ---
'isline3': r'(\_*)', # ___
'tabbed': r'((\t)|( ))(.*)', # an indented line
- 'quoted' : r'> ?(.*)', # a quoted block ("> ...")
+ 'quoted': r'> ?(.*)', # a quoted block ("> ...")
}
- def __init__ (self) :
+ def __init__ (self):
self.regExp = {}
- for key in self.patterns.keys() :
+ for key in self.patterns.keys():
self.regExp[key] = re.compile("^%s$" % self.patterns[key],
re.DOTALL)
@@ -1128,48 +1128,48 @@ class Markdown:
self.stripTopLevelTags = 1
self.docType = ""
- self.textPreprocessors = [ HTML_BLOCK_PREPROCESSOR]
+ self.textPreprocessors = [HTML_BLOCK_PREPROCESSOR]
- self.preprocessors = [ HEADER_PREPROCESSOR,
- LINE_PREPROCESSOR,
- # A footnote preprocessor will
- # get inserted here
- REFERENCE_PREPROCESSOR ]
+ self.preprocessors = [HEADER_PREPROCESSOR,
+ LINE_PREPROCESSOR,
+ # A footnote preprocessor will
+ # get inserted here
+ REFERENCE_PREPROCESSOR]
self.postprocessors = [] # a footnote postprocessor will get
# inserted later
- self.textPostprocessors = [ # a footnote postprocessor will get
- # inserted here
- RAWHTMLTEXTPOSTPROCESSOR ]
+ self.textPostprocessors = [# a footnote postprocessor will get
+ # inserted here
+ RAWHTMLTEXTPOSTPROCESSOR]
self.prePatterns = []
- self.inlinePatterns = [ DOUBLE_BACKTICK_PATTERN,
- BACKTICK_PATTERN,
- ESCAPE_PATTERN,
- IMAGE_LINK_PATTERN,
- IMAGE_REFERENCE_PATTERN,
- REFERENCE_PATTERN,
- LINK_ANGLED_PATTERN,
- LINK_PATTERN,
- AUTOLINK_PATTERN,
- AUTOMAIL_PATTERN,
- LINE_BREAK_PATTERN_2,
- LINE_BREAK_PATTERN,
- HTML_PATTERN,
- ENTITY_PATTERN,
- NOT_STRONG_PATTERN,
- STRONG_EM_PATTERN,
- STRONG_EM_PATTERN_2,
- STRONG_PATTERN,
- STRONG_PATTERN_2,
- EMPHASIS_PATTERN,
- EMPHASIS_PATTERN_2
- # The order of the handlers matters!!!
- ]
+ self.inlinePatterns = [DOUBLE_BACKTICK_PATTERN,
+ BACKTICK_PATTERN,
+ ESCAPE_PATTERN,
+ IMAGE_LINK_PATTERN,
+ IMAGE_REFERENCE_PATTERN,
+ REFERENCE_PATTERN,
+ LINK_ANGLED_PATTERN,
+ LINK_PATTERN,
+ AUTOLINK_PATTERN,
+ AUTOMAIL_PATTERN,
+ LINE_BREAK_PATTERN_2,
+ LINE_BREAK_PATTERN,
+ HTML_PATTERN,
+ ENTITY_PATTERN,
+ NOT_STRONG_PATTERN,
+ STRONG_EM_PATTERN,
+ STRONG_EM_PATTERN_2,
+ STRONG_PATTERN,
+ STRONG_PATTERN_2,
+ EMPHASIS_PATTERN,
+ EMPHASIS_PATTERN_2
+ # The order of the handlers matters!!!
+ ]
self.registerExtensions(extensions = extensions,
configs = extension_configs)
@@ -1177,27 +1177,27 @@ class Markdown:
self.reset()
- def registerExtensions(self, extensions, configs) :
+ def registerExtensions(self, extensions, configs):
- if not configs :
+ if not configs:
configs = {}
- for ext in extensions :
+ for ext in extensions:
extension_module_name = "mdx_" + ext
- try :
+ try:
module = __import__(extension_module_name)
- except :
+ except:
message(CRITICAL,
"couldn't load extension %s (looking for %s module)"
% (ext, extension_module_name) )
- else :
+ else:
- if configs.has_key(ext) :
+ if configs.has_key(ext):
configs_for_ext = configs[ext]
- else :
+ else:
configs_for_ext = []
extension = module.makeExtension(configs_for_ext)
extension.extendMarkdown(self, globals())
@@ -1205,11 +1205,11 @@ class Markdown:
- def registerExtension(self, extension) :
+ def registerExtension(self, extension):
""" This gets called by the extension """
self.registeredExtensions.append(extension)
- def reset(self) :
+ def reset(self):
"""Resets all state variables so that we can start
with a new text."""
self.references={}
@@ -1225,7 +1225,7 @@ class Markdown:
RAWHTMLTEXTPOSTPROCESSOR.stash = self.htmlStash
RAWHTMLTEXTPOSTPROCESSOR.safeMode = self.safeMode
- for extension in self.registeredExtensions :
+ for extension in self.registeredExtensions:
extension.reset()
@@ -1261,11 +1261,11 @@ class Markdown:
buffer = []
- for line in self.lines :
- if line.startswith("#") :
+ for line in self.lines:
+ if line.startswith("#"):
self._processSection(self.top_element, buffer)
buffer = [line]
- else :
+ else:
buffer.append(line)
self._processSection(self.top_element, buffer)
@@ -1275,14 +1275,14 @@ class Markdown:
self.top_element.appendChild(self.doc.createTextNode('\n'))
# Run the post-processors
- for postprocessor in self.postprocessors :
+ for postprocessor in self.postprocessors:
postprocessor.run(self.doc)
return self.doc
def _processSection(self, parent_elem, lines,
- inList = 0, looseList = 0) :
+ inList = 0, looseList = 0):
"""Process a section of a source document, looking for high
level structural elements like lists, block quotes, code
@@ -1297,19 +1297,19 @@ class Markdown:
@returns: None"""
# Loop through lines until none left.
- while lines :
+ while lines:
# Check if this section starts with a list, a blockquote or
# a code block
- processFn = { 'ul' : self._processUList,
- 'ol' : self._processOList,
- 'quoted' : self._processQuote,
- 'tabbed' : self._processCodeBlock }
+ processFn = { 'ul': self._processUList,
+ 'ol': self._processOList,
+ 'quoted': self._processQuote,
+ 'tabbed': self._processCodeBlock}
- for regexp in ['ul', 'ol', 'quoted', 'tabbed'] :
+ for regexp in ['ul', 'ol', 'quoted', 'tabbed']:
m = RE.regExp[regexp].match(lines[0])
- if m :
+ if m:
processFn[regexp](parent_elem, lines, inList)
return
@@ -1328,7 +1328,7 @@ class Markdown:
# * Underneath we might have a sublist.
#
- if inList :
+ if inList:
start, lines = self._linesUntil(lines, (lambda line:
RE.regExp['ul'].match(line)
@@ -1339,35 +1339,35 @@ class Markdown:
inList - 1, looseList = looseList)
inList = inList-1
- else : # Ok, so it's just a simple block
+ else: # Ok, so it's just a simple block
paragraph, lines = self._linesUntil(lines, lambda line:
not line.strip())
- if len(paragraph) and paragraph[0].startswith('#') :
+ if len(paragraph) and paragraph[0].startswith('#'):
self._processHeader(parent_elem, paragraph)
- elif paragraph :
+ elif paragraph:
self._processParagraph(parent_elem, paragraph,
inList, looseList)
- if lines and not lines[0].strip() :
+ if lines and not lines[0].strip():
lines = lines[1:] # skip the first (blank) line
- def _processHeader(self, parent_elem, paragraph) :
+ def _processHeader(self, parent_elem, paragraph):
m = RE.regExp['header'].match(paragraph[0])
- if m :
+ if m:
level = len(m.group(1))
h = self.doc.createElement("h%d" % level)
parent_elem.appendChild(h)
- for item in self._handleInlineWrapper(m.group(2).strip()) :
+ for item in self._handleInlineWrapper(m.group(2).strip()):
h.appendChild(item)
- else :
+ else:
message(CRITICAL, "We've got a problem header!")
- def _processParagraph(self, parent_elem, paragraph, inList, looseList) :
+ def _processParagraph(self, parent_elem, paragraph, inList, looseList):
list = self._handleInlineWrapper("\n".join(paragraph))
if ( parent_elem.nodeName == 'li'
@@ -1377,25 +1377,25 @@ class Markdown:
# put <p> around it - append the paragraph bits directly
# onto parent_elem
el = parent_elem
- else :
+ else:
# Otherwise make a "p" element
el = self.doc.createElement("p")
parent_elem.appendChild(el)
- for item in list :
+ for item in list:
el.appendChild(item)
- def _processUList(self, parent_elem, lines, inList) :
+ def _processUList(self, parent_elem, lines, inList):
self._processList(parent_elem, lines, inList,
listexpr='ul', tag = 'ul')
- def _processOList(self, parent_elem, lines, inList) :
+ def _processOList(self, parent_elem, lines, inList):
self._processList(parent_elem, lines, inList,
listexpr='ol', tag = 'ol')
- def _processList(self, parent_elem, lines, inList, listexpr, tag) :
+ def _processList(self, parent_elem, lines, inList, listexpr, tag):
"""Given a list of document lines starting with a list item,
finds the end of the list, breaks it up, and recursively
processes each list item and the remainder of the text file.
@@ -1416,20 +1416,20 @@ class Markdown:
i = 0 # a counter to keep track of where we are
- for line in lines :
+ for line in lines:
loose = 0
- if not line.strip() :
+ if not line.strip():
# If we see a blank line, this _might_ be the end of the list
i += 1
loose = 1
# Find the next non-blank line
- for j in range(i, len(lines)) :
- if lines[j].strip() :
+ for j in range(i, len(lines)):
+ if lines[j].strip():
next = lines[j]
break
- else :
+ else:
# There is no more text => end of the list
break
@@ -1441,7 +1441,7 @@ class Markdown:
items[item].append(line.strip())
looseList = loose or looseList
continue
- else :
+ else:
break # found end of the list
# Now we need to detect list items (at the current level)
@@ -1450,26 +1450,26 @@ class Markdown:
for expr in ['ul', 'ol', 'tabbed']:
m = RE.regExp[expr].match(line)
- if m :
- if expr in ['ul', 'ol'] : # We are looking at a new item
+ if m:
+ if expr in ['ul', 'ol']: # We are looking at a new item
#if m.group(1) :
# Removed the check to allow for a blank line
# at the beginning of the list item
items.append([m.group(1)])
item += 1
- elif expr == 'tabbed' : # This line needs to be detabbed
+ elif expr == 'tabbed': # This line needs to be detabbed
items[item].append(m.group(4)) #after the 'tab'
i += 1
break
- else :
+ else:
items[item].append(line) # Just regular continuation
i += 1 # added on 2006.02.25
- else :
+ else:
i += 1
# Add the dom elements
- for item in items :
+ for item in items:
li = self.doc.createElement("li")
ul.appendChild(li)
@@ -1480,21 +1480,21 @@ class Markdown:
self._processSection(parent_elem, lines[i:], inList)
- def _linesUntil(self, lines, condition) :
+ def _linesUntil(self, lines, condition):
""" A utility function to break a list of lines upon the
first line that satisfied a condition. The condition
argument should be a predicate function.
"""
i = -1
- for line in lines :
+ for line in lines:
i += 1
- if condition(line) : break
- else :
+ if condition(line): break
+ else:
i += 1
return lines[:i], lines[i:]
- def _processQuote(self, parent_elem, lines, inList) :
+ def _processQuote(self, parent_elem, lines, inList):
"""Given a list of document lines starting with a quote finds
the end of the quote, unindents it and recursively
processes the body of the quote and the remainder of the
@@ -1508,20 +1508,20 @@ class Markdown:
dequoted = []
i = 0
blank_line = False # allow one blank line between paragraphs
- for line in lines :
+ for line in lines:
m = RE.regExp['quoted'].match(line)
- if m :
+ if m:
dequoted.append(m.group(1))
i += 1
blank_line = False
- elif not blank_line and line.strip() != '' :
+ elif not blank_line and line.strip() != '':
dequoted.append(line)
i += 1
- elif not blank_line and line.strip() == '' :
+ elif not blank_line and line.strip() == '':
dequoted.append(line)
i += 1
blank_line = True
- else :
+ else:
break
blockquote = self.doc.createElement('blockquote')
@@ -1533,7 +1533,7 @@ class Markdown:
- def _processCodeBlock(self, parent_elem, lines, inList) :
+ def _processCodeBlock(self, parent_elem, lines, inList):
"""Given a list of document lines starting with a code block
finds the end of the block, puts it into the dom verbatim
wrapped in ("<pre><code>") and recursively processes the
@@ -1557,35 +1557,35 @@ class Markdown:
- def _handleInlineWrapper (self, line, patternIndex=0) :
+ def _handleInlineWrapper (self, line, patternIndex=0):
parts = [line]
- while patternIndex < len(self.inlinePatterns) :
+ while patternIndex < len(self.inlinePatterns):
i = 0
- while i < len(parts) :
+ while i < len(parts):
x = parts[i]
- if isinstance(x, (str, unicode)) :
+ if isinstance(x, (str, unicode)):
result = self._applyPattern(x, \
self.inlinePatterns[patternIndex], \
- patternIndex )
+ patternIndex)
- if result :
+ if result:
i -= 1
parts.remove(x)
- for y in result :
+ for y in result:
parts.insert(i+1,y)
i += 1
patternIndex += 1
- for i in range(len(parts)) :
+ for i in range(len(parts)):
x = parts[i]
- if isinstance(x, (str, unicode)) :
+ if isinstance(x, (str, unicode)):
parts[i] = self.doc.createTextNode(x)
return parts
@@ -1604,13 +1604,13 @@ class Markdown:
if not(line):
return [self.doc.createTextNode(' ')]
- for pattern in self.inlinePatterns :
+ for pattern in self.inlinePatterns:
list = self._applyPattern( line, pattern)
if list: return list
return [self.doc.createTextNode(line)]
- def _applyPattern(self, line, pattern, patternIndex) :
+ def _applyPattern(self, line, pattern, patternIndex):
""" Given a pattern name, this function checks if the line
fits the pattern, creates the necessary elements, and returns
@@ -1629,7 +1629,7 @@ class Markdown:
m = pattern.getCompiledRegExp().match(line)
- if not m :
+ if not m:
return None
# if we got a match let the pattern make us a NanoDom node
@@ -1640,15 +1640,15 @@ class Markdown:
if isinstance(node, Element):
- if not node.nodeName in ["code", "pre"] :
- for child in node.childNodes :
+ if not node.nodeName in ["code", "pre"]:
+ for child in node.childNodes:
if isinstance(child, TextNode):
result = self._handleInlineWrapper(child.value, patternIndex+1)
if result:
- if result == [child] :
+ if result == [child]:
continue
result.reverse()
@@ -1670,13 +1670,13 @@ class Markdown:
- if node :
+ if node:
# Those are in the reverse order!
return ( m.groups()[-1], # the string to the left
node, # the new node
m.group(1)) # the string to the right of the match
- else :
+ else:
return None
def convert (self, source = None):
@@ -1688,12 +1688,12 @@ class Markdown:
if source is not None: #Allow blank string
self.source = source
- if not self.source :
+ if not self.source:
return ""
self.source = removeBOM(self.source, self.encoding)
- for pp in self.textPreprocessors :
+ for pp in self.textPreprocessors:
self.source = pp.run(self.source)
doc = self._transform()
@@ -1704,10 +1704,10 @@ class Markdown:
# Return everything but the top level tag
- if self.stripTopLevelTags :
+ if self.stripTopLevelTags:
xml = xml.strip()[23:-7] + "\n"
- for pp in self.textPostprocessors :
+ for pp in self.textPostprocessors:
xml = pp.run(xml)
return (self.docType + xml).strip()
@@ -1737,14 +1737,14 @@ def markdownFromFile(input = None,
extensions = [],
encoding = None,
message_threshold = CRITICAL,
- safe = False) :
+ safe = False):
global console_hndlr
console_hndlr.setLevel(message_threshold)
message(DEBUG, "input file: %s" % input)
- if not encoding :
+ if not encoding:
encoding = "utf-8"
input_file = codecs.open(input, mode="r", encoding=encoding)
@@ -1753,29 +1753,29 @@ def markdownFromFile(input = None,
new_text = markdown(text, extensions, encoding, safe_mode = safe)
- if output :
+ if output:
output_file = codecs.open(output, "w", encoding=encoding)
output_file.write(new_text)
output_file.close()
- else :
+ else:
sys.stdout.write(new_text.encode(encoding))
def markdown(text,
extensions = [],
encoding = None,
- safe_mode = False) :
+ safe_mode = False):
message(DEBUG, "in markdown.markdown(), received text:\n%s" % text)
extension_names = []
extension_configs = {}
- for ext in extensions :
+ for ext in extensions:
pos = ext.find("(")
- if pos == -1 :
+ if pos == -1:
extension_names.append(ext)
- else :
+ else:
name = ext[:pos]
extension_names.append(name)
pairs = [x.split("=") for x in ext[pos+1:-1].split(",")]
@@ -1789,21 +1789,21 @@ def markdown(text,
return md.convert(text)
-class Extension :
+class Extension:
- def __init__(self, configs = {}) :
+ def __init__(self, configs = {}):
self.config = configs
- def getConfig(self, key) :
- if self.config.has_key(key) :
+ def getConfig(self, key):
+ if self.config.has_key(key):
return self.config[key][0]
- else :
+ else:
return ""
- def getConfigInfo(self) :
+ def getConfigInfo(self):
return [(key, self.config[key][1]) for key in self.config.keys()]
- def setConfig(self, key, value) :
+ def setConfig(self, key, value):
self.config[key][0] = value
@@ -1815,20 +1815,20 @@ For lower versions of Python use:
""" % EXECUTABLE_NAME_FOR_USAGE
-def parse_options() :
+def parse_options():
- try :
+ try:
optparse = __import__("optparse")
- except :
- if len(sys.argv) == 2 :
- return {'input' : sys.argv[1],
- 'output' : None,
- 'message_threshold' : CRITICAL,
- 'safe' : False,
- 'extensions' : [],
- 'encoding' : None }
-
- else :
+ except:
+ if len(sys.argv) == 2:
+ return {'input': sys.argv[1],
+ 'output': None,
+ 'message_threshold': CRITICAL,
+ 'safe': False,
+ 'extensions': [],
+ 'encoding': None }
+
+ else:
print OPTPARSE_WARNING
return None
@@ -1857,21 +1857,21 @@ def parse_options() :
(options, args) = parser.parse_args()
- if not len(args) == 1 :
+ if not len(args) == 1:
parser.print_help()
return None
- else :
+ else:
input_file = args[0]
- if not options.extensions :
+ if not options.extensions:
options.extensions = []
- return {'input' : input_file,
- 'output' : options.filename,
- 'message_threshold' : options.verbose,
- 'safe' : options.safe,
- 'extensions' : options.extensions,
- 'encoding' : options.encoding }
+ return {'input': input_file,
+ 'output': options.filename,
+ 'message_threshold': options.verbose,
+ 'safe': options.safe,
+ 'extensions': options.extensions,
+ 'encoding': options.encoding }
if __name__ == '__main__':
""" Run Markdown from the command line. """
@@ -1880,7 +1880,7 @@ if __name__ == '__main__':
#if os.access(inFile, os.R_OK):
- if not options :
+ if not options:
sys.exit(0)
markdownFromFile(**options)