mirror of
https://github.com/ansible/awx.git
synced 2026-04-07 02:59:21 -02:30
Upgrade Markdown to 2.5.2
This commit is contained in:
@@ -33,7 +33,7 @@ importlib==1.0.3 (importlib/*, needed for Python 2.6 support)
|
|||||||
iso8601==0.1.10 (iso8601/*)
|
iso8601==0.1.10 (iso8601/*)
|
||||||
keyring==4.0 (keyring/*, excluded bin/keyring)
|
keyring==4.0 (keyring/*, excluded bin/keyring)
|
||||||
kombu==3.0.21 (kombu/*)
|
kombu==3.0.21 (kombu/*)
|
||||||
Markdown==2.4.1 (markdown/*, excluded bin/markdown_py)
|
Markdown==2.5.2 (markdown/*, excluded bin/markdown_py)
|
||||||
mock==1.0.1 (mock.py)
|
mock==1.0.1 (mock.py)
|
||||||
ordereddict==1.1 (ordereddict.py, needed for Python 2.6 support)
|
ordereddict==1.1 (ordereddict.py, needed for Python 2.6 support)
|
||||||
os-diskconfig-python-novaclient-ext==0.1.2 (os_diskconfig_python_novaclient_ext/*)
|
os-diskconfig-python-novaclient-ext==0.1.2 (os_diskconfig_python_novaclient_ext/*)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ called from the command line.
|
|||||||
import markdown
|
import markdown
|
||||||
html = markdown.markdown(your_text_string)
|
html = markdown.markdown(your_text_string)
|
||||||
|
|
||||||
See <http://packages.python.org/Markdown/> for more
|
See <https://pythonhosted.org/Markdown/> for more
|
||||||
information and instructions on how to extend the functionality of
|
information and instructions on how to extend the functionality of
|
||||||
Python Markdown. Read that before you try modifying this file.
|
Python Markdown. Read that before you try modifying this file.
|
||||||
|
|
||||||
@@ -36,6 +36,8 @@ from .__version__ import version, version_info
|
|||||||
import codecs
|
import codecs
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
|
import warnings
|
||||||
|
import importlib
|
||||||
from . import util
|
from . import util
|
||||||
from .preprocessors import build_preprocessors
|
from .preprocessors import build_preprocessors
|
||||||
from .blockprocessors import build_block_parser
|
from .blockprocessors import build_block_parser
|
||||||
@@ -48,6 +50,7 @@ from .serializers import to_html_string, to_xhtml_string
|
|||||||
__all__ = ['Markdown', 'markdown', 'markdownFromFile']
|
__all__ = ['Markdown', 'markdown', 'markdownFromFile']
|
||||||
|
|
||||||
logger = logging.getLogger('MARKDOWN')
|
logger = logging.getLogger('MARKDOWN')
|
||||||
|
logging.captureWarnings(True)
|
||||||
|
|
||||||
|
|
||||||
class Markdown(object):
|
class Markdown(object):
|
||||||
@@ -96,8 +99,8 @@ class Markdown(object):
|
|||||||
Note that it is suggested that the more specific formats ("xhtml1"
|
Note that it is suggested that the more specific formats ("xhtml1"
|
||||||
and "html4") be used as "xhtml" or "html" may change in the future
|
and "html4") be used as "xhtml" or "html" may change in the future
|
||||||
if it makes sense at that time.
|
if it makes sense at that time.
|
||||||
* safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
|
* safe_mode: Deprecated! Disallow raw html. One of "remove", "replace" or "escape".
|
||||||
* html_replacement_text: Text used when safe_mode is set to "replace".
|
* html_replacement_text: Deprecated! Text used when safe_mode is set to "replace".
|
||||||
* tab_length: Length of tabs in the source. Default: 4
|
* tab_length: Length of tabs in the source. Default: 4
|
||||||
* enable_attributes: Enable the conversion of attributes. Default: True
|
* enable_attributes: Enable the conversion of attributes. Default: True
|
||||||
* smart_emphasis: Treat `_connected_words_` intelligently Default: True
|
* smart_emphasis: Treat `_connected_words_` intelligently Default: True
|
||||||
@@ -107,14 +110,16 @@ class Markdown(object):
|
|||||||
|
|
||||||
# For backward compatibility, loop through old positional args
|
# For backward compatibility, loop through old positional args
|
||||||
pos = ['extensions', 'extension_configs', 'safe_mode', 'output_format']
|
pos = ['extensions', 'extension_configs', 'safe_mode', 'output_format']
|
||||||
c = 0
|
for c, arg in enumerate(args):
|
||||||
for arg in args:
|
|
||||||
if pos[c] not in kwargs:
|
if pos[c] not in kwargs:
|
||||||
kwargs[pos[c]] = arg
|
kwargs[pos[c]] = arg
|
||||||
c += 1
|
if c+1 == len(pos): #pragma: no cover
|
||||||
if c == len(pos):
|
|
||||||
# ignore any additional args
|
# ignore any additional args
|
||||||
break
|
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
|
# Loop through kwargs and assign defaults
|
||||||
for option, default in self.option_defaults.items():
|
for option, default in self.option_defaults.items():
|
||||||
@@ -125,6 +130,18 @@ class Markdown(object):
|
|||||||
# Disable attributes in safeMode when not explicitly set
|
# Disable attributes in safeMode when not explicitly set
|
||||||
self.enable_attributes = False
|
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.registeredExtensions = []
|
||||||
self.docType = ""
|
self.docType = ""
|
||||||
self.stripTopLevelTags = True
|
self.stripTopLevelTags = True
|
||||||
@@ -160,9 +177,11 @@ class Markdown(object):
|
|||||||
"""
|
"""
|
||||||
for ext in extensions:
|
for ext in extensions:
|
||||||
if isinstance(ext, util.string_type):
|
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):
|
if isinstance(ext, Extension):
|
||||||
ext.extendMarkdown(self, globals())
|
ext.extendMarkdown(self, globals())
|
||||||
|
logger.debug('Successfully loaded extension "%s.%s".'
|
||||||
|
% (ext.__class__.__module__, ext.__class__.__name__))
|
||||||
elif ext is not None:
|
elif ext is not None:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
'Extension "%s.%s" must be of type: "markdown.Extension"'
|
'Extension "%s.%s" must be of type: "markdown.Extension"'
|
||||||
@@ -170,7 +189,7 @@ class Markdown(object):
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def build_extension(self, ext_name, configs = []):
|
def build_extension(self, ext_name, configs):
|
||||||
"""Build extension by name, then return the module.
|
"""Build extension by name, then return the module.
|
||||||
|
|
||||||
The extension name may contain arguments as part of the string in the
|
The extension name may contain arguments as part of the string in the
|
||||||
@@ -178,44 +197,79 @@ class Markdown(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Parse extensions config params (ignore the order)
|
|
||||||
configs = dict(configs)
|
configs = dict(configs)
|
||||||
|
|
||||||
|
# Parse extensions config params (ignore the order)
|
||||||
pos = ext_name.find("(") # find the first "("
|
pos = ext_name.find("(") # find the first "("
|
||||||
if pos > 0:
|
if pos > 0:
|
||||||
ext_args = ext_name[pos+1:-1]
|
ext_args = ext_name[pos+1:-1]
|
||||||
ext_name = ext_name[:pos]
|
ext_name = ext_name[:pos]
|
||||||
pairs = [x.split("=") for x in ext_args.split(",")]
|
pairs = [x.split("=") for x in ext_args.split(",")]
|
||||||
configs.update([(x.strip(), y.strip()) for (x, y) in pairs])
|
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)
|
||||||
|
|
||||||
# Setup the module name
|
# Get class name (if provided): `path.to.module:ClassName`
|
||||||
module_name = ext_name
|
ext_name, class_name = ext_name.split(':', 1) if ':' in ext_name else (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 loading the extension first from one place, then another
|
||||||
try: # New style (markdown.extensions.<extension>)
|
try:
|
||||||
module = __import__(module_name, {}, {}, [module_name.rpartition('.')[0]])
|
# 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
|
||||||
except ImportError:
|
except ImportError:
|
||||||
module_name_old_style = '_'.join(['mdx', ext_name])
|
# Preppend `markdown.extensions.` to name
|
||||||
try: # Old style (mdx_<extension>)
|
module_name = '.'.join(['markdown.extensions', ext_name])
|
||||||
module = __import__(module_name_old_style)
|
try:
|
||||||
except ImportError as e:
|
module = importlib.import_module(module_name)
|
||||||
message = "Failed loading extension '%s' from '%s' or '%s'" \
|
logger.debug('Successfuly imported extension module "%s".' % module_name)
|
||||||
% (ext_name, module_name, module_name_old_style)
|
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)
|
||||||
e.args = (message,) + e.args[1:]
|
e.args = (message,) + e.args[1:]
|
||||||
raise
|
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):
|
def registerExtension(self, extension):
|
||||||
""" This gets called by the extension """
|
""" This gets called by the extension """
|
||||||
self.registeredExtensions.append(extension)
|
self.registeredExtensions.append(extension)
|
||||||
@@ -303,7 +357,7 @@ class Markdown(object):
|
|||||||
start = output.index('<%s>'%self.doc_tag)+len(self.doc_tag)+2
|
start = output.index('<%s>'%self.doc_tag)+len(self.doc_tag)+2
|
||||||
end = output.rindex('</%s>'%self.doc_tag)
|
end = output.rindex('</%s>'%self.doc_tag)
|
||||||
output = output[start:end].strip()
|
output = output[start:end].strip()
|
||||||
except ValueError:
|
except ValueError: #pragma: no cover
|
||||||
if output.strip().endswith('<%s />'%self.doc_tag):
|
if output.strip().endswith('<%s />'%self.doc_tag):
|
||||||
# We have an empty document
|
# We have an empty document
|
||||||
output = ''
|
output = ''
|
||||||
@@ -434,6 +488,10 @@ def markdownFromFile(*args, **kwargs):
|
|||||||
c += 1
|
c += 1
|
||||||
if c == len(pos):
|
if c == len(pos):
|
||||||
break
|
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 = Markdown(**kwargs)
|
||||||
md.convertFile(kwargs.get('input', None),
|
md.convertFile(kwargs.get('input', None),
|
||||||
|
|||||||
@@ -7,20 +7,25 @@ COMMAND-LINE SPECIFIC STUFF
|
|||||||
import markdown
|
import markdown
|
||||||
import sys
|
import sys
|
||||||
import optparse
|
import optparse
|
||||||
|
import codecs
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except ImportError: #pragma: no cover
|
||||||
|
import json as yaml
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from logging import DEBUG, INFO, CRITICAL
|
from logging import DEBUG, INFO, CRITICAL
|
||||||
|
|
||||||
logger = logging.getLogger('MARKDOWN')
|
logger = logging.getLogger('MARKDOWN')
|
||||||
|
|
||||||
def parse_options():
|
def parse_options(args=None, values=None):
|
||||||
"""
|
"""
|
||||||
Define and parse `optparse` options for command-line usage.
|
Define and parse `optparse` options for command-line usage.
|
||||||
"""
|
"""
|
||||||
usage = """%prog [options] [INPUTFILE]
|
usage = """%prog [options] [INPUTFILE]
|
||||||
(STDIN is assumed if no INPUTFILE is given)"""
|
(STDIN is assumed if no INPUTFILE is given)"""
|
||||||
desc = "A Python implementation of John Gruber's Markdown. " \
|
desc = "A Python implementation of John Gruber's Markdown. " \
|
||||||
"http://packages.python.org/Markdown/"
|
"https://pythonhosted.org/Markdown/"
|
||||||
ver = "%%prog %s" % markdown.version
|
ver = "%%prog %s" % markdown.version
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage=usage, description=desc, version=ver)
|
parser = optparse.OptionParser(usage=usage, description=desc, version=ver)
|
||||||
@@ -29,28 +34,36 @@ def parse_options():
|
|||||||
metavar="OUTPUT_FILE")
|
metavar="OUTPUT_FILE")
|
||||||
parser.add_option("-e", "--encoding", dest="encoding",
|
parser.add_option("-e", "--encoding", dest="encoding",
|
||||||
help="Encoding for input and output files.",)
|
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,
|
parser.add_option("-q", "--quiet", default = CRITICAL,
|
||||||
action="store_const", const=CRITICAL+10, dest="verbose",
|
action="store_const", const=CRITICAL+10, dest="verbose",
|
||||||
help="Suppress all warnings.")
|
help="Suppress all warnings.")
|
||||||
parser.add_option("-v", "--verbose",
|
parser.add_option("-v", "--verbose",
|
||||||
action="store_const", const=INFO, dest="verbose",
|
action="store_const", const=INFO, dest="verbose",
|
||||||
help="Print all warnings.")
|
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",
|
parser.add_option("--noisy",
|
||||||
action="store_const", const=DEBUG, dest="verbose",
|
action="store_const", const=DEBUG, dest="verbose",
|
||||||
help="Print debug messages.")
|
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()
|
(options, args) = parser.parse_args(args, values)
|
||||||
|
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
input_file = None
|
input_file = None
|
||||||
@@ -60,15 +73,26 @@ def parse_options():
|
|||||||
if not options.extensions:
|
if not options.extensions:
|
||||||
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,
|
return {'input': input_file,
|
||||||
'output': options.filename,
|
'output': options.filename,
|
||||||
'safe_mode': options.safe,
|
'safe_mode': options.safe,
|
||||||
'extensions': options.extensions,
|
'extensions': options.extensions,
|
||||||
|
'extension_configs': extension_configs,
|
||||||
'encoding': options.encoding,
|
'encoding': options.encoding,
|
||||||
'output_format': options.output_format,
|
'output_format': options.output_format,
|
||||||
'lazy_ol': options.lazy_ol}, options.verbose
|
'lazy_ol': options.lazy_ol}, options.verbose
|
||||||
|
|
||||||
def run():
|
def run(): #pragma: no cover
|
||||||
"""Run Markdown from the command line."""
|
"""Run Markdown from the command line."""
|
||||||
|
|
||||||
# Parse options and adjust logging level if necessary
|
# Parse options and adjust logging level if necessary
|
||||||
@@ -80,7 +104,7 @@ def run():
|
|||||||
# Run
|
# Run
|
||||||
markdown.markdownFromFile(**options)
|
markdown.markdownFromFile(**options)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__': #pragma: no cover
|
||||||
# Support running module as a commandline command.
|
# Support running module as a commandline command.
|
||||||
# Python 2.5 & 2.6 do: `python -m markdown.__main__ [options] [args]`.
|
# Python 2.5 & 2.6 do: `python -m markdown.__main__ [options] [args]`.
|
||||||
# Python 2.7 & 3.x do: `python -m markdown [options] [args]`.
|
# Python 2.7 & 3.x do: `python -m markdown [options] [args]`.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
# (major, minor, micro, alpha/beta/rc/final, #)
|
# (major, minor, micro, alpha/beta/rc/final, #)
|
||||||
# (1, 1, 2, 'alpha', 0) => "1.1.2.dev"
|
# (1, 1, 2, 'alpha', 0) => "1.1.2.dev"
|
||||||
# (1, 2, 0, 'beta', 2) => "1.2b2"
|
# (1, 2, 0, 'beta', 2) => "1.2b2"
|
||||||
version_info = (2, 4, 1, 'final', 0)
|
version_info = (2, 5, 2, 'final', 0)
|
||||||
|
|
||||||
def _get_version():
|
def _get_version():
|
||||||
" Returns a PEP 386-compliant version number from version_info. "
|
" Returns a PEP 386-compliant version number from version_info. "
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class BlockProcessor:
|
|||||||
* ``block``: A block of text from the source which has been split at
|
* ``block``: A block of text from the source which has been split at
|
||||||
blank lines.
|
blank lines.
|
||||||
"""
|
"""
|
||||||
pass
|
pass #pragma: no cover
|
||||||
|
|
||||||
def run(self, parent, blocks):
|
def run(self, parent, blocks):
|
||||||
""" Run processor. Must be overridden by subclasses.
|
""" 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.
|
* ``parent``: A etree element which is the parent of the current block.
|
||||||
* ``blocks``: A list of all remaining blocks of the document.
|
* ``blocks``: A list of all remaining blocks of the document.
|
||||||
"""
|
"""
|
||||||
pass
|
pass #pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
class ListIndentProcessor(BlockProcessor):
|
class ListIndentProcessor(BlockProcessor):
|
||||||
@@ -433,7 +433,7 @@ class HashHeaderProcessor(BlockProcessor):
|
|||||||
if after:
|
if after:
|
||||||
# Insert remaining lines as first block for future parsing.
|
# Insert remaining lines as first block for future parsing.
|
||||||
blocks.insert(0, after)
|
blocks.insert(0, after)
|
||||||
else:
|
else: #pragma: no cover
|
||||||
# This should never happen, but just in case...
|
# This should never happen, but just in case...
|
||||||
logger.warn("We've got a problem header: %r" % block)
|
logger.warn("We've got a problem header: %r" % block)
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,45 @@ Extensions
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from ..util import parseBoolValue
|
||||||
|
import warnings
|
||||||
|
|
||||||
class Extension(object):
|
class Extension(object):
|
||||||
""" Base class for extensions to subclass. """
|
""" Base class for extensions to subclass. """
|
||||||
def __init__(self, configs = {}):
|
|
||||||
"""Create an instance of an Extention.
|
|
||||||
|
|
||||||
Keyword arguments:
|
# 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. """
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
* configs: A dict of configuration setting used by an Extension.
|
|
||||||
"""
|
|
||||||
self.config = configs
|
|
||||||
|
|
||||||
def getConfig(self, key, default=''):
|
def getConfig(self, key, default=''):
|
||||||
""" Return a setting for the given key or an empty string. """
|
""" Return a setting for the given key or an empty string. """
|
||||||
@@ -33,8 +61,20 @@ class Extension(object):
|
|||||||
|
|
||||||
def setConfig(self, key, value):
|
def setConfig(self, key, value):
|
||||||
""" Set a config setting for `key` with the given `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
|
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):
|
def extendMarkdown(self, md, md_globals):
|
||||||
"""
|
"""
|
||||||
Add the various proccesors and patterns to the Markdown Instance.
|
Add the various proccesors and patterns to the Markdown Instance.
|
||||||
|
|||||||
@@ -4,22 +4,15 @@ Abbreviation Extension for Python-Markdown
|
|||||||
|
|
||||||
This extension adds abbreviation handling to Python-Markdown.
|
This extension adds abbreviation handling to Python-Markdown.
|
||||||
|
|
||||||
Simple Usage:
|
See <https://pythonhosted.org/Markdown/extensions/abbreviations.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
>>> import markdown
|
Oringinal code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) and
|
||||||
>>> text = """
|
[Seemant Kulleen](http://www.kulleen.org/)
|
||||||
... 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>
|
|
||||||
|
|
||||||
Copyright 2007-2008
|
All changes Copyright 2008-2014 The Python Markdown Project
|
||||||
* [Waylan Limberg](http://achinghead.com/)
|
|
||||||
* [Seemant Kulleen](http://www.kulleen.org/)
|
|
||||||
|
|
||||||
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -92,5 +85,5 @@ class AbbrPattern(Pattern):
|
|||||||
abbr.set('title', self.title)
|
abbr.set('title', self.title)
|
||||||
return abbr
|
return abbr
|
||||||
|
|
||||||
def makeExtension(configs=None):
|
def makeExtension(*args, **kwargs):
|
||||||
return AbbrExtension(configs=configs)
|
return AbbrExtension(*args, **kwargs)
|
||||||
|
|||||||
@@ -4,39 +4,16 @@ Admonition extension for Python-Markdown
|
|||||||
|
|
||||||
Adds rST-style admonitions. Inspired by [rST][] feature with the same name.
|
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
|
[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
|
||||||
|
|
||||||
By [Tiago Serafim](http://www.tiagoserafim.com/).
|
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)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -114,5 +91,6 @@ class AdmonitionProcessor(BlockProcessor):
|
|||||||
return klass, title
|
return klass, title
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return AdmonitionExtension(configs=configs)
|
return AdmonitionExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,14 @@ Adds attribute list syntax. Inspired by
|
|||||||
[maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s
|
[maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s
|
||||||
feature of the same name.
|
feature of the same name.
|
||||||
|
|
||||||
Copyright 2011 [Waylan Limberg](http://achinghead.com/).
|
See <https://pythonhosted.org/Markdown/extensions/attr_list.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
Contact: markdown@freewisdom.org
|
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com/).
|
||||||
|
|
||||||
License: BSD (see ../LICENSE.md for details)
|
All changes Copyright 2011-2014 The Python Markdown Project
|
||||||
|
|
||||||
Dependencies:
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
* [Python 2.4+](http://python.org)
|
|
||||||
* [Markdown 2.1+](http://packages.python.org/Markdown/)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -27,7 +26,7 @@ import re
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
Scanner = re.Scanner
|
Scanner = re.Scanner
|
||||||
except AttributeError:
|
except AttributeError: #pragma: no cover
|
||||||
# must be on Python 2.4
|
# must be on Python 2.4
|
||||||
from sre import Scanner
|
from sre import Scanner
|
||||||
|
|
||||||
@@ -164,5 +163,5 @@ class AttrListExtension(Extension):
|
|||||||
md.treeprocessors.add('attr_list', AttrListTreeprocessor(md), '>prettify')
|
md.treeprocessors.add('attr_list', AttrListTreeprocessor(md), '>prettify')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return AttrListExtension(configs=configs)
|
return AttrListExtension(*args, **kwargs)
|
||||||
|
|||||||
@@ -4,17 +4,14 @@ CodeHilite Extension for Python-Markdown
|
|||||||
|
|
||||||
Adds code/syntax highlighting to standard Python-Markdown code blocks.
|
Adds code/syntax highlighting to standard Python-Markdown code blocks.
|
||||||
|
|
||||||
Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
|
See <https://pythonhosted.org/Markdown/extensions/code_hilite.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
Project website: <http://packages.python.org/Markdown/extensions/code_hilite.html>
|
Original code Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
|
||||||
Contact: markdown@freewisdom.org
|
|
||||||
|
|
||||||
License: BSD (see ../LICENSE.md for details)
|
All changes Copyright 2008-2014 The Python Markdown Project
|
||||||
|
|
||||||
Dependencies:
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
* [Python 2.3+](http://python.org/)
|
|
||||||
* [Markdown 2.0+](http://packages.python.org/Markdown/)
|
|
||||||
* [Pygments](http://pygments.org/)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -25,8 +22,8 @@ from ..treeprocessors import Treeprocessor
|
|||||||
import warnings
|
import warnings
|
||||||
try:
|
try:
|
||||||
from pygments import highlight
|
from pygments import highlight
|
||||||
from pygments.lexers import get_lexer_by_name, guess_lexer, TextLexer
|
from pygments.lexers import get_lexer_by_name, guess_lexer
|
||||||
from pygments.formatters import HtmlFormatter
|
from pygments.formatters import get_formatter_by_name
|
||||||
pygments = True
|
pygments = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pygments = False
|
pygments = False
|
||||||
@@ -112,14 +109,15 @@ class CodeHilite(object):
|
|||||||
if self.guess_lang:
|
if self.guess_lang:
|
||||||
lexer = guess_lexer(self.src)
|
lexer = guess_lexer(self.src)
|
||||||
else:
|
else:
|
||||||
lexer = TextLexer()
|
lexer = get_lexer_by_name('text')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
lexer = TextLexer()
|
lexer = get_lexer_by_name('text')
|
||||||
formatter = HtmlFormatter(linenos=self.linenums,
|
formatter = get_formatter_by_name('html',
|
||||||
cssclass=self.css_class,
|
linenos=self.linenums,
|
||||||
style=self.style,
|
cssclass=self.css_class,
|
||||||
noclasses=self.noclasses,
|
style=self.style,
|
||||||
hl_lines=self.hl_lines)
|
noclasses=self.noclasses,
|
||||||
|
hl_lines=self.hl_lines)
|
||||||
return highlight(self.src, lexer, formatter)
|
return highlight(self.src, lexer, formatter)
|
||||||
else:
|
else:
|
||||||
# just escape and build markup usable by JS highlighting libs
|
# just escape and build markup usable by JS highlighting libs
|
||||||
@@ -225,7 +223,7 @@ class HiliteTreeprocessor(Treeprocessor):
|
|||||||
class CodeHiliteExtension(Extension):
|
class CodeHiliteExtension(Extension):
|
||||||
""" Add source code hilighting to markdown codeblocks. """
|
""" Add source code hilighting to markdown codeblocks. """
|
||||||
|
|
||||||
def __init__(self, configs):
|
def __init__(self, *args, **kwargs):
|
||||||
# define default configs
|
# define default configs
|
||||||
self.config = {
|
self.config = {
|
||||||
'linenums': [None, "Use lines numbers. True=yes, False=no, None=auto"],
|
'linenums': [None, "Use lines numbers. True=yes, False=no, None=auto"],
|
||||||
@@ -237,22 +235,7 @@ class CodeHiliteExtension(Extension):
|
|||||||
'noclasses': [False, 'Use inline styles instead of CSS classes - Default false']
|
'noclasses': [False, 'Use inline styles instead of CSS classes - Default false']
|
||||||
}
|
}
|
||||||
|
|
||||||
# Override defaults with user settings
|
super(CodeHiliteExtension, self).__init__(*args, **kwargs)
|
||||||
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):
|
def extendMarkdown(self, md, md_globals):
|
||||||
""" Add HilitePostprocessor to Markdown instance. """
|
""" Add HilitePostprocessor to Markdown instance. """
|
||||||
@@ -263,6 +246,5 @@ class CodeHiliteExtension(Extension):
|
|||||||
md.registerExtension(self)
|
md.registerExtension(self)
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return CodeHiliteExtension(configs=configs)
|
return CodeHiliteExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,16 @@
|
|||||||
Definition List Extension for Python-Markdown
|
Definition List Extension for Python-Markdown
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
Added parsing of Definition Lists to Python-Markdown.
|
Adds parsing of Definition Lists to Python-Markdown.
|
||||||
|
|
||||||
A simple example:
|
See <https://pythonhosted.org/Markdown/extensions/definition_lists.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
Apple
|
Original code Copyright 2008 [Waylan Limberg](http://achinghead.com)
|
||||||
: Pomaceous fruit of plants of the genus Malus in
|
|
||||||
the family Rosaceae.
|
|
||||||
: An american computer company.
|
|
||||||
|
|
||||||
Orange
|
All changes Copyright 2008-2014 The Python Markdown Project
|
||||||
: The fruit of an evergreen tree of the genus Citrus.
|
|
||||||
|
|
||||||
Copyright 2008 - [Waylan Limberg](http://achinghead.com)
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -113,6 +110,6 @@ class DefListExtension(Extension):
|
|||||||
'>ulist')
|
'>ulist')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return DefListExtension(configs=configs)
|
return DefListExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ convenience so that only one extension needs to be listed when
|
|||||||
initiating Markdown. See the documentation for each individual
|
initiating Markdown. See the documentation for each individual
|
||||||
extension for specifics about that extension.
|
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
|
There may be additional extensions that are distributed with
|
||||||
Python-Markdown that are not included here in Extra. Those extensions
|
Python-Markdown that are not included here in Extra. Those extensions
|
||||||
are not part of PHP Markdown Extra, and therefore, not part of
|
are not part of PHP Markdown Extra, and therefore, not part of
|
||||||
@@ -24,6 +20,13 @@ under a differant name. You could also edit the `extensions` global
|
|||||||
variable defined below, but be aware that such changes may be lost
|
variable defined below, but be aware that such changes may be lost
|
||||||
when you upgrade to any future version of Python-Markdown.
|
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
|
from __future__ import absolute_import
|
||||||
@@ -33,19 +36,25 @@ from ..blockprocessors import BlockProcessor
|
|||||||
from .. import util
|
from .. import util
|
||||||
import re
|
import re
|
||||||
|
|
||||||
extensions = ['smart_strong',
|
extensions = [
|
||||||
'fenced_code',
|
'markdown.extensions.smart_strong',
|
||||||
'footnotes',
|
'markdown.extensions.fenced_code',
|
||||||
'attr_list',
|
'markdown.extensions.footnotes',
|
||||||
'def_list',
|
'markdown.extensions.attr_list',
|
||||||
'tables',
|
'markdown.extensions.def_list',
|
||||||
'abbr',
|
'markdown.extensions.tables',
|
||||||
]
|
'markdown.extensions.abbr'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ExtraExtension(Extension):
|
class ExtraExtension(Extension):
|
||||||
""" Add various extensions to Markdown class."""
|
""" 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):
|
def extendMarkdown(self, md, md_globals):
|
||||||
""" Register extension instances. """
|
""" Register extension instances. """
|
||||||
md.registerExtensions(extensions, self.config)
|
md.registerExtensions(extensions, self.config)
|
||||||
@@ -60,8 +69,8 @@ class ExtraExtension(Extension):
|
|||||||
r'^(p|h[1-6]|li|dd|dt|td|th|legend|address)$', re.IGNORECASE)
|
r'^(p|h[1-6]|li|dd|dt|td|th|legend|address)$', re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return ExtraExtension(configs=dict(configs))
|
return ExtraExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class MarkdownInHtmlProcessor(BlockProcessor):
|
class MarkdownInHtmlProcessor(BlockProcessor):
|
||||||
|
|||||||
@@ -4,87 +4,15 @@ Fenced Code Extension for Python Markdown
|
|||||||
|
|
||||||
This extension adds Fenced Code Blocks to Python-Markdown.
|
This extension adds Fenced Code Blocks to Python-Markdown.
|
||||||
|
|
||||||
>>> import markdown
|
See <https://pythonhosted.org/Markdown/extensions/fenced_code_blocks.html>
|
||||||
>>> text = '''
|
for documentation.
|
||||||
... 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>
|
|
||||||
|
|
||||||
Works with safe_mode also (we check this because we are using the HtmlStash):
|
Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
|
||||||
|
|
||||||
>>> 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>
|
|
||||||
|
|
||||||
Include tilde's in a code block and wrap with blank lines:
|
All changes Copyright 2008-2014 The Python Markdown Project
|
||||||
|
|
||||||
>>> 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
|
from __future__ import absolute_import
|
||||||
@@ -175,5 +103,6 @@ class FencedBlockPreprocessor(Preprocessor):
|
|||||||
return txt
|
return txt
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs=None):
|
def makeExtension(*args, **kwargs):
|
||||||
return FencedCodeExtension(configs=configs)
|
return FencedCodeExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,15 @@
|
|||||||
"""
|
"""
|
||||||
========================= FOOTNOTES =================================
|
Footnotes Extension for Python-Markdown
|
||||||
|
=======================================
|
||||||
|
|
||||||
This section adds footnote handling to markdown. It can be used as
|
Adds footnote handling to Python-Markdown.
|
||||||
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.
|
|
||||||
|
|
||||||
Footnote functionality is attached by calling extendMarkdown()
|
See <https://pythonhosted.org/Markdown/extensions/footnotes.html>
|
||||||
method of FootnoteExtension. The method also registers the
|
for documentation.
|
||||||
extension to allow it's state to be reset by a call to reset()
|
|
||||||
method.
|
|
||||||
|
|
||||||
Example:
|
Copyright The Python Markdown Project
|
||||||
Footnotes[^1] have a label[^label] and a definition[^!DEF].
|
|
||||||
|
|
||||||
[^1]: This is a footnote
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
[^label]: A footnote on "label"
|
|
||||||
[^!DEF]: The footnote for definition
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -42,22 +32,22 @@ TABBED_RE = re.compile(r'((\t)|( ))(.*)')
|
|||||||
class FootnoteExtension(Extension):
|
class FootnoteExtension(Extension):
|
||||||
""" Footnote Extension. """
|
""" Footnote Extension. """
|
||||||
|
|
||||||
def __init__ (self, configs):
|
def __init__ (self, *args, **kwargs):
|
||||||
""" Setup 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":
|
|
||||||
["↩",
|
|
||||||
"The text string that links from the footnote to the reader's place."]
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value in configs:
|
self.config = {
|
||||||
self.config[key][0] = value
|
'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":
|
||||||
|
["↩",
|
||||||
|
"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.
|
# In multiple invocations, emit links that don't get tangled.
|
||||||
self.unique_prefix = 0
|
self.unique_prefix = 0
|
||||||
@@ -309,7 +299,7 @@ class FootnotePostprocessor(Postprocessor):
|
|||||||
text = text.replace(FN_BACKLINK_TEXT, self.footnotes.getConfig("BACKLINK_TEXT"))
|
text = text.replace(FN_BACKLINK_TEXT, self.footnotes.getConfig("BACKLINK_TEXT"))
|
||||||
return text.replace(NBSP_PLACEHOLDER, " ")
|
return text.replace(NBSP_PLACEHOLDER, " ")
|
||||||
|
|
||||||
def makeExtension(configs=[]):
|
def makeExtension(*args, **kwargs):
|
||||||
""" Return an instance of the FootnoteExtension """
|
""" Return an instance of the FootnoteExtension """
|
||||||
return FootnoteExtension(configs=configs)
|
return FootnoteExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -4,73 +4,14 @@ HeaderID Extension for Python-Markdown
|
|||||||
|
|
||||||
Auto-generate id attributes for HTML headers.
|
Auto-generate id attributes for HTML headers.
|
||||||
|
|
||||||
Basic usage:
|
See <https://pythonhosted.org/Markdown/extensions/header_id.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
>>> import markdown
|
Original code Copyright 2007-2011 [Waylan Limberg](http://achinghead.com/).
|
||||||
>>> text = "# Some Header #"
|
|
||||||
>>> md = markdown.markdown(text, ['headerid'])
|
|
||||||
>>> print md
|
|
||||||
<h1 id="some-header">Some Header</h1>
|
|
||||||
|
|
||||||
All header IDs are unique:
|
All changes Copyright 2011-2014 The Python Markdown Project
|
||||||
|
|
||||||
>>> text = '''
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
... #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/)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -127,7 +68,7 @@ def stashedHTML2text(text, md):
|
|||||||
def _html_sub(m):
|
def _html_sub(m):
|
||||||
""" Substitute raw html with plain text. """
|
""" Substitute raw html with plain text. """
|
||||||
try:
|
try:
|
||||||
raw, safe = md.htmlStash.rawHtmlBlocks[int(m.group(1))]
|
raw, safe = md.htmlStash.rawHtmlBlocks[int(m.group(1))]
|
||||||
except (IndexError, TypeError):
|
except (IndexError, TypeError):
|
||||||
return m.group(0)
|
return m.group(0)
|
||||||
if md.safeMode and not safe:
|
if md.safeMode and not safe:
|
||||||
@@ -176,7 +117,7 @@ class HeaderIdTreeprocessor(Treeprocessor):
|
|||||||
|
|
||||||
|
|
||||||
class HeaderIdExtension(Extension):
|
class HeaderIdExtension(Extension):
|
||||||
def __init__(self, configs):
|
def __init__(self, *args, **kwargs):
|
||||||
# set defaults
|
# set defaults
|
||||||
self.config = {
|
self.config = {
|
||||||
'level' : ['1', 'Base level for headers.'],
|
'level' : ['1', 'Base level for headers.'],
|
||||||
@@ -185,8 +126,7 @@ class HeaderIdExtension(Extension):
|
|||||||
'slugify' : [slugify, 'Callable to generate anchors'],
|
'slugify' : [slugify, 'Callable to generate anchors'],
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value in configs:
|
super(HeaderIdExtension, self).__init__(*args, **kwargs)
|
||||||
self.setConfig(key, value)
|
|
||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
md.registerExtension(self)
|
md.registerExtension(self)
|
||||||
@@ -204,5 +144,6 @@ class HeaderIdExtension(Extension):
|
|||||||
self.processor.IDs = set()
|
self.processor.IDs = set()
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs=None):
|
def makeExtension(*args, **kwargs):
|
||||||
return HeaderIdExtension(configs=configs)
|
return HeaderIdExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -4,38 +4,14 @@ Meta Data Extension for Python-Markdown
|
|||||||
|
|
||||||
This extension adds Meta Data handling to markdown.
|
This extension adds Meta Data handling to markdown.
|
||||||
|
|
||||||
Basic Usage:
|
See <https://pythonhosted.org/Markdown/extensions/meta_data.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
>>> import markdown
|
Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
|
||||||
>>> 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.']}
|
|
||||||
|
|
||||||
Make sure text without Meta Data still works (markdown < 1.6b returns a <p>).
|
All changes Copyright 2008-2014 The Python Markdown Project
|
||||||
|
|
||||||
>>> text = ' Some Code - not extra lines of meta data.'
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
>>> 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)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -55,7 +31,7 @@ class MetaExtension (Extension):
|
|||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
""" Add MetaPreprocessor to Markdown instance. """
|
""" Add MetaPreprocessor to Markdown instance. """
|
||||||
|
|
||||||
md.preprocessors.add("meta", MetaPreprocessor(md), "_begin")
|
md.preprocessors.add("meta", MetaPreprocessor(md), ">normalize_whitespace")
|
||||||
|
|
||||||
|
|
||||||
class MetaPreprocessor(Preprocessor):
|
class MetaPreprocessor(Preprocessor):
|
||||||
@@ -89,5 +65,6 @@ class MetaPreprocessor(Preprocessor):
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return MetaExtension(configs=configs)
|
return MetaExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -5,18 +5,14 @@ NL2BR Extension
|
|||||||
A Python-Markdown extension to treat newlines as hard breaks; like
|
A Python-Markdown extension to treat newlines as hard breaks; like
|
||||||
GitHub-flavored Markdown does.
|
GitHub-flavored Markdown does.
|
||||||
|
|
||||||
Usage:
|
See <https://pythonhosted.org/Markdown/extensions/nl2br.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
>>> import markdown
|
Oringinal code Copyright 2011 [Brian Neal](http://deathofagremmie.com/)
|
||||||
>>> print markdown.markdown('line 1\\nline 2', extensions=['nl2br'])
|
|
||||||
<p>line 1<br />
|
|
||||||
line 2</p>
|
|
||||||
|
|
||||||
Copyright 2011 [Brian Neal](http://deathofagremmie.com/)
|
All changes Copyright 2011-2014 The Python Markdown Project
|
||||||
|
|
||||||
Dependencies:
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
* [Python 2.4+](http://python.org)
|
|
||||||
* [Markdown 2.1+](http://packages.python.org/Markdown/)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -34,5 +30,6 @@ class Nl2BrExtension(Extension):
|
|||||||
md.inlinePatterns.add('nl', br_tag, '_end')
|
md.inlinePatterns.add('nl', br_tag, '_end')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs=None):
|
def makeExtension(*args, **kwargs):
|
||||||
return Nl2BrExtension(configs)
|
return Nl2BrExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,16 @@
|
|||||||
Sane List Extension for Python-Markdown
|
Sane List Extension for Python-Markdown
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
Modify the behavior of Lists in Python-Markdown t act in a sane manor.
|
Modify the behavior of Lists in Python-Markdown to act in a sane manor.
|
||||||
|
|
||||||
In standard Markdown syntax, the following would constitute a single
|
See <https://pythonhosted.org/Markdown/extensions/sane_lists.html>
|
||||||
ordered list. However, with this extension, the output would include
|
for documentation.
|
||||||
two lists, the first an ordered list and the second and unordered list.
|
|
||||||
|
|
||||||
1. ordered
|
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com)
|
||||||
2. list
|
|
||||||
|
|
||||||
* unordered
|
All changes Copyright 2011-2014 The Python Markdown Project
|
||||||
* list
|
|
||||||
|
|
||||||
Copyright 2011 - [Waylan Limberg](http://achinghead.com)
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -46,6 +43,6 @@ class SaneListExtension(Extension):
|
|||||||
md.parser.blockprocessors['ulist'] = SaneUListProcessor(md.parser)
|
md.parser.blockprocessors['ulist'] = SaneUListProcessor(md.parser)
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return SaneListExtension(configs=configs)
|
return SaneListExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -4,21 +4,14 @@ Smart_Strong Extension for Python-Markdown
|
|||||||
|
|
||||||
This extention adds smarter handling of double underscores within words.
|
This extention adds smarter handling of double underscores within words.
|
||||||
|
|
||||||
Simple Usage:
|
See <https://pythonhosted.org/Markdown/extensions/smart_strong.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
>>> import markdown
|
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com)
|
||||||
>>> 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>
|
|
||||||
|
|
||||||
Copyright 2011
|
All changes Copyright 2011-2014 The Python Markdown Project
|
||||||
[Waylan Limberg](http://achinghead.com)
|
|
||||||
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -38,5 +31,5 @@ class SmartEmphasisExtension(Extension):
|
|||||||
md.inlinePatterns['strong'] = SimpleTagPattern(STRONG_RE, 'strong')
|
md.inlinePatterns['strong'] = SimpleTagPattern(STRONG_RE, 'strong')
|
||||||
md.inlinePatterns.add('strong2', SimpleTagPattern(SMART_STRONG_RE, 'strong'), '>emphasis2')
|
md.inlinePatterns.add('strong2', SimpleTagPattern(SMART_STRONG_RE, 'strong'), '>emphasis2')
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return SmartEmphasisExtension(configs=dict(configs))
|
return SmartEmphasisExtension(*args, **kwargs)
|
||||||
|
|||||||
@@ -1,73 +1,91 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Smarty extension for Python-Markdown
|
'''
|
||||||
# Author: 2013, Dmitry Shachnev <mitya57@gmail.com>
|
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.
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
# 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 __future__ import unicode_literals
|
||||||
from . import Extension
|
from . import Extension
|
||||||
from ..inlinepatterns import HtmlPattern
|
from ..inlinepatterns import HtmlPattern
|
||||||
|
from ..odict import OrderedDict
|
||||||
|
from ..treeprocessors import InlineProcessor
|
||||||
from ..util import parseBoolValue
|
from ..util import parseBoolValue
|
||||||
|
|
||||||
# Constants for quote education.
|
# Constants for quote education.
|
||||||
@@ -85,10 +103,23 @@ openingQuotesBase = (
|
|||||||
')'
|
')'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
substitutions = {
|
||||||
|
'mdash': '—',
|
||||||
|
'ndash': '–',
|
||||||
|
'ellipsis': '…',
|
||||||
|
'left-angle-quote': '«',
|
||||||
|
'right-angle-quote': '»',
|
||||||
|
'left-single-quote': '‘',
|
||||||
|
'right-single-quote': '’',
|
||||||
|
'left-double-quote': '“',
|
||||||
|
'right-double-quote': '”',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Special case if the very first character is a quote
|
# Special case if the very first character is a quote
|
||||||
# followed by punctuation at a non-word-break. Close the quotes by brute force:
|
# followed by punctuation at a non-word-break. Close the quotes by brute force:
|
||||||
singleQuoteStartRe = r"^'(?=%s\\B)" % punctClass
|
singleQuoteStartRe = r"^'(?=%s\B)" % punctClass
|
||||||
doubleQuoteStartRe = r'^"(?=%s\\B)' % punctClass
|
doubleQuoteStartRe = r'^"(?=%s\B)' % punctClass
|
||||||
|
|
||||||
# Special case for double sets of quotes, e.g.:
|
# Special case for double sets of quotes, e.g.:
|
||||||
# <p>He said, "'Quoted' words in a larger quote."</p>
|
# <p>He said, "'Quoted' words in a larger quote."</p>
|
||||||
@@ -113,8 +144,6 @@ closingSingleQuotesRegex2 = r"(?<=%s)'(\s|s\b)" % closeClass
|
|||||||
remainingSingleQuotesRegex = "'"
|
remainingSingleQuotesRegex = "'"
|
||||||
remainingDoubleQuotesRegex = '"'
|
remainingDoubleQuotesRegex = '"'
|
||||||
|
|
||||||
lsquo, rsquo, ldquo, rdquo = '‘', '’', '“', '”'
|
|
||||||
|
|
||||||
class SubstituteTextPattern(HtmlPattern):
|
class SubstituteTextPattern(HtmlPattern):
|
||||||
def __init__(self, pattern, replace, markdown_instance):
|
def __init__(self, pattern, replace, markdown_instance):
|
||||||
""" Replaces matches with some text. """
|
""" Replaces matches with some text. """
|
||||||
@@ -132,35 +161,56 @@ class SubstituteTextPattern(HtmlPattern):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
class SmartyExtension(Extension):
|
class SmartyExtension(Extension):
|
||||||
def __init__(self, configs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.config = {
|
self.config = {
|
||||||
'smart_quotes': [True, 'Educate quotes'],
|
'smart_quotes': [True, 'Educate quotes'],
|
||||||
|
'smart_angled_quotes': [False, 'Educate angled quotes'],
|
||||||
'smart_dashes': [True, 'Educate dashes'],
|
'smart_dashes': [True, 'Educate dashes'],
|
||||||
'smart_ellipses': [True, 'Educate ellipses']
|
'smart_ellipses': [True, 'Educate ellipses'],
|
||||||
|
'substitutions' : [{}, 'Overwrite default substitutions'],
|
||||||
}
|
}
|
||||||
for key, value in configs:
|
super(SmartyExtension, self).__init__(*args, **kwargs)
|
||||||
self.setConfig(key, parseBoolValue(value))
|
self.substitutions = dict(substitutions)
|
||||||
|
self.substitutions.update(self.getConfig('substitutions', default={}))
|
||||||
|
|
||||||
def _addPatterns(self, md, patterns, serie):
|
def _addPatterns(self, md, patterns, serie):
|
||||||
for ind, pattern in enumerate(patterns):
|
for ind, pattern in enumerate(patterns):
|
||||||
pattern += (md,)
|
pattern += (md,)
|
||||||
pattern = SubstituteTextPattern(*pattern)
|
pattern = SubstituteTextPattern(*pattern)
|
||||||
after = ('>smarty-%s-%d' % (serie, ind - 1) if ind else '>entity')
|
after = ('>smarty-%s-%d' % (serie, ind - 1) if ind else '_begin')
|
||||||
name = 'smarty-%s-%d' % (serie, ind)
|
name = 'smarty-%s-%d' % (serie, ind)
|
||||||
md.inlinePatterns.add(name, pattern, after)
|
self.inlinePatterns.add(name, pattern, after)
|
||||||
|
|
||||||
def educateDashes(self, md):
|
def educateDashes(self, md):
|
||||||
emDashesPattern = SubstituteTextPattern(r'(?<!-)---(?!-)', ('—',), md)
|
emDashesPattern = SubstituteTextPattern(r'(?<!-)---(?!-)',
|
||||||
enDashesPattern = SubstituteTextPattern(r'(?<!-)--(?!-)', ('–',), md)
|
(self.substitutions['mdash'],), md)
|
||||||
md.inlinePatterns.add('smarty-em-dashes', emDashesPattern, '>entity')
|
enDashesPattern = SubstituteTextPattern(r'(?<!-)--(?!-)',
|
||||||
md.inlinePatterns.add('smarty-en-dashes', enDashesPattern,
|
(self.substitutions['ndash'],), md)
|
||||||
|
self.inlinePatterns.add('smarty-em-dashes', emDashesPattern, '_begin')
|
||||||
|
self.inlinePatterns.add('smarty-en-dashes', enDashesPattern,
|
||||||
'>smarty-em-dashes')
|
'>smarty-em-dashes')
|
||||||
|
|
||||||
def educateEllipses(self, md):
|
def educateEllipses(self, md):
|
||||||
ellipsesPattern = SubstituteTextPattern(r'(?<!\.)\.{3}(?!\.)', ('…',), md)
|
ellipsesPattern = SubstituteTextPattern(r'(?<!\.)\.{3}(?!\.)',
|
||||||
md.inlinePatterns.add('smarty-ellipses', ellipsesPattern, '>entity')
|
(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')
|
||||||
|
|
||||||
def educateQuotes(self, md):
|
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 = (
|
patterns = (
|
||||||
(singleQuoteStartRe, (rsquo,)),
|
(singleQuoteStartRe, (rsquo,)),
|
||||||
(doubleQuoteStartRe, (rdquo,)),
|
(doubleQuoteStartRe, (rdquo,)),
|
||||||
@@ -179,13 +229,19 @@ class SmartyExtension(Extension):
|
|||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
configs = self.getConfigs()
|
configs = self.getConfigs()
|
||||||
if configs['smart_quotes']:
|
self.inlinePatterns = OrderedDict()
|
||||||
self.educateQuotes(md)
|
|
||||||
if configs['smart_dashes']:
|
|
||||||
self.educateDashes(md)
|
|
||||||
if configs['smart_ellipses']:
|
if configs['smart_ellipses']:
|
||||||
self.educateEllipses(md)
|
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')
|
||||||
md.ESCAPED_CHARS.extend(['"', "'"])
|
md.ESCAPED_CHARS.extend(['"', "'"])
|
||||||
|
|
||||||
def makeExtension(configs=None):
|
def makeExtension(*args, **kwargs):
|
||||||
return SmartyExtension(configs)
|
return SmartyExtension(*args, **kwargs)
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ Tables Extension for Python-Markdown
|
|||||||
|
|
||||||
Added parsing of tables to Python-Markdown.
|
Added parsing of tables to Python-Markdown.
|
||||||
|
|
||||||
A simple example:
|
See <https://pythonhosted.org/Markdown/extensions/tables.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
First Header | Second Header
|
Original code Copyright 2009 [Waylan Limberg](http://achinghead.com)
|
||||||
------------- | -------------
|
|
||||||
Content Cell | Content Cell
|
All changes Copyright 2008-2014 The Python Markdown Project
|
||||||
Content Cell | Content Cell
|
|
||||||
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
Copyright 2009 - [Waylan Limberg](http://achinghead.com)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
@@ -71,7 +72,7 @@ class TableProcessor(BlockProcessor):
|
|||||||
c = etree.SubElement(tr, tag)
|
c = etree.SubElement(tr, tag)
|
||||||
try:
|
try:
|
||||||
c.text = cells[i].strip()
|
c.text = cells[i].strip()
|
||||||
except IndexError:
|
except IndexError: #pragma: no cover
|
||||||
c.text = ""
|
c.text = ""
|
||||||
if a:
|
if a:
|
||||||
c.set('align', a)
|
c.set('align', a)
|
||||||
@@ -96,5 +97,6 @@ class TableExtension(Extension):
|
|||||||
'<hashheader')
|
'<hashheader')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return TableExtension(configs=configs)
|
return TableExtension(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
"""
|
"""
|
||||||
Table of Contents Extension for Python-Markdown
|
Table of Contents Extension for Python-Markdown
|
||||||
* * *
|
===============================================
|
||||||
|
|
||||||
(c) 2008 [Jack Miller](http://codezen.org)
|
See <https://pythonhosted.org/Markdown/extensions/toc.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
Dependencies:
|
Oringinal code Copyright 2008 [Jack Miller](http://codezen.org)
|
||||||
* [Markdown 2.1+](http://packages.python.org/Markdown/)
|
|
||||||
|
All changes Copyright 2008-2014 The Python Markdown Project
|
||||||
|
|
||||||
|
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -30,53 +34,52 @@ def order_toc_list(toc_list):
|
|||||||
[{'level': 2, 'children': []}, {'level': 1, 'children': []}]
|
[{'level': 2, 'children': []}, {'level': 1, 'children': []}]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def build_correct(remaining_list, prev_elements=[{'level': 1000}]):
|
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 = []
|
||||||
|
|
||||||
if not remaining_list:
|
# Walk the rest nesting the entries properly
|
||||||
return [], []
|
while toc_list:
|
||||||
|
t = toc_list.pop(0)
|
||||||
|
current_level = t['level']
|
||||||
|
t['children'] = []
|
||||||
|
|
||||||
current = remaining_list.pop(0)
|
# Reduce depth if current level < last item's level
|
||||||
if not 'children' in current.keys():
|
if current_level < levels[-1]:
|
||||||
current['children'] = []
|
# Pop last level since we know we are less than it
|
||||||
|
levels.pop()
|
||||||
|
|
||||||
if not prev_elements:
|
# Pop parents and levels we are less than or equal to
|
||||||
# This happens for instance with [8, 1, 1], ie. when some
|
to_pop = 0
|
||||||
# header level is outside a scope. We treat it as a
|
for p in reversed(parents):
|
||||||
# top-level
|
if current_level <= p['level']:
|
||||||
next_elements, children = build_correct(remaining_list, [current])
|
to_pop += 1
|
||||||
current['children'].append(children)
|
else:
|
||||||
return [current] + next_elements, []
|
break
|
||||||
|
if to_pop:
|
||||||
|
levels = levels[:-to_pop]
|
||||||
|
parents = parents[:-to_pop]
|
||||||
|
|
||||||
prev_element = prev_elements.pop()
|
# Note current level as last
|
||||||
children = []
|
levels.append(current_level)
|
||||||
next_elements = []
|
|
||||||
# Is current part of the child list or next list?
|
# Level is the same, so append to the current parent (if available)
|
||||||
if current['level'] > prev_element['level']:
|
if current_level == levels[-1]:
|
||||||
#print "%d is a child of %d" % (current['level'], prev_element['level'])
|
(parents[-1]['children'] if parents else ordered_list).append(t)
|
||||||
prev_elements.append(prev_element)
|
|
||||||
prev_elements.append(current)
|
# Current level is > last item's level,
|
||||||
prev_element['children'].append(current)
|
# So make last item a parent and append current as child
|
||||||
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:
|
else:
|
||||||
#print "Previous elements, comparing to those first"
|
last['children'].append(t)
|
||||||
remaining_list.insert(0, current)
|
parents.append(last)
|
||||||
next_elements2, children2 = build_correct(remaining_list, prev_elements)
|
levels.append(current_level)
|
||||||
children.extend(children2)
|
last = t
|
||||||
next_elements += next_elements2
|
|
||||||
|
|
||||||
return next_elements, children
|
|
||||||
|
|
||||||
ordered_list, __ = build_correct(toc_list)
|
|
||||||
return ordered_list
|
return ordered_list
|
||||||
|
|
||||||
|
|
||||||
@@ -204,26 +207,26 @@ class TocExtension(Extension):
|
|||||||
|
|
||||||
TreeProcessorClass = TocTreeprocessor
|
TreeProcessorClass = TocTreeprocessor
|
||||||
|
|
||||||
def __init__(self, configs=[]):
|
def __init__(self, *args, **kwargs):
|
||||||
self.config = { "marker" : ["[TOC]",
|
self.config = {
|
||||||
"Text to find and replace with Table of Contents -"
|
"marker" : ["[TOC]",
|
||||||
"Defaults to \"[TOC]\""],
|
"Text to find and replace with Table of Contents - "
|
||||||
"slugify" : [slugify,
|
"Defaults to \"[TOC]\""],
|
||||||
"Function to generate anchors based on header text-"
|
"slugify" : [slugify,
|
||||||
"Defaults to the headerid ext's slugify function."],
|
"Function to generate anchors based on header text - "
|
||||||
"title" : [None,
|
"Defaults to the headerid ext's slugify function."],
|
||||||
"Title to insert into TOC <div> - "
|
"title" : ["",
|
||||||
"Defaults to None"],
|
"Title to insert into TOC <div> - "
|
||||||
"anchorlink" : [0,
|
"Defaults to an empty string"],
|
||||||
"1 if header should be a self link"
|
"anchorlink" : [0,
|
||||||
"Defaults to 0"],
|
"1 if header should be a self link - "
|
||||||
"permalink" : [0,
|
"Defaults to 0"],
|
||||||
"1 or link text if a Sphinx-style permalink should be added",
|
"permalink" : [0,
|
||||||
"Defaults to 0"]
|
"1 or link text if a Sphinx-style permalink should be added - "
|
||||||
}
|
"Defaults to 0"]
|
||||||
|
}
|
||||||
|
|
||||||
for key, value in configs:
|
super(TocExtension, self).__init__(*args, **kwargs)
|
||||||
self.setConfig(key, value)
|
|
||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
tocext = self.TreeProcessorClass(md)
|
tocext = self.TreeProcessorClass(md)
|
||||||
@@ -236,5 +239,5 @@ class TocExtension(Extension):
|
|||||||
md.treeprocessors.add("toc", tocext, "_end")
|
md.treeprocessors.add("toc", tocext, "_end")
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs={}):
|
def makeExtension(*args, **kwargs):
|
||||||
return TocExtension(configs=configs)
|
return TocExtension(*args, **kwargs)
|
||||||
|
|||||||
@@ -2,78 +2,17 @@
|
|||||||
WikiLinks Extension for Python-Markdown
|
WikiLinks Extension for Python-Markdown
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
Converts [[WikiLinks]] to relative links. Requires Python-Markdown 2.0+
|
Converts [[WikiLinks]] to relative links.
|
||||||
|
|
||||||
Basic usage:
|
See <https://pythonhosted.org/Markdown/extensions/wikilinks.html>
|
||||||
|
for documentation.
|
||||||
|
|
||||||
>>> import markdown
|
Original code Copyright [Waylan Limberg](http://achinghead.com/).
|
||||||
>>> 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>
|
|
||||||
|
|
||||||
Whitespace behavior:
|
All changes Copyright The Python Markdown Project
|
||||||
|
|
||||||
>>> 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)
|
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
|
from __future__ import absolute_import
|
||||||
@@ -90,18 +29,16 @@ def build_url(label, base, end):
|
|||||||
|
|
||||||
|
|
||||||
class WikiLinkExtension(Extension):
|
class WikiLinkExtension(Extension):
|
||||||
def __init__(self, configs):
|
|
||||||
# set extension defaults
|
def __init__ (self, *args, **kwargs):
|
||||||
self.config = {
|
self.config = {
|
||||||
'base_url' : ['/', 'String to append to beginning or URL.'],
|
'base_url' : ['/', 'String to append to beginning or URL.'],
|
||||||
'end_url' : ['/', 'String to append to end of URL.'],
|
'end_url' : ['/', 'String to append to end of URL.'],
|
||||||
'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'],
|
'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'],
|
||||||
'build_url' : [build_url, 'Callable formats URL from label.'],
|
'build_url' : [build_url, 'Callable formats URL from label.'],
|
||||||
}
|
}
|
||||||
configs = dict(configs) or {}
|
|
||||||
# Override defaults with user settings
|
super(WikiLinkExtension, self).__init__(*args, **kwargs)
|
||||||
for key, value in configs.items():
|
|
||||||
self.setConfig(key, value)
|
|
||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
self.md = md
|
self.md = md
|
||||||
@@ -147,5 +84,5 @@ class WikiLinks(Pattern):
|
|||||||
return base_url, end_url, html_class
|
return base_url, end_url, html_class
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(configs=None) :
|
def makeExtension(*args, **kwargs) :
|
||||||
return WikiLinkExtension(configs=configs)
|
return WikiLinkExtension(*args, **kwargs)
|
||||||
|
|||||||
@@ -46,13 +46,13 @@ from __future__ import unicode_literals
|
|||||||
from . import util
|
from . import util
|
||||||
from . import odict
|
from . import odict
|
||||||
import re
|
import re
|
||||||
try:
|
try: #pragma: no cover
|
||||||
from urllib.parse import urlparse, urlunparse
|
from urllib.parse import urlparse, urlunparse
|
||||||
except ImportError:
|
except ImportError: #pragma: no cover
|
||||||
from urlparse import urlparse, urlunparse
|
from urlparse import urlparse, urlunparse
|
||||||
try:
|
try: #pragma: no cover
|
||||||
from html import entities
|
from html import entities
|
||||||
except ImportError:
|
except ImportError: #pragma: no cover
|
||||||
import htmlentitydefs as entities
|
import htmlentitydefs as entities
|
||||||
|
|
||||||
|
|
||||||
@@ -75,7 +75,8 @@ def build_inlinepatterns(md_instance, **kwargs):
|
|||||||
inlinePatterns["html"] = HtmlPattern(HTML_RE, md_instance)
|
inlinePatterns["html"] = HtmlPattern(HTML_RE, md_instance)
|
||||||
inlinePatterns["entity"] = HtmlPattern(ENTITY_RE, md_instance)
|
inlinePatterns["entity"] = HtmlPattern(ENTITY_RE, md_instance)
|
||||||
inlinePatterns["not_strong"] = SimpleTextPattern(NOT_STRONG_RE)
|
inlinePatterns["not_strong"] = SimpleTextPattern(NOT_STRONG_RE)
|
||||||
inlinePatterns["strong_em"] = DoubleTagPattern(STRONG_EM_RE, 'strong,em')
|
inlinePatterns["em_strong"] = DoubleTagPattern(EM_STRONG_RE, 'strong,em')
|
||||||
|
inlinePatterns["strong_em"] = DoubleTagPattern(STRONG_EM_RE, 'em,strong')
|
||||||
inlinePatterns["strong"] = SimpleTagPattern(STRONG_RE, 'strong')
|
inlinePatterns["strong"] = SimpleTagPattern(STRONG_RE, 'strong')
|
||||||
inlinePatterns["emphasis"] = SimpleTagPattern(EMPHASIS_RE, 'em')
|
inlinePatterns["emphasis"] = SimpleTagPattern(EMPHASIS_RE, 'em')
|
||||||
if md_instance.smart_emphasis:
|
if md_instance.smart_emphasis:
|
||||||
@@ -100,7 +101,8 @@ BACKTICK_RE = r'(?<!\\)(`+)(.+?)(?<!`)\2(?!`)' # `e=f()` or ``e=f("`")``
|
|||||||
ESCAPE_RE = r'\\(.)' # \<
|
ESCAPE_RE = r'\\(.)' # \<
|
||||||
EMPHASIS_RE = r'(\*)([^\*]+)\2' # *emphasis*
|
EMPHASIS_RE = r'(\*)([^\*]+)\2' # *emphasis*
|
||||||
STRONG_RE = r'(\*{2}|_{2})(.+?)\2' # **strong**
|
STRONG_RE = r'(\*{2}|_{2})(.+?)\2' # **strong**
|
||||||
STRONG_EM_RE = r'(\*{3}|_{3})(.+?)\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*
|
||||||
SMART_EMPHASIS_RE = r'(?<!\w)(_)(?!_)(.+?)(?<!_)\2(?!\w)' # _smart_emphasis_
|
SMART_EMPHASIS_RE = r'(?<!\w)(_)(?!_)(.+?)(?<!_)\2(?!\w)' # _smart_emphasis_
|
||||||
EMPHASIS_2_RE = r'(_)(.+?)\2' # _emphasis_
|
EMPHASIS_2_RE = r'(_)(.+?)\2' # _emphasis_
|
||||||
LINK_RE = NOIMG + BRK + \
|
LINK_RE = NOIMG + BRK + \
|
||||||
@@ -178,7 +180,7 @@ class Pattern(object):
|
|||||||
* m: A re match object containing a match of the pattern.
|
* m: A re match object containing a match of the pattern.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass #pragma: no cover
|
||||||
|
|
||||||
def type(self):
|
def type(self):
|
||||||
""" Return class name, to define pattern type """
|
""" Return class name, to define pattern type """
|
||||||
@@ -188,9 +190,9 @@ class Pattern(object):
|
|||||||
""" Return unescaped text given text with an inline placeholder. """
|
""" Return unescaped text given text with an inline placeholder. """
|
||||||
try:
|
try:
|
||||||
stash = self.markdown.treeprocessors['inline'].stashed_nodes
|
stash = self.markdown.treeprocessors['inline'].stashed_nodes
|
||||||
except KeyError:
|
except KeyError: #pragma: no cover
|
||||||
return text
|
return text
|
||||||
def itertext(el):
|
def itertext(el): #pragma: no cover
|
||||||
' Reimplement Element.itertext for older python versions '
|
' Reimplement Element.itertext for older python versions '
|
||||||
tag = el.tag
|
tag = el.tag
|
||||||
if not isinstance(tag, util.string_type) and tag is not None:
|
if not isinstance(tag, util.string_type) and tag is not None:
|
||||||
@@ -217,10 +219,7 @@ class Pattern(object):
|
|||||||
class SimpleTextPattern(Pattern):
|
class SimpleTextPattern(Pattern):
|
||||||
""" Return a simple text of group(2) of a Pattern. """
|
""" Return a simple text of group(2) of a Pattern. """
|
||||||
def handleMatch(self, m):
|
def handleMatch(self, m):
|
||||||
text = m.group(2)
|
return m.group(2)
|
||||||
if text == util.INLINE_PLACEHOLDER_PREFIX:
|
|
||||||
return None
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
class EscapePattern(Pattern):
|
class EscapePattern(Pattern):
|
||||||
@@ -279,6 +278,8 @@ class DoubleTagPattern(SimpleTagPattern):
|
|||||||
el1 = util.etree.Element(tag1)
|
el1 = util.etree.Element(tag1)
|
||||||
el2 = util.etree.SubElement(el1, tag2)
|
el2 = util.etree.SubElement(el1, tag2)
|
||||||
el2.text = m.group(3)
|
el2.text = m.group(3)
|
||||||
|
if len(m.groups())==5:
|
||||||
|
el2.tail = m.group(4)
|
||||||
return el1
|
return el1
|
||||||
|
|
||||||
|
|
||||||
@@ -293,7 +294,7 @@ class HtmlPattern(Pattern):
|
|||||||
""" Return unescaped text given text with an inline placeholder. """
|
""" Return unescaped text given text with an inline placeholder. """
|
||||||
try:
|
try:
|
||||||
stash = self.markdown.treeprocessors['inline'].stashed_nodes
|
stash = self.markdown.treeprocessors['inline'].stashed_nodes
|
||||||
except KeyError:
|
except KeyError: #pragma: no cover
|
||||||
return text
|
return text
|
||||||
def get_stash(m):
|
def get_stash(m):
|
||||||
id = m.group(1)
|
id = m.group(1)
|
||||||
@@ -350,7 +351,7 @@ class LinkPattern(Pattern):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
scheme, netloc, path, params, query, fragment = url = urlparse(url)
|
scheme, netloc, path, params, query, fragment = url = urlparse(url)
|
||||||
except ValueError:
|
except ValueError: #pragma: no cover
|
||||||
# Bad url - so bad it couldn't be parsed.
|
# Bad url - so bad it couldn't be parsed.
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@@ -360,7 +361,7 @@ class LinkPattern(Pattern):
|
|||||||
# Not a known (allowed) scheme. Not safe.
|
# Not a known (allowed) scheme. Not safe.
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
if netloc == '' and scheme not in locless_schemes:
|
if netloc == '' and scheme not in locless_schemes: #pragma: no cover
|
||||||
# This should not happen. Treat as suspect.
|
# This should not happen. Treat as suspect.
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|||||||
@@ -82,11 +82,11 @@ class OrderedDict(dict):
|
|||||||
for key in self.keyOrder:
|
for key in self.keyOrder:
|
||||||
yield self[key]
|
yield self[key]
|
||||||
|
|
||||||
if util.PY3:
|
if util.PY3: #pragma: no cover
|
||||||
items = _iteritems
|
items = _iteritems
|
||||||
keys = _iterkeys
|
keys = _iterkeys
|
||||||
values = _itervalues
|
values = _itervalues
|
||||||
else:
|
else: #pragma: no cover
|
||||||
iteritems = _iteritems
|
iteritems = _iteritems
|
||||||
iterkeys = _iterkeys
|
iterkeys = _iterkeys
|
||||||
itervalues = _itervalues
|
itervalues = _itervalues
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class Postprocessor(util.Processor):
|
|||||||
(possibly modified) string.
|
(possibly modified) string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass #pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
class RawHtmlPostprocessor(Postprocessor):
|
class RawHtmlPostprocessor(Postprocessor):
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Preprocessor(util.Processor):
|
|||||||
the (possibly modified) list of lines.
|
the (possibly modified) list of lines.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass #pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
class NormalizeWhitespace(Preprocessor):
|
class NormalizeWhitespace(Preprocessor):
|
||||||
@@ -174,9 +174,10 @@ class HtmlBlockPreprocessor(Preprocessor):
|
|||||||
else: # raw html
|
else: # raw html
|
||||||
if len(items) - right_listindex <= 1: # last element
|
if len(items) - right_listindex <= 1: # last element
|
||||||
right_listindex -= 1
|
right_listindex -= 1
|
||||||
|
offset = 1 if i == right_listindex else 0
|
||||||
placeholder = self.markdown.htmlStash.store('\n\n'.join(
|
placeholder = self.markdown.htmlStash.store('\n\n'.join(
|
||||||
items[i:right_listindex + 1]))
|
items[i:right_listindex + offset]))
|
||||||
del items[i:right_listindex + 1]
|
del items[i:right_listindex + offset]
|
||||||
items.insert(i, placeholder)
|
items.insert(i, placeholder)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ from __future__ import unicode_literals
|
|||||||
from . import util
|
from . import util
|
||||||
ElementTree = util.etree.ElementTree
|
ElementTree = util.etree.ElementTree
|
||||||
QName = util.etree.QName
|
QName = util.etree.QName
|
||||||
if hasattr(util.etree, 'test_comment'):
|
if hasattr(util.etree, 'test_comment'): #pragma: no cover
|
||||||
Comment = util.etree.test_comment
|
Comment = util.etree.test_comment
|
||||||
else:
|
else: #pragma: no cover
|
||||||
Comment = util.etree.Comment
|
Comment = util.etree.Comment
|
||||||
PI = util.etree.PI
|
PI = util.etree.PI
|
||||||
ProcessingInstruction = util.etree.ProcessingInstruction
|
ProcessingInstruction = util.etree.ProcessingInstruction
|
||||||
@@ -56,7 +56,7 @@ HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
HTML_EMPTY = set(HTML_EMPTY)
|
HTML_EMPTY = set(HTML_EMPTY)
|
||||||
except NameError:
|
except NameError: #pragma: no cover
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_namespace_map = {
|
_namespace_map = {
|
||||||
@@ -73,7 +73,7 @@ _namespace_map = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _raise_serialization_error(text):
|
def _raise_serialization_error(text): #pragma: no cover
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"cannot serialize %r (type %s)" % (text, type(text).__name__)
|
"cannot serialize %r (type %s)" % (text, type(text).__name__)
|
||||||
)
|
)
|
||||||
@@ -81,7 +81,7 @@ def _raise_serialization_error(text):
|
|||||||
def _encode(text, encoding):
|
def _encode(text, encoding):
|
||||||
try:
|
try:
|
||||||
return text.encode(encoding, "xmlcharrefreplace")
|
return text.encode(encoding, "xmlcharrefreplace")
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError): #pragma: no cover
|
||||||
_raise_serialization_error(text)
|
_raise_serialization_error(text)
|
||||||
|
|
||||||
def _escape_cdata(text):
|
def _escape_cdata(text):
|
||||||
@@ -97,7 +97,7 @@ def _escape_cdata(text):
|
|||||||
if ">" in text:
|
if ">" in text:
|
||||||
text = text.replace(">", ">")
|
text = text.replace(">", ">")
|
||||||
return text
|
return text
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError): #pragma: no cover
|
||||||
_raise_serialization_error(text)
|
_raise_serialization_error(text)
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ def _escape_attrib(text):
|
|||||||
if "\n" in text:
|
if "\n" in text:
|
||||||
text = text.replace("\n", " ")
|
text = text.replace("\n", " ")
|
||||||
return text
|
return text
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError): #pragma: no cover
|
||||||
_raise_serialization_error(text)
|
_raise_serialization_error(text)
|
||||||
|
|
||||||
def _escape_attrib_html(text):
|
def _escape_attrib_html(text):
|
||||||
@@ -130,7 +130,7 @@ def _escape_attrib_html(text):
|
|||||||
if "\"" in text:
|
if "\"" in text:
|
||||||
text = text.replace("\"", """)
|
text = text.replace("\"", """)
|
||||||
return text
|
return text
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError): #pragma: no cover
|
||||||
_raise_serialization_error(text)
|
_raise_serialization_error(text)
|
||||||
|
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ def _namespaces(elem, default_namespace=None):
|
|||||||
"default_namespace option"
|
"default_namespace option"
|
||||||
)
|
)
|
||||||
qnames[qname] = qname
|
qnames[qname] = qname
|
||||||
except TypeError:
|
except TypeError: #pragma: no cover
|
||||||
_raise_serialization_error(qname)
|
_raise_serialization_error(qname)
|
||||||
|
|
||||||
# populate qname and namespaces table
|
# populate qname and namespaces table
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Treeprocessor(util.Processor):
|
|||||||
object, and the existing root ElementTree will be replaced, or it can
|
object, and the existing root ElementTree will be replaced, or it can
|
||||||
modify the current tree and return None.
|
modify the current tree and return None.
|
||||||
"""
|
"""
|
||||||
pass
|
pass #pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
class InlineProcessor(Treeprocessor):
|
class InlineProcessor(Treeprocessor):
|
||||||
@@ -53,6 +53,7 @@ class InlineProcessor(Treeprocessor):
|
|||||||
+ len(self.__placeholder_suffix)
|
+ len(self.__placeholder_suffix)
|
||||||
self.__placeholder_re = util.INLINE_PLACEHOLDER_RE
|
self.__placeholder_re = util.INLINE_PLACEHOLDER_RE
|
||||||
self.markdown = md
|
self.markdown = md
|
||||||
|
self.inlinePatterns = md.inlinePatterns
|
||||||
|
|
||||||
def __makePlaceholder(self, type):
|
def __makePlaceholder(self, type):
|
||||||
""" Generate a placeholder """
|
""" Generate a placeholder """
|
||||||
@@ -99,9 +100,9 @@ class InlineProcessor(Treeprocessor):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(data, util.AtomicString):
|
if not isinstance(data, util.AtomicString):
|
||||||
startIndex = 0
|
startIndex = 0
|
||||||
while patternIndex < len(self.markdown.inlinePatterns):
|
while patternIndex < len(self.inlinePatterns):
|
||||||
data, matched, startIndex = self.__applyPattern(
|
data, matched, startIndex = self.__applyPattern(
|
||||||
self.markdown.inlinePatterns.value_for_index(patternIndex),
|
self.inlinePatterns.value_for_index(patternIndex),
|
||||||
data, patternIndex, startIndex)
|
data, patternIndex, startIndex)
|
||||||
if not matched:
|
if not matched:
|
||||||
patternIndex += 1
|
patternIndex += 1
|
||||||
@@ -128,11 +129,10 @@ class InlineProcessor(Treeprocessor):
|
|||||||
text = subnode.tail
|
text = subnode.tail
|
||||||
subnode.tail = None
|
subnode.tail = None
|
||||||
|
|
||||||
childResult = self.__processPlaceholders(text, subnode)
|
childResult = self.__processPlaceholders(text, subnode, isText)
|
||||||
|
|
||||||
if not isText and node is not subnode:
|
if not isText and node is not subnode:
|
||||||
pos = list(node).index(subnode)
|
pos = list(node).index(subnode) + 1
|
||||||
node.remove(subnode)
|
|
||||||
else:
|
else:
|
||||||
pos = 0
|
pos = 0
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ class InlineProcessor(Treeprocessor):
|
|||||||
for newChild in childResult:
|
for newChild in childResult:
|
||||||
node.insert(pos, newChild)
|
node.insert(pos, newChild)
|
||||||
|
|
||||||
def __processPlaceholders(self, data, parent):
|
def __processPlaceholders(self, data, parent, isText=True):
|
||||||
"""
|
"""
|
||||||
Process string with placeholders and generate ElementTree tree.
|
Process string with placeholders and generate ElementTree tree.
|
||||||
|
|
||||||
@@ -159,6 +159,11 @@ class InlineProcessor(Treeprocessor):
|
|||||||
result[-1].tail += text
|
result[-1].tail += text
|
||||||
else:
|
else:
|
||||||
result[-1].tail = text
|
result[-1].tail = text
|
||||||
|
elif not isText:
|
||||||
|
if parent.tail:
|
||||||
|
parent.tail += text
|
||||||
|
else:
|
||||||
|
parent.tail = text
|
||||||
else:
|
else:
|
||||||
if parent.text:
|
if parent.text:
|
||||||
parent.text += text
|
parent.text += text
|
||||||
@@ -182,7 +187,7 @@ class InlineProcessor(Treeprocessor):
|
|||||||
for child in [node] + list(node):
|
for child in [node] + list(node):
|
||||||
if child.tail:
|
if child.tail:
|
||||||
if child.tail.strip():
|
if child.tail.strip():
|
||||||
self.__processElementText(node, child,False)
|
self.__processElementText(node, child, False)
|
||||||
if child.text:
|
if child.text:
|
||||||
if child.text.strip():
|
if child.text.strip():
|
||||||
self.__processElementText(child, child)
|
self.__processElementText(child, child)
|
||||||
@@ -287,11 +292,10 @@ class InlineProcessor(Treeprocessor):
|
|||||||
if child.tail:
|
if child.tail:
|
||||||
tail = self.__handleInline(child.tail)
|
tail = self.__handleInline(child.tail)
|
||||||
dumby = util.etree.Element('d')
|
dumby = util.etree.Element('d')
|
||||||
tailResult = self.__processPlaceholders(tail, dumby)
|
child.tail = None
|
||||||
if dumby.text:
|
tailResult = self.__processPlaceholders(tail, dumby, False)
|
||||||
child.tail = dumby.text
|
if dumby.tail:
|
||||||
else:
|
child.tail = dumby.tail
|
||||||
child.tail = None
|
|
||||||
pos = list(currElement).index(child) + 1
|
pos = list(currElement).index(child) + 1
|
||||||
tailResult.reverse()
|
tailResult.reverse()
|
||||||
for newChild in tailResult:
|
for newChild in tailResult:
|
||||||
@@ -357,4 +361,4 @@ class PrettifyTreeprocessor(Treeprocessor):
|
|||||||
pres = root.getiterator('pre')
|
pres = root.getiterator('pre')
|
||||||
for pre in pres:
|
for pre in pres:
|
||||||
if len(pre) and pre[0].tag == 'code':
|
if len(pre) and pre[0].tag == 'code':
|
||||||
pre[0].text = pre[0].text.rstrip() + '\n'
|
pre[0].text = util.AtomicString(pre[0].text.rstrip() + '\n')
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ Python 3 Stuff
|
|||||||
"""
|
"""
|
||||||
PY3 = sys.version_info[0] == 3
|
PY3 = sys.version_info[0] == 3
|
||||||
|
|
||||||
if PY3:
|
if PY3: #pragma: no cover
|
||||||
string_type = str
|
string_type = str
|
||||||
text_type = str
|
text_type = str
|
||||||
int2str = chr
|
int2str = chr
|
||||||
else:
|
else: #pragma: no cover
|
||||||
string_type = basestring
|
string_type = basestring
|
||||||
text_type = unicode
|
text_type = unicode
|
||||||
int2str = unichr
|
int2str = unichr
|
||||||
@@ -58,14 +58,15 @@ RTL_BIDI_RANGES = ( ('\u0590', '\u07FF'),
|
|||||||
# Extensions should use "markdown.util.etree" instead of "etree" (or do `from
|
# Extensions should use "markdown.util.etree" instead of "etree" (or do `from
|
||||||
# markdown.util import etree`). Do not import it by yourself.
|
# markdown.util import etree`). Do not import it by yourself.
|
||||||
|
|
||||||
try: # Is the C implementation of ElementTree available?
|
try: #pragma: no cover
|
||||||
|
# Is the C implementation of ElementTree available?
|
||||||
import xml.etree.cElementTree as etree
|
import xml.etree.cElementTree as etree
|
||||||
from xml.etree.ElementTree import Comment
|
from xml.etree.ElementTree import Comment
|
||||||
# Serializers (including ours) test with non-c Comment
|
# Serializers (including ours) test with non-c Comment
|
||||||
etree.test_comment = Comment
|
etree.test_comment = Comment
|
||||||
if etree.VERSION < "1.0.5":
|
if etree.VERSION < "1.0.5":
|
||||||
raise RuntimeError("cElementTree version 1.0.5 or higher is required.")
|
raise RuntimeError("cElementTree version 1.0.5 or higher is required.")
|
||||||
except (ImportError, RuntimeError):
|
except (ImportError, RuntimeError): #pragma: no cover
|
||||||
# Use the Python implementation of ElementTree?
|
# Use the Python implementation of ElementTree?
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
if etree.VERSION < "1.1":
|
if etree.VERSION < "1.1":
|
||||||
@@ -85,15 +86,20 @@ def isBlockLevel(tag):
|
|||||||
# Some ElementTree tags are not strings, so return False.
|
# Some ElementTree tags are not strings, so return False.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def parseBoolValue(value, fail_on_errors=True):
|
def parseBoolValue(value, fail_on_errors=True, preserve_none=False):
|
||||||
"""Parses a string representing bool value. If parsing was successful,
|
"""Parses a string representing bool value. If parsing was successful,
|
||||||
returns True or False. If parsing was not successful, raises
|
returns True or False. If preserve_none=True, returns True, False,
|
||||||
ValueError, or, if fail_on_errors=False, returns None."""
|
or None. If parsing was not successful, raises ValueError, or, if
|
||||||
|
fail_on_errors=False, returns None."""
|
||||||
if not isinstance(value, string_type):
|
if not isinstance(value, string_type):
|
||||||
|
if preserve_none and value is None:
|
||||||
|
return value
|
||||||
return bool(value)
|
return bool(value)
|
||||||
|
elif preserve_none and value.lower() == 'none':
|
||||||
|
return None
|
||||||
elif value.lower() in ('true', 'yes', 'y', 'on', '1'):
|
elif value.lower() in ('true', 'yes', 'y', 'on', '1'):
|
||||||
return True
|
return True
|
||||||
elif value.lower() in ('false', 'no', 'n', 'off', '0'):
|
elif value.lower() in ('false', 'no', 'n', 'off', '0', 'none'):
|
||||||
return False
|
return False
|
||||||
elif fail_on_errors:
|
elif fail_on_errors:
|
||||||
raise ValueError('Cannot parse bool value: %r' % value)
|
raise ValueError('Cannot parse bool value: %r' % value)
|
||||||
|
|||||||
Reference in New Issue
Block a user