Revert "Upgrade Markdown to 2.5.2" due to issues with logging in python

2.6.

This reverts commit 6787490e6d854eecea70b511673290277ea3bccc.
This commit is contained in:
Matthew Jones 2015-02-02 10:24:18 -05:00
parent 57e2548265
commit d9a2acb252
30 changed files with 747 additions and 661 deletions

View File

@ -33,7 +33,7 @@ importlib==1.0.3 (importlib/*, needed for Python 2.6 support)
iso8601==0.1.10 (iso8601/*)
keyring==4.1 (keyring/*, excluded bin/keyring)
kombu==3.0.21 (kombu/*)
Markdown==2.5.2 (markdown/*, excluded bin/markdown_py)
Markdown==2.4.1 (markdown/*, excluded bin/markdown_py)
mock==1.0.1 (mock.py)
ordereddict==1.1 (ordereddict.py, needed for Python 2.6 support)
os-diskconfig-python-novaclient-ext==0.1.2 (os_diskconfig_python_novaclient_ext/*)

View File

@ -10,7 +10,7 @@ called from the command line.
import markdown
html = markdown.markdown(your_text_string)
See <https://pythonhosted.org/Markdown/> for more
See <http://packages.python.org/Markdown/> for more
information and instructions on how to extend the functionality of
Python Markdown. Read that before you try modifying this file.
@ -36,8 +36,6 @@ from .__version__ import version, version_info
import codecs
import sys
import logging
import warnings
import importlib
from . import util
from .preprocessors import build_preprocessors
from .blockprocessors import build_block_parser
@ -50,7 +48,6 @@ from .serializers import to_html_string, to_xhtml_string
__all__ = ['Markdown', 'markdown', 'markdownFromFile']
logger = logging.getLogger('MARKDOWN')
logging.captureWarnings(True)
class Markdown(object):
@ -99,8 +96,8 @@ class Markdown(object):
Note that it is suggested that the more specific formats ("xhtml1"
and "html4") be used as "xhtml" or "html" may change in the future
if it makes sense at that time.
* safe_mode: Deprecated! Disallow raw html. One of "remove", "replace" or "escape".
* html_replacement_text: Deprecated! Text used when safe_mode is set to "replace".
* safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
* html_replacement_text: Text used when safe_mode is set to "replace".
* tab_length: Length of tabs in the source. Default: 4
* enable_attributes: Enable the conversion of attributes. Default: True
* smart_emphasis: Treat `_connected_words_` intelligently Default: True
@ -110,16 +107,14 @@ class Markdown(object):
# For backward compatibility, loop through old positional args
pos = ['extensions', 'extension_configs', 'safe_mode', 'output_format']
for c, arg in enumerate(args):
c = 0
for arg in args:
if pos[c] not in kwargs:
kwargs[pos[c]] = arg
if c+1 == len(pos): #pragma: no cover
c += 1
if c == len(pos):
# ignore any additional args
break
if len(args):
warnings.warn('Positional arguments are pending depreacted in Markdown '
'and will be deprecated in version 2.6. Use keyword '
'arguments only.', PendingDeprecationWarning)
# Loop through kwargs and assign defaults
for option, default in self.option_defaults.items():
@ -130,18 +125,6 @@ class Markdown(object):
# Disable attributes in safeMode when not explicitly set
self.enable_attributes = False
if 'safe_mode' in kwargs:
warnings.warn('"safe_mode" is pending deprecation in Python-Markdown '
'and will be deprecated in version 2.6. Use an HTML '
'sanitizer (like Bleach http://bleach.readthedocs.org/) '
'if you are parsing untrusted markdown text. See the '
'2.5 release notes for more info', PendingDeprecationWarning)
if 'html_replacement_text' in kwargs:
warnings.warn('The "html_replacement_text" keyword is pending deprecation '
'in Python-Markdown and will be deprecated in version 2.6 '
'along with "safe_mode".', PendingDeprecationWarning)
self.registeredExtensions = []
self.docType = ""
self.stripTopLevelTags = True
@ -177,11 +160,9 @@ class Markdown(object):
"""
for ext in extensions:
if isinstance(ext, util.string_type):
ext = self.build_extension(ext, configs.get(ext, {}))
ext = self.build_extension(ext, configs.get(ext, []))
if isinstance(ext, Extension):
ext.extendMarkdown(self, globals())
logger.debug('Successfully loaded extension "%s.%s".'
% (ext.__class__.__module__, ext.__class__.__name__))
elif ext is not None:
raise TypeError(
'Extension "%s.%s" must be of type: "markdown.Extension"'
@ -189,87 +170,52 @@ class Markdown(object):
return self
def build_extension(self, ext_name, configs):
def build_extension(self, ext_name, configs = []):
"""Build extension by name, then return the module.
The extension name may contain arguments as part of the string in the
following format: "extname(key1=value1,key2=value2)"
"""
configs = dict(configs)
# Parse extensions config params (ignore the order)
configs = dict(configs)
pos = ext_name.find("(") # find the first "("
if pos > 0:
ext_args = ext_name[pos+1:-1]
ext_name = ext_name[:pos]
pairs = [x.split("=") for x in ext_args.split(",")]
configs.update([(x.strip(), y.strip()) for (x, y) in pairs])
warnings.warn('Setting configs in the Named Extension string is pending deprecation. '
'It is recommended that you pass an instance of the extension class to '
'Markdown or use the "extension_configs" keyword. The current behavior '
'will be deprecated in version 2.6 and raise an error in version 2.7. '
'See the Release Notes for Python-Markdown version 2.5 for more info.',
PendingDeprecationWarning)
# Get class name (if provided): `path.to.module:ClassName`
ext_name, class_name = ext_name.split(':', 1) if ':' in ext_name else (ext_name, '')
# Setup the module name
module_name = ext_name
if '.' not in ext_name:
module_name = '.'.join(['markdown.extensions', ext_name])
# Try loading the extension first from one place, then another
try:
# Assume string uses dot syntax (`path.to.some.module`)
module = importlib.import_module(ext_name)
logger.debug('Successfuly imported extension module "%s".' % ext_name)
# For backward compat (until deprecation) check that this is an extension
if '.' not in ext_name and not (hasattr(module, 'extendMarkdown') or (class_name and hasattr(module, class_name))):
# We have a name conflict (eg: extensions=['tables'] and PyTables is installed)
raise ImportError
try: # New style (markdown.extensions.<extension>)
module = __import__(module_name, {}, {}, [module_name.rpartition('.')[0]])
except ImportError:
# Preppend `markdown.extensions.` to name
module_name = '.'.join(['markdown.extensions', ext_name])
try:
module = importlib.import_module(module_name)
logger.debug('Successfuly imported extension module "%s".' % module_name)
warnings.warn('Using short names for Markdown\'s builtin extensions is pending deprecation. '
'Use the full path to the extension with Python\'s dot notation '
'(eg: "%s" instead of "%s"). The current behavior will be deprecated in '
'version 2.6 and raise an error in version 2.7. See the Release Notes for '
'Python-Markdown version 2.5 for more info.' % (module_name, ext_name),
PendingDeprecationWarning)
except ImportError:
# Preppend `mdx_` to name
module_name_old_style = '_'.join(['mdx', ext_name])
try:
module = importlib.import_module(module_name_old_style)
logger.debug('Successfuly imported extension module "%s".' % module_name_old_style)
warnings.warn('Markdown\'s behavuor of appending "mdx_" to an extension name '
'is pending deprecation. Use the full path to the extension with '
'Python\'s dot notation (eg: "%s" instead of "%s"). The '
'current behavior will be deprecated in version 2.6 and raise an '
'error in version 2.7. See the Release Notes for Python-Markdown '
'version 2.5 for more info.' % (module_name_old_style, ext_name),
PendingDeprecationWarning)
except ImportError as e:
message = "Failed loading extension '%s' from '%s', '%s' or '%s'" \
% (ext_name, ext_name, module_name, module_name_old_style)
e.args = (message,) + e.args[1:]
raise
if class_name:
# Load given class name from module.
return getattr(module, class_name)(**configs)
else:
# Expect makeExtension() function to return a class.
try:
return module.makeExtension(**configs)
except AttributeError as e:
message = e.args[0]
message = "Failed to initiate extension " \
"'%s': %s" % (ext_name, message)
module_name_old_style = '_'.join(['mdx', ext_name])
try: # Old style (mdx_<extension>)
module = __import__(module_name_old_style)
except ImportError as e:
message = "Failed loading extension '%s' from '%s' or '%s'" \
% (ext_name, module_name, module_name_old_style)
e.args = (message,) + e.args[1:]
raise
# If the module is loaded successfully, we expect it to define a
# function called makeExtension()
try:
return module.makeExtension(configs.items())
except AttributeError as e:
message = e.args[0]
message = "Failed to initiate extension " \
"'%s': %s" % (ext_name, message)
e.args = (message,) + e.args[1:]
raise
def registerExtension(self, extension):
""" This gets called by the extension """
self.registeredExtensions.append(extension)
@ -357,7 +303,7 @@ class Markdown(object):
start = output.index('<%s>'%self.doc_tag)+len(self.doc_tag)+2
end = output.rindex('</%s>'%self.doc_tag)
output = output[start:end].strip()
except ValueError: #pragma: no cover
except ValueError:
if output.strip().endswith('<%s />'%self.doc_tag):
# We have an empty document
output = ''
@ -488,10 +434,6 @@ def markdownFromFile(*args, **kwargs):
c += 1
if c == len(pos):
break
if len(args):
warnings.warn('Positional arguments are pending depreacted in Markdown '
'and will be deprecated in version 2.6. Use keyword '
'arguments only.', PendingDeprecationWarning)
md = Markdown(**kwargs)
md.convertFile(kwargs.get('input', None),

View File

@ -7,25 +7,20 @@ COMMAND-LINE SPECIFIC STUFF
import markdown
import sys
import optparse
import codecs
try:
import yaml
except ImportError: #pragma: no cover
import json as yaml
import logging
from logging import DEBUG, INFO, CRITICAL
logger = logging.getLogger('MARKDOWN')
def parse_options(args=None, values=None):
def parse_options():
"""
Define and parse `optparse` options for command-line usage.
"""
usage = """%prog [options] [INPUTFILE]
(STDIN is assumed if no INPUTFILE is given)"""
desc = "A Python implementation of John Gruber's Markdown. " \
"https://pythonhosted.org/Markdown/"
"http://packages.python.org/Markdown/"
ver = "%%prog %s" % markdown.version
parser = optparse.OptionParser(usage=usage, description=desc, version=ver)
@ -34,36 +29,28 @@ def parse_options(args=None, values=None):
metavar="OUTPUT_FILE")
parser.add_option("-e", "--encoding", dest="encoding",
help="Encoding for input and output files.",)
parser.add_option("-s", "--safe", dest="safe", default=False,
metavar="SAFE_MODE",
help="Deprecated! 'replace', 'remove' or 'escape' HTML tags in input")
parser.add_option("-o", "--output_format", dest="output_format",
default='xhtml1', metavar="OUTPUT_FORMAT",
help="'xhtml1' (default), 'html4' or 'html5'.")
parser.add_option("-n", "--no_lazy_ol", dest="lazy_ol",
action='store_false', default=True,
help="Observe number of first item of ordered lists.")
parser.add_option("-x", "--extension", action="append", dest="extensions",
help = "Load extension EXTENSION.", metavar="EXTENSION")
parser.add_option("-c", "--extension_configs", dest="configfile", default=None,
help="Read extension configurations from CONFIG_FILE. "
"CONFIG_FILE must be of JSON or YAML format. YAML format requires "
"that a python YAML library be installed. The parsed JSON or YAML "
"must result in a python dictionary which would be accepted by the "
"'extension_configs' keyword on the markdown.Markdown class. "
"The extensions must also be loaded with the `--extension` option.",
metavar="CONFIG_FILE")
parser.add_option("-q", "--quiet", default = CRITICAL,
action="store_const", const=CRITICAL+10, dest="verbose",
help="Suppress all warnings.")
parser.add_option("-v", "--verbose",
action="store_const", const=INFO, dest="verbose",
help="Print all warnings.")
parser.add_option("-s", "--safe", dest="safe", default=False,
metavar="SAFE_MODE",
help="'replace', 'remove' or 'escape' HTML tags in input")
parser.add_option("-o", "--output_format", dest="output_format",
default='xhtml1', metavar="OUTPUT_FORMAT",
help="'xhtml1' (default), 'html4' or 'html5'.")
parser.add_option("--noisy",
action="store_const", const=DEBUG, dest="verbose",
help="Print debug messages.")
parser.add_option("-x", "--extension", action="append", dest="extensions",
help = "Load extension EXTENSION.", metavar="EXTENSION")
parser.add_option("-n", "--no_lazy_ol", dest="lazy_ol",
action='store_false', default=True,
help="Observe number of first item of ordered lists.")
(options, args) = parser.parse_args(args, values)
(options, args) = parser.parse_args()
if len(args) == 0:
input_file = None
@ -73,26 +60,15 @@ def parse_options(args=None, values=None):
if not options.extensions:
options.extensions = []
extension_configs = {}
if options.configfile:
with codecs.open(options.configfile, mode="r", encoding=options.encoding) as fp:
try:
extension_configs = yaml.load(fp)
except Exception as e:
message = "Failed parsing extension config file: %s" % options.configfile
e.args = (message,) + e.args[1:]
raise
return {'input': input_file,
'output': options.filename,
'safe_mode': options.safe,
'extensions': options.extensions,
'extension_configs': extension_configs,
'encoding': options.encoding,
'output_format': options.output_format,
'lazy_ol': options.lazy_ol}, options.verbose
def run(): #pragma: no cover
def run():
"""Run Markdown from the command line."""
# Parse options and adjust logging level if necessary
@ -104,7 +80,7 @@ def run(): #pragma: no cover
# Run
markdown.markdownFromFile(**options)
if __name__ == '__main__': #pragma: no cover
if __name__ == '__main__':
# Support running module as a commandline command.
# Python 2.5 & 2.6 do: `python -m markdown.__main__ [options] [args]`.
# Python 2.7 & 3.x do: `python -m markdown [options] [args]`.

View File

@ -5,7 +5,7 @@
# (major, minor, micro, alpha/beta/rc/final, #)
# (1, 1, 2, 'alpha', 0) => "1.1.2.dev"
# (1, 2, 0, 'beta', 2) => "1.2b2"
version_info = (2, 5, 2, 'final', 0)
version_info = (2, 4, 1, 'final', 0)
def _get_version():
" Returns a PEP 386-compliant version number from version_info. "

View File

@ -99,7 +99,7 @@ class BlockProcessor:
* ``block``: A block of text from the source which has been split at
blank lines.
"""
pass #pragma: no cover
pass
def run(self, parent, blocks):
""" Run processor. Must be overridden by subclasses.
@ -123,7 +123,7 @@ class BlockProcessor:
* ``parent``: A etree element which is the parent of the current block.
* ``blocks``: A list of all remaining blocks of the document.
"""
pass #pragma: no cover
pass
class ListIndentProcessor(BlockProcessor):
@ -433,7 +433,7 @@ class HashHeaderProcessor(BlockProcessor):
if after:
# Insert remaining lines as first block for future parsing.
blocks.insert(0, after)
else: #pragma: no cover
else:
# This should never happen, but just in case...
logger.warn("We've got a problem header: %r" % block)

View File

@ -4,45 +4,17 @@ Extensions
"""
from __future__ import unicode_literals
from ..util import parseBoolValue
import warnings
class Extension(object):
""" Base class for extensions to subclass. """
# Default config -- to be overriden by a subclass
# Must be of the following format:
# {
# 'key': ['value', 'description']
# }
# Note that Extension.setConfig will raise a KeyError
# if a default is not set here.
config = {}
def __init__(self, *args, **kwargs):
""" Initiate Extension and set up configs. """
def __init__(self, configs = {}):
"""Create an instance of an Extention.
# check for configs arg for backward compat.
# (there only ever used to be one so we use arg[0])
if len(args):
self.setConfigs(args[0])
warnings.warn('Extension classes accepting positional args is pending Deprecation. '
'Each setting should be passed into the Class as a keyword. Positional '
'args will be deprecated in version 2.6 and raise an error in version '
'2.7. See the Release Notes for Python-Markdown version 2.5 for more info.',
PendingDeprecationWarning)
# check for configs kwarg for backward compat.
if 'configs' in kwargs.keys():
self.setConfigs(kwargs.pop('configs', {}))
warnings.warn('Extension classes accepting a dict on the single keyword "config" is '
'pending Deprecation. Each setting should be passed into the Class as '
'a keyword directly. The "config" keyword will be deprecated in version '
'2.6 and raise an error in version 2.7. See the Release Notes for '
'Python-Markdown version 2.5 for more info.',
PendingDeprecationWarning)
# finally, use kwargs
self.setConfigs(kwargs)
Keyword arguments:
* configs: A dict of configuration setting used by an Extension.
"""
self.config = configs
def getConfig(self, key, default=''):
""" Return a setting for the given key or an empty string. """
@ -61,20 +33,8 @@ class Extension(object):
def setConfig(self, key, value):
""" Set a config setting for `key` with the given `value`. """
if isinstance(self.config[key][0], bool):
value = parseBoolValue(value)
if self.config[key][0] is None:
value = parseBoolValue(value, preserve_none=True)
self.config[key][0] = value
def setConfigs(self, items):
""" Set multiple config settings given a dict or list of tuples. """
if hasattr(items, 'items'):
# it's a dict
items = items.items()
for key, value in items:
self.setConfig(key, value)
def extendMarkdown(self, md, md_globals):
"""
Add the various proccesors and patterns to the Markdown Instance.

View File

@ -4,15 +4,22 @@ Abbreviation Extension for Python-Markdown
This extension adds abbreviation handling to Python-Markdown.
See <https://pythonhosted.org/Markdown/extensions/abbreviations.html>
for documentation.
Simple Usage:
Oringinal code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) and
[Seemant Kulleen](http://www.kulleen.org/)
>>> import markdown
>>> text = """
... Some text with an ABBR and a REF. Ignore REFERENCE and ref.
...
... *[ABBR]: Abbreviation
... *[REF]: Abbreviation Reference
... """
>>> print markdown.markdown(text, ['abbr'])
<p>Some text with an <abbr title="Abbreviation">ABBR</abbr> and a <abbr title="Abbreviation Reference">REF</abbr>. Ignore REFERENCE and ref.</p>
All changes Copyright 2008-2014 The Python Markdown Project
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Copyright 2007-2008
* [Waylan Limberg](http://achinghead.com/)
* [Seemant Kulleen](http://www.kulleen.org/)
'''
@ -85,5 +92,5 @@ class AbbrPattern(Pattern):
abbr.set('title', self.title)
return abbr
def makeExtension(*args, **kwargs):
return AbbrExtension(*args, **kwargs)
def makeExtension(configs=None):
return AbbrExtension(configs=configs)

View File

@ -4,16 +4,39 @@ Admonition extension for Python-Markdown
Adds rST-style admonitions. Inspired by [rST][] feature with the same name.
The syntax is (followed by an indented block with the contents):
!!! [type] [optional explicit title]
Where `type` is used as a CSS class name of the div. If not present, `title`
defaults to the capitalized `type`, so "note" -> "Note".
rST suggests the following `types`, but you're free to use whatever you want:
attention, caution, danger, error, hint, important, note, tip, warning
A simple example:
!!! note
This is the first line inside the box.
Outputs:
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>This is the first line inside the box</p>
</div>
You can also specify the title and CSS class of the admonition:
!!! custom "Did you know?"
Another line here.
Outputs:
<div class="admonition custom">
<p class="admonition-title">Did you know?</p>
<p>Another line here.</p>
</div>
[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
See <https://pythonhosted.org/Markdown/extensions/admonition.html>
for documentation.
Original code Copyright [Tiago Serafim](http://www.tiagoserafim.com/).
All changes Copyright The Python Markdown Project
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
By [Tiago Serafim](http://www.tiagoserafim.com/).
"""
@ -91,6 +114,5 @@ class AdmonitionProcessor(BlockProcessor):
return klass, title
def makeExtension(*args, **kwargs):
return AdmonitionExtension(*args, **kwargs)
def makeExtension(configs={}):
return AdmonitionExtension(configs=configs)

View File

@ -6,14 +6,15 @@ Adds attribute list syntax. Inspired by
[maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s
feature of the same name.
See <https://pythonhosted.org/Markdown/extensions/attr_list.html>
for documentation.
Copyright 2011 [Waylan Limberg](http://achinghead.com/).
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com/).
Contact: markdown@freewisdom.org
All changes Copyright 2011-2014 The Python Markdown Project
License: BSD (see ../LICENSE.md for details)
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Dependencies:
* [Python 2.4+](http://python.org)
* [Markdown 2.1+](http://packages.python.org/Markdown/)
"""
@ -26,7 +27,7 @@ import re
try:
Scanner = re.Scanner
except AttributeError: #pragma: no cover
except AttributeError:
# must be on Python 2.4
from sre import Scanner
@ -163,5 +164,5 @@ class AttrListExtension(Extension):
md.treeprocessors.add('attr_list', AttrListTreeprocessor(md), '>prettify')
def makeExtension(*args, **kwargs):
return AttrListExtension(*args, **kwargs)
def makeExtension(configs={}):
return AttrListExtension(configs=configs)

View File

@ -4,14 +4,17 @@ CodeHilite Extension for Python-Markdown
Adds code/syntax highlighting to standard Python-Markdown code blocks.
See <https://pythonhosted.org/Markdown/extensions/code_hilite.html>
for documentation.
Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
Original code Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
Project website: <http://packages.python.org/Markdown/extensions/code_hilite.html>
Contact: markdown@freewisdom.org
All changes Copyright 2008-2014 The Python Markdown Project
License: BSD (see ../LICENSE.md for details)
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Dependencies:
* [Python 2.3+](http://python.org/)
* [Markdown 2.0+](http://packages.python.org/Markdown/)
* [Pygments](http://pygments.org/)
"""
@ -22,8 +25,8 @@ from ..treeprocessors import Treeprocessor
import warnings
try:
from pygments import highlight
from pygments.lexers import get_lexer_by_name, guess_lexer
from pygments.formatters import get_formatter_by_name
from pygments.lexers import get_lexer_by_name, guess_lexer, TextLexer
from pygments.formatters import HtmlFormatter
pygments = True
except ImportError:
pygments = False
@ -109,15 +112,14 @@ class CodeHilite(object):
if self.guess_lang:
lexer = guess_lexer(self.src)
else:
lexer = get_lexer_by_name('text')
lexer = TextLexer()
except ValueError:
lexer = get_lexer_by_name('text')
formatter = get_formatter_by_name('html',
linenos=self.linenums,
cssclass=self.css_class,
style=self.style,
noclasses=self.noclasses,
hl_lines=self.hl_lines)
lexer = TextLexer()
formatter = HtmlFormatter(linenos=self.linenums,
cssclass=self.css_class,
style=self.style,
noclasses=self.noclasses,
hl_lines=self.hl_lines)
return highlight(self.src, lexer, formatter)
else:
# just escape and build markup usable by JS highlighting libs
@ -223,7 +225,7 @@ class HiliteTreeprocessor(Treeprocessor):
class CodeHiliteExtension(Extension):
""" Add source code hilighting to markdown codeblocks. """
def __init__(self, *args, **kwargs):
def __init__(self, configs):
# define default configs
self.config = {
'linenums': [None, "Use lines numbers. True=yes, False=no, None=auto"],
@ -235,7 +237,22 @@ class CodeHiliteExtension(Extension):
'noclasses': [False, 'Use inline styles instead of CSS classes - Default false']
}
super(CodeHiliteExtension, self).__init__(*args, **kwargs)
# Override defaults with user settings
for key, value in configs:
# convert strings to booleans
if value == 'True': value = True
if value == 'False': value = False
if value == 'None': value = None
if key == 'force_linenos':
warnings.warn('The "force_linenos" config setting'
' to the CodeHilite extension is deprecrecated.'
' Use "linenums" instead.', DeprecationWarning)
if value:
# Carry 'force_linenos' over to new 'linenos'.
self.setConfig('linenums', True)
self.setConfig(key, value)
def extendMarkdown(self, md, md_globals):
""" Add HilitePostprocessor to Markdown instance. """
@ -246,5 +263,6 @@ class CodeHiliteExtension(Extension):
md.registerExtension(self)
def makeExtension(*args, **kwargs):
return CodeHiliteExtension(*args, **kwargs)
def makeExtension(configs={}):
return CodeHiliteExtension(configs=configs)

View File

@ -2,16 +2,19 @@
Definition List Extension for Python-Markdown
=============================================
Adds parsing of Definition Lists to Python-Markdown.
Added parsing of Definition Lists to Python-Markdown.
See <https://pythonhosted.org/Markdown/extensions/definition_lists.html>
for documentation.
A simple example:
Original code Copyright 2008 [Waylan Limberg](http://achinghead.com)
Apple
: Pomaceous fruit of plants of the genus Malus in
the family Rosaceae.
: An american computer company.
All changes Copyright 2008-2014 The Python Markdown Project
Orange
: The fruit of an evergreen tree of the genus Citrus.
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Copyright 2008 - [Waylan Limberg](http://achinghead.com)
"""
@ -110,6 +113,6 @@ class DefListExtension(Extension):
'>ulist')
def makeExtension(*args, **kwargs):
return DefListExtension(*args, **kwargs)
def makeExtension(configs={}):
return DefListExtension(configs=configs)

View File

@ -11,6 +11,10 @@ convenience so that only one extension needs to be listed when
initiating Markdown. See the documentation for each individual
extension for specifics about that extension.
In the event that one or more of the supported extensions are not
available for import, Markdown will issue a warning and simply continue
without that extension.
There may be additional extensions that are distributed with
Python-Markdown that are not included here in Extra. Those extensions
are not part of PHP Markdown Extra, and therefore, not part of
@ -20,13 +24,6 @@ under a differant name. You could also edit the `extensions` global
variable defined below, but be aware that such changes may be lost
when you upgrade to any future version of Python-Markdown.
See <https://pythonhosted.org/Markdown/extensions/extra.html>
for documentation.
Copyright The Python Markdown Project
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
"""
from __future__ import absolute_import
@ -36,25 +33,19 @@ from ..blockprocessors import BlockProcessor
from .. import util
import re
extensions = [
'markdown.extensions.smart_strong',
'markdown.extensions.fenced_code',
'markdown.extensions.footnotes',
'markdown.extensions.attr_list',
'markdown.extensions.def_list',
'markdown.extensions.tables',
'markdown.extensions.abbr'
]
extensions = ['smart_strong',
'fenced_code',
'footnotes',
'attr_list',
'def_list',
'tables',
'abbr',
]
class ExtraExtension(Extension):
""" Add various extensions to Markdown class."""
def __init__(self, *args, **kwargs):
""" config is just a dumb holder which gets passed to actual ext later. """
self.config = kwargs.pop('configs', {})
self.config.update(kwargs)
def extendMarkdown(self, md, md_globals):
""" Register extension instances. """
md.registerExtensions(extensions, self.config)
@ -69,8 +60,8 @@ class ExtraExtension(Extension):
r'^(p|h[1-6]|li|dd|dt|td|th|legend|address)$', re.IGNORECASE)
def makeExtension(*args, **kwargs):
return ExtraExtension(*args, **kwargs)
def makeExtension(configs={}):
return ExtraExtension(configs=dict(configs))
class MarkdownInHtmlProcessor(BlockProcessor):

View File

@ -4,15 +4,87 @@ Fenced Code Extension for Python Markdown
This extension adds Fenced Code Blocks to Python-Markdown.
See <https://pythonhosted.org/Markdown/extensions/fenced_code_blocks.html>
for documentation.
>>> import markdown
>>> text = '''
... A paragraph before a fenced code block:
...
... ~~~
... Fenced code block
... ~~~
... '''
>>> html = markdown.markdown(text, extensions=['fenced_code'])
>>> print html
<p>A paragraph before a fenced code block:</p>
<pre><code>Fenced code block
</code></pre>
Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
Works with safe_mode also (we check this because we are using the HtmlStash):
>>> print markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace')
<p>A paragraph before a fenced code block:</p>
<pre><code>Fenced code block
</code></pre>
All changes Copyright 2008-2014 The Python Markdown Project
Include tilde's in a code block and wrap with blank lines:
>>> text = '''
... ~~~~~~~~
...
... ~~~~
... ~~~~~~~~'''
>>> print markdown.markdown(text, extensions=['fenced_code'])
<pre><code>
~~~~
</code></pre>
Language tags:
>>> text = '''
... ~~~~{.python}
... # Some python code
... ~~~~'''
>>> print markdown.markdown(text, extensions=['fenced_code'])
<pre><code class="python"># Some python code
</code></pre>
Optionally backticks instead of tildes as per how github's code block markdown is identified:
>>> text = '''
... `````
... # Arbitrary code
... ~~~~~ # these tildes will not close the block
... `````'''
>>> print markdown.markdown(text, extensions=['fenced_code'])
<pre><code># Arbitrary code
~~~~~ # these tildes will not close the block
</code></pre>
If the codehighlite extension and Pygments are installed, lines can be highlighted:
>>> text = '''
... ```hl_lines="1 3"
... line 1
... line 2
... line 3
... ```'''
>>> print markdown.markdown(text, extensions=['codehilite', 'fenced_code'])
<pre><code><span class="hilight">line 1</span>
line 2
<span class="hilight">line 3</span>
</code></pre>
Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
Project website: <http://packages.python.org/Markdown/extensions/fenced_code_blocks.html>
Contact: markdown@freewisdom.org
License: BSD (see ../docs/LICENSE for details)
Dependencies:
* [Python 2.4+](http://python.org)
* [Markdown 2.0+](http://packages.python.org/Markdown/)
* [Pygments (optional)](http://pygments.org)
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
"""
from __future__ import absolute_import
@ -103,6 +175,5 @@ class FencedBlockPreprocessor(Preprocessor):
return txt
def makeExtension(*args, **kwargs):
return FencedCodeExtension(*args, **kwargs)
def makeExtension(configs=None):
return FencedCodeExtension(configs=configs)

View File

@ -1,15 +1,25 @@
"""
Footnotes Extension for Python-Markdown
=======================================
========================= FOOTNOTES =================================
Adds footnote handling to Python-Markdown.
This section adds footnote handling to markdown. It can be used as
an example for extending python-markdown with relatively complex
functionality. While in this case the extension is included inside
the module itself, it could just as easily be added from outside the
module. Not that all markdown classes above are ignorant about
footnotes. All footnote functionality is provided separately and
then added to the markdown instance at the run time.
See <https://pythonhosted.org/Markdown/extensions/footnotes.html>
for documentation.
Footnote functionality is attached by calling extendMarkdown()
method of FootnoteExtension. The method also registers the
extension to allow it's state to be reset by a call to reset()
method.
Copyright The Python Markdown Project
Example:
Footnotes[^1] have a label[^label] and a definition[^!DEF].
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
[^1]: This is a footnote
[^label]: A footnote on "label"
[^!DEF]: The footnote for definition
"""
@ -32,23 +42,23 @@ TABBED_RE = re.compile(r'((\t)|( ))(.*)')
class FootnoteExtension(Extension):
""" Footnote Extension. """
def __init__ (self, *args, **kwargs):
def __init__ (self, configs):
""" Setup configs. """
self.config = {'PLACE_MARKER':
["///Footnotes Go Here///",
"The text string that marks where the footnotes go"],
'UNIQUE_IDS':
[False,
"Avoid name collisions across "
"multiple calls to reset()."],
"BACKLINK_TEXT":
["&#8617;",
"The text string that links from the footnote to the reader's place."]
}
for key, value in configs:
self.config[key][0] = value
self.config = {
'PLACE_MARKER':
["///Footnotes Go Here///",
"The text string that marks where the footnotes go"],
'UNIQUE_IDS':
[False,
"Avoid name collisions across "
"multiple calls to reset()."],
"BACKLINK_TEXT":
["&#8617;",
"The text string that links from the footnote to the reader's place."]
}
super(FootnoteExtension, self).__init__(*args, **kwargs)
# In multiple invocations, emit links that don't get tangled.
self.unique_prefix = 0
@ -299,7 +309,7 @@ class FootnotePostprocessor(Postprocessor):
text = text.replace(FN_BACKLINK_TEXT, self.footnotes.getConfig("BACKLINK_TEXT"))
return text.replace(NBSP_PLACEHOLDER, "&#160;")
def makeExtension(*args, **kwargs):
def makeExtension(configs=[]):
""" Return an instance of the FootnoteExtension """
return FootnoteExtension(*args, **kwargs)
return FootnoteExtension(configs=configs)

View File

@ -4,14 +4,73 @@ HeaderID Extension for Python-Markdown
Auto-generate id attributes for HTML headers.
See <https://pythonhosted.org/Markdown/extensions/header_id.html>
for documentation.
Basic usage:
Original code Copyright 2007-2011 [Waylan Limberg](http://achinghead.com/).
>>> import markdown
>>> text = "# Some Header #"
>>> md = markdown.markdown(text, ['headerid'])
>>> print md
<h1 id="some-header">Some Header</h1>
All changes Copyright 2011-2014 The Python Markdown Project
All header IDs are unique:
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
>>> text = '''
... #Header
... #Header
... #Header'''
>>> md = markdown.markdown(text, ['headerid'])
>>> print md
<h1 id="header">Header</h1>
<h1 id="header_1">Header</h1>
<h1 id="header_2">Header</h1>
To fit within a html template's hierarchy, set the header base level:
>>> text = '''
... #Some Header
... ## Next Level'''
>>> md = markdown.markdown(text, ['headerid(level=3)'])
>>> print md
<h3 id="some-header">Some Header</h3>
<h4 id="next-level">Next Level</h4>
Works with inline markup.
>>> text = '#Some *Header* with [markup](http://example.com).'
>>> md = markdown.markdown(text, ['headerid'])
>>> print md
<h1 id="some-header-with-markup">Some <em>Header</em> with <a href="http://example.com">markup</a>.</h1>
Turn off auto generated IDs:
>>> text = '''
... # Some Header
... # Another Header'''
>>> md = markdown.markdown(text, ['headerid(forceid=False)'])
>>> print md
<h1>Some Header</h1>
<h1>Another Header</h1>
Use with MetaData extension:
>>> text = '''header_level: 2
... header_forceid: Off
...
... # A Header'''
>>> md = markdown.markdown(text, ['headerid', 'meta'])
>>> print md
<h2>A Header</h2>
Copyright 2007-2011 [Waylan Limberg](http://achinghead.com/).
Project website: <http://packages.python.org/Markdown/extensions/header_id.html>
Contact: markdown@freewisdom.org
License: BSD (see ../docs/LICENSE for details)
Dependencies:
* [Python 2.3+](http://python.org)
* [Markdown 2.0+](http://packages.python.org/Markdown/)
"""
@ -68,7 +127,7 @@ def stashedHTML2text(text, md):
def _html_sub(m):
""" Substitute raw html with plain text. """
try:
raw, safe = md.htmlStash.rawHtmlBlocks[int(m.group(1))]
raw, safe = md.htmlStash.rawHtmlBlocks[int(m.group(1))]
except (IndexError, TypeError):
return m.group(0)
if md.safeMode and not safe:
@ -117,7 +176,7 @@ class HeaderIdTreeprocessor(Treeprocessor):
class HeaderIdExtension(Extension):
def __init__(self, *args, **kwargs):
def __init__(self, configs):
# set defaults
self.config = {
'level' : ['1', 'Base level for headers.'],
@ -126,7 +185,8 @@ class HeaderIdExtension(Extension):
'slugify' : [slugify, 'Callable to generate anchors'],
}
super(HeaderIdExtension, self).__init__(*args, **kwargs)
for key, value in configs:
self.setConfig(key, value)
def extendMarkdown(self, md, md_globals):
md.registerExtension(self)
@ -144,6 +204,5 @@ class HeaderIdExtension(Extension):
self.processor.IDs = set()
def makeExtension(*args, **kwargs):
return HeaderIdExtension(*args, **kwargs)
def makeExtension(configs=None):
return HeaderIdExtension(configs=configs)

View File

@ -4,14 +4,38 @@ Meta Data Extension for Python-Markdown
This extension adds Meta Data handling to markdown.
See <https://pythonhosted.org/Markdown/extensions/meta_data.html>
for documentation.
Basic Usage:
Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
>>> import markdown
>>> text = '''Title: A Test Doc.
... Author: Waylan Limberg
... John Doe
... Blank_Data:
...
... The body. This is paragraph one.
... '''
>>> md = markdown.Markdown(['meta'])
>>> print md.convert(text)
<p>The body. This is paragraph one.</p>
>>> print md.Meta
{u'blank_data': [u''], u'author': [u'Waylan Limberg', u'John Doe'], u'title': [u'A Test Doc.']}
All changes Copyright 2008-2014 The Python Markdown Project
Make sure text without Meta Data still works (markdown < 1.6b returns a <p>).
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
>>> text = ' Some Code - not extra lines of meta data.'
>>> md = markdown.Markdown(['meta'])
>>> print md.convert(text)
<pre><code>Some Code - not extra lines of meta data.
</code></pre>
>>> md.Meta
{}
Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
Project website: <http://packages.python.org/Markdown/meta_data.html>
Contact: markdown@freewisdom.org
License: BSD (see ../LICENSE.md for details)
"""
@ -31,7 +55,7 @@ class MetaExtension (Extension):
def extendMarkdown(self, md, md_globals):
""" Add MetaPreprocessor to Markdown instance. """
md.preprocessors.add("meta", MetaPreprocessor(md), ">normalize_whitespace")
md.preprocessors.add("meta", MetaPreprocessor(md), "_begin")
class MetaPreprocessor(Preprocessor):
@ -65,6 +89,5 @@ class MetaPreprocessor(Preprocessor):
return lines
def makeExtension(*args, **kwargs):
return MetaExtension(*args, **kwargs)
def makeExtension(configs={}):
return MetaExtension(configs=configs)

View File

@ -5,14 +5,18 @@ NL2BR Extension
A Python-Markdown extension to treat newlines as hard breaks; like
GitHub-flavored Markdown does.
See <https://pythonhosted.org/Markdown/extensions/nl2br.html>
for documentation.
Usage:
Oringinal code Copyright 2011 [Brian Neal](http://deathofagremmie.com/)
>>> import markdown
>>> print markdown.markdown('line 1\\nline 2', extensions=['nl2br'])
<p>line 1<br />
line 2</p>
All changes Copyright 2011-2014 The Python Markdown Project
Copyright 2011 [Brian Neal](http://deathofagremmie.com/)
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Dependencies:
* [Python 2.4+](http://python.org)
* [Markdown 2.1+](http://packages.python.org/Markdown/)
"""
@ -30,6 +34,5 @@ class Nl2BrExtension(Extension):
md.inlinePatterns.add('nl', br_tag, '_end')
def makeExtension(*args, **kwargs):
return Nl2BrExtension(*args, **kwargs)
def makeExtension(configs=None):
return Nl2BrExtension(configs)

View File

@ -2,16 +2,19 @@
Sane List Extension for Python-Markdown
=======================================
Modify the behavior of Lists in Python-Markdown to act in a sane manor.
Modify the behavior of Lists in Python-Markdown t act in a sane manor.
See <https://pythonhosted.org/Markdown/extensions/sane_lists.html>
for documentation.
In standard Markdown syntax, the following would constitute a single
ordered list. However, with this extension, the output would include
two lists, the first an ordered list and the second and unordered list.
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com)
1. ordered
2. list
All changes Copyright 2011-2014 The Python Markdown Project
* unordered
* list
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Copyright 2011 - [Waylan Limberg](http://achinghead.com)
"""
@ -43,6 +46,6 @@ class SaneListExtension(Extension):
md.parser.blockprocessors['ulist'] = SaneUListProcessor(md.parser)
def makeExtension(*args, **kwargs):
return SaneListExtension(*args, **kwargs)
def makeExtension(configs={}):
return SaneListExtension(configs=configs)

View File

@ -4,14 +4,21 @@ Smart_Strong Extension for Python-Markdown
This extention adds smarter handling of double underscores within words.
See <https://pythonhosted.org/Markdown/extensions/smart_strong.html>
for documentation.
Simple Usage:
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com)
>>> import markdown
>>> print markdown.markdown('Text with double__underscore__words.',
... extensions=['smart_strong'])
<p>Text with double__underscore__words.</p>
>>> print markdown.markdown('__Strong__ still works.',
... extensions=['smart_strong'])
<p><strong>Strong</strong> still works.</p>
>>> print markdown.markdown('__this__works__too__.',
... extensions=['smart_strong'])
<p><strong>this__works__too</strong>.</p>
All changes Copyright 2011-2014 The Python Markdown Project
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Copyright 2011
[Waylan Limberg](http://achinghead.com)
'''
@ -31,5 +38,5 @@ class SmartEmphasisExtension(Extension):
md.inlinePatterns['strong'] = SimpleTagPattern(STRONG_RE, 'strong')
md.inlinePatterns.add('strong2', SimpleTagPattern(SMART_STRONG_RE, 'strong'), '>emphasis2')
def makeExtension(*args, **kwargs):
return SmartEmphasisExtension(*args, **kwargs)
def makeExtension(configs={}):
return SmartEmphasisExtension(configs=dict(configs))

View File

@ -1,91 +1,73 @@
# -*- coding: utf-8 -*-
'''
Smarty extension for Python-Markdown
====================================
Adds conversion of ASCII dashes, quotes and ellipses to their HTML
entity equivalents.
See <https://pythonhosted.org/Markdown/extensions/smarty.html>
for documentation.
Author: 2013, Dmitry Shachnev <mitya57@gmail.com>
All changes Copyright 2013-2014 The Python Markdown Project
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
SmartyPants license:
Copyright (c) 2003 John Gruber <http://daringfireball.net/>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name "SmartyPants" nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
This software is provided by the copyright holders and contributors "as
is" and any express or implied warranties, including, but not limited
to, the implied warranties of merchantability and fitness for a
particular purpose are disclaimed. In no event shall the copyright
owner or contributors be liable for any direct, indirect, incidental,
special, exemplary, or consequential damages (including, but not
limited to, procurement of substitute goods or services; loss of use,
data, or profits; or business interruption) however caused and on any
theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use
of this software, even if advised of the possibility of such damage.
smartypants.py license:
smartypants.py is a derivative work of SmartyPants.
Copyright (c) 2004, 2007 Chad Miller <http://web.chad.org/>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
This software is provided by the copyright holders and contributors "as
is" and any express or implied warranties, including, but not limited
to, the implied warranties of merchantability and fitness for a
particular purpose are disclaimed. In no event shall the copyright
owner or contributors be liable for any direct, indirect, incidental,
special, exemplary, or consequential damages (including, but not
limited to, procurement of substitute goods or services; loss of use,
data, or profits; or business interruption) however caused and on any
theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use
of this software, even if advised of the possibility of such damage.
'''
# Smarty extension for Python-Markdown
# Author: 2013, Dmitry Shachnev <mitya57@gmail.com>
# SmartyPants license:
#
# Copyright (c) 2003 John Gruber <http://daringfireball.net/>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# * Neither the name "SmartyPants" nor the names of its contributors
# may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# This software is provided by the copyright holders and contributors "as
# is" and any express or implied warranties, including, but not limited
# to, the implied warranties of merchantability and fitness for a
# particular purpose are disclaimed. In no event shall the copyright
# owner or contributors be liable for any direct, indirect, incidental,
# special, exemplary, or consequential damages (including, but not
# limited to, procurement of substitute goods or services; loss of use,
# data, or profits; or business interruption) however caused and on any
# theory of liability, whether in contract, strict liability, or tort
# (including negligence or otherwise) arising in any way out of the use
# of this software, even if advised of the possibility of such damage.
#
#
# smartypants.py license:
#
# smartypants.py is a derivative work of SmartyPants.
# Copyright (c) 2004, 2007 Chad Miller <http://web.chad.org/>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# This software is provided by the copyright holders and contributors "as
# is" and any express or implied warranties, including, but not limited
# to, the implied warranties of merchantability and fitness for a
# particular purpose are disclaimed. In no event shall the copyright
# owner or contributors be liable for any direct, indirect, incidental,
# special, exemplary, or consequential damages (including, but not
# limited to, procurement of substitute goods or services; loss of use,
# data, or profits; or business interruption) however caused and on any
# theory of liability, whether in contract, strict liability, or tort
# (including negligence or otherwise) arising in any way out of the use
# of this software, even if advised of the possibility of such damage.
from __future__ import unicode_literals
from . import Extension
from ..inlinepatterns import HtmlPattern
from ..odict import OrderedDict
from ..treeprocessors import InlineProcessor
from ..util import parseBoolValue
# Constants for quote education.
@ -101,25 +83,12 @@ openingQuotesBase = (
'|&[mn]dash;' # or named dash entities
'|&#8211;|&#8212;' # or decimal entities
')'
)
substitutions = {
'mdash': '&mdash;',
'ndash': '&ndash;',
'ellipsis': '&hellip;',
'left-angle-quote': '&laquo;',
'right-angle-quote': '&raquo;',
'left-single-quote': '&lsquo;',
'right-single-quote': '&rsquo;',
'left-double-quote': '&ldquo;',
'right-double-quote': '&rdquo;',
}
)
# Special case if the very first character is a quote
# followed by punctuation at a non-word-break. Close the quotes by brute force:
singleQuoteStartRe = r"^'(?=%s\B)" % punctClass
doubleQuoteStartRe = r'^"(?=%s\B)' % punctClass
singleQuoteStartRe = r"^'(?=%s\\B)" % punctClass
doubleQuoteStartRe = r'^"(?=%s\\B)' % punctClass
# Special case for double sets of quotes, e.g.:
# <p>He said, "'Quoted' words in a larger quote."</p>
@ -144,6 +113,8 @@ closingSingleQuotesRegex2 = r"(?<=%s)'(\s|s\b)" % closeClass
remainingSingleQuotesRegex = "'"
remainingDoubleQuotesRegex = '"'
lsquo, rsquo, ldquo, rdquo = '&lsquo;', '&rsquo;', '&ldquo;', '&rdquo;'
class SubstituteTextPattern(HtmlPattern):
def __init__(self, pattern, replace, markdown_instance):
""" Replaces matches with some text. """
@ -161,56 +132,35 @@ class SubstituteTextPattern(HtmlPattern):
return result
class SmartyExtension(Extension):
def __init__(self, *args, **kwargs):
def __init__(self, configs):
self.config = {
'smart_quotes': [True, 'Educate quotes'],
'smart_angled_quotes': [False, 'Educate angled quotes'],
'smart_dashes': [True, 'Educate dashes'],
'smart_ellipses': [True, 'Educate ellipses'],
'substitutions' : [{}, 'Overwrite default substitutions'],
'smart_ellipses': [True, 'Educate ellipses']
}
super(SmartyExtension, self).__init__(*args, **kwargs)
self.substitutions = dict(substitutions)
self.substitutions.update(self.getConfig('substitutions', default={}))
for key, value in configs:
self.setConfig(key, parseBoolValue(value))
def _addPatterns(self, md, patterns, serie):
for ind, pattern in enumerate(patterns):
pattern += (md,)
pattern = SubstituteTextPattern(*pattern)
after = ('>smarty-%s-%d' % (serie, ind - 1) if ind else '_begin')
after = ('>smarty-%s-%d' % (serie, ind - 1) if ind else '>entity')
name = 'smarty-%s-%d' % (serie, ind)
self.inlinePatterns.add(name, pattern, after)
md.inlinePatterns.add(name, pattern, after)
def educateDashes(self, md):
emDashesPattern = SubstituteTextPattern(r'(?<!-)---(?!-)',
(self.substitutions['mdash'],), md)
enDashesPattern = SubstituteTextPattern(r'(?<!-)--(?!-)',
(self.substitutions['ndash'],), md)
self.inlinePatterns.add('smarty-em-dashes', emDashesPattern, '_begin')
self.inlinePatterns.add('smarty-en-dashes', enDashesPattern,
emDashesPattern = SubstituteTextPattern(r'(?<!-)---(?!-)', ('&mdash;',), md)
enDashesPattern = SubstituteTextPattern(r'(?<!-)--(?!-)', ('&ndash;',), md)
md.inlinePatterns.add('smarty-em-dashes', emDashesPattern, '>entity')
md.inlinePatterns.add('smarty-en-dashes', enDashesPattern,
'>smarty-em-dashes')
def educateEllipses(self, md):
ellipsesPattern = SubstituteTextPattern(r'(?<!\.)\.{3}(?!\.)',
(self.substitutions['ellipsis'],), md)
self.inlinePatterns.add('smarty-ellipses', ellipsesPattern, '_begin')
def educateAngledQuotes(self, md):
leftAngledQuotePattern = SubstituteTextPattern(r'\<\<',
(self.substitutions['left-angle-quote'],), md)
rightAngledQuotePattern = SubstituteTextPattern(r'\>\>',
(self.substitutions['right-angle-quote'],), md)
self.inlinePatterns.add('smarty-left-angle-quotes',
leftAngledQuotePattern, '_begin')
self.inlinePatterns.add('smarty-right-angle-quotes',
rightAngledQuotePattern, '>smarty-left-angle-quotes')
ellipsesPattern = SubstituteTextPattern(r'(?<!\.)\.{3}(?!\.)', ('&hellip;',), md)
md.inlinePatterns.add('smarty-ellipses', ellipsesPattern, '>entity')
def educateQuotes(self, md):
configs = self.getConfigs()
lsquo = self.substitutions['left-single-quote']
rsquo = self.substitutions['right-single-quote']
ldquo = self.substitutions['left-double-quote']
rdquo = self.substitutions['right-double-quote']
patterns = (
(singleQuoteStartRe, (rsquo,)),
(doubleQuoteStartRe, (rdquo,)),
@ -229,19 +179,13 @@ class SmartyExtension(Extension):
def extendMarkdown(self, md, md_globals):
configs = self.getConfigs()
self.inlinePatterns = OrderedDict()
if configs['smart_ellipses']:
self.educateEllipses(md)
if configs['smart_quotes']:
self.educateQuotes(md)
if configs['smart_angled_quotes']:
self.educateAngledQuotes(md)
if configs['smart_dashes']:
self.educateDashes(md)
inlineProcessor = InlineProcessor(md)
inlineProcessor.inlinePatterns = self.inlinePatterns
md.treeprocessors.add('smarty', inlineProcessor, '_end')
if configs['smart_ellipses']:
self.educateEllipses(md)
md.ESCAPED_CHARS.extend(['"', "'"])
def makeExtension(*args, **kwargs):
return SmartyExtension(*args, **kwargs)
def makeExtension(configs=None):
return SmartyExtension(configs)

View File

@ -4,15 +4,14 @@ Tables Extension for Python-Markdown
Added parsing of tables to Python-Markdown.
See <https://pythonhosted.org/Markdown/extensions/tables.html>
for documentation.
A simple example:
Original code Copyright 2009 [Waylan Limberg](http://achinghead.com)
All changes Copyright 2008-2014 The Python Markdown Project
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
First Header | Second Header
------------- | -------------
Content Cell | Content Cell
Content Cell | Content Cell
Copyright 2009 - [Waylan Limberg](http://achinghead.com)
"""
from __future__ import absolute_import
@ -72,7 +71,7 @@ class TableProcessor(BlockProcessor):
c = etree.SubElement(tr, tag)
try:
c.text = cells[i].strip()
except IndexError: #pragma: no cover
except IndexError:
c.text = ""
if a:
c.set('align', a)
@ -97,6 +96,5 @@ class TableExtension(Extension):
'<hashheader')
def makeExtension(*args, **kwargs):
return TableExtension(*args, **kwargs)
def makeExtension(configs={}):
return TableExtension(configs=configs)

View File

@ -1,15 +1,11 @@
"""
Table of Contents Extension for Python-Markdown
===============================================
* * *
See <https://pythonhosted.org/Markdown/extensions/toc.html>
for documentation.
(c) 2008 [Jack Miller](http://codezen.org)
Oringinal code Copyright 2008 [Jack Miller](http://codezen.org)
All changes Copyright 2008-2014 The Python Markdown Project
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Dependencies:
* [Markdown 2.1+](http://packages.python.org/Markdown/)
"""
@ -27,59 +23,60 @@ def order_toc_list(toc_list):
[{'level': 1}, {'level': 2}]
=>
[{'level': 1, 'children': [{'level': 2, 'children': []}]}]
A wrong list is also converted:
[{'level': 2}, {'level': 1}]
=>
[{'level': 2, 'children': []}, {'level': 1, 'children': []}]
"""
ordered_list = []
if len(toc_list):
# Initialize everything by processing the first entry
last = toc_list.pop(0)
last['children'] = []
levels = [last['level']]
ordered_list.append(last)
parents = []
# Walk the rest nesting the entries properly
while toc_list:
t = toc_list.pop(0)
current_level = t['level']
t['children'] = []
# Reduce depth if current level < last item's level
if current_level < levels[-1]:
# Pop last level since we know we are less than it
levels.pop()
# Pop parents and levels we are less than or equal to
to_pop = 0
for p in reversed(parents):
if current_level <= p['level']:
to_pop += 1
else:
break
if to_pop:
levels = levels[:-to_pop]
parents = parents[:-to_pop]
# Note current level as last
levels.append(current_level)
# Level is the same, so append to the current parent (if available)
if current_level == levels[-1]:
(parents[-1]['children'] if parents else ordered_list).append(t)
# Current level is > last item's level,
# So make last item a parent and append current as child
def build_correct(remaining_list, prev_elements=[{'level': 1000}]):
if not remaining_list:
return [], []
current = remaining_list.pop(0)
if not 'children' in current.keys():
current['children'] = []
if not prev_elements:
# This happens for instance with [8, 1, 1], ie. when some
# header level is outside a scope. We treat it as a
# top-level
next_elements, children = build_correct(remaining_list, [current])
current['children'].append(children)
return [current] + next_elements, []
prev_element = prev_elements.pop()
children = []
next_elements = []
# Is current part of the child list or next list?
if current['level'] > prev_element['level']:
#print "%d is a child of %d" % (current['level'], prev_element['level'])
prev_elements.append(prev_element)
prev_elements.append(current)
prev_element['children'].append(current)
next_elements2, children2 = build_correct(remaining_list, prev_elements)
children += children2
next_elements += next_elements2
else:
#print "%d is ancestor of %d" % (current['level'], prev_element['level'])
if not prev_elements:
#print "No previous elements, so appending to the next set"
next_elements.append(current)
prev_elements = [current]
next_elements2, children2 = build_correct(remaining_list, prev_elements)
current['children'].extend(children2)
else:
last['children'].append(t)
parents.append(last)
levels.append(current_level)
last = t
#print "Previous elements, comparing to those first"
remaining_list.insert(0, current)
next_elements2, children2 = build_correct(remaining_list, prev_elements)
children.extend(children2)
next_elements += next_elements2
return next_elements, children
ordered_list, __ = build_correct(toc_list)
return ordered_list
@ -207,26 +204,26 @@ class TocExtension(Extension):
TreeProcessorClass = TocTreeprocessor
def __init__(self, *args, **kwargs):
self.config = {
"marker" : ["[TOC]",
"Text to find and replace with Table of Contents - "
"Defaults to \"[TOC]\""],
"slugify" : [slugify,
"Function to generate anchors based on header text - "
"Defaults to the headerid ext's slugify function."],
"title" : ["",
"Title to insert into TOC <div> - "
"Defaults to an empty string"],
"anchorlink" : [0,
"1 if header should be a self link - "
"Defaults to 0"],
"permalink" : [0,
"1 or link text if a Sphinx-style permalink should be added - "
"Defaults to 0"]
}
def __init__(self, configs=[]):
self.config = { "marker" : ["[TOC]",
"Text to find and replace with Table of Contents -"
"Defaults to \"[TOC]\""],
"slugify" : [slugify,
"Function to generate anchors based on header text-"
"Defaults to the headerid ext's slugify function."],
"title" : [None,
"Title to insert into TOC <div> - "
"Defaults to None"],
"anchorlink" : [0,
"1 if header should be a self link"
"Defaults to 0"],
"permalink" : [0,
"1 or link text if a Sphinx-style permalink should be added",
"Defaults to 0"]
}
super(TocExtension, self).__init__(*args, **kwargs)
for key, value in configs:
self.setConfig(key, value)
def extendMarkdown(self, md, md_globals):
tocext = self.TreeProcessorClass(md)
@ -239,5 +236,5 @@ class TocExtension(Extension):
md.treeprocessors.add("toc", tocext, "_end")
def makeExtension(*args, **kwargs):
return TocExtension(*args, **kwargs)
def makeExtension(configs={}):
return TocExtension(configs=configs)

View File

@ -2,17 +2,78 @@
WikiLinks Extension for Python-Markdown
======================================
Converts [[WikiLinks]] to relative links.
Converts [[WikiLinks]] to relative links. Requires Python-Markdown 2.0+
See <https://pythonhosted.org/Markdown/extensions/wikilinks.html>
for documentation.
Basic usage:
Original code Copyright [Waylan Limberg](http://achinghead.com/).
>>> import markdown
>>> text = "Some text with a [[WikiLink]]."
>>> html = markdown.markdown(text, ['wikilinks'])
>>> print html
<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>
All changes Copyright The Python Markdown Project
Whitespace behavior:
>>> print markdown.markdown('[[ foo bar_baz ]]', ['wikilinks'])
<p><a class="wikilink" href="/foo_bar_baz/">foo bar_baz</a></p>
>>> print markdown.markdown('foo [[ ]] bar', ['wikilinks'])
<p>foo bar</p>
To define custom settings the simple way:
>>> print markdown.markdown(text,
... ['wikilinks(base_url=/wiki/,end_url=.html,html_class=foo)']
... )
<p>Some text with a <a class="foo" href="/wiki/WikiLink.html">WikiLink</a>.</p>
Custom settings the complex way:
>>> md = markdown.Markdown(
... extensions = ['wikilinks'],
... extension_configs = {'wikilinks': [
... ('base_url', 'http://example.com/'),
... ('end_url', '.html'),
... ('html_class', '') ]},
... safe_mode = True)
>>> print md.convert(text)
<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>
Use MetaData with mdx_meta.py (Note the blank html_class in MetaData):
>>> text = """wiki_base_url: http://example.com/
... wiki_end_url: .html
... wiki_html_class:
...
... Some text with a [[WikiLink]]."""
>>> md = markdown.Markdown(extensions=['meta', 'wikilinks'])
>>> print md.convert(text)
<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>
MetaData should not carry over to next document:
>>> print md.convert("No [[MetaData]] here.")
<p>No <a class="wikilink" href="/MetaData/">MetaData</a> here.</p>
Define a custom URL builder:
>>> def my_url_builder(label, base, end):
... return '/bar/'
>>> md = markdown.Markdown(extensions=['wikilinks'],
... extension_configs={'wikilinks' : [('build_url', my_url_builder)]})
>>> print md.convert('[[foo]]')
<p><a class="wikilink" href="/bar/">foo</a></p>
From the command line:
python markdown.py -x wikilinks(base_url=http://example.com/,end_url=.html,html_class=foo) src.txt
By [Waylan Limberg](http://achinghead.com/).
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
Dependencies:
* [Python 2.3+](http://python.org)
* [Markdown 2.0+](http://packages.python.org/Markdown/)
'''
from __future__ import absolute_import
@ -29,17 +90,19 @@ def build_url(label, base, end):
class WikiLinkExtension(Extension):
def __init__ (self, *args, **kwargs):
def __init__(self, configs):
# set extension defaults
self.config = {
'base_url' : ['/', 'String to append to beginning or URL.'],
'end_url' : ['/', 'String to append to end of URL.'],
'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'],
'build_url' : [build_url, 'Callable formats URL from label.'],
'base_url' : ['/', 'String to append to beginning or URL.'],
'end_url' : ['/', 'String to append to end of URL.'],
'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'],
'build_url' : [build_url, 'Callable formats URL from label.'],
}
configs = dict(configs) or {}
# Override defaults with user settings
for key, value in configs.items():
self.setConfig(key, value)
super(WikiLinkExtension, self).__init__(*args, **kwargs)
def extendMarkdown(self, md, md_globals):
self.md = md
@ -84,5 +147,5 @@ class WikiLinks(Pattern):
return base_url, end_url, html_class
def makeExtension(*args, **kwargs) :
return WikiLinkExtension(*args, **kwargs)
def makeExtension(configs=None) :
return WikiLinkExtension(configs=configs)

View File

@ -46,13 +46,13 @@ from __future__ import unicode_literals
from . import util
from . import odict
import re
try: #pragma: no cover
try:
from urllib.parse import urlparse, urlunparse
except ImportError: #pragma: no cover
except ImportError:
from urlparse import urlparse, urlunparse
try: #pragma: no cover
try:
from html import entities
except ImportError: #pragma: no cover
except ImportError:
import htmlentitydefs as entities
@ -75,8 +75,7 @@ def build_inlinepatterns(md_instance, **kwargs):
inlinePatterns["html"] = HtmlPattern(HTML_RE, md_instance)
inlinePatterns["entity"] = HtmlPattern(ENTITY_RE, md_instance)
inlinePatterns["not_strong"] = SimpleTextPattern(NOT_STRONG_RE)
inlinePatterns["em_strong"] = DoubleTagPattern(EM_STRONG_RE, 'strong,em')
inlinePatterns["strong_em"] = DoubleTagPattern(STRONG_EM_RE, 'em,strong')
inlinePatterns["strong_em"] = DoubleTagPattern(STRONG_EM_RE, 'strong,em')
inlinePatterns["strong"] = SimpleTagPattern(STRONG_RE, 'strong')
inlinePatterns["emphasis"] = SimpleTagPattern(EMPHASIS_RE, 'em')
if md_instance.smart_emphasis:
@ -101,8 +100,7 @@ BACKTICK_RE = r'(?<!\\)(`+)(.+?)(?<!`)\2(?!`)' # `e=f()` or ``e=f("`")``
ESCAPE_RE = r'\\(.)' # \<
EMPHASIS_RE = r'(\*)([^\*]+)\2' # *emphasis*
STRONG_RE = r'(\*{2}|_{2})(.+?)\2' # **strong**
EM_STRONG_RE = r'(\*|_)\2{2}(.+?)\2(.*?)\2{2}' # ***strongem*** or ***em*strong**
STRONG_EM_RE = r'(\*|_)\2{2}(.+?)\2{2}(.*?)\2' # ***strong**em*
STRONG_EM_RE = r'(\*{3}|_{3})(.+?)\2' # ***strong***
SMART_EMPHASIS_RE = r'(?<!\w)(_)(?!_)(.+?)(?<!_)\2(?!\w)' # _smart_emphasis_
EMPHASIS_2_RE = r'(_)(.+?)\2' # _emphasis_
LINK_RE = NOIMG + BRK + \
@ -158,7 +156,7 @@ class Pattern(object):
"""
self.pattern = pattern
self.compiled_re = re.compile("^(.*?)%s(.*?)$" % pattern,
self.compiled_re = re.compile("^(.*?)%s(.*?)$" % pattern,
re.DOTALL | re.UNICODE)
# Api for Markdown to pass safe_mode into instance
@ -180,7 +178,7 @@ class Pattern(object):
* m: A re match object containing a match of the pattern.
"""
pass #pragma: no cover
pass
def type(self):
""" Return class name, to define pattern type """
@ -190,9 +188,9 @@ class Pattern(object):
""" Return unescaped text given text with an inline placeholder. """
try:
stash = self.markdown.treeprocessors['inline'].stashed_nodes
except KeyError: #pragma: no cover
except KeyError:
return text
def itertext(el): #pragma: no cover
def itertext(el):
' Reimplement Element.itertext for older python versions '
tag = el.tag
if not isinstance(tag, util.string_type) and tag is not None:
@ -212,14 +210,17 @@ class Pattern(object):
return value
else:
# An etree Element - return text content only
return ''.join(itertext(value))
return ''.join(itertext(value))
return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
class SimpleTextPattern(Pattern):
""" Return a simple text of group(2) of a Pattern. """
def handleMatch(self, m):
return m.group(2)
text = m.group(2)
if text == util.INLINE_PLACEHOLDER_PREFIX:
return None
return text
class EscapePattern(Pattern):
@ -230,7 +231,7 @@ class EscapePattern(Pattern):
if char in self.markdown.ESCAPED_CHARS:
return '%s%s%s' % (util.STX, ord(char), util.ETX)
else:
return None
return None
class SimpleTagPattern(Pattern):
@ -278,8 +279,6 @@ class DoubleTagPattern(SimpleTagPattern):
el1 = util.etree.Element(tag1)
el2 = util.etree.SubElement(el1, tag2)
el2.text = m.group(3)
if len(m.groups())==5:
el2.tail = m.group(4)
return el1
@ -294,7 +293,7 @@ class HtmlPattern(Pattern):
""" Return unescaped text given text with an inline placeholder. """
try:
stash = self.markdown.treeprocessors['inline'].stashed_nodes
except KeyError: #pragma: no cover
except KeyError:
return text
def get_stash(m):
id = m.group(1)
@ -304,7 +303,7 @@ class HtmlPattern(Pattern):
return self.markdown.serializer(value)
except:
return '\%s' % value
return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
@ -324,7 +323,7 @@ class LinkPattern(Pattern):
el.set("href", "")
if title:
title = dequote(self.unescape(title))
title = dequote(self.unescape(title))
el.set("title", title)
return el
@ -348,20 +347,20 @@ class LinkPattern(Pattern):
if not self.markdown.safeMode:
# Return immediately bipassing parsing.
return url
try:
scheme, netloc, path, params, query, fragment = url = urlparse(url)
except ValueError: #pragma: no cover
except ValueError:
# Bad url - so bad it couldn't be parsed.
return ''
locless_schemes = ['', 'mailto', 'news']
allowed_schemes = locless_schemes + ['http', 'https', 'ftp', 'ftps']
if scheme not in allowed_schemes:
# Not a known (allowed) scheme. Not safe.
return ''
if netloc == '' and scheme not in locless_schemes: #pragma: no cover
if netloc == '' and scheme not in locless_schemes:
# This should not happen. Treat as suspect.
return ''

View File

@ -82,11 +82,11 @@ class OrderedDict(dict):
for key in self.keyOrder:
yield self[key]
if util.PY3: #pragma: no cover
if util.PY3:
items = _iteritems
keys = _iterkeys
values = _itervalues
else: #pragma: no cover
else:
iteritems = _iteritems
iterkeys = _iterkeys
itervalues = _itervalues

View File

@ -42,7 +42,7 @@ class Postprocessor(util.Processor):
(possibly modified) string.
"""
pass #pragma: no cover
pass
class RawHtmlPostprocessor(Postprocessor):

View File

@ -41,7 +41,7 @@ class Preprocessor(util.Processor):
the (possibly modified) list of lines.
"""
pass #pragma: no cover
pass
class NormalizeWhitespace(Preprocessor):
@ -174,10 +174,9 @@ class HtmlBlockPreprocessor(Preprocessor):
else: # raw html
if len(items) - right_listindex <= 1: # last element
right_listindex -= 1
offset = 1 if i == right_listindex else 0
placeholder = self.markdown.htmlStash.store('\n\n'.join(
items[i:right_listindex + offset]))
del items[i:right_listindex + offset]
items[i:right_listindex + 1]))
del items[i:right_listindex + 1]
items.insert(i, placeholder)
return items

View File

@ -42,9 +42,9 @@ from __future__ import unicode_literals
from . import util
ElementTree = util.etree.ElementTree
QName = util.etree.QName
if hasattr(util.etree, 'test_comment'): #pragma: no cover
if hasattr(util.etree, 'test_comment'):
Comment = util.etree.test_comment
else: #pragma: no cover
else:
Comment = util.etree.Comment
PI = util.etree.PI
ProcessingInstruction = util.etree.ProcessingInstruction
@ -56,7 +56,7 @@ HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
try:
HTML_EMPTY = set(HTML_EMPTY)
except NameError: #pragma: no cover
except NameError:
pass
_namespace_map = {
@ -73,7 +73,7 @@ _namespace_map = {
}
def _raise_serialization_error(text): #pragma: no cover
def _raise_serialization_error(text):
raise TypeError(
"cannot serialize %r (type %s)" % (text, type(text).__name__)
)
@ -81,7 +81,7 @@ def _raise_serialization_error(text): #pragma: no cover
def _encode(text, encoding):
try:
return text.encode(encoding, "xmlcharrefreplace")
except (TypeError, AttributeError): #pragma: no cover
except (TypeError, AttributeError):
_raise_serialization_error(text)
def _escape_cdata(text):
@ -97,7 +97,7 @@ def _escape_cdata(text):
if ">" in text:
text = text.replace(">", "&gt;")
return text
except (TypeError, AttributeError): #pragma: no cover
except (TypeError, AttributeError):
_raise_serialization_error(text)
@ -115,7 +115,7 @@ def _escape_attrib(text):
if "\n" in text:
text = text.replace("\n", "&#10;")
return text
except (TypeError, AttributeError): #pragma: no cover
except (TypeError, AttributeError):
_raise_serialization_error(text)
def _escape_attrib_html(text):
@ -130,7 +130,7 @@ def _escape_attrib_html(text):
if "\"" in text:
text = text.replace("\"", "&quot;")
return text
except (TypeError, AttributeError): #pragma: no cover
except (TypeError, AttributeError):
_raise_serialization_error(text)
@ -240,7 +240,7 @@ def _namespaces(elem, default_namespace=None):
"default_namespace option"
)
qnames[qname] = qname
except TypeError: #pragma: no cover
except TypeError:
_raise_serialization_error(qname)
# populate qname and namespaces table

View File

@ -34,11 +34,11 @@ class Treeprocessor(util.Processor):
def run(self, root):
"""
Subclasses of Treeprocessor should implement a `run` method, which
takes a root ElementTree. This method can return another ElementTree
object, and the existing root ElementTree will be replaced, or it can
takes a root ElementTree. This method can return another ElementTree
object, and the existing root ElementTree will be replaced, or it can
modify the current tree and return None.
"""
pass #pragma: no cover
pass
class InlineProcessor(Treeprocessor):
@ -53,7 +53,6 @@ class InlineProcessor(Treeprocessor):
+ len(self.__placeholder_suffix)
self.__placeholder_re = util.INLINE_PLACEHOLDER_RE
self.markdown = md
self.inlinePatterns = md.inlinePatterns
def __makePlaceholder(self, type):
""" Generate a placeholder """
@ -71,7 +70,7 @@ class InlineProcessor(Treeprocessor):
* index: index, from which we start search
Returns: placeholder id and string index, after the found placeholder.
"""
m = self.__placeholder_re.search(data, index)
if m:
@ -100,9 +99,9 @@ class InlineProcessor(Treeprocessor):
"""
if not isinstance(data, util.AtomicString):
startIndex = 0
while patternIndex < len(self.inlinePatterns):
while patternIndex < len(self.markdown.inlinePatterns):
data, matched, startIndex = self.__applyPattern(
self.inlinePatterns.value_for_index(patternIndex),
self.markdown.inlinePatterns.value_for_index(patternIndex),
data, patternIndex, startIndex)
if not matched:
patternIndex += 1
@ -129,10 +128,11 @@ class InlineProcessor(Treeprocessor):
text = subnode.tail
subnode.tail = None
childResult = self.__processPlaceholders(text, subnode, isText)
childResult = self.__processPlaceholders(text, subnode)
if not isText and node is not subnode:
pos = list(node).index(subnode) + 1
pos = list(node).index(subnode)
node.remove(subnode)
else:
pos = 0
@ -140,7 +140,7 @@ class InlineProcessor(Treeprocessor):
for newChild in childResult:
node.insert(pos, newChild)
def __processPlaceholders(self, data, parent, isText=True):
def __processPlaceholders(self, data, parent):
"""
Process string with placeholders and generate ElementTree tree.
@ -150,7 +150,7 @@ class InlineProcessor(Treeprocessor):
* parent: Element, which contains processing inline data
Returns: list with ElementTree elements with applied inline patterns.
"""
def linkText(text):
if text:
@ -159,11 +159,6 @@ class InlineProcessor(Treeprocessor):
result[-1].tail += text
else:
result[-1].tail = text
elif not isText:
if parent.tail:
parent.tail += text
else:
parent.tail = text
else:
if parent.text:
parent.text += text
@ -187,7 +182,7 @@ class InlineProcessor(Treeprocessor):
for child in [node] + list(node):
if child.tail:
if child.tail.strip():
self.__processElementText(node, child, False)
self.__processElementText(node, child,False)
if child.text:
if child.text.strip():
self.__processElementText(child, child)
@ -244,7 +239,7 @@ class InlineProcessor(Treeprocessor):
# We need to process current node too
for child in [node] + list(node):
if not isString(node):
if child.text:
if child.text:
child.text = self.__handleInline(child.text,
patternIndex + 1)
if child.tail:
@ -292,10 +287,11 @@ class InlineProcessor(Treeprocessor):
if child.tail:
tail = self.__handleInline(child.tail)
dumby = util.etree.Element('d')
child.tail = None
tailResult = self.__processPlaceholders(tail, dumby, False)
if dumby.tail:
child.tail = dumby.tail
tailResult = self.__processPlaceholders(tail, dumby)
if dumby.text:
child.tail = dumby.text
else:
child.tail = None
pos = list(currElement).index(child) + 1
tailResult.reverse()
for newChild in tailResult:
@ -307,7 +303,7 @@ class InlineProcessor(Treeprocessor):
if self.markdown.enable_attributes:
if element.text and isString(element.text):
element.text = \
inlinepatterns.handleAttributes(element.text,
inlinepatterns.handleAttributes(element.text,
element)
i = 0
for newChild in lst:
@ -361,4 +357,4 @@ class PrettifyTreeprocessor(Treeprocessor):
pres = root.getiterator('pre')
for pre in pres:
if len(pre) and pre[0].tag == 'code':
pre[0].text = util.AtomicString(pre[0].text.rstrip() + '\n')
pre[0].text = pre[0].text.rstrip() + '\n'

View File

@ -10,11 +10,11 @@ Python 3 Stuff
"""
PY3 = sys.version_info[0] == 3
if PY3: #pragma: no cover
if PY3:
string_type = str
text_type = str
int2str = chr
else: #pragma: no cover
else:
string_type = basestring
text_type = unicode
int2str = unichr
@ -58,15 +58,14 @@ RTL_BIDI_RANGES = ( ('\u0590', '\u07FF'),
# Extensions should use "markdown.util.etree" instead of "etree" (or do `from
# markdown.util import etree`). Do not import it by yourself.
try: #pragma: no cover
# Is the C implementation of ElementTree available?
try: # Is the C implementation of ElementTree available?
import xml.etree.cElementTree as etree
from xml.etree.ElementTree import Comment
# Serializers (including ours) test with non-c Comment
etree.test_comment = Comment
if etree.VERSION < "1.0.5":
raise RuntimeError("cElementTree version 1.0.5 or higher is required.")
except (ImportError, RuntimeError): #pragma: no cover
except (ImportError, RuntimeError):
# Use the Python implementation of ElementTree?
import xml.etree.ElementTree as etree
if etree.VERSION < "1.1":
@ -86,20 +85,15 @@ def isBlockLevel(tag):
# Some ElementTree tags are not strings, so return False.
return False
def parseBoolValue(value, fail_on_errors=True, preserve_none=False):
def parseBoolValue(value, fail_on_errors=True):
"""Parses a string representing bool value. If parsing was successful,
returns True or False. If preserve_none=True, returns True, False,
or None. If parsing was not successful, raises ValueError, or, if
fail_on_errors=False, returns None."""
returns True or False. If parsing was not successful, raises
ValueError, or, if fail_on_errors=False, returns None."""
if not isinstance(value, string_type):
if preserve_none and value is None:
return value
return bool(value)
elif preserve_none and value.lower() == 'none':
return None
elif value.lower() in ('true', 'yes', 'y', 'on', '1'):
return True
elif value.lower() in ('false', 'no', 'n', 'off', '0', 'none'):
elif value.lower() in ('false', 'no', 'n', 'off', '0'):
return False
elif fail_on_errors:
raise ValueError('Cannot parse bool value: %r' % value)