From b37ab16ba56ac6fe4e64f87521996bad323058f2 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Tue, 26 Feb 2013 11:49:18 -0500 Subject: Simlify importing ElementTree As we no longer support older python versions, importing ElementTree is much simpler. The documented way for extensions to use etree still remains the same. --- markdown/etree_loader.py | 31 ------------------------------- markdown/util.py | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 33 deletions(-) delete mode 100644 markdown/etree_loader.py 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/util.py b/markdown/util.py index 12dcbd5..34333f0 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- import re -import etree_loader """ @@ -42,7 +41,19 @@ RTL_BIDI_RANGES = ( (u'\u0590', u'\u07FF'), # 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 -- cgit v1.2.3 From 579288c5eb684dd09d1ef298929a566f40151205 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 27 Feb 2013 09:10:47 -0500 Subject: Now using universal code for Python 2 & 3. The most notable changes are the use of unicode_literals and absolute_imports. Actually, absolute_imports was the biggest deal as it gives us relative imports. For the first time extensions import markdown relative to themselves. This allows other packages to embed the markdown lib in a subdir of their project and still be able to use our extensions. --- fabfile.py | 4 -- markdown/__init__.py | 50 +++++++++--------- markdown/blockparser.py | 7 +-- markdown/blockprocessors.py | 32 +++++------ markdown/extensions/__init__.py | 7 +-- markdown/extensions/abbr.py | 20 +++---- markdown/extensions/admonition.py | 15 +++--- markdown/extensions/attr_list.py | 15 +++--- markdown/extensions/codehilite.py | 13 ++--- markdown/extensions/def_list.py | 14 ++--- markdown/extensions/extra.py | 7 +-- markdown/extensions/fenced_code.py | 20 +++---- markdown/extensions/footnotes.py | 27 ++++++---- markdown/extensions/headerid.py | 22 ++++---- markdown/extensions/html_tidy.py | 14 ++--- markdown/extensions/meta.py | 17 +++--- markdown/extensions/nl2br.py | 10 ++-- markdown/extensions/sane_lists.py | 12 +++-- markdown/extensions/smart_strong.py | 12 ++--- markdown/extensions/tables.py | 12 +++-- markdown/extensions/toc.py | 13 +++-- markdown/extensions/wikilinks.py | 28 +++++----- markdown/inlinepatterns.py | 30 ++++++----- markdown/odict.py | 102 ++++++++++++++++++++++-------------- markdown/postprocessors.py | 9 ++-- markdown/preprocessors.py | 6 ++- markdown/serializers.py | 6 ++- markdown/treeprocessors.py | 18 +++---- markdown/util.py | 31 +++++++---- setup.py | 9 ---- 30 files changed, 311 insertions(+), 271 deletions(-) diff --git a/fabfile.py b/fabfile.py index b50f007..d0be188 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_) 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/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[^\]]*)\][ ]?:\s*(?P.*)') -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 3a79d85..d0d4873 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 1d6639e..f50f11b 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 34333f0..1036197 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -1,11 +1,24 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals import re +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 @@ -19,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})') @@ -31,11 +44,11 @@ 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 @@ -63,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 @@ -73,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, -- cgit v1.2.3