aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fabfile.py4
-rw-r--r--markdown/__init__.py50
-rw-r--r--markdown/blockparser.py7
-rw-r--r--markdown/blockprocessors.py32
-rw-r--r--markdown/etree_loader.py31
-rw-r--r--markdown/extensions/__init__.py7
-rw-r--r--markdown/extensions/abbr.py20
-rw-r--r--markdown/extensions/admonition.py15
-rw-r--r--markdown/extensions/attr_list.py15
-rw-r--r--markdown/extensions/codehilite.py13
-rw-r--r--markdown/extensions/def_list.py14
-rw-r--r--markdown/extensions/extra.py7
-rw-r--r--markdown/extensions/fenced_code.py20
-rw-r--r--markdown/extensions/footnotes.py27
-rw-r--r--markdown/extensions/headerid.py22
-rw-r--r--markdown/extensions/html_tidy.py14
-rw-r--r--markdown/extensions/meta.py17
-rw-r--r--markdown/extensions/nl2br.py10
-rw-r--r--markdown/extensions/sane_lists.py12
-rw-r--r--markdown/extensions/smart_strong.py12
-rw-r--r--markdown/extensions/tables.py12
-rw-r--r--markdown/extensions/toc.py13
-rw-r--r--markdown/extensions/wikilinks.py28
-rw-r--r--markdown/inlinepatterns.py30
-rw-r--r--markdown/odict.py102
-rw-r--r--markdown/postprocessors.py9
-rw-r--r--markdown/preprocessors.py6
-rw-r--r--markdown/serializers.py6
-rw-r--r--markdown/treeprocessors.py18
-rw-r--r--markdown/util.py46
-rwxr-xr-xsetup.py9
31 files changed, 324 insertions, 304 deletions
diff --git a/fabfile.py b/fabfile.py
index afd563c..58f21ba 100644
--- a/fabfile.py
+++ b/fabfile.py
@@ -55,10 +55,6 @@ def build_tests(version=_pyversion[:3]):
local('cp -r tests/* build/test.%s/tests' % version)
local('cp run-tests.py build/test.%s/run-tests.py' % version)
local('cp setup.cfg build/test.%s/setup.cfg' % version)
- if version.startswith('3'):
- # Do 2to3 conversion
- local('2to3-%s -w -d build/test.%s/markdown' % (version, version))
-
def generate_test(file):
""" Generate a given test. """
diff --git a/markdown/__init__.py b/markdown/__init__.py
index aceaf60..068e966 100644
--- a/markdown/__init__.py
+++ b/markdown/__init__.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
Python Markdown
===============
@@ -22,7 +23,7 @@ Limberg](http://achinghead.com/) and [Artem Yunusov](http://blog.splyer.com).
Contact: markdown@freewisdom.org
-Copyright 2007-2012 The Python Markdown Project (v. 1.7 and later)
+Copyright 2007-2013 The Python Markdown Project (v. 1.7 and later)
Copyright 200? Django Software Foundation (OrderedDict implementation)
Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
Copyright 2004 Manfred Stienstra (the original version)
@@ -30,26 +31,27 @@ Copyright 2004 Manfred Stienstra (the original version)
License: BSD (see LICENSE for details).
"""
-from __version__ import version, version_info
+from __future__ import absolute_import
+from .__version__ import version, version_info
import re
import codecs
import sys
import logging
-import util
-from preprocessors import build_preprocessors
-from blockprocessors import build_block_parser
-from treeprocessors import build_treeprocessors
-from inlinepatterns import build_inlinepatterns
-from postprocessors import build_postprocessors
-from extensions import Extension
-from serializers import to_html_string, to_xhtml_string
+from . import util
+from .preprocessors import build_preprocessors
+from .blockprocessors import build_block_parser
+from .treeprocessors import build_treeprocessors
+from .inlinepatterns import build_inlinepatterns
+from .postprocessors import build_postprocessors
+from .extensions import Extension
+from .serializers import to_html_string, to_xhtml_string
__all__ = ['Markdown', 'markdown', 'markdownFromFile']
logger = logging.getLogger('MARKDOWN')
-class Markdown:
+class Markdown(object):
"""Convert Markdown to HTML."""
doc_tag = "div" # Element used to wrap document - later removed
@@ -108,7 +110,7 @@ class Markdown:
pos = ['extensions', 'extension_configs', 'safe_mode', 'output_format']
c = 0
for arg in args:
- if not kwargs.has_key(pos[c]):
+ if pos[c] not in kwargs:
kwargs[pos[c]] = arg
c += 1
if c == len(pos):
@@ -120,7 +122,7 @@ class Markdown:
setattr(self, option, kwargs.get(option, default))
self.safeMode = kwargs.get('safe_mode', False)
- if self.safeMode and not kwargs.has_key('enable_attributes'):
+ if self.safeMode and 'enable_attributes' not in kwargs:
# Disable attributes in safeMode when not explicitly set
self.enable_attributes = False
@@ -158,7 +160,7 @@ class Markdown:
"""
for ext in extensions:
- if isinstance(ext, basestring):
+ if isinstance(ext, util.string_type):
ext = self.build_extension(ext, configs.get(ext, []))
if isinstance(ext, Extension):
ext.extendMarkdown(self, globals())
@@ -198,7 +200,7 @@ class Markdown:
module_name_old_style = '_'.join(['mdx', ext_name])
try: # Old style (mdx_<extension>)
module = __import__(module_name_old_style)
- except ImportError, e:
+ except ImportError as e:
message = "Failed loading extension '%s' from '%s' or '%s'" \
% (ext_name, module_name, module_name_old_style)
e.args = (message,) + e.args[1:]
@@ -208,7 +210,7 @@ class Markdown:
# function called makeExtension()
try:
return module.makeExtension(configs.items())
- except AttributeError, e:
+ except AttributeError as e:
message = e.args[0]
message = "Failed to initiate extension " \
"'%s': %s" % (ext_name, message)
@@ -238,7 +240,7 @@ class Markdown:
self.output_format = format.lower()
try:
self.serializer = self.output_formats[self.output_format]
- except KeyError, e:
+ except KeyError as e:
valid_formats = self.output_formats.keys()
valid_formats.sort()
message = 'Invalid Output Format: "%s". Use one of %s.' \
@@ -272,11 +274,11 @@ class Markdown:
# Fixup the source text
if not source.strip():
- return u"" # a blank unicode string
+ return '' # a blank unicode string
try:
- source = unicode(source)
- except UnicodeDecodeError, e:
+ source = util.text_type(source)
+ except UnicodeDecodeError as e:
# Customise error message while maintaining original trackback
e.reason += '. -- Note: Markdown only accepts unicode input!'
raise
@@ -341,7 +343,7 @@ class Markdown:
# Read the source
if input:
- if isinstance(input, str):
+ if isinstance(input, util.string_type):
input_file = codecs.open(input, mode="r", encoding=encoding)
else:
input_file = codecs.getreader(encoding)(input)
@@ -349,7 +351,7 @@ class Markdown:
input_file.close()
else:
text = sys.stdin.read()
- if not isinstance(text, unicode):
+ if not isinstance(text, util.text_type):
text = text.decode(encoding)
text = text.lstrip('\ufeff') # remove the byte-order mark
@@ -359,7 +361,7 @@ class Markdown:
# Write to file or stdout
if output:
- if isinstance(output, str):
+ if isinstance(output, util.string_type):
output_file = codecs.open(output, "w",
encoding=encoding,
errors="xmlcharrefreplace")
@@ -428,7 +430,7 @@ def markdownFromFile(*args, **kwargs):
pos = ['input', 'output', 'extensions', 'encoding']
c = 0
for arg in args:
- if not kwargs.has_key(pos[c]):
+ if pos[c] not in kwargs:
kwargs[pos[c]] = arg
c += 1
if c == len(pos):
diff --git a/markdown/blockparser.py b/markdown/blockparser.py
index 9b59a97..4504a16 100644
--- a/markdown/blockparser.py
+++ b/markdown/blockparser.py
@@ -1,6 +1,7 @@
-
-import util
-import odict
+from __future__ import unicode_literals
+from __future__ import absolute_import
+from . import util
+from . import odict
class State(list):
""" Track the current and nested state of the parser.
diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py
index 8b41a37..a681d6c 100644
--- a/markdown/blockprocessors.py
+++ b/markdown/blockprocessors.py
@@ -1,21 +1,21 @@
-"""
-CORE MARKDOWN BLOCKPARSER
-=============================================================================
-
-This parser handles basic parsing of Markdown blocks. It doesn't concern itself
-with inline elements such as **bold** or *italics*, but rather just catches
-blocks, lists, quotes, etc.
-
-The BlockParser is made up of a bunch of BlockProssors, each handling a
-different type of block. Extensions may add/replace/remove BlockProcessors
-as they need to alter how markdown blocks are parsed.
-
-"""
-
+from __future__ import unicode_literals
+# CORE MARKDOWN BLOCKPARSER
+# ===========================================================================
+#
+# This parser handles basic parsing of Markdown blocks. It doesn't concern itself
+# with inline elements such as **bold** or *italics*, but rather just catches
+# blocks, lists, quotes, etc.
+#
+# The BlockParser is made up of a bunch of BlockProssors, each handling a
+# different type of block. Extensions may add/replace/remove BlockProcessors
+# as they need to alter how markdown blocks are parsed.
+
+from __future__ import absolute_import
+from __future__ import division
import logging
import re
-import util
-from blockparser import BlockParser
+from . import util
+from .blockparser import BlockParser
logger = logging.getLogger('MARKDOWN')
diff --git a/markdown/etree_loader.py b/markdown/etree_loader.py
deleted file mode 100644
index f605aa2..0000000
--- a/markdown/etree_loader.py
+++ /dev/null
@@ -1,31 +0,0 @@
-
-## Import
-def importETree():
- """Import the best implementation of ElementTree, return a module object."""
- etree_in_c = None
- try: # Is it Python 2.5+ with C implemenation of ElementTree installed?
- import xml.etree.cElementTree as etree_in_c
- from xml.etree.ElementTree import Comment
- except ImportError:
- try: # Is it Python 2.5+ with Python implementation of ElementTree?
- import xml.etree.ElementTree as etree
- except ImportError:
- try: # An earlier version of Python with cElementTree installed?
- import cElementTree as etree_in_c
- from elementtree.ElementTree import Comment
- except ImportError:
- try: # An earlier version of Python with Python ElementTree?
- import elementtree.ElementTree as etree
- except ImportError:
- raise ImportError("Failed to import ElementTree")
- if etree_in_c:
- if etree_in_c.VERSION < "1.0.5":
- raise RuntimeError("cElementTree version 1.0.5 or higher is required.")
- # Third party serializers (including ours) test with non-c Comment
- etree_in_c.test_comment = Comment
- return etree_in_c
- elif etree.VERSION < "1.1":
- raise RuntimeError("ElementTree version 1.1 or higher is required")
- else:
- return etree
-
diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py
index 0222c91..960d8f9 100644
--- a/markdown/extensions/__init__.py
+++ b/markdown/extensions/__init__.py
@@ -1,9 +1,10 @@
+from __future__ import unicode_literals
"""
Extensions
-----------------------------------------------------------------------------
"""
-class Extension:
+class Extension(object):
""" Base class for extensions to subclass. """
def __init__(self, configs = {}):
"""Create an instance of an Extention.
@@ -46,6 +47,6 @@ class Extension:
* md_globals: Global variables in the markdown module namespace.
"""
- raise NotImplementedError, 'Extension "%s.%s" must define an "extendMarkdown"' \
- 'method.' % (self.__class__.__module__, self.__class__.__name__)
+ raise NotImplementedError('Extension "%s.%s" must define an "extendMarkdown"' \
+ 'method.' % (self.__class__.__module__, self.__class__.__name__))
diff --git a/markdown/extensions/abbr.py b/markdown/extensions/abbr.py
index 45663c0..76a08cd 100644
--- a/markdown/extensions/abbr.py
+++ b/markdown/extensions/abbr.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
'''
Abbreviation Extension for Python-Markdown
==========================================
@@ -23,14 +24,17 @@ Copyright 2007-2008
'''
+from __future__ import absolute_import
+from . import Extension
+from ..preprocessors import Preprocessor
+from ..inlinepatterns import Pattern
+from ..util import etree
import re
-import markdown
-from markdown.util import etree
# Global Vars
ABBR_REF_RE = re.compile(r'[*]\[(?P<abbr>[^\]]*)\][ ]?:\s*(?P<title>.*)')
-class AbbrExtension(markdown.Extension):
+class AbbrExtension(Extension):
""" Abbreviation Extension for Python-Markdown. """
def extendMarkdown(self, md, md_globals):
@@ -38,7 +42,7 @@ class AbbrExtension(markdown.Extension):
md.preprocessors.add('abbr', AbbrPreprocessor(md), '<reference')
-class AbbrPreprocessor(markdown.preprocessors.Preprocessor):
+class AbbrPreprocessor(Preprocessor):
""" Abbreviation Preprocessor - parse text for abbr references. """
def run(self, lines):
@@ -75,11 +79,11 @@ class AbbrPreprocessor(markdown.preprocessors.Preprocessor):
return r'(?P<abbr>\b%s\b)' % (r''.join(chars))
-class AbbrPattern(markdown.inlinepatterns.Pattern):
+class AbbrPattern(Pattern):
""" Abbreviation inline pattern. """
def __init__(self, pattern, title):
- markdown.inlinepatterns.Pattern.__init__(self, pattern)
+ super(AbbrPattern, self).__init__(pattern)
self.title = title
def handleMatch(self, m):
@@ -90,7 +94,3 @@ class AbbrPattern(markdown.inlinepatterns.Pattern):
def makeExtension(configs=None):
return AbbrExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
diff --git a/markdown/extensions/admonition.py b/markdown/extensions/admonition.py
index 122eb87..98dcb3a 100644
--- a/markdown/extensions/admonition.py
+++ b/markdown/extensions/admonition.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-
+from __future__ import unicode_literals
"""
Admonition extension for Python-Markdown
========================================
@@ -42,12 +41,14 @@ By [Tiago Serafim](http://www.tiagoserafim.com/).
"""
+from __future__ import absolute_import
+from . import Extension
+from ..blockprocessors import BlockProcessor
+from ..util import etree
import re
-import markdown
-from markdown.util import etree
-class AdmonitionExtension(markdown.Extension):
+class AdmonitionExtension(Extension):
""" Admonition extension for Python-Markdown. """
def extendMarkdown(self, md, md_globals):
@@ -59,7 +60,7 @@ class AdmonitionExtension(markdown.Extension):
'_begin')
-class AdmonitionProcessor(markdown.blockprocessors.BlockProcessor):
+class AdmonitionProcessor(BlockProcessor):
CLASSNAME = 'admonition'
CLASSNAME_TITLE = 'admonition-title'
@@ -84,7 +85,7 @@ class AdmonitionProcessor(markdown.blockprocessors.BlockProcessor):
if m:
klass, title = self.get_class_and_title(m)
div = etree.SubElement(parent, 'div')
- div.set('class', u'%s %s' % (self.CLASSNAME, klass))
+ div.set('class', '%s %s' % (self.CLASSNAME, klass))
if title:
p = etree.SubElement(div, 'p')
p.text = title
diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py
index a61e2be..7beaa6a 100644
--- a/markdown/extensions/attr_list.py
+++ b/markdown/extensions/attr_list.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
Attribute List Extension for Python-Markdown
============================================
@@ -18,9 +19,11 @@ Dependencies:
"""
-import markdown
+from __future__ import absolute_import
+from . import Extension
+from ..treeprocessors import Treeprocessor
+from ..util import isBlockLevel
import re
-from markdown.util import isBlockLevel
try:
Scanner = re.Scanner
@@ -41,9 +44,9 @@ def _handle_key_value(s, t):
def _handle_word(s, t):
if t.startswith('.'):
- return u'.', t[1:]
+ return '.', t[1:]
if t.startswith('#'):
- return u'id', t[1:]
+ return 'id', t[1:]
return t, t
_scanner = Scanner([
@@ -61,7 +64,7 @@ def get_attrs(str):
def isheader(elem):
return elem.tag in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
-class AttrListTreeprocessor(markdown.treeprocessors.Treeprocessor):
+class AttrListTreeprocessor(Treeprocessor):
BASE_RE = r'\{\:?([^\}]*)\}'
HEADER_RE = re.compile(r'[ ]*%s[ ]*$' % BASE_RE)
@@ -128,7 +131,7 @@ class AttrListTreeprocessor(markdown.treeprocessors.Treeprocessor):
return self.NAME_RE.sub('_', name)
-class AttrListExtension(markdown.extensions.Extension):
+class AttrListExtension(Extension):
def extendMarkdown(self, md, md_globals):
md.treeprocessors.add('attr_list', AttrListTreeprocessor(md), '>prettify')
diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py
index fd8e2f4..89c0251 100644
--- a/markdown/extensions/codehilite.py
+++ b/markdown/extensions/codehilite.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+from __future__ import unicode_literals
"""
CodeHilite Extension for Python-Markdown
========================================
@@ -20,7 +19,9 @@ Dependencies:
"""
-import markdown
+from __future__ import absolute_import
+from . import Extension
+from ..treeprocessors import Treeprocessor
import warnings
try:
from pygments import highlight
@@ -31,7 +32,7 @@ except ImportError:
pygments = False
# ------------------ The Main CodeHilite Class ----------------------
-class CodeHilite:
+class CodeHilite(object):
"""
Determine language of source code, and pass it into the pygments hilighter.
@@ -167,7 +168,7 @@ class CodeHilite:
# ------------------ The Markdown Extension -------------------------------
-class HiliteTreeprocessor(markdown.treeprocessors.Treeprocessor):
+class HiliteTreeprocessor(Treeprocessor):
""" Hilight source code in code blocks. """
def run(self, root):
@@ -193,7 +194,7 @@ class HiliteTreeprocessor(markdown.treeprocessors.Treeprocessor):
block.text = placeholder
-class CodeHiliteExtension(markdown.Extension):
+class CodeHiliteExtension(Extension):
""" Add source code hilighting to markdown codeblocks. """
def __init__(self, configs):
diff --git a/markdown/extensions/def_list.py b/markdown/extensions/def_list.py
index 382445c..cd9dc9c 100644
--- a/markdown/extensions/def_list.py
+++ b/markdown/extensions/def_list.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+from __future__ import unicode_literals
"""
Definition List Extension for Python-Markdown
=============================================
@@ -19,12 +19,14 @@ Copyright 2008 - [Waylan Limberg](http://achinghead.com)
"""
+from __future__ import absolute_import
+from . import Extension
+from ..blockprocessors import BlockProcessor, ListIndentProcessor
+from ..util import etree
import re
-import markdown
-from markdown.util import etree
-class DefListProcessor(markdown.blockprocessors.BlockProcessor):
+class DefListProcessor(BlockProcessor):
""" Process Definition Lists. """
RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)')
@@ -85,7 +87,7 @@ class DefListProcessor(markdown.blockprocessors.BlockProcessor):
if theRest:
blocks.insert(0, theRest)
-class DefListIndentProcessor(markdown.blockprocessors.ListIndentProcessor):
+class DefListIndentProcessor(ListIndentProcessor):
""" Process indented children of definition list items. """
ITEM_TYPES = ['dd']
@@ -98,7 +100,7 @@ class DefListIndentProcessor(markdown.blockprocessors.ListIndentProcessor):
-class DefListExtension(markdown.Extension):
+class DefListExtension(Extension):
""" Add definition lists to Markdown. """
def extendMarkdown(self, md, md_globals):
diff --git a/markdown/extensions/extra.py b/markdown/extensions/extra.py
index ba646f5..5b8876c 100644
--- a/markdown/extensions/extra.py
+++ b/markdown/extensions/extra.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+from __future__ import unicode_literals
"""
Python-Markdown Extra Extension
===============================
@@ -27,7 +27,8 @@ when you upgrade to any future version of Python-Markdown.
"""
-import markdown
+from __future__ import absolute_import
+from . import Extension
extensions = ['smart_strong',
'fenced_code',
@@ -39,7 +40,7 @@ extensions = ['smart_strong',
]
-class ExtraExtension(markdown.Extension):
+class ExtraExtension(Extension):
""" Add various extensions to Markdown class."""
def extendMarkdown(self, md, md_globals):
diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py
index 76d644f..91c59ee 100644
--- a/markdown/extensions/fenced_code.py
+++ b/markdown/extensions/fenced_code.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-
+from __future__ import unicode_literals
"""
Fenced Code Extension for Python Markdown
=========================================
@@ -75,9 +74,11 @@ Dependencies:
"""
+from __future__ import absolute_import
+from . import Extension
+from ..preprocessors import Preprocessor
+from .codehilite import CodeHilite, CodeHiliteExtension
import re
-import markdown
-from markdown.extensions.codehilite import CodeHilite, CodeHiliteExtension
# Global vars
FENCED_BLOCK_RE = re.compile( \
@@ -87,7 +88,7 @@ FENCED_BLOCK_RE = re.compile( \
CODE_WRAP = '<pre><code%s>%s</code></pre>'
LANG_TAG = ' class="%s"'
-class FencedCodeExtension(markdown.Extension):
+class FencedCodeExtension(Extension):
def extendMarkdown(self, md, md_globals):
""" Add FencedBlockPreprocessor to the Markdown instance. """
@@ -98,10 +99,10 @@ class FencedCodeExtension(markdown.Extension):
">normalize_whitespace")
-class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
+class FencedBlockPreprocessor(Preprocessor):
def __init__(self, md):
- markdown.preprocessors.Preprocessor.__init__(self, md)
+ super(FencedBlockPreprocessor, self).__init__(md)
self.checked_for_codehilite = False
self.codehilite_conf = {}
@@ -158,8 +159,3 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
def makeExtension(configs=None):
return FencedCodeExtension(configs=configs)
-
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py
index 0a0ddea..b7ebc35 100644
--- a/markdown/extensions/footnotes.py
+++ b/markdown/extensions/footnotes.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
========================= FOOTNOTES =================================
@@ -23,16 +24,22 @@ Example:
"""
+from __future__ import absolute_import
+from . import Extension
+from ..preprocessors import Preprocessor
+from ..inlinepatterns import Pattern
+from ..treeprocessors import Treeprocessor
+from ..postprocessors import Postprocessor
+from ..util import etree, text_type
+from ..odict import OrderedDict
import re
-import markdown
-from markdown.util import etree
FN_BACKLINK_TEXT = "zz1337820767766393qq"
NBSP_PLACEHOLDER = "qq3936677670287331zz"
DEF_RE = re.compile(r'[ ]{0,3}\[\^([^\]]*)\]:\s*(.*)')
TABBED_RE = re.compile(r'((\t)|( ))(.*)')
-class FootnoteExtension(markdown.Extension):
+class FootnoteExtension(Extension):
""" Footnote Extension. """
def __init__ (self, configs):
@@ -83,7 +90,7 @@ class FootnoteExtension(markdown.Extension):
def reset(self):
""" Clear the footnotes on reset, and prepare for a distinct document. """
- self.footnotes = markdown.odict.OrderedDict()
+ self.footnotes = OrderedDict()
self.unique_prefix += 1
def findFootnotesPlaceholder(self, root):
@@ -155,7 +162,7 @@ class FootnoteExtension(markdown.Extension):
return div
-class FootnotePreprocessor(markdown.preprocessors.Preprocessor):
+class FootnotePreprocessor(Preprocessor):
""" Find all footnote references and store for later use. """
def __init__ (self, footnotes):
@@ -246,11 +253,11 @@ class FootnotePreprocessor(markdown.preprocessors.Preprocessor):
return items, i
-class FootnotePattern(markdown.inlinepatterns.Pattern):
+class FootnotePattern(Pattern):
""" InlinePattern for footnote markers in a document's body text. """
def __init__(self, pattern, footnotes):
- markdown.inlinepatterns.Pattern.__init__(self, pattern)
+ super(FootnotePattern, self).__init__(pattern)
self.footnotes = footnotes
def handleMatch(self, m):
@@ -263,13 +270,13 @@ class FootnotePattern(markdown.inlinepatterns.Pattern):
if self.footnotes.md.output_format not in ['html5', 'xhtml5']:
a.set('rel', 'footnote') # invalid in HTML5
a.set('class', 'footnote-ref')
- a.text = unicode(self.footnotes.footnotes.index(id) + 1)
+ a.text = text_type(self.footnotes.footnotes.index(id) + 1)
return sup
else:
return None
-class FootnoteTreeprocessor(markdown.treeprocessors.Treeprocessor):
+class FootnoteTreeprocessor(Treeprocessor):
""" Build and append footnote div to end of document. """
def __init__ (self, footnotes):
@@ -291,7 +298,7 @@ class FootnoteTreeprocessor(markdown.treeprocessors.Treeprocessor):
else:
root.append(footnotesDiv)
-class FootnotePostprocessor(markdown.postprocessors.Postprocessor):
+class FootnotePostprocessor(Postprocessor):
""" Replace placeholders with html entities. """
def __init__(self, footnotes):
self.footnotes = footnotes
diff --git a/markdown/extensions/headerid.py b/markdown/extensions/headerid.py
index cf3df17..33d7d90 100644
--- a/markdown/extensions/headerid.py
+++ b/markdown/extensions/headerid.py
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+from __future__ import unicode_literals
"""
HeaderID Extension for Python-Markdown
======================================
@@ -76,7 +75,9 @@ Dependencies:
"""
-import markdown
+from __future__ import absolute_import
+from . import Extension
+from ..treeprocessors import Treeprocessor
import re
import logging
import unicodedata
@@ -120,7 +121,7 @@ def itertext(elem):
yield e.tail
-class HeaderIdTreeprocessor(markdown.treeprocessors.Treeprocessor):
+class HeaderIdTreeprocessor(Treeprocessor):
""" Assign IDs to headers. """
IDs = set()
@@ -135,7 +136,7 @@ class HeaderIdTreeprocessor(markdown.treeprocessors.Treeprocessor):
if "id" in elem.attrib:
id = elem.get('id')
else:
- id = slugify(u''.join(itertext(elem)), sep)
+ id = slugify(''.join(itertext(elem)), sep)
elem.set('id', unique(id, self.IDs))
if start_level:
level = int(elem.tag[-1]) + start_level
@@ -149,9 +150,9 @@ class HeaderIdTreeprocessor(markdown.treeprocessors.Treeprocessor):
level = int(self.config['level']) - 1
force = self._str2bool(self.config['forceid'])
if hasattr(self.md, 'Meta'):
- if self.md.Meta.has_key('header_level'):
+ if 'header_level' in self.md.Meta:
level = int(self.md.Meta['header_level'][0]) - 1
- if self.md.Meta.has_key('header_forceid'):
+ if 'header_forceid' in self.md.Meta:
force = self._str2bool(self.md.Meta['header_forceid'][0])
return level, force
@@ -165,7 +166,7 @@ class HeaderIdTreeprocessor(markdown.treeprocessors.Treeprocessor):
return default
-class HeaderIdExtension (markdown.Extension):
+class HeaderIdExtension(Extension):
def __init__(self, configs):
# set defaults
self.config = {
@@ -196,8 +197,3 @@ class HeaderIdExtension (markdown.Extension):
def makeExtension(configs=None):
return HeaderIdExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
-
diff --git a/markdown/extensions/html_tidy.py b/markdown/extensions/html_tidy.py
index 80272a3..e5f060c 100644
--- a/markdown/extensions/html_tidy.py
+++ b/markdown/extensions/html_tidy.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-
+from __future__ import unicode_literals
"""
HTML Tidy Extension for Python-Markdown
=======================================
@@ -28,13 +27,16 @@ Dependencies:
"""
-import markdown
+from __future__ import absolute_import
+from . import Extension
+from ..postprocessors import Postprocessor
+from ..util import text_type
try:
import tidy
except ImportError:
tidy = None
-class TidyExtension(markdown.Extension):
+class TidyExtension(Extension):
def __init__(self, configs):
# Set defaults to match typical markdown behavior.
@@ -54,13 +56,13 @@ class TidyExtension(markdown.Extension):
md.postprocessors['tidy'] = TidyProcessor(md)
-class TidyProcessor(markdown.postprocessors.Postprocessor):
+class TidyProcessor(Postprocessor):
def run(self, text):
# Pass text to Tidy. As Tidy does not accept unicode we need to encode
# it and decode its return value.
enc = self.markdown.tidy_options.get('char_encoding', 'utf8')
- return unicode(tidy.parseString(text.encode(enc),
+ return text_type(tidy.parseString(text.encode(enc),
**self.markdown.tidy_options),
encoding=enc)
diff --git a/markdown/extensions/meta.py b/markdown/extensions/meta.py
index a3ee6fb..a2fbe80 100644
--- a/markdown/extensions/meta.py
+++ b/markdown/extensions/meta.py
@@ -1,5 +1,4 @@
-#!usr/bin/python
-
+from __future__ import unicode_literals
"""
Meta Data Extension for Python-Markdown
=======================================
@@ -40,15 +39,17 @@ Contact: markdown@freewisdom.org
License: BSD (see ../LICENSE.md for details)
"""
-import re
-import markdown
+from __future__ import absolute_import
+from . import Extension
+from ..preprocessors import Preprocessor
+import re
# Global Vars
META_RE = re.compile(r'^[ ]{0,3}(?P<key>[A-Za-z0-9_-]+):\s*(?P<value>.*)')
META_MORE_RE = re.compile(r'^[ ]{4,}(?P<value>.*)')
-class MetaExtension (markdown.Extension):
+class MetaExtension (Extension):
""" Meta-Data extension for Python-Markdown. """
def extendMarkdown(self, md, md_globals):
@@ -57,7 +58,7 @@ class MetaExtension (markdown.Extension):
md.preprocessors.add("meta", MetaPreprocessor(md), "_begin")
-class MetaPreprocessor(markdown.preprocessors.Preprocessor):
+class MetaPreprocessor(Preprocessor):
""" Get Meta-Data. """
def run(self, lines):
@@ -90,7 +91,3 @@ class MetaPreprocessor(markdown.preprocessors.Preprocessor):
def makeExtension(configs={}):
return MetaExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
diff --git a/markdown/extensions/nl2br.py b/markdown/extensions/nl2br.py
index 3967c75..5636214 100644
--- a/markdown/extensions/nl2br.py
+++ b/markdown/extensions/nl2br.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
NL2BR Extension
===============
@@ -20,17 +21,18 @@ Dependencies:
"""
-import markdown
+from __future__ import absolute_import
+from . import Extension
+from ..inlinepatterns import SubstituteTagPattern
BR_RE = r'\n'
-class Nl2BrExtension(markdown.Extension):
+class Nl2BrExtension(Extension):
def extendMarkdown(self, md, md_globals):
- br_tag = markdown.inlinepatterns.SubstituteTagPattern(BR_RE, 'br')
+ br_tag = SubstituteTagPattern(BR_RE, 'br')
md.inlinePatterns.add('nl', br_tag, '_end')
def makeExtension(configs=None):
return Nl2BrExtension(configs)
-
diff --git a/markdown/extensions/sane_lists.py b/markdown/extensions/sane_lists.py
index dce04ea..5620ccd 100644
--- a/markdown/extensions/sane_lists.py
+++ b/markdown/extensions/sane_lists.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+from __future__ import unicode_literals
"""
Sane List Extension for Python-Markdown
=======================================
@@ -19,23 +19,25 @@ Copyright 2011 - [Waylan Limberg](http://achinghead.com)
"""
+from __future__ import absolute_import
+from . import Extension
+from ..blockprocessors import OListProcessor, UListProcessor
import re
-import markdown
-class SaneOListProcessor(markdown.blockprocessors.OListProcessor):
+class SaneOListProcessor(OListProcessor):
CHILD_RE = re.compile(r'^[ ]{0,3}((\d+\.))[ ]+(.*)')
SIBLING_TAGS = ['ol']
-class SaneUListProcessor(markdown.blockprocessors.UListProcessor):
+class SaneUListProcessor(UListProcessor):
CHILD_RE = re.compile(r'^[ ]{0,3}(([*+-]))[ ]+(.*)')
SIBLING_TAGS = ['ul']
-class SaneListExtension(markdown.Extension):
+class SaneListExtension(Extension):
""" Add sane lists to Markdown. """
def extendMarkdown(self, md, md_globals):
diff --git a/markdown/extensions/smart_strong.py b/markdown/extensions/smart_strong.py
index 7166989..7ce2d4d 100644
--- a/markdown/extensions/smart_strong.py
+++ b/markdown/extensions/smart_strong.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
'''
Smart_Strong Extension for Python-Markdown
==========================================
@@ -22,13 +23,14 @@ Copyright 2011
'''
-import markdown
-from markdown.inlinepatterns import SimpleTagPattern
+from __future__ import absolute_import
+from . import Extension
+from ..inlinepatterns import SimpleTagPattern
SMART_STRONG_RE = r'(?<!\w)(_{2})(?!_)(.+?)(?<!_)\2(?!\w)'
STRONG_RE = r'(\*{2})(.+?)\2'
-class SmartEmphasisExtension(markdown.extensions.Extension):
+class SmartEmphasisExtension(Extension):
""" Add smart_emphasis extension to Markdown class."""
def extendMarkdown(self, md, md_globals):
@@ -38,7 +40,3 @@ class SmartEmphasisExtension(markdown.extensions.Extension):
def makeExtension(configs={}):
return SmartEmphasisExtension(configs=dict(configs))
-
-if __name__ == '__main__':
- import doctest
- doctest.testmod()
diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py
index 1388cb5..3edaccf 100644
--- a/markdown/extensions/tables.py
+++ b/markdown/extensions/tables.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+from __future__ import unicode_literals
"""
Tables Extension for Python-Markdown
====================================
@@ -14,11 +14,13 @@ A simple example:
Copyright 2009 - [Waylan Limberg](http://achinghead.com)
"""
-import markdown
-from markdown.util import etree
+from __future__ import absolute_import
+from . import Extension
+from ..blockprocessors import BlockProcessor
+from ..util import etree
-class TableProcessor(markdown.blockprocessors.BlockProcessor):
+class TableProcessor(BlockProcessor):
""" Process Tables. """
def test(self, parent, block):
@@ -84,7 +86,7 @@ class TableProcessor(markdown.blockprocessors.BlockProcessor):
return row.split('|')
-class TableExtension(markdown.Extension):
+class TableExtension(Extension):
""" Add tables to Markdown. """
def extendMarkdown(self, md, md_globals):
diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py
index bade490..c672313 100644
--- a/markdown/extensions/toc.py
+++ b/markdown/extensions/toc.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
Table of Contents Extension for Python-Markdown
* * *
@@ -8,10 +9,12 @@ Dependencies:
* [Markdown 2.1+](http://packages.python.org/Markdown/)
"""
-import markdown
-from markdown.util import etree
-from markdown.extensions.headerid import slugify, unique, itertext
+from __future__ import absolute_import
+from . import Extension
+from ..treeprocessors import Treeprocessor
+from ..util import etree
+from .headerid import slugify, unique, itertext
import re
@@ -77,7 +80,7 @@ def order_toc_list(toc_list):
return ordered_list
-class TocTreeprocessor(markdown.treeprocessors.Treeprocessor):
+class TocTreeprocessor(Treeprocessor):
# Iterator wrapper to get parent and child all at once
def iterparent(self, root):
@@ -182,7 +185,7 @@ class TocTreeprocessor(markdown.treeprocessors.Treeprocessor):
self.markdown.toc = toc
-class TocExtension(markdown.Extension):
+class TocExtension(Extension):
TreeProcessorClass = TocTreeprocessor
diff --git a/markdown/extensions/wikilinks.py b/markdown/extensions/wikilinks.py
index 5384adb..de4d9aa 100644
--- a/markdown/extensions/wikilinks.py
+++ b/markdown/extensions/wikilinks.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-
+from __future__ import unicode_literals
'''
WikiLinks Extension for Python-Markdown
======================================
@@ -78,7 +77,10 @@ Dependencies:
* [Markdown 2.0+](http://packages.python.org/Markdown/)
'''
-import markdown
+from __future__ import absolute_import
+from . import Extension
+from ..inlinepatterns import Pattern
+from ..util import etree
import re
def build_url(label, base, end):
@@ -87,7 +89,7 @@ def build_url(label, base, end):
return '%s%s%s'% (base, clean_label, end)
-class WikiLinkExtension(markdown.Extension):
+class WikiLinkExtension(Extension):
def __init__(self, configs):
# set extension defaults
self.config = {
@@ -111,9 +113,9 @@ class WikiLinkExtension(markdown.Extension):
md.inlinePatterns.add('wikilink', wikilinkPattern, "<not_strong")
-class WikiLinks(markdown.inlinepatterns.Pattern):
+class WikiLinks(Pattern):
def __init__(self, pattern, config):
- markdown.inlinepatterns.Pattern.__init__(self, pattern)
+ super(WikiLinks, self).__init__(pattern)
self.config = config
def handleMatch(self, m):
@@ -121,7 +123,7 @@ class WikiLinks(markdown.inlinepatterns.Pattern):
base_url, end_url, html_class = self._getMeta()
label = m.group(2).strip()
url = self.config['build_url'](label, base_url, end_url)
- a = markdown.util.etree.Element('a')
+ a = etree.Element('a')
a.text = label
a.set('href', url)
if html_class:
@@ -136,20 +138,14 @@ class WikiLinks(markdown.inlinepatterns.Pattern):
end_url = self.config['end_url']
html_class = self.config['html_class']
if hasattr(self.md, 'Meta'):
- if self.md.Meta.has_key('wiki_base_url'):
+ if 'wiki_base_url' in self.md.Meta:
base_url = self.md.Meta['wiki_base_url'][0]
- if self.md.Meta.has_key('wiki_end_url'):
+ if 'wiki_end_url' in self.md.Meta:
end_url = self.md.Meta['wiki_end_url'][0]
- if self.md.Meta.has_key('wiki_html_class'):
+ if 'wiki_html_class' in self.md.Meta:
html_class = self.md.Meta['wiki_html_class'][0]
return base_url, end_url, html_class
def makeExtension(configs=None) :
return WikiLinkExtension(configs=configs)
-
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
-
diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py
index f64aa58..e8ecaea 100644
--- a/markdown/inlinepatterns.py
+++ b/markdown/inlinepatterns.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
INLINE PATTERNS
=============================================================================
@@ -41,17 +42,18 @@ So, we apply the expressions in the following order:
* finally we apply strong and emphasis
"""
-import util
-import odict
+from __future__ import absolute_import
+from . import util
+from . import odict
import re
-from urlparse import urlparse, urlunparse
-# If you see an ImportError for htmlentitydefs after using 2to3 to convert for
-# use by Python3, then you are probably using the buggy version from Python 3.0.
-# We recomend using the tool from Python 3.1 even if you will be running the
-# code on Python 3.0. The following line should be converted by the tool to:
-# `from html import entities` and later calls to `htmlentitydefs` should be
-# changed to call `entities`. Python 3.1's tool does this but 3.0's does not.
-import htmlentitydefs
+try:
+ from urllib.parse import urlparse, urlunparse
+except ImportError:
+ from urlparse import urlparse, urlunparse
+try:
+ from html import entities
+except ImportError:
+ import htmlentitydefs as entities
def build_inlinepatterns(md_instance, **kwargs):
@@ -141,7 +143,7 @@ The pattern classes
-----------------------------------------------------------------------------
"""
-class Pattern:
+class Pattern(object):
"""Base class that inline patterns subclass. """
def __init__(self, pattern, markdown_instance=None):
@@ -191,7 +193,7 @@ class Pattern:
def itertext(el):
' Reimplement Element.itertext for older python versions '
tag = el.tag
- if not isinstance(tag, basestring) and tag is not None:
+ if not isinstance(tag, util.string_type) and tag is not None:
return
if el.text:
yield el.text
@@ -204,7 +206,7 @@ class Pattern:
id = m.group(1)
if id in stash:
value = stash.get(id)
- if isinstance(value, basestring):
+ if isinstance(value, util.string_type):
return value
else:
# An etree Element - return text content only
@@ -464,7 +466,7 @@ class AutomailPattern(Pattern):
def codepoint2name(code):
"""Return entity definition by code, or the code if not defined."""
- entity = htmlentitydefs.codepoint2name.get(code)
+ entity = entities.codepoint2name.get(code)
if entity:
return "%s%s;" % (util.AMP_SUBSTITUTE, entity)
else:
diff --git a/markdown/odict.py b/markdown/odict.py
index 02864bf..578cc76 100644
--- a/markdown/odict.py
+++ b/markdown/odict.py
@@ -1,3 +1,7 @@
+from __future__ import unicode_literals
+from __future__ import absolute_import
+from . import util
+
class OrderedDict(dict):
"""
A dictionary that keeps its keys in the order in which they're inserted.
@@ -11,34 +15,44 @@ class OrderedDict(dict):
return instance
def __init__(self, data=None):
- if data is None:
- data = {}
- super(OrderedDict, self).__init__(data)
- if isinstance(data, dict):
- self.keyOrder = data.keys()
+ if data is None or isinstance(data, dict):
+ data = data or []
+ super(OrderedDict, self).__init__(data)
+ self.keyOrder = list(data) if data else []
else:
- self.keyOrder = []
+ super(OrderedDict, self).__init__()
+ super_set = super(OrderedDict, self).__setitem__
for key, value in data:
- if key not in self.keyOrder:
+ # Take the ordering from first key
+ if key not in self:
self.keyOrder.append(key)
+ # But override with last value in data (dict() does this)
+ super_set(key, value)
def __deepcopy__(self, memo):
- from copy import deepcopy
- return self.__class__([(key, deepcopy(value, memo))
- for key, value in self.iteritems()])
+ return self.__class__([(key, copy.deepcopy(value, memo))
+ for key, value in self.items()])
+
+ def __copy__(self):
+ # The Python's default copy implementation will alter the state
+ # of self. The reason for this seems complex but is likely related to
+ # subclassing dict.
+ return self.copy()
def __setitem__(self, key, value):
- super(OrderedDict, self).__setitem__(key, value)
- if key not in self.keyOrder:
+ if key not in self:
self.keyOrder.append(key)
+ super(OrderedDict, self).__setitem__(key, value)
def __delitem__(self, key):
super(OrderedDict, self).__delitem__(key)
self.keyOrder.remove(key)
def __iter__(self):
- for k in self.keyOrder:
- yield k
+ return iter(self.keyOrder)
+
+ def __reversed__(self):
+ return reversed(self.keyOrder)
def pop(self, k, *args):
result = super(OrderedDict, self).pop(k, *args)
@@ -54,41 +68,51 @@ class OrderedDict(dict):
self.keyOrder.remove(result[0])
return result
- def items(self):
- return zip(self.keyOrder, self.values())
+ def _iteritems(self):
+ for key in self.keyOrder:
+ yield key, self[key]
- def iteritems(self):
+ def _iterkeys(self):
for key in self.keyOrder:
- yield key, super(OrderedDict, self).__getitem__(key)
+ yield key
- def keys(self):
- return self.keyOrder[:]
+ def _itervalues(self):
+ for key in self.keyOrder:
+ yield self[key]
- def iterkeys(self):
- return iter(self.keyOrder)
+ if util.PY3:
+ items = _iteritems
+ keys = _iterkeys
+ values = _itervalues
+ else:
+ iteritems = _iteritems
+ iterkeys = _iterkeys
+ itervalues = _itervalues
- def values(self):
- return [super(OrderedDict, self).__getitem__(k) for k in self.keyOrder]
+ def items(self):
+ return [(k, self[k]) for k in self.keyOrder]
- def itervalues(self):
- for key in self.keyOrder:
- yield super(OrderedDict, self).__getitem__(key)
+ def keys(self):
+ return self.keyOrder[:]
+
+ def values(self):
+ return [self[k] for k in self.keyOrder]
def update(self, dict_):
- for k, v in dict_.items():
- self.__setitem__(k, v)
+ for k, v in six.iteritems(dict_):
+ self[k] = v
def setdefault(self, key, default):
- if key not in self.keyOrder:
+ if key not in self:
self.keyOrder.append(key)
return super(OrderedDict, self).setdefault(key, default)
def value_for_index(self, index):
- """Return the value of the item at the given zero-based index."""
+ """Returns the value of the item at the given zero-based index."""
return self[self.keyOrder[index]]
def insert(self, index, key, value):
- """Insert the key, value pair before the item with the given index."""
+ """Inserts the key, value pair before the item with the given index."""
if key in self.keyOrder:
n = self.keyOrder.index(key)
del self.keyOrder[n]
@@ -98,18 +122,16 @@ class OrderedDict(dict):
super(OrderedDict, self).__setitem__(key, value)
def copy(self):
- """Return a copy of this object."""
+ """Returns a copy of this object."""
# This way of initializing the copy means it works for subclasses, too.
- obj = self.__class__(self)
- obj.keyOrder = self.keyOrder[:]
- return obj
+ return self.__class__(self)
def __repr__(self):
"""
- Replace the normal dict.__repr__ with a version that returns the keys
- in their sorted order.
+ Replaces the normal dict.__repr__ with a version that returns the keys
+ in their Ordered order.
"""
- return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()])
+ return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in six.iteritems(self)])
def clear(self):
super(OrderedDict, self).clear()
@@ -159,7 +181,7 @@ class OrderedDict(dict):
self.keyOrder.insert(i, key)
else:
self.keyOrder.append(key)
- except Exception, e:
+ except Exception as e:
# restore to prevent data loss and reraise
self.keyOrder.insert(n, key)
raise e
diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py
index 071791a..36fa98d 100644
--- a/markdown/postprocessors.py
+++ b/markdown/postprocessors.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
POST-PROCESSORS
=============================================================================
@@ -8,9 +9,11 @@ processing.
"""
+from __future__ import absolute_import
+from . import util
+from . import odict
import re
-import util
-import odict
+
def build_postprocessors(md_instance, **kwargs):
""" Build the default postprocessors for Markdown. """
@@ -95,7 +98,7 @@ class UnescapePostprocessor(Postprocessor):
RE = re.compile('%s(\d+)%s' % (util.STX, util.ETX))
def unescape(self, m):
- return unichr(int(m.group(1)))
+ return util.int2str(int(m.group(1)))
def run(self, text):
return self.RE.sub(self.unescape, text)
diff --git a/markdown/preprocessors.py b/markdown/preprocessors.py
index 6238303..e61a6b8 100644
--- a/markdown/preprocessors.py
+++ b/markdown/preprocessors.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
"""
PRE-PROCESSORS
=============================================================================
@@ -6,9 +7,10 @@ Preprocessors work on source text before we start doing anything too
complicated.
"""
+from __future__ import absolute_import
+from . import util
+from . import odict
import re
-import util
-import odict
def build_preprocessors(md_instance, **kwargs):
diff --git a/markdown/serializers.py b/markdown/serializers.py
index 22a83d4..977d6e8 100644
--- a/markdown/serializers.py
+++ b/markdown/serializers.py
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
# markdown/searializers.py
#
# Add x/html serialization to Elementree
@@ -37,7 +38,8 @@
# --------------------------------------------------------------------
-import util
+from __future__ import absolute_import
+from . import util
ElementTree = util.etree.ElementTree
QName = util.etree.QName
if hasattr(util.etree, 'test_comment'):
@@ -251,7 +253,7 @@ def _namespaces(elem, default_namespace=None):
tag = elem.tag
if isinstance(tag, QName) and tag.text not in qnames:
add_qname(tag.text)
- elif isinstance(tag, basestring):
+ elif isinstance(tag, util.string_type):
if tag not in qnames:
add_qname(tag)
elif tag is not None and tag is not Comment and tag is not PI:
diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py
index b5eedbd..2df80f8 100644
--- a/markdown/treeprocessors.py
+++ b/markdown/treeprocessors.py
@@ -1,6 +1,8 @@
-import inlinepatterns
-import util
-import odict
+from __future__ import unicode_literals
+from __future__ import absolute_import
+from . import util
+from . import odict
+from . import inlinepatterns
def build_treeprocessors(md_instance, **kwargs):
@@ -14,17 +16,11 @@ def build_treeprocessors(md_instance, **kwargs):
def isString(s):
""" Check if it's string """
if not isinstance(s, util.AtomicString):
- return isinstance(s, basestring)
+ return isinstance(s, util.string_type)
return False
-class Processor:
- def __init__(self, markdown_instance=None):
- if markdown_instance:
- self.markdown = markdown_instance
-
-
-class Treeprocessor(Processor):
+class Treeprocessor(util.Processor):
"""
Treeprocessors are run on the ElementTree object before serialization.
diff --git a/markdown/util.py b/markdown/util.py
index 12dcbd5..1036197 100644
--- a/markdown/util.py
+++ b/markdown/util.py
@@ -1,12 +1,24 @@
# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
import re
-import etree_loader
+import sys
"""
-CONSTANTS
+Python 3 Stuff
=============================================================================
"""
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+ string_type = str
+ text_type = str
+ int2str = chr
+else:
+ string_type = basestring
+ text_type = unicode
+ int2str = unichr
+
"""
Constants you might want to modify
@@ -20,8 +32,8 @@ BLOCK_LEVEL_ELEMENTS = re.compile("^(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul"
"|figcaption|aside|article|canvas|output"
"|progress|video)$", re.IGNORECASE)
# Placeholders
-STX = u'\u0002' # Use STX ("Start of text") for start-of-placeholder
-ETX = u'\u0003' # Use ETX ("End of text") for end-of-placeholder
+STX = '\u0002' # Use STX ("Start of text") for start-of-placeholder
+ETX = '\u0003' # Use ETX ("End of text") for end-of-placeholder
INLINE_PLACEHOLDER_PREFIX = STX+"klzzwxh:"
INLINE_PLACEHOLDER = INLINE_PLACEHOLDER_PREFIX + "%s" + ETX
INLINE_PLACEHOLDER_RE = re.compile(INLINE_PLACEHOLDER % r'([0-9]{4})')
@@ -32,17 +44,29 @@ Constants you probably do not need to change
-----------------------------------------------------------------------------
"""
-RTL_BIDI_RANGES = ( (u'\u0590', u'\u07FF'),
+RTL_BIDI_RANGES = ( ('\u0590', '\u07FF'),
# Hebrew (0590-05FF), Arabic (0600-06FF),
# Syriac (0700-074F), Arabic supplement (0750-077F),
# Thaana (0780-07BF), Nko (07C0-07FF).
- (u'\u2D30', u'\u2D7F'), # Tifinagh
+ ('\u2D30', '\u2D7F'), # Tifinagh
)
# Extensions should use "markdown.util.etree" instead of "etree" (or do `from
# markdown.util import etree`). Do not import it by yourself.
-etree = etree_loader.importETree()
+try: # Is the C implemenation of ElementTree available?
+ import xml.etree.cElementTree as etree
+ from xml.etree.ElementTree import Comment
+ # Serializers (including ours) test with non-c Comment
+ etree.test_comment = Comment
+ if etree.VERSION < "1.0.5":
+ raise RuntimeError("cElementTree version 1.0.5 or higher is required.")
+except (ImportError, RuntimeError):
+ # Use the Python implementation of ElementTree?
+ import xml.etree.ElementTree as etree
+ if etree.VERSION < "1.1":
+ raise RuntimeError("ElementTree version 1.1 or higher is required")
+
"""
AUXILIARY GLOBAL FUNCTIONS
@@ -52,7 +76,7 @@ AUXILIARY GLOBAL FUNCTIONS
def isBlockLevel(tag):
"""Check if the tag is a block level HTML tag."""
- if isinstance(tag, basestring):
+ if isinstance(tag, string_type):
return BLOCK_LEVEL_ELEMENTS.match(tag)
# Some ElementTree tags are not strings, so return False.
return False
@@ -62,18 +86,18 @@ MISC AUXILIARY CLASSES
=============================================================================
"""
-class AtomicString(unicode):
+class AtomicString(text_type):
"""A string which should not be further processed."""
pass
-class Processor:
+class Processor(object):
def __init__(self, markdown_instance=None):
if markdown_instance:
self.markdown = markdown_instance
-class HtmlStash:
+class HtmlStash(object):
"""
This class is used for stashing HTML objects that we extract
in the beginning and replace with place-holders.
diff --git a/setup.py b/setup.py
index b244b64..140a0ae 100755
--- a/setup.py
+++ b/setup.py
@@ -10,14 +10,6 @@ from distutils.util import change_root, newer
import codecs
import imp
-# Try to run 2to3 automaticaly when building in Python 3.x
-try:
- from distutils.command.build_py import build_py_2to3 as build_py
-except ImportError:
- if sys.version_info >= (3, 0):
- raise ImportError("build_py_2to3 is required to build in Python 3.x.")
- from distutils.command.build_py import build_py
-
def get_version():
" Get version & version_info without importing markdown.__init__ "
path = os.path.join(os.path.dirname(__file__), 'markdown')
@@ -235,7 +227,6 @@ setup(
packages = ['markdown', 'markdown.extensions'],
scripts = ['bin/%s' % SCRIPT_NAME],
cmdclass = {'install_scripts': md_install_scripts,
- 'build_py': build_py,
'build_docs': build_docs,
'build': md_build},
classifiers = ['Development Status :: %s' % DEVSTATUS,