mirror of
https://github.com/ansible/awx.git
synced 2026-04-14 14:39:26 -02:30
Revert "Upgrade Markdown to 2.5.2" due to issues with logging in python
2.6. This reverts commit 6787490e6d854eecea70b511673290277ea3bccc.
This commit is contained in:
@@ -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.1 (keyring/*, excluded bin/keyring)
|
keyring==4.1 (keyring/*, excluded bin/keyring)
|
||||||
kombu==3.0.21 (kombu/*)
|
kombu==3.0.21 (kombu/*)
|
||||||
Markdown==2.5.2 (markdown/*, excluded bin/markdown_py)
|
Markdown==2.4.1 (markdown/*, excluded bin/markdown_py)
|
||||||
mock==1.0.1 (mock.py)
|
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 <https://pythonhosted.org/Markdown/> for more
|
See <http://packages.python.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,8 +36,6 @@ 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
|
||||||
@@ -50,7 +48,6 @@ 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):
|
||||||
@@ -99,8 +96,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: Deprecated! Disallow raw html. One of "remove", "replace" or "escape".
|
* safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
|
||||||
* html_replacement_text: Deprecated! Text used when safe_mode is set to "replace".
|
* html_replacement_text: 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
|
||||||
@@ -110,16 +107,14 @@ 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']
|
||||||
for c, arg in enumerate(args):
|
c = 0
|
||||||
|
for arg in args:
|
||||||
if pos[c] not in kwargs:
|
if pos[c] not in kwargs:
|
||||||
kwargs[pos[c]] = arg
|
kwargs[pos[c]] = arg
|
||||||
if c+1 == len(pos): #pragma: no cover
|
c += 1
|
||||||
|
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():
|
||||||
@@ -130,18 +125,6 @@ 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
|
||||||
@@ -177,11 +160,9 @@ 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"'
|
||||||
@@ -189,87 +170,52 @@ 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
|
||||||
following format: "extname(key1=value1,key2=value2)"
|
following format: "extname(key1=value1,key2=value2)"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
configs = dict(configs)
|
|
||||||
|
|
||||||
# Parse extensions config params (ignore the order)
|
# Parse extensions config params (ignore the order)
|
||||||
|
configs = dict(configs)
|
||||||
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)
|
|
||||||
|
|
||||||
# Get class name (if provided): `path.to.module:ClassName`
|
# Setup the module name
|
||||||
ext_name, class_name = ext_name.split(':', 1) if ':' in ext_name else (ext_name, '')
|
module_name = ext_name
|
||||||
|
if '.' not in ext_name:
|
||||||
|
module_name = '.'.join(['markdown.extensions', ext_name])
|
||||||
|
|
||||||
# Try loading the extension first from one place, then another
|
# Try loading the extension first from one place, then another
|
||||||
try:
|
try: # New style (markdown.extensions.<extension>)
|
||||||
# Assume string uses dot syntax (`path.to.some.module`)
|
module = __import__(module_name, {}, {}, [module_name.rpartition('.')[0]])
|
||||||
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:
|
||||||
# Preppend `markdown.extensions.` to name
|
module_name_old_style = '_'.join(['mdx', ext_name])
|
||||||
module_name = '.'.join(['markdown.extensions', ext_name])
|
try: # Old style (mdx_<extension>)
|
||||||
try:
|
module = __import__(module_name_old_style)
|
||||||
module = importlib.import_module(module_name)
|
except ImportError as e:
|
||||||
logger.debug('Successfuly imported extension module "%s".' % module_name)
|
message = "Failed loading extension '%s' from '%s' or '%s'" \
|
||||||
warnings.warn('Using short names for Markdown\'s builtin extensions is pending deprecation. '
|
% (ext_name, module_name, module_name_old_style)
|
||||||
'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)
|
||||||
@@ -357,7 +303,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: #pragma: no cover
|
except ValueError:
|
||||||
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 = ''
|
||||||
@@ -488,10 +434,6 @@ 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,25 +7,20 @@ 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(args=None, values=None):
|
def parse_options():
|
||||||
"""
|
"""
|
||||||
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. " \
|
||||||
"https://pythonhosted.org/Markdown/"
|
"http://packages.python.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)
|
||||||
@@ -34,36 +29,28 @@ def parse_options(args=None, values=None):
|
|||||||
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(args, values)
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
input_file = None
|
input_file = None
|
||||||
@@ -73,26 +60,15 @@ def parse_options(args=None, values=None):
|
|||||||
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(): #pragma: no cover
|
def run():
|
||||||
"""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
|
||||||
@@ -104,7 +80,7 @@ def run(): #pragma: no cover
|
|||||||
# Run
|
# Run
|
||||||
markdown.markdownFromFile(**options)
|
markdown.markdownFromFile(**options)
|
||||||
|
|
||||||
if __name__ == '__main__': #pragma: no cover
|
if __name__ == '__main__':
|
||||||
# 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, 5, 2, 'final', 0)
|
version_info = (2, 4, 1, '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 #pragma: no cover
|
pass
|
||||||
|
|
||||||
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 #pragma: no cover
|
pass
|
||||||
|
|
||||||
|
|
||||||
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: #pragma: no cover
|
else:
|
||||||
# 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,45 +4,17 @@ 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 = {}):
|
||||||
# Default config -- to be overriden by a subclass
|
"""Create an instance of an Extention.
|
||||||
# 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.
|
Keyword arguments:
|
||||||
# (there only ever used to be one so we use arg[0])
|
|
||||||
if len(args):
|
* configs: A dict of configuration setting used by an Extension.
|
||||||
self.setConfigs(args[0])
|
"""
|
||||||
warnings.warn('Extension classes accepting positional args is pending Deprecation. '
|
self.config = configs
|
||||||
'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)
|
|
||||||
|
|
||||||
|
|
||||||
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. """
|
||||||
@@ -61,20 +33,8 @@ 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,15 +4,22 @@ Abbreviation Extension for Python-Markdown
|
|||||||
|
|
||||||
This extension adds abbreviation handling to Python-Markdown.
|
This extension adds abbreviation handling to Python-Markdown.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/abbreviations.html>
|
Simple Usage:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Oringinal code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) and
|
>>> import markdown
|
||||||
[Seemant Kulleen](http://www.kulleen.org/)
|
>>> text = """
|
||||||
|
... Some text with an ABBR and a REF. Ignore REFERENCE and ref.
|
||||||
|
...
|
||||||
|
... *[ABBR]: Abbreviation
|
||||||
|
... *[REF]: Abbreviation Reference
|
||||||
|
... """
|
||||||
|
>>> print markdown.markdown(text, ['abbr'])
|
||||||
|
<p>Some text with an <abbr title="Abbreviation">ABBR</abbr> and a <abbr title="Abbreviation Reference">REF</abbr>. Ignore REFERENCE and ref.</p>
|
||||||
|
|
||||||
All changes Copyright 2008-2014 The Python Markdown Project
|
Copyright 2007-2008
|
||||||
|
* [Waylan Limberg](http://achinghead.com/)
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
* [Seemant Kulleen](http://www.kulleen.org/)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -85,5 +92,5 @@ class AbbrPattern(Pattern):
|
|||||||
abbr.set('title', self.title)
|
abbr.set('title', self.title)
|
||||||
return abbr
|
return abbr
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs=None):
|
||||||
return AbbrExtension(*args, **kwargs)
|
return AbbrExtension(configs=configs)
|
||||||
|
|||||||
@@ -4,16 +4,39 @@ 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
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/admonition.html>
|
By [Tiago Serafim](http://www.tiagoserafim.com/).
|
||||||
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)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -91,6 +114,5 @@ class AdmonitionProcessor(BlockProcessor):
|
|||||||
return klass, title
|
return klass, title
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return AdmonitionExtension(*args, **kwargs)
|
return AdmonitionExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ 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.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/attr_list.html>
|
Copyright 2011 [Waylan Limberg](http://achinghead.com/).
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com/).
|
Contact: markdown@freewisdom.org
|
||||||
|
|
||||||
All changes Copyright 2011-2014 The Python Markdown Project
|
License: BSD (see ../LICENSE.md for details)
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
Dependencies:
|
||||||
|
* [Python 2.4+](http://python.org)
|
||||||
|
* [Markdown 2.1+](http://packages.python.org/Markdown/)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ import re
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
Scanner = re.Scanner
|
Scanner = re.Scanner
|
||||||
except AttributeError: #pragma: no cover
|
except AttributeError:
|
||||||
# must be on Python 2.4
|
# must be on Python 2.4
|
||||||
from sre import Scanner
|
from sre import Scanner
|
||||||
|
|
||||||
@@ -163,5 +164,5 @@ class AttrListExtension(Extension):
|
|||||||
md.treeprocessors.add('attr_list', AttrListTreeprocessor(md), '>prettify')
|
md.treeprocessors.add('attr_list', AttrListTreeprocessor(md), '>prettify')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return AttrListExtension(*args, **kwargs)
|
return AttrListExtension(configs=configs)
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ 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.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/code_hilite.html>
|
Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
|
Project website: <http://packages.python.org/Markdown/extensions/code_hilite.html>
|
||||||
|
Contact: markdown@freewisdom.org
|
||||||
|
|
||||||
All changes Copyright 2008-2014 The Python Markdown Project
|
License: BSD (see ../LICENSE.md for details)
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
Dependencies:
|
||||||
|
* [Python 2.3+](http://python.org/)
|
||||||
|
* [Markdown 2.0+](http://packages.python.org/Markdown/)
|
||||||
|
* [Pygments](http://pygments.org/)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -22,8 +25,8 @@ from ..treeprocessors import Treeprocessor
|
|||||||
import warnings
|
import warnings
|
||||||
try:
|
try:
|
||||||
from pygments import highlight
|
from pygments import highlight
|
||||||
from pygments.lexers import get_lexer_by_name, guess_lexer
|
from pygments.lexers import get_lexer_by_name, guess_lexer, TextLexer
|
||||||
from pygments.formatters import get_formatter_by_name
|
from pygments.formatters import HtmlFormatter
|
||||||
pygments = True
|
pygments = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pygments = False
|
pygments = False
|
||||||
@@ -109,15 +112,14 @@ class CodeHilite(object):
|
|||||||
if self.guess_lang:
|
if self.guess_lang:
|
||||||
lexer = guess_lexer(self.src)
|
lexer = guess_lexer(self.src)
|
||||||
else:
|
else:
|
||||||
lexer = get_lexer_by_name('text')
|
lexer = TextLexer()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
lexer = get_lexer_by_name('text')
|
lexer = TextLexer()
|
||||||
formatter = get_formatter_by_name('html',
|
formatter = HtmlFormatter(linenos=self.linenums,
|
||||||
linenos=self.linenums,
|
cssclass=self.css_class,
|
||||||
cssclass=self.css_class,
|
style=self.style,
|
||||||
style=self.style,
|
noclasses=self.noclasses,
|
||||||
noclasses=self.noclasses,
|
hl_lines=self.hl_lines)
|
||||||
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
|
||||||
@@ -223,7 +225,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, *args, **kwargs):
|
def __init__(self, configs):
|
||||||
# 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"],
|
||||||
@@ -235,7 +237,22 @@ 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']
|
||||||
}
|
}
|
||||||
|
|
||||||
super(CodeHiliteExtension, self).__init__(*args, **kwargs)
|
# Override defaults with user settings
|
||||||
|
for key, value in configs:
|
||||||
|
# convert strings to booleans
|
||||||
|
if value == 'True': value = True
|
||||||
|
if value == 'False': value = False
|
||||||
|
if value == 'None': value = None
|
||||||
|
|
||||||
|
if key == 'force_linenos':
|
||||||
|
warnings.warn('The "force_linenos" config setting'
|
||||||
|
' to the CodeHilite extension is deprecrecated.'
|
||||||
|
' Use "linenums" instead.', DeprecationWarning)
|
||||||
|
if value:
|
||||||
|
# Carry 'force_linenos' over to new 'linenos'.
|
||||||
|
self.setConfig('linenums', True)
|
||||||
|
|
||||||
|
self.setConfig(key, value)
|
||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
""" Add HilitePostprocessor to Markdown instance. """
|
""" Add HilitePostprocessor to Markdown instance. """
|
||||||
@@ -246,5 +263,6 @@ class CodeHiliteExtension(Extension):
|
|||||||
md.registerExtension(self)
|
md.registerExtension(self)
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return CodeHiliteExtension(*args, **kwargs)
|
return CodeHiliteExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,19 @@
|
|||||||
Definition List Extension for Python-Markdown
|
Definition List Extension for Python-Markdown
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
Adds parsing of Definition Lists to Python-Markdown.
|
Added parsing of Definition Lists to Python-Markdown.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/definition_lists.html>
|
A simple example:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright 2008 [Waylan Limberg](http://achinghead.com)
|
Apple
|
||||||
|
: Pomaceous fruit of plants of the genus Malus in
|
||||||
|
the family Rosaceae.
|
||||||
|
: An american computer company.
|
||||||
|
|
||||||
All changes Copyright 2008-2014 The Python Markdown Project
|
Orange
|
||||||
|
: The fruit of an evergreen tree of the genus Citrus.
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
Copyright 2008 - [Waylan Limberg](http://achinghead.com)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -110,6 +113,6 @@ class DefListExtension(Extension):
|
|||||||
'>ulist')
|
'>ulist')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return DefListExtension(*args, **kwargs)
|
return DefListExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ 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
|
||||||
@@ -20,13 +24,6 @@ under a differant name. You could also edit the `extensions` global
|
|||||||
variable defined below, but be aware that such changes may be lost
|
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
|
||||||
@@ -36,25 +33,19 @@ from ..blockprocessors import BlockProcessor
|
|||||||
from .. import util
|
from .. import util
|
||||||
import re
|
import re
|
||||||
|
|
||||||
extensions = [
|
extensions = ['smart_strong',
|
||||||
'markdown.extensions.smart_strong',
|
'fenced_code',
|
||||||
'markdown.extensions.fenced_code',
|
'footnotes',
|
||||||
'markdown.extensions.footnotes',
|
'attr_list',
|
||||||
'markdown.extensions.attr_list',
|
'def_list',
|
||||||
'markdown.extensions.def_list',
|
'tables',
|
||||||
'markdown.extensions.tables',
|
'abbr',
|
||||||
'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)
|
||||||
@@ -69,8 +60,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(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return ExtraExtension(*args, **kwargs)
|
return ExtraExtension(configs=dict(configs))
|
||||||
|
|
||||||
|
|
||||||
class MarkdownInHtmlProcessor(BlockProcessor):
|
class MarkdownInHtmlProcessor(BlockProcessor):
|
||||||
|
|||||||
@@ -4,15 +4,87 @@ Fenced Code Extension for Python Markdown
|
|||||||
|
|
||||||
This extension adds Fenced Code Blocks to Python-Markdown.
|
This extension adds Fenced Code Blocks to Python-Markdown.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/fenced_code_blocks.html>
|
>>> import markdown
|
||||||
for documentation.
|
>>> text = '''
|
||||||
|
... A paragraph before a fenced code block:
|
||||||
|
...
|
||||||
|
... ~~~
|
||||||
|
... Fenced code block
|
||||||
|
... ~~~
|
||||||
|
... '''
|
||||||
|
>>> html = markdown.markdown(text, extensions=['fenced_code'])
|
||||||
|
>>> print html
|
||||||
|
<p>A paragraph before a fenced code block:</p>
|
||||||
|
<pre><code>Fenced code block
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
|
Works with safe_mode also (we check this because we are using the HtmlStash):
|
||||||
|
|
||||||
|
>>> print markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace')
|
||||||
|
<p>A paragraph before a fenced code block:</p>
|
||||||
|
<pre><code>Fenced code block
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
All changes Copyright 2008-2014 The Python Markdown Project
|
Include tilde's in a code block and wrap with blank lines:
|
||||||
|
|
||||||
|
>>> text = '''
|
||||||
|
... ~~~~~~~~
|
||||||
|
...
|
||||||
|
... ~~~~
|
||||||
|
... ~~~~~~~~'''
|
||||||
|
>>> print markdown.markdown(text, extensions=['fenced_code'])
|
||||||
|
<pre><code>
|
||||||
|
~~~~
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
Language tags:
|
||||||
|
|
||||||
|
>>> text = '''
|
||||||
|
... ~~~~{.python}
|
||||||
|
... # Some python code
|
||||||
|
... ~~~~'''
|
||||||
|
>>> print markdown.markdown(text, extensions=['fenced_code'])
|
||||||
|
<pre><code class="python"># Some python code
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
Optionally backticks instead of tildes as per how github's code block markdown is identified:
|
||||||
|
|
||||||
|
>>> text = '''
|
||||||
|
... `````
|
||||||
|
... # Arbitrary code
|
||||||
|
... ~~~~~ # these tildes will not close the block
|
||||||
|
... `````'''
|
||||||
|
>>> print markdown.markdown(text, extensions=['fenced_code'])
|
||||||
|
<pre><code># Arbitrary code
|
||||||
|
~~~~~ # these tildes will not close the block
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
If the codehighlite extension and Pygments are installed, lines can be highlighted:
|
||||||
|
|
||||||
|
>>> text = '''
|
||||||
|
... ```hl_lines="1 3"
|
||||||
|
... line 1
|
||||||
|
... line 2
|
||||||
|
... line 3
|
||||||
|
... ```'''
|
||||||
|
>>> print markdown.markdown(text, extensions=['codehilite', 'fenced_code'])
|
||||||
|
<pre><code><span class="hilight">line 1</span>
|
||||||
|
line 2
|
||||||
|
<span class="hilight">line 3</span>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
|
||||||
|
|
||||||
|
Project website: <http://packages.python.org/Markdown/extensions/fenced_code_blocks.html>
|
||||||
|
Contact: markdown@freewisdom.org
|
||||||
|
|
||||||
|
License: BSD (see ../docs/LICENSE for details)
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
* [Python 2.4+](http://python.org)
|
||||||
|
* [Markdown 2.0+](http://packages.python.org/Markdown/)
|
||||||
|
* [Pygments (optional)](http://pygments.org)
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
@@ -103,6 +175,5 @@ class FencedBlockPreprocessor(Preprocessor):
|
|||||||
return txt
|
return txt
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs=None):
|
||||||
return FencedCodeExtension(*args, **kwargs)
|
return FencedCodeExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,25 @@
|
|||||||
"""
|
"""
|
||||||
Footnotes Extension for Python-Markdown
|
========================= FOOTNOTES =================================
|
||||||
=======================================
|
|
||||||
|
|
||||||
Adds footnote handling to Python-Markdown.
|
This section adds footnote handling to markdown. It can be used as
|
||||||
|
an example for extending python-markdown with relatively complex
|
||||||
|
functionality. While in this case the extension is included inside
|
||||||
|
the module itself, it could just as easily be added from outside the
|
||||||
|
module. Not that all markdown classes above are ignorant about
|
||||||
|
footnotes. All footnote functionality is provided separately and
|
||||||
|
then added to the markdown instance at the run time.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/footnotes.html>
|
Footnote functionality is attached by calling extendMarkdown()
|
||||||
for documentation.
|
method of FootnoteExtension. The method also registers the
|
||||||
|
extension to allow it's state to be reset by a call to reset()
|
||||||
|
method.
|
||||||
|
|
||||||
Copyright The Python Markdown Project
|
Example:
|
||||||
|
Footnotes[^1] have a label[^label] and a definition[^!DEF].
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
[^1]: This is a footnote
|
||||||
|
[^label]: A footnote on "label"
|
||||||
|
[^!DEF]: The footnote for definition
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -32,23 +42,23 @@ TABBED_RE = re.compile(r'((\t)|( ))(.*)')
|
|||||||
class FootnoteExtension(Extension):
|
class FootnoteExtension(Extension):
|
||||||
""" Footnote Extension. """
|
""" Footnote Extension. """
|
||||||
|
|
||||||
def __init__ (self, *args, **kwargs):
|
def __init__ (self, configs):
|
||||||
""" 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[key][0] = value
|
||||||
|
|
||||||
self.config = {
|
|
||||||
'PLACE_MARKER':
|
|
||||||
["///Footnotes Go Here///",
|
|
||||||
"The text string that marks where the footnotes go"],
|
|
||||||
'UNIQUE_IDS':
|
|
||||||
[False,
|
|
||||||
"Avoid name collisions across "
|
|
||||||
"multiple calls to reset()."],
|
|
||||||
"BACKLINK_TEXT":
|
|
||||||
["↩",
|
|
||||||
"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
|
||||||
|
|
||||||
@@ -299,7 +309,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(*args, **kwargs):
|
def makeExtension(configs=[]):
|
||||||
""" Return an instance of the FootnoteExtension """
|
""" Return an instance of the FootnoteExtension """
|
||||||
return FootnoteExtension(*args, **kwargs)
|
return FootnoteExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,73 @@ HeaderID Extension for Python-Markdown
|
|||||||
|
|
||||||
Auto-generate id attributes for HTML headers.
|
Auto-generate id attributes for HTML headers.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/header_id.html>
|
Basic usage:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright 2007-2011 [Waylan Limberg](http://achinghead.com/).
|
>>> import markdown
|
||||||
|
>>> text = "# Some Header #"
|
||||||
|
>>> md = markdown.markdown(text, ['headerid'])
|
||||||
|
>>> print md
|
||||||
|
<h1 id="some-header">Some Header</h1>
|
||||||
|
|
||||||
All changes Copyright 2011-2014 The Python Markdown Project
|
All header IDs are unique:
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
>>> text = '''
|
||||||
|
... #Header
|
||||||
|
... #Header
|
||||||
|
... #Header'''
|
||||||
|
>>> md = markdown.markdown(text, ['headerid'])
|
||||||
|
>>> print md
|
||||||
|
<h1 id="header">Header</h1>
|
||||||
|
<h1 id="header_1">Header</h1>
|
||||||
|
<h1 id="header_2">Header</h1>
|
||||||
|
|
||||||
|
To fit within a html template's hierarchy, set the header base level:
|
||||||
|
|
||||||
|
>>> text = '''
|
||||||
|
... #Some Header
|
||||||
|
... ## Next Level'''
|
||||||
|
>>> md = markdown.markdown(text, ['headerid(level=3)'])
|
||||||
|
>>> print md
|
||||||
|
<h3 id="some-header">Some Header</h3>
|
||||||
|
<h4 id="next-level">Next Level</h4>
|
||||||
|
|
||||||
|
Works with inline markup.
|
||||||
|
|
||||||
|
>>> text = '#Some *Header* with [markup](http://example.com).'
|
||||||
|
>>> md = markdown.markdown(text, ['headerid'])
|
||||||
|
>>> print md
|
||||||
|
<h1 id="some-header-with-markup">Some <em>Header</em> with <a href="http://example.com">markup</a>.</h1>
|
||||||
|
|
||||||
|
Turn off auto generated IDs:
|
||||||
|
|
||||||
|
>>> text = '''
|
||||||
|
... # Some Header
|
||||||
|
... # Another Header'''
|
||||||
|
>>> md = markdown.markdown(text, ['headerid(forceid=False)'])
|
||||||
|
>>> print md
|
||||||
|
<h1>Some Header</h1>
|
||||||
|
<h1>Another Header</h1>
|
||||||
|
|
||||||
|
Use with MetaData extension:
|
||||||
|
|
||||||
|
>>> text = '''header_level: 2
|
||||||
|
... header_forceid: Off
|
||||||
|
...
|
||||||
|
... # A Header'''
|
||||||
|
>>> md = markdown.markdown(text, ['headerid', 'meta'])
|
||||||
|
>>> print md
|
||||||
|
<h2>A Header</h2>
|
||||||
|
|
||||||
|
Copyright 2007-2011 [Waylan Limberg](http://achinghead.com/).
|
||||||
|
|
||||||
|
Project website: <http://packages.python.org/Markdown/extensions/header_id.html>
|
||||||
|
Contact: markdown@freewisdom.org
|
||||||
|
|
||||||
|
License: BSD (see ../docs/LICENSE for details)
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
* [Python 2.3+](http://python.org)
|
||||||
|
* [Markdown 2.0+](http://packages.python.org/Markdown/)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -68,7 +127,7 @@ def stashedHTML2text(text, md):
|
|||||||
def _html_sub(m):
|
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:
|
||||||
@@ -117,7 +176,7 @@ class HeaderIdTreeprocessor(Treeprocessor):
|
|||||||
|
|
||||||
|
|
||||||
class HeaderIdExtension(Extension):
|
class HeaderIdExtension(Extension):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, configs):
|
||||||
# set defaults
|
# set defaults
|
||||||
self.config = {
|
self.config = {
|
||||||
'level' : ['1', 'Base level for headers.'],
|
'level' : ['1', 'Base level for headers.'],
|
||||||
@@ -126,7 +185,8 @@ class HeaderIdExtension(Extension):
|
|||||||
'slugify' : [slugify, 'Callable to generate anchors'],
|
'slugify' : [slugify, 'Callable to generate anchors'],
|
||||||
}
|
}
|
||||||
|
|
||||||
super(HeaderIdExtension, self).__init__(*args, **kwargs)
|
for key, value in configs:
|
||||||
|
self.setConfig(key, value)
|
||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
md.registerExtension(self)
|
md.registerExtension(self)
|
||||||
@@ -144,6 +204,5 @@ class HeaderIdExtension(Extension):
|
|||||||
self.processor.IDs = set()
|
self.processor.IDs = set()
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs=None):
|
||||||
return HeaderIdExtension(*args, **kwargs)
|
return HeaderIdExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,38 @@ Meta Data Extension for Python-Markdown
|
|||||||
|
|
||||||
This extension adds Meta Data handling to markdown.
|
This extension adds Meta Data handling to markdown.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/meta_data.html>
|
Basic Usage:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
|
>>> import markdown
|
||||||
|
>>> text = '''Title: A Test Doc.
|
||||||
|
... Author: Waylan Limberg
|
||||||
|
... John Doe
|
||||||
|
... Blank_Data:
|
||||||
|
...
|
||||||
|
... The body. This is paragraph one.
|
||||||
|
... '''
|
||||||
|
>>> md = markdown.Markdown(['meta'])
|
||||||
|
>>> print md.convert(text)
|
||||||
|
<p>The body. This is paragraph one.</p>
|
||||||
|
>>> print md.Meta
|
||||||
|
{u'blank_data': [u''], u'author': [u'Waylan Limberg', u'John Doe'], u'title': [u'A Test Doc.']}
|
||||||
|
|
||||||
All changes Copyright 2008-2014 The Python Markdown Project
|
Make sure text without Meta Data still works (markdown < 1.6b returns a <p>).
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
>>> text = ' Some Code - not extra lines of meta data.'
|
||||||
|
>>> md = markdown.Markdown(['meta'])
|
||||||
|
>>> print md.convert(text)
|
||||||
|
<pre><code>Some Code - not extra lines of meta data.
|
||||||
|
</code></pre>
|
||||||
|
>>> md.Meta
|
||||||
|
{}
|
||||||
|
|
||||||
|
Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
|
||||||
|
|
||||||
|
Project website: <http://packages.python.org/Markdown/meta_data.html>
|
||||||
|
Contact: markdown@freewisdom.org
|
||||||
|
|
||||||
|
License: BSD (see ../LICENSE.md for details)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -31,7 +55,7 @@ class MetaExtension (Extension):
|
|||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
""" Add MetaPreprocessor to Markdown instance. """
|
""" Add MetaPreprocessor to Markdown instance. """
|
||||||
|
|
||||||
md.preprocessors.add("meta", MetaPreprocessor(md), ">normalize_whitespace")
|
md.preprocessors.add("meta", MetaPreprocessor(md), "_begin")
|
||||||
|
|
||||||
|
|
||||||
class MetaPreprocessor(Preprocessor):
|
class MetaPreprocessor(Preprocessor):
|
||||||
@@ -65,6 +89,5 @@ class MetaPreprocessor(Preprocessor):
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return MetaExtension(*args, **kwargs)
|
return MetaExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,18 @@ 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.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/nl2br.html>
|
Usage:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Oringinal code Copyright 2011 [Brian Neal](http://deathofagremmie.com/)
|
>>> import markdown
|
||||||
|
>>> print markdown.markdown('line 1\\nline 2', extensions=['nl2br'])
|
||||||
|
<p>line 1<br />
|
||||||
|
line 2</p>
|
||||||
|
|
||||||
All changes Copyright 2011-2014 The Python Markdown Project
|
Copyright 2011 [Brian Neal](http://deathofagremmie.com/)
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
Dependencies:
|
||||||
|
* [Python 2.4+](http://python.org)
|
||||||
|
* [Markdown 2.1+](http://packages.python.org/Markdown/)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -30,6 +34,5 @@ class Nl2BrExtension(Extension):
|
|||||||
md.inlinePatterns.add('nl', br_tag, '_end')
|
md.inlinePatterns.add('nl', br_tag, '_end')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs=None):
|
||||||
return Nl2BrExtension(*args, **kwargs)
|
return Nl2BrExtension(configs)
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,19 @@
|
|||||||
Sane List Extension for Python-Markdown
|
Sane List Extension for Python-Markdown
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
Modify the behavior of Lists in Python-Markdown to act in a sane manor.
|
Modify the behavior of Lists in Python-Markdown t act in a sane manor.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/sane_lists.html>
|
In standard Markdown syntax, the following would constitute a single
|
||||||
for documentation.
|
ordered list. However, with this extension, the output would include
|
||||||
|
two lists, the first an ordered list and the second and unordered list.
|
||||||
|
|
||||||
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com)
|
1. ordered
|
||||||
|
2. list
|
||||||
|
|
||||||
All changes Copyright 2011-2014 The Python Markdown Project
|
* unordered
|
||||||
|
* list
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
Copyright 2011 - [Waylan Limberg](http://achinghead.com)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -43,6 +46,6 @@ class SaneListExtension(Extension):
|
|||||||
md.parser.blockprocessors['ulist'] = SaneUListProcessor(md.parser)
|
md.parser.blockprocessors['ulist'] = SaneUListProcessor(md.parser)
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return SaneListExtension(*args, **kwargs)
|
return SaneListExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,21 @@ 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.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/smart_strong.html>
|
Simple Usage:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright 2011 [Waylan Limberg](http://achinghead.com)
|
>>> import markdown
|
||||||
|
>>> print markdown.markdown('Text with double__underscore__words.',
|
||||||
|
... extensions=['smart_strong'])
|
||||||
|
<p>Text with double__underscore__words.</p>
|
||||||
|
>>> print markdown.markdown('__Strong__ still works.',
|
||||||
|
... extensions=['smart_strong'])
|
||||||
|
<p><strong>Strong</strong> still works.</p>
|
||||||
|
>>> print markdown.markdown('__this__works__too__.',
|
||||||
|
... extensions=['smart_strong'])
|
||||||
|
<p><strong>this__works__too</strong>.</p>
|
||||||
|
|
||||||
All changes Copyright 2011-2014 The Python Markdown Project
|
Copyright 2011
|
||||||
|
[Waylan Limberg](http://achinghead.com)
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -31,5 +38,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(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return SmartEmphasisExtension(*args, **kwargs)
|
return SmartEmphasisExtension(configs=dict(configs))
|
||||||
|
|||||||
@@ -1,91 +1,73 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
'''
|
# Smarty extension for Python-Markdown
|
||||||
Smarty extension for Python-Markdown
|
# Author: 2013, Dmitry Shachnev <mitya57@gmail.com>
|
||||||
====================================
|
|
||||||
|
|
||||||
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.
|
||||||
@@ -101,25 +83,12 @@ openingQuotesBase = (
|
|||||||
'|&[mn]dash;' # or named dash entities
|
'|&[mn]dash;' # or named dash entities
|
||||||
'|–|—' # or decimal entities
|
'|–|—' # or decimal entities
|
||||||
')'
|
')'
|
||||||
)
|
)
|
||||||
|
|
||||||
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>
|
||||||
@@ -144,6 +113,8 @@ 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. """
|
||||||
@@ -161,56 +132,35 @@ class SubstituteTextPattern(HtmlPattern):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
class SmartyExtension(Extension):
|
class SmartyExtension(Extension):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, configs):
|
||||||
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'],
|
|
||||||
}
|
}
|
||||||
super(SmartyExtension, self).__init__(*args, **kwargs)
|
for key, value in configs:
|
||||||
self.substitutions = dict(substitutions)
|
self.setConfig(key, parseBoolValue(value))
|
||||||
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 '_begin')
|
after = ('>smarty-%s-%d' % (serie, ind - 1) if ind else '>entity')
|
||||||
name = 'smarty-%s-%d' % (serie, ind)
|
name = 'smarty-%s-%d' % (serie, ind)
|
||||||
self.inlinePatterns.add(name, pattern, after)
|
md.inlinePatterns.add(name, pattern, after)
|
||||||
|
|
||||||
def educateDashes(self, md):
|
def educateDashes(self, md):
|
||||||
emDashesPattern = SubstituteTextPattern(r'(?<!-)---(?!-)',
|
emDashesPattern = SubstituteTextPattern(r'(?<!-)---(?!-)', ('—',), md)
|
||||||
(self.substitutions['mdash'],), md)
|
enDashesPattern = SubstituteTextPattern(r'(?<!-)--(?!-)', ('–',), md)
|
||||||
enDashesPattern = SubstituteTextPattern(r'(?<!-)--(?!-)',
|
md.inlinePatterns.add('smarty-em-dashes', emDashesPattern, '>entity')
|
||||||
(self.substitutions['ndash'],), md)
|
md.inlinePatterns.add('smarty-en-dashes', enDashesPattern,
|
||||||
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}(?!\.)',
|
ellipsesPattern = SubstituteTextPattern(r'(?<!\.)\.{3}(?!\.)', ('…',), md)
|
||||||
(self.substitutions['ellipsis'],), md)
|
md.inlinePatterns.add('smarty-ellipses', ellipsesPattern, '>entity')
|
||||||
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,)),
|
||||||
@@ -229,19 +179,13 @@ class SmartyExtension(Extension):
|
|||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
configs = self.getConfigs()
|
configs = self.getConfigs()
|
||||||
self.inlinePatterns = OrderedDict()
|
|
||||||
if configs['smart_ellipses']:
|
|
||||||
self.educateEllipses(md)
|
|
||||||
if configs['smart_quotes']:
|
if configs['smart_quotes']:
|
||||||
self.educateQuotes(md)
|
self.educateQuotes(md)
|
||||||
if configs['smart_angled_quotes']:
|
|
||||||
self.educateAngledQuotes(md)
|
|
||||||
if configs['smart_dashes']:
|
if configs['smart_dashes']:
|
||||||
self.educateDashes(md)
|
self.educateDashes(md)
|
||||||
inlineProcessor = InlineProcessor(md)
|
if configs['smart_ellipses']:
|
||||||
inlineProcessor.inlinePatterns = self.inlinePatterns
|
self.educateEllipses(md)
|
||||||
md.treeprocessors.add('smarty', inlineProcessor, '_end')
|
|
||||||
md.ESCAPED_CHARS.extend(['"', "'"])
|
md.ESCAPED_CHARS.extend(['"', "'"])
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs=None):
|
||||||
return SmartyExtension(*args, **kwargs)
|
return SmartyExtension(configs)
|
||||||
|
|||||||
@@ -4,15 +4,14 @@ Tables Extension for Python-Markdown
|
|||||||
|
|
||||||
Added parsing of tables to Python-Markdown.
|
Added parsing of tables to Python-Markdown.
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/tables.html>
|
A simple example:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright 2009 [Waylan Limberg](http://achinghead.com)
|
First Header | Second Header
|
||||||
|
------------- | -------------
|
||||||
All changes Copyright 2008-2014 The Python Markdown Project
|
Content Cell | Content Cell
|
||||||
|
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
|
||||||
@@ -72,7 +71,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: #pragma: no cover
|
except IndexError:
|
||||||
c.text = ""
|
c.text = ""
|
||||||
if a:
|
if a:
|
||||||
c.set('align', a)
|
c.set('align', a)
|
||||||
@@ -97,6 +96,5 @@ class TableExtension(Extension):
|
|||||||
'<hashheader')
|
'<hashheader')
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return TableExtension(*args, **kwargs)
|
return TableExtension(configs=configs)
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
"""
|
"""
|
||||||
Table of Contents Extension for Python-Markdown
|
Table of Contents Extension for Python-Markdown
|
||||||
===============================================
|
* * *
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/toc.html>
|
(c) 2008 [Jack Miller](http://codezen.org)
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Oringinal code Copyright 2008 [Jack Miller](http://codezen.org)
|
Dependencies:
|
||||||
|
* [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)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -27,59 +23,60 @@ def order_toc_list(toc_list):
|
|||||||
[{'level': 1}, {'level': 2}]
|
[{'level': 1}, {'level': 2}]
|
||||||
=>
|
=>
|
||||||
[{'level': 1, 'children': [{'level': 2, 'children': []}]}]
|
[{'level': 1, 'children': [{'level': 2, 'children': []}]}]
|
||||||
|
|
||||||
A wrong list is also converted:
|
A wrong list is also converted:
|
||||||
[{'level': 2}, {'level': 1}]
|
[{'level': 2}, {'level': 1}]
|
||||||
=>
|
=>
|
||||||
[{'level': 2, 'children': []}, {'level': 1, 'children': []}]
|
[{'level': 2, 'children': []}, {'level': 1, 'children': []}]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ordered_list = []
|
def build_correct(remaining_list, prev_elements=[{'level': 1000}]):
|
||||||
if len(toc_list):
|
|
||||||
# Initialize everything by processing the first entry
|
if not remaining_list:
|
||||||
last = toc_list.pop(0)
|
return [], []
|
||||||
last['children'] = []
|
|
||||||
levels = [last['level']]
|
current = remaining_list.pop(0)
|
||||||
ordered_list.append(last)
|
if not 'children' in current.keys():
|
||||||
parents = []
|
current['children'] = []
|
||||||
|
|
||||||
# Walk the rest nesting the entries properly
|
if not prev_elements:
|
||||||
while toc_list:
|
# This happens for instance with [8, 1, 1], ie. when some
|
||||||
t = toc_list.pop(0)
|
# header level is outside a scope. We treat it as a
|
||||||
current_level = t['level']
|
# top-level
|
||||||
t['children'] = []
|
next_elements, children = build_correct(remaining_list, [current])
|
||||||
|
current['children'].append(children)
|
||||||
# Reduce depth if current level < last item's level
|
return [current] + next_elements, []
|
||||||
if current_level < levels[-1]:
|
|
||||||
# Pop last level since we know we are less than it
|
prev_element = prev_elements.pop()
|
||||||
levels.pop()
|
children = []
|
||||||
|
next_elements = []
|
||||||
# Pop parents and levels we are less than or equal to
|
# Is current part of the child list or next list?
|
||||||
to_pop = 0
|
if current['level'] > prev_element['level']:
|
||||||
for p in reversed(parents):
|
#print "%d is a child of %d" % (current['level'], prev_element['level'])
|
||||||
if current_level <= p['level']:
|
prev_elements.append(prev_element)
|
||||||
to_pop += 1
|
prev_elements.append(current)
|
||||||
else:
|
prev_element['children'].append(current)
|
||||||
break
|
next_elements2, children2 = build_correct(remaining_list, prev_elements)
|
||||||
if to_pop:
|
children += children2
|
||||||
levels = levels[:-to_pop]
|
next_elements += next_elements2
|
||||||
parents = parents[:-to_pop]
|
else:
|
||||||
|
#print "%d is ancestor of %d" % (current['level'], prev_element['level'])
|
||||||
# Note current level as last
|
if not prev_elements:
|
||||||
levels.append(current_level)
|
#print "No previous elements, so appending to the next set"
|
||||||
|
next_elements.append(current)
|
||||||
# Level is the same, so append to the current parent (if available)
|
prev_elements = [current]
|
||||||
if current_level == levels[-1]:
|
next_elements2, children2 = build_correct(remaining_list, prev_elements)
|
||||||
(parents[-1]['children'] if parents else ordered_list).append(t)
|
current['children'].extend(children2)
|
||||||
|
|
||||||
# Current level is > last item's level,
|
|
||||||
# So make last item a parent and append current as child
|
|
||||||
else:
|
else:
|
||||||
last['children'].append(t)
|
#print "Previous elements, comparing to those first"
|
||||||
parents.append(last)
|
remaining_list.insert(0, current)
|
||||||
levels.append(current_level)
|
next_elements2, children2 = build_correct(remaining_list, prev_elements)
|
||||||
last = t
|
children.extend(children2)
|
||||||
|
next_elements += next_elements2
|
||||||
|
|
||||||
|
return next_elements, children
|
||||||
|
|
||||||
|
ordered_list, __ = build_correct(toc_list)
|
||||||
return ordered_list
|
return ordered_list
|
||||||
|
|
||||||
|
|
||||||
@@ -207,26 +204,26 @@ class TocExtension(Extension):
|
|||||||
|
|
||||||
TreeProcessorClass = TocTreeprocessor
|
TreeProcessorClass = TocTreeprocessor
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, configs=[]):
|
||||||
self.config = {
|
self.config = { "marker" : ["[TOC]",
|
||||||
"marker" : ["[TOC]",
|
"Text to find and replace with Table of Contents -"
|
||||||
"Text to find and replace with Table of Contents - "
|
"Defaults to \"[TOC]\""],
|
||||||
"Defaults to \"[TOC]\""],
|
"slugify" : [slugify,
|
||||||
"slugify" : [slugify,
|
"Function to generate anchors based on header text-"
|
||||||
"Function to generate anchors based on header text - "
|
"Defaults to the headerid ext's slugify function."],
|
||||||
"Defaults to the headerid ext's slugify function."],
|
"title" : [None,
|
||||||
"title" : ["",
|
"Title to insert into TOC <div> - "
|
||||||
"Title to insert into TOC <div> - "
|
"Defaults to None"],
|
||||||
"Defaults to an empty string"],
|
"anchorlink" : [0,
|
||||||
"anchorlink" : [0,
|
"1 if header should be a self link"
|
||||||
"1 if header should be a self link - "
|
"Defaults to 0"],
|
||||||
"Defaults to 0"],
|
"permalink" : [0,
|
||||||
"permalink" : [0,
|
"1 or link text if a Sphinx-style permalink should be added",
|
||||||
"1 or link text if a Sphinx-style permalink should be added - "
|
"Defaults to 0"]
|
||||||
"Defaults to 0"]
|
}
|
||||||
}
|
|
||||||
|
|
||||||
super(TocExtension, self).__init__(*args, **kwargs)
|
for key, value in configs:
|
||||||
|
self.setConfig(key, value)
|
||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
tocext = self.TreeProcessorClass(md)
|
tocext = self.TreeProcessorClass(md)
|
||||||
@@ -239,5 +236,5 @@ class TocExtension(Extension):
|
|||||||
md.treeprocessors.add("toc", tocext, "_end")
|
md.treeprocessors.add("toc", tocext, "_end")
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs):
|
def makeExtension(configs={}):
|
||||||
return TocExtension(*args, **kwargs)
|
return TocExtension(configs=configs)
|
||||||
|
|||||||
@@ -2,17 +2,78 @@
|
|||||||
WikiLinks Extension for Python-Markdown
|
WikiLinks Extension for Python-Markdown
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
Converts [[WikiLinks]] to relative links.
|
Converts [[WikiLinks]] to relative links. Requires Python-Markdown 2.0+
|
||||||
|
|
||||||
See <https://pythonhosted.org/Markdown/extensions/wikilinks.html>
|
Basic usage:
|
||||||
for documentation.
|
|
||||||
|
|
||||||
Original code Copyright [Waylan Limberg](http://achinghead.com/).
|
>>> import markdown
|
||||||
|
>>> text = "Some text with a [[WikiLink]]."
|
||||||
|
>>> html = markdown.markdown(text, ['wikilinks'])
|
||||||
|
>>> print html
|
||||||
|
<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>
|
||||||
|
|
||||||
All changes Copyright The Python Markdown Project
|
Whitespace behavior:
|
||||||
|
|
||||||
|
>>> print markdown.markdown('[[ foo bar_baz ]]', ['wikilinks'])
|
||||||
|
<p><a class="wikilink" href="/foo_bar_baz/">foo bar_baz</a></p>
|
||||||
|
>>> print markdown.markdown('foo [[ ]] bar', ['wikilinks'])
|
||||||
|
<p>foo bar</p>
|
||||||
|
|
||||||
|
To define custom settings the simple way:
|
||||||
|
|
||||||
|
>>> print markdown.markdown(text,
|
||||||
|
... ['wikilinks(base_url=/wiki/,end_url=.html,html_class=foo)']
|
||||||
|
... )
|
||||||
|
<p>Some text with a <a class="foo" href="/wiki/WikiLink.html">WikiLink</a>.</p>
|
||||||
|
|
||||||
|
Custom settings the complex way:
|
||||||
|
|
||||||
|
>>> md = markdown.Markdown(
|
||||||
|
... extensions = ['wikilinks'],
|
||||||
|
... extension_configs = {'wikilinks': [
|
||||||
|
... ('base_url', 'http://example.com/'),
|
||||||
|
... ('end_url', '.html'),
|
||||||
|
... ('html_class', '') ]},
|
||||||
|
... safe_mode = True)
|
||||||
|
>>> print md.convert(text)
|
||||||
|
<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>
|
||||||
|
|
||||||
|
Use MetaData with mdx_meta.py (Note the blank html_class in MetaData):
|
||||||
|
|
||||||
|
>>> text = """wiki_base_url: http://example.com/
|
||||||
|
... wiki_end_url: .html
|
||||||
|
... wiki_html_class:
|
||||||
|
...
|
||||||
|
... Some text with a [[WikiLink]]."""
|
||||||
|
>>> md = markdown.Markdown(extensions=['meta', 'wikilinks'])
|
||||||
|
>>> print md.convert(text)
|
||||||
|
<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>
|
||||||
|
|
||||||
|
MetaData should not carry over to next document:
|
||||||
|
|
||||||
|
>>> print md.convert("No [[MetaData]] here.")
|
||||||
|
<p>No <a class="wikilink" href="/MetaData/">MetaData</a> here.</p>
|
||||||
|
|
||||||
|
Define a custom URL builder:
|
||||||
|
|
||||||
|
>>> def my_url_builder(label, base, end):
|
||||||
|
... return '/bar/'
|
||||||
|
>>> md = markdown.Markdown(extensions=['wikilinks'],
|
||||||
|
... extension_configs={'wikilinks' : [('build_url', my_url_builder)]})
|
||||||
|
>>> print md.convert('[[foo]]')
|
||||||
|
<p><a class="wikilink" href="/bar/">foo</a></p>
|
||||||
|
|
||||||
|
From the command line:
|
||||||
|
|
||||||
|
python markdown.py -x wikilinks(base_url=http://example.com/,end_url=.html,html_class=foo) src.txt
|
||||||
|
|
||||||
|
By [Waylan Limberg](http://achinghead.com/).
|
||||||
|
|
||||||
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
|
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
|
||||||
@@ -29,17 +90,19 @@ def build_url(label, base, end):
|
|||||||
|
|
||||||
|
|
||||||
class WikiLinkExtension(Extension):
|
class WikiLinkExtension(Extension):
|
||||||
|
def __init__(self, configs):
|
||||||
def __init__ (self, *args, **kwargs):
|
# set extension defaults
|
||||||
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
|
||||||
|
for key, value in configs.items():
|
||||||
|
self.setConfig(key, value)
|
||||||
|
|
||||||
super(WikiLinkExtension, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def extendMarkdown(self, md, md_globals):
|
def extendMarkdown(self, md, md_globals):
|
||||||
self.md = md
|
self.md = md
|
||||||
|
|
||||||
@@ -84,5 +147,5 @@ class WikiLinks(Pattern):
|
|||||||
return base_url, end_url, html_class
|
return base_url, end_url, html_class
|
||||||
|
|
||||||
|
|
||||||
def makeExtension(*args, **kwargs) :
|
def makeExtension(configs=None) :
|
||||||
return WikiLinkExtension(*args, **kwargs)
|
return WikiLinkExtension(configs=configs)
|
||||||
|
|||||||
@@ -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: #pragma: no cover
|
try:
|
||||||
from urllib.parse import urlparse, urlunparse
|
from urllib.parse import urlparse, urlunparse
|
||||||
except ImportError: #pragma: no cover
|
except ImportError:
|
||||||
from urlparse import urlparse, urlunparse
|
from urlparse import urlparse, urlunparse
|
||||||
try: #pragma: no cover
|
try:
|
||||||
from html import entities
|
from html import entities
|
||||||
except ImportError: #pragma: no cover
|
except ImportError:
|
||||||
import htmlentitydefs as entities
|
import htmlentitydefs as entities
|
||||||
|
|
||||||
|
|
||||||
@@ -75,8 +75,7 @@ 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["em_strong"] = DoubleTagPattern(EM_STRONG_RE, 'strong,em')
|
inlinePatterns["strong_em"] = DoubleTagPattern(STRONG_EM_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:
|
||||||
@@ -101,8 +100,7 @@ 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**
|
||||||
EM_STRONG_RE = r'(\*|_)\2{2}(.+?)\2(.*?)\2{2}' # ***strongem*** or ***em*strong**
|
STRONG_EM_RE = r'(\*{3}|_{3})(.+?)\2' # ***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 + \
|
||||||
@@ -158,7 +156,7 @@ class Pattern(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
self.pattern = pattern
|
self.pattern = pattern
|
||||||
self.compiled_re = re.compile("^(.*?)%s(.*?)$" % pattern,
|
self.compiled_re = re.compile("^(.*?)%s(.*?)$" % pattern,
|
||||||
re.DOTALL | re.UNICODE)
|
re.DOTALL | re.UNICODE)
|
||||||
|
|
||||||
# Api for Markdown to pass safe_mode into instance
|
# Api for Markdown to pass safe_mode into instance
|
||||||
@@ -180,7 +178,7 @@ class Pattern(object):
|
|||||||
* m: A re match object containing a match of the pattern.
|
* m: A re match object containing a match of the pattern.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass #pragma: no cover
|
pass
|
||||||
|
|
||||||
def type(self):
|
def type(self):
|
||||||
""" Return class name, to define pattern type """
|
""" Return class name, to define pattern type """
|
||||||
@@ -190,9 +188,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: #pragma: no cover
|
except KeyError:
|
||||||
return text
|
return text
|
||||||
def itertext(el): #pragma: no cover
|
def itertext(el):
|
||||||
' 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:
|
||||||
@@ -212,14 +210,17 @@ class Pattern(object):
|
|||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
# An etree Element - return text content only
|
# An etree Element - return text content only
|
||||||
return ''.join(itertext(value))
|
return ''.join(itertext(value))
|
||||||
return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
|
return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
return m.group(2)
|
text = m.group(2)
|
||||||
|
if text == util.INLINE_PLACEHOLDER_PREFIX:
|
||||||
|
return None
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
class EscapePattern(Pattern):
|
class EscapePattern(Pattern):
|
||||||
@@ -230,7 +231,7 @@ class EscapePattern(Pattern):
|
|||||||
if char in self.markdown.ESCAPED_CHARS:
|
if char in self.markdown.ESCAPED_CHARS:
|
||||||
return '%s%s%s' % (util.STX, ord(char), util.ETX)
|
return '%s%s%s' % (util.STX, ord(char), util.ETX)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class SimpleTagPattern(Pattern):
|
class SimpleTagPattern(Pattern):
|
||||||
@@ -278,8 +279,6 @@ 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
|
||||||
|
|
||||||
|
|
||||||
@@ -294,7 +293,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: #pragma: no cover
|
except KeyError:
|
||||||
return text
|
return text
|
||||||
def get_stash(m):
|
def get_stash(m):
|
||||||
id = m.group(1)
|
id = m.group(1)
|
||||||
@@ -304,7 +303,7 @@ class HtmlPattern(Pattern):
|
|||||||
return self.markdown.serializer(value)
|
return self.markdown.serializer(value)
|
||||||
except:
|
except:
|
||||||
return '\%s' % value
|
return '\%s' % value
|
||||||
|
|
||||||
return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
|
return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
|
||||||
|
|
||||||
|
|
||||||
@@ -324,7 +323,7 @@ class LinkPattern(Pattern):
|
|||||||
el.set("href", "")
|
el.set("href", "")
|
||||||
|
|
||||||
if title:
|
if title:
|
||||||
title = dequote(self.unescape(title))
|
title = dequote(self.unescape(title))
|
||||||
el.set("title", title)
|
el.set("title", title)
|
||||||
return el
|
return el
|
||||||
|
|
||||||
@@ -348,20 +347,20 @@ class LinkPattern(Pattern):
|
|||||||
if not self.markdown.safeMode:
|
if not self.markdown.safeMode:
|
||||||
# Return immediately bipassing parsing.
|
# Return immediately bipassing parsing.
|
||||||
return url
|
return url
|
||||||
|
|
||||||
try:
|
try:
|
||||||
scheme, netloc, path, params, query, fragment = url = urlparse(url)
|
scheme, netloc, path, params, query, fragment = url = urlparse(url)
|
||||||
except ValueError: #pragma: no cover
|
except ValueError:
|
||||||
# Bad url - so bad it couldn't be parsed.
|
# Bad url - so bad it couldn't be parsed.
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
locless_schemes = ['', 'mailto', 'news']
|
locless_schemes = ['', 'mailto', 'news']
|
||||||
allowed_schemes = locless_schemes + ['http', 'https', 'ftp', 'ftps']
|
allowed_schemes = locless_schemes + ['http', 'https', 'ftp', 'ftps']
|
||||||
if scheme not in allowed_schemes:
|
if scheme not in allowed_schemes:
|
||||||
# Not a known (allowed) scheme. Not safe.
|
# Not a known (allowed) scheme. Not safe.
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
if netloc == '' and scheme not in locless_schemes: #pragma: no cover
|
if netloc == '' and scheme not in locless_schemes:
|
||||||
# This should not happen. Treat as suspect.
|
# 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: #pragma: no cover
|
if util.PY3:
|
||||||
items = _iteritems
|
items = _iteritems
|
||||||
keys = _iterkeys
|
keys = _iterkeys
|
||||||
values = _itervalues
|
values = _itervalues
|
||||||
else: #pragma: no cover
|
else:
|
||||||
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 #pragma: no cover
|
pass
|
||||||
|
|
||||||
|
|
||||||
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 #pragma: no cover
|
pass
|
||||||
|
|
||||||
|
|
||||||
class NormalizeWhitespace(Preprocessor):
|
class NormalizeWhitespace(Preprocessor):
|
||||||
@@ -174,10 +174,9 @@ 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 + offset]))
|
items[i:right_listindex + 1]))
|
||||||
del items[i:right_listindex + offset]
|
del items[i:right_listindex + 1]
|
||||||
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'): #pragma: no cover
|
if hasattr(util.etree, 'test_comment'):
|
||||||
Comment = util.etree.test_comment
|
Comment = util.etree.test_comment
|
||||||
else: #pragma: no cover
|
else:
|
||||||
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: #pragma: no cover
|
except NameError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_namespace_map = {
|
_namespace_map = {
|
||||||
@@ -73,7 +73,7 @@ _namespace_map = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _raise_serialization_error(text): #pragma: no cover
|
def _raise_serialization_error(text):
|
||||||
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): #pragma: no cover
|
|||||||
def _encode(text, encoding):
|
def _encode(text, encoding):
|
||||||
try:
|
try:
|
||||||
return text.encode(encoding, "xmlcharrefreplace")
|
return text.encode(encoding, "xmlcharrefreplace")
|
||||||
except (TypeError, AttributeError): #pragma: no cover
|
except (TypeError, AttributeError):
|
||||||
_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): #pragma: no cover
|
except (TypeError, AttributeError):
|
||||||
_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): #pragma: no cover
|
except (TypeError, AttributeError):
|
||||||
_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): #pragma: no cover
|
except (TypeError, AttributeError):
|
||||||
_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: #pragma: no cover
|
except TypeError:
|
||||||
_raise_serialization_error(qname)
|
_raise_serialization_error(qname)
|
||||||
|
|
||||||
# populate qname and namespaces table
|
# populate qname and namespaces table
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ class Treeprocessor(util.Processor):
|
|||||||
def run(self, root):
|
def run(self, root):
|
||||||
"""
|
"""
|
||||||
Subclasses of Treeprocessor should implement a `run` method, which
|
Subclasses of Treeprocessor should implement a `run` method, which
|
||||||
takes a root ElementTree. This method can return another ElementTree
|
takes a root ElementTree. This method can return another ElementTree
|
||||||
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 #pragma: no cover
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InlineProcessor(Treeprocessor):
|
class InlineProcessor(Treeprocessor):
|
||||||
@@ -53,7 +53,6 @@ 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 """
|
||||||
@@ -71,7 +70,7 @@ class InlineProcessor(Treeprocessor):
|
|||||||
* index: index, from which we start search
|
* index: index, from which we start search
|
||||||
|
|
||||||
Returns: placeholder id and string index, after the found placeholder.
|
Returns: placeholder id and string index, after the found placeholder.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
m = self.__placeholder_re.search(data, index)
|
m = self.__placeholder_re.search(data, index)
|
||||||
if m:
|
if m:
|
||||||
@@ -100,9 +99,9 @@ class InlineProcessor(Treeprocessor):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(data, util.AtomicString):
|
if not isinstance(data, util.AtomicString):
|
||||||
startIndex = 0
|
startIndex = 0
|
||||||
while patternIndex < len(self.inlinePatterns):
|
while patternIndex < len(self.markdown.inlinePatterns):
|
||||||
data, matched, startIndex = self.__applyPattern(
|
data, matched, startIndex = self.__applyPattern(
|
||||||
self.inlinePatterns.value_for_index(patternIndex),
|
self.markdown.inlinePatterns.value_for_index(patternIndex),
|
||||||
data, patternIndex, startIndex)
|
data, patternIndex, startIndex)
|
||||||
if not matched:
|
if not matched:
|
||||||
patternIndex += 1
|
patternIndex += 1
|
||||||
@@ -129,10 +128,11 @@ class InlineProcessor(Treeprocessor):
|
|||||||
text = subnode.tail
|
text = subnode.tail
|
||||||
subnode.tail = None
|
subnode.tail = None
|
||||||
|
|
||||||
childResult = self.__processPlaceholders(text, subnode, isText)
|
childResult = self.__processPlaceholders(text, subnode)
|
||||||
|
|
||||||
if not isText and node is not subnode:
|
if not isText and node is not subnode:
|
||||||
pos = list(node).index(subnode) + 1
|
pos = list(node).index(subnode)
|
||||||
|
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, isText=True):
|
def __processPlaceholders(self, data, parent):
|
||||||
"""
|
"""
|
||||||
Process string with placeholders and generate ElementTree tree.
|
Process string with placeholders and generate ElementTree tree.
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ class InlineProcessor(Treeprocessor):
|
|||||||
* parent: Element, which contains processing inline data
|
* parent: Element, which contains processing inline data
|
||||||
|
|
||||||
Returns: list with ElementTree elements with applied inline patterns.
|
Returns: list with ElementTree elements with applied inline patterns.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def linkText(text):
|
def linkText(text):
|
||||||
if text:
|
if text:
|
||||||
@@ -159,11 +159,6 @@ 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
|
||||||
@@ -187,7 +182,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)
|
||||||
@@ -244,7 +239,7 @@ class InlineProcessor(Treeprocessor):
|
|||||||
# We need to process current node too
|
# We need to process current node too
|
||||||
for child in [node] + list(node):
|
for child in [node] + list(node):
|
||||||
if not isString(node):
|
if not isString(node):
|
||||||
if child.text:
|
if child.text:
|
||||||
child.text = self.__handleInline(child.text,
|
child.text = self.__handleInline(child.text,
|
||||||
patternIndex + 1)
|
patternIndex + 1)
|
||||||
if child.tail:
|
if child.tail:
|
||||||
@@ -292,10 +287,11 @@ 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')
|
||||||
child.tail = None
|
tailResult = self.__processPlaceholders(tail, dumby)
|
||||||
tailResult = self.__processPlaceholders(tail, dumby, False)
|
if dumby.text:
|
||||||
if dumby.tail:
|
child.tail = dumby.text
|
||||||
child.tail = dumby.tail
|
else:
|
||||||
|
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:
|
||||||
@@ -307,7 +303,7 @@ class InlineProcessor(Treeprocessor):
|
|||||||
if self.markdown.enable_attributes:
|
if self.markdown.enable_attributes:
|
||||||
if element.text and isString(element.text):
|
if element.text and isString(element.text):
|
||||||
element.text = \
|
element.text = \
|
||||||
inlinepatterns.handleAttributes(element.text,
|
inlinepatterns.handleAttributes(element.text,
|
||||||
element)
|
element)
|
||||||
i = 0
|
i = 0
|
||||||
for newChild in lst:
|
for newChild in lst:
|
||||||
@@ -361,4 +357,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 = util.AtomicString(pre[0].text.rstrip() + '\n')
|
pre[0].text = 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: #pragma: no cover
|
if PY3:
|
||||||
string_type = str
|
string_type = str
|
||||||
text_type = str
|
text_type = str
|
||||||
int2str = chr
|
int2str = chr
|
||||||
else: #pragma: no cover
|
else:
|
||||||
string_type = basestring
|
string_type = basestring
|
||||||
text_type = unicode
|
text_type = unicode
|
||||||
int2str = unichr
|
int2str = unichr
|
||||||
@@ -58,15 +58,14 @@ 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: #pragma: no cover
|
try: # Is the C implementation of ElementTree available?
|
||||||
# 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): #pragma: no cover
|
except (ImportError, RuntimeError):
|
||||||
# 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":
|
||||||
@@ -86,20 +85,15 @@ 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, preserve_none=False):
|
def parseBoolValue(value, fail_on_errors=True):
|
||||||
"""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 preserve_none=True, returns True, False,
|
returns True or False. If parsing was not successful, raises
|
||||||
or None. If parsing was not successful, raises ValueError, or, if
|
ValueError, or, if fail_on_errors=False, returns None."""
|
||||||
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', 'none'):
|
elif value.lower() in ('false', 'no', 'n', 'off', '0'):
|
||||||
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