Hello community, here is the log from the commit of package python-Markdown for openSUSE:Factory checked in at 2017-01-29 10:40:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Markdown (Old) and /work/SRC/openSUSE:Factory/.python-Markdown.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Markdown" Changes: -------- --- /work/SRC/openSUSE:Factory/python-Markdown/python-Markdown.changes 2016-09-27 13:45:03.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-Markdown.new/python-Markdown.changes 2017-02-03 18:57:00.088875348 +0100 @@ -1,0 +2,5 @@ +Thu Jan 26 20:11:27 UTC 2017 - [email protected] + +- update to version 2.6.8: bugfix release + +------------------------------------------------------------------- Old: ---- Markdown-2.6.7.tar.gz New: ---- Markdown-2.6.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Markdown.spec ++++++ --- /var/tmp/diff_new_pack.kVhD8o/_old 2017-02-03 18:57:00.444825360 +0100 +++ /var/tmp/diff_new_pack.kVhD8o/_new 2017-02-03 18:57:00.444825360 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-Markdown # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: python-Markdown -Version: 2.6.7 +Version: 2.6.8 Release: 0 Summary: Python implementation of Markdown License: BSD-3-Clause ++++++ Markdown-2.6.7.tar.gz -> Markdown-2.6.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/PKG-INFO new/Markdown-2.6.8/PKG-INFO --- old/Markdown-2.6.7/PKG-INFO 2016-09-24 02:08:27.000000000 +0200 +++ new/Markdown-2.6.8/PKG-INFO 2017-01-26 00:07:04.000000000 +0100 @@ -1,12 +1,12 @@ Metadata-Version: 1.1 Name: Markdown -Version: 2.6.7 +Version: 2.6.8 Summary: Python implementation of Markdown. Home-page: https://pythonhosted.org/Markdown/ Author: Waylan Limberg Author-email: waylan.limberg [at] icloud.com License: BSD License -Download-URL: http://pypi.python.org/packages/source/M/Markdown/Markdown-2.6.7.tar.gz +Download-URL: http://pypi.python.org/packages/source/M/Markdown/Markdown-2.6.8.tar.gz Description: This is a Python implementation of John Gruber's Markdown_. It is almost completely compliant with the reference implementation, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/docs/extensions/code_hilite.txt new/Markdown-2.6.8/docs/extensions/code_hilite.txt --- old/Markdown-2.6.7/docs/extensions/code_hilite.txt 2016-09-24 01:31:43.000000000 +0200 +++ new/Markdown-2.6.8/docs/extensions/code_hilite.txt 2017-01-04 06:33:56.000000000 +0100 @@ -36,7 +36,7 @@ HTML templates. Pygments can generate CSS rules for you. Just run the following command from the command line: - pygmentize -S default -f html -a codehilite > styles.css + pygmentize -S default -f html -a .codehilite > styles.css If you are using a different `css_class` (default: `codehilite`), then set the value of the `-a` option to that class name. The CSS rules will be @@ -47,7 +47,7 @@ theme. For a list of themes installed on your system (additional themes can be installed via Pygments plugins), run the following command: - pygmetize -L style + pygmentize -L style !!! see also diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/docs/reference.txt new/Markdown-2.6.8/docs/reference.txt --- old/Markdown-2.6.7/docs/reference.txt 2016-04-12 01:37:21.000000000 +0200 +++ new/Markdown-2.6.8/docs/reference.txt 2017-01-04 06:33:56.000000000 +0100 @@ -128,16 +128,12 @@ The dictionary of configuration settings must be in the following format: - extension_configs = - { - 'extension_name_1': - { + extension_configs = { + 'extension_name_1': { 'option_1': 'value_1', 'option_2': 'value_2' }, - { - 'extension_name_2': - { + 'extension_name_2': { 'option_1': 'value_1' } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/__init__.py new/Markdown-2.6.8/markdown/__init__.py --- old/Markdown-2.6.7/markdown/__init__.py 2016-06-13 03:12:58.000000000 +0200 +++ new/Markdown-2.6.8/markdown/__init__.py 2017-01-25 23:05:42.000000000 +0100 @@ -75,9 +75,6 @@ 'xhtml5': to_xhtml_string, } - ESCAPED_CHARS = ['\\', '`', '*', '_', '{', '}', '[', ']', - '(', ')', '>', '#', '+', '-', '.', '!'] - def __init__(self, *args, **kwargs): """ Creates a new Markdown instance. @@ -147,6 +144,9 @@ 'deprecated along with "safe_mode".', DeprecationWarning) + self.ESCAPED_CHARS = ['\\', '`', '*', '_', '{', '}', '[', ']', + '(', ')', '>', '#', '+', '-', '.', '!'] + self.registeredExtensions = [] self.docType = "" self.stripTopLevelTags = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/__version__.py new/Markdown-2.6.8/markdown/__version__.py --- old/Markdown-2.6.7/markdown/__version__.py 2016-09-24 02:04:03.000000000 +0200 +++ new/Markdown-2.6.8/markdown/__version__.py 2017-01-26 00:02:19.000000000 +0100 @@ -5,7 +5,7 @@ # (major, minor, micro, alpha/beta/rc/final, #) # (1, 1, 2, 'alpha', 0) => "1.1.2.dev" # (1, 2, 0, 'beta', 2) => "1.2b2" -version_info = (2, 6, 7, 'final', 0) +version_info = (2, 6, 8, 'final', 0) def _get_version(): @@ -26,4 +26,5 @@ return str(main + sub) + version = _get_version() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/blockprocessors.py new/Markdown-2.6.8/markdown/blockprocessors.py --- old/Markdown-2.6.7/markdown/blockprocessors.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/markdown/blockprocessors.py 2017-01-25 23:05:42.000000000 +0100 @@ -493,15 +493,16 @@ def run(self, parent, blocks): block = blocks.pop(0) + match = self.match # Check for lines in block before hr. - prelines = block[:self.match.start()].rstrip('\n') + prelines = block[:match.start()].rstrip('\n') if prelines: # Recursively parse lines before hr so they get parsed first. self.parser.parseBlocks(parent, [prelines]) # create hr util.etree.SubElement(parent, 'hr') # check for lines in block after hr. - postlines = block[self.match.end():].lstrip('\n') + postlines = block[match.end():].lstrip('\n') if postlines: # Add lines after hr to master blocks for later parsing. blocks.insert(0, postlines) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/extensions/attr_list.py new/Markdown-2.6.8/markdown/extensions/attr_list.py --- old/Markdown-2.6.7/markdown/extensions/attr_list.py 2016-09-24 01:56:41.000000000 +0200 +++ new/Markdown-2.6.8/markdown/extensions/attr_list.py 2017-01-04 06:33:56.000000000 +0100 @@ -52,6 +52,7 @@ return 'id', t[1:] return t, t + _scanner = Scanner([ (r'[^ =]+=".*?"', _handle_double_quote), (r"[^ =]+='.*?'", _handle_single_quote), @@ -83,7 +84,7 @@ r'\:\-\.0-9\u00b7\u0300-\u036f\u203f-\u2040]+') def run(self, doc): - for elem in doc.getiterator(): + for elem in doc.iter(): if isBlockLevel(elem.tag): # Block level: check for attrs on last line of text RE = self.BLOCK_RE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/extensions/codehilite.py new/Markdown-2.6.8/markdown/extensions/codehilite.py --- old/Markdown-2.6.7/markdown/extensions/codehilite.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/markdown/extensions/codehilite.py 2017-01-25 23:05:42.000000000 +0100 @@ -166,7 +166,7 @@ c = re.compile(r''' (?:(?:^::+)|(?P<shebang>^[#]!)) # Shebang or 2 or more colons (?P<path>(?:/\w+)*[/ ])? # Zero or 1 path - (?P<lang>[\w+-]*) # The language + (?P<lang>[\w#.+-]*) # The language \s* # Arbitrary whitespace # Optional highlight lines, single- or double-quote-delimited (hl_lines=(?P<quot>"|')(?P<hl_lines>.*?)(?P=quot))? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/extensions/fenced_code.py new/Markdown-2.6.8/markdown/extensions/fenced_code.py --- old/Markdown-2.6.7/markdown/extensions/fenced_code.py 2016-04-12 01:37:21.000000000 +0200 +++ new/Markdown-2.6.8/markdown/extensions/fenced_code.py 2017-01-25 23:05:42.000000000 +0100 @@ -37,7 +37,7 @@ class FencedBlockPreprocessor(Preprocessor): FENCED_BLOCK_RE = re.compile(r''' (?P<fence>^(?:~{3,}|`{3,}))[ ]* # Opening ``` or ~~~ -(\{?\.?(?P<lang>[a-zA-Z0-9_+-]*))?[ ]* # Optional {, and lang +(\{?\.?(?P<lang>[\w#.+-]*))?[ ]* # Optional {, and lang # Optional highlight lines, single- or double-quote-delimited (hl_lines=(?P<quot>"|')(?P<hl_lines>.*?)(?P=quot))?[ ]* }?[ ]*\n # Optional closing } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/extensions/footnotes.py new/Markdown-2.6.8/markdown/extensions/footnotes.py --- old/Markdown-2.6.7/markdown/extensions/footnotes.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/markdown/extensions/footnotes.py 2017-01-25 23:05:42.000000000 +0100 @@ -20,14 +20,16 @@ from ..inlinepatterns import Pattern from ..treeprocessors import Treeprocessor from ..postprocessors import Postprocessor -from ..util import etree, text_type +from .. import util from ..odict import OrderedDict import re +import copy -FN_BACKLINK_TEXT = "zz1337820767766393qq" -NBSP_PLACEHOLDER = "qq3936677670287331zz" +FN_BACKLINK_TEXT = util.STX + "zz1337820767766393qq" + util.ETX +NBSP_PLACEHOLDER = util.STX + "qq3936677670287331zz" + util.ETX DEF_RE = re.compile(r'[ ]{0,3}\[\^([^\]]*)\]:\s*(.*)') TABBED_RE = re.compile(r'((\t)|( ))(.*)') +RE_REF_ID = re.compile(r'(fnref)(\d+)') class FootnoteExtension(Extension): @@ -53,6 +55,8 @@ # In multiple invocations, emit links that don't get tangled. self.unique_prefix = 0 + self.found_refs = {} + self.used_refs = set() self.reset() @@ -76,6 +80,15 @@ md.treeprocessors.add( "footnote", FootnoteTreeprocessor(self), "_begin" ) + + # Insert a tree-processor that will run after inline is done. + # In this tree-processor we want to check our duplicate footnote tracker + # And add additional backrefs to the footnote pointing back to the + # duplicated references. + md.treeprocessors.add( + "footnote-duplicate", FootnotePostTreeprocessor(self), '>inline' + ) + # Insert a postprocessor after amp_substitute oricessor md.postprocessors.add( "footnote", FootnotePostprocessor(self), ">amp_substitute" @@ -85,6 +98,29 @@ """ Clear footnotes on reset, and prepare for distinct document. """ self.footnotes = OrderedDict() self.unique_prefix += 1 + self.found_refs = {} + self.used_refs = set() + + def unique_ref(self, reference, found=False): + """ Get a unique reference if there are duplicates. """ + if not found: + return reference + + original_ref = reference + while reference in self.used_refs: + ref, rest = reference.split(self.get_separator(), 1) + m = RE_REF_ID.match(ref) + if m: + reference = '%s%d%s%s' % (m.group(1), int(m.group(2))+1, self.get_separator(), rest) + else: + reference = '%s%d%s%s' % (ref, 2, self.get_separator(), rest) + + self.used_refs.add(reference) + if original_ref in self.found_refs: + self.found_refs[original_ref] += 1 + else: + self.found_refs[original_ref] = 1 + return reference def findFootnotesPlaceholder(self, root): """ Return ElementTree Element that contains Footnote placeholder. """ @@ -120,13 +156,12 @@ else: return 'fn%s%s' % (self.get_separator(), id) - def makeFootnoteRefId(self, id): + def makeFootnoteRefId(self, id, found=False): """ Return footnote back-link id. """ if self.getConfig("UNIQUE_IDS"): - return 'fnref%s%d-%s' % (self.get_separator(), - self.unique_prefix, id) + return self.unique_ref('fnref%s%d-%s' % (self.get_separator(), self.unique_prefix, id), found) else: - return 'fnref%s%s' % (self.get_separator(), id) + return self.unique_ref('fnref%s%s' % (self.get_separator(), id), found) def makeFootnotesDiv(self, root): """ Return div of footnotes as et Element. """ @@ -134,16 +169,23 @@ if not list(self.footnotes.keys()): return None - div = etree.Element("div") + div = util.etree.Element("div") div.set('class', 'footnote') - etree.SubElement(div, "hr") - ol = etree.SubElement(div, "ol") + util.etree.SubElement(div, "hr") + ol = util.etree.SubElement(div, "ol") + surrogate_parent = util.etree.Element("div") for id in self.footnotes.keys(): - li = etree.SubElement(ol, "li") + li = util.etree.SubElement(ol, "li") li.set("id", self.makeFootnoteId(id)) - self.parser.parseChunk(li, self.footnotes[id]) - backlink = etree.Element("a") + # Parse footnote with surrogate parent as li cannot be used. + # List block handlers have special logic to deal with li. + # When we are done parsing, we will copy everything over to li. + self.parser.parseChunk(surrogate_parent, self.footnotes[id]) + for el in list(surrogate_parent): + li.append(el) + surrogate_parent.remove(el) + backlink = util.etree.Element("a") backlink.set("href", "#" + self.makeFootnoteRefId(id)) if self.md.output_format not in ['html5', 'xhtml5']: backlink.set("rev", "footnote") # Invalid in HTML5 @@ -161,7 +203,7 @@ node.text = node.text + NBSP_PLACEHOLDER node.append(backlink) else: - p = etree.SubElement(li, "p") + p = util.etree.SubElement(li, "p") p.append(backlink) return div @@ -268,19 +310,72 @@ def handleMatch(self, m): id = m.group(2) if id in self.footnotes.footnotes.keys(): - sup = etree.Element("sup") - a = etree.SubElement(sup, "a") - sup.set('id', self.footnotes.makeFootnoteRefId(id)) + sup = util.etree.Element("sup") + a = util.etree.SubElement(sup, "a") + sup.set('id', self.footnotes.makeFootnoteRefId(id, found=True)) a.set('href', '#' + self.footnotes.makeFootnoteId(id)) if self.footnotes.md.output_format not in ['html5', 'xhtml5']: a.set('rel', 'footnote') # invalid in HTML5 a.set('class', 'footnote-ref') - a.text = text_type(self.footnotes.footnotes.index(id) + 1) + a.text = util.text_type(self.footnotes.footnotes.index(id) + 1) return sup else: return None +class FootnotePostTreeprocessor(Treeprocessor): + """ Ammend footnote div with duplicates. """ + + def __init__(self, footnotes): + self.footnotes = footnotes + + def add_duplicates(self, li, duplicates): + """ Adjust current li and add the duplicates: fnref2, fnref3, etc. """ + for link in li.iter('a'): + # Find the link that needs to be duplicated. + if link.attrib.get('class', '') == 'footnote-backref': + ref, rest = link.attrib['href'].split(self.footnotes.get_separator(), 1) + # Duplicate link the number of times we need to + # and point the to the appropriate references. + links = [] + for index in range(2, duplicates + 1): + sib_link = copy.deepcopy(link) + sib_link.attrib['href'] = '%s%d%s%s' % (ref, index, self.footnotes.get_separator(), rest) + links.append(sib_link) + self.offset += 1 + # Add all the new duplicate links. + el = list(li)[-1] + for l in links: + el.append(l) + break + + def get_num_duplicates(self, li): + """ Get the number of duplicate refs of the footnote. """ + fn, rest = li.attrib.get('id', '').split(self.footnotes.get_separator(), 1) + link_id = '%sref%s%s' % (fn, self.footnotes.get_separator(), rest) + return self.footnotes.found_refs.get(link_id, 0) + + def handle_duplicates(self, parent): + """ Find duplicate footnotes and format and add the duplicates. """ + for li in list(parent): + # Check number of duplicates footnotes and insert + # additional links if needed. + count = self.get_num_duplicates(li) + if count > 1: + self.add_duplicates(li, count) + + def run(self, root): + """ Crawl the footnote div and add missing duplicate footnotes. """ + self.offset = 0 + for div in root.iter('div'): + if div.attrib.get('class', '') == 'footnote': + # Footnotes shoul be under the first orderd list under + # the footnote div. So once we find it, quit. + for ol in div.iter('ol'): + self.handle_duplicates(ol) + break + + class FootnoteTreeprocessor(Treeprocessor): """ Build and append footnote div to end of document. """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/extensions/tables.py new/Markdown-2.6.8/markdown/extensions/tables.py --- old/Markdown-2.6.7/markdown/extensions/tables.py 2016-09-24 01:36:40.000000000 +0200 +++ new/Markdown-2.6.8/markdown/extensions/tables.py 2017-01-25 23:05:42.000000000 +0100 @@ -19,32 +19,50 @@ from __future__ import unicode_literals from . import Extension from ..blockprocessors import BlockProcessor -from ..inlinepatterns import BacktickPattern, BACKTICK_RE from ..util import etree +import re class TableProcessor(BlockProcessor): """ Process Tables. """ + RE_CODE_PIPES = re.compile(r'(?:(\\\\)|(\\`+)|(`+)|(\\\|)|(\|))') + RE_END_BORDER = re.compile(r'(?<!\\)(?:\\\\)*\|$') + + def __init__(self, parser): + self.border = False + self.separator = '' + super(TableProcessor, self).__init__(parser) + def test(self, parent, block): - rows = block.split('\n') - return (len(rows) > 1 and '|' in rows[0] and - '|' in rows[1] and '-' in rows[1] and - rows[1].strip()[0] in ['|', ':', '-']) + """ + Ensure first two rows (column header and separator row) are valid table rows. + + Keep border check and separator row do avoid repeating the work. + """ + is_table = False + header = [row.strip() for row in block.split('\n')[0:2]] + if len(header) == 2: + self.border = header[0].startswith('|') + row = self._split_row(header[0]) + is_table = len(row) > 1 + + if is_table: + row = self._split_row(header[1]) + is_table = len(row) > 1 and set(''.join(row)) <= set('|:- ') + if is_table: + self.separator = row + return is_table def run(self, parent, blocks): """ Parse a table block and build table. """ block = blocks.pop(0).split('\n') header = block[0].strip() - seperator = block[1].strip() rows = [] if len(block) < 3 else block[2:] - # Get format type (bordered by pipes or not) - border = False - if header.startswith('|'): - border = True + # Get alignment of columns align = [] - for c in self._split_row(seperator, border): + for c in self.separator: c = c.strip() if c.startswith(':') and c.endswith(':'): align.append('center') @@ -54,21 +72,22 @@ align.append('right') else: align.append(None) + # Build table table = etree.SubElement(parent, 'table') thead = etree.SubElement(table, 'thead') - self._build_row(header, thead, align, border) + self._build_row(header, thead, align) tbody = etree.SubElement(table, 'tbody') for row in rows: - self._build_row(row.strip(), tbody, align, border) + self._build_row(row.strip(), tbody, align) - def _build_row(self, row, parent, align, border): + def _build_row(self, row, parent, align): """ Given a row of text, build table cells. """ tr = etree.SubElement(parent, 'tr') tag = 'td' if parent.tag == 'thead': tag = 'th' - cells = self._split_row(row, border) + cells = self._split_row(row) # We use align here rather than cells to ensure every row # contains the same number of columns. for i, a in enumerate(align): @@ -80,63 +99,94 @@ if a: c.set('align', a) - def _split_row(self, row, border): + def _split_row(self, row): """ split a row of text into list of cells. """ - if border: + if self.border: if row.startswith('|'): row = row[1:] - if row.endswith('|'): - row = row[:-1] - return self._split(row, '|') + row = self.RE_END_BORDER.sub('', row) + return self._split(row) - def _split(self, row, marker): + def _split(self, row): """ split a row of text with some code into a list of cells. """ - if self._row_has_unpaired_backticks(row): - # fallback on old behaviour - return row.split(marker) - # modify the backtick pattern to only match at the beginning of the search string - backtick_pattern = BacktickPattern('^' + BACKTICK_RE) elements = [] - current = '' - i = 0 - while i < len(row): - letter = row[i] - if letter == marker: - if current != '' or len(elements) == 0: - # Don't append empty string unless it is the first element - # The border is already removed when we get the row, then the line is strip()'d - # If the first element is a marker, then we have an empty first cell - elements.append(current) - current = '' - else: - match = backtick_pattern.getCompiledRegExp().match(row[i:]) - if not match: - current += letter - else: - groups = match.groups() - delim = groups[1] # the code block delimeter (ie 1 or more backticks) - row_contents = groups[2] # the text contained inside the code block - i += match.start(4) - 1 # jump pointer to the beginning of the rest of the text (group #4) - element = delim + row_contents + delim # reinstert backticks - current += element - i += 1 - elements.append(current) + pipes = [] + tics = [] + tic_points = [] + tic_region = [] + good_pipes = [] + + # Parse row + # Throw out \\, and \| + for m in self.RE_CODE_PIPES.finditer(row): + # Store ` data (len, start_pos, end_pos) + if m.group(2): + # \`+ + # Store length of each tic group: subtract \ + tics.append(len(m.group(2)) - 1) + # Store start of group, end of group, and escape length + tic_points.append((m.start(2), m.end(2) - 1, 1)) + elif m.group(3): + # `+ + # Store length of each tic group + tics.append(len(m.group(3))) + # Store start of group, end of group, and escape length + tic_points.append((m.start(3), m.end(3) - 1, 0)) + # Store pipe location + elif m.group(5): + pipes.append(m.start(5)) + + # Pair up tics according to size if possible + # Subtract the escape length *only* from the opening. + # Walk through tic list and see if tic has a close. + # Store the tic region (start of region, end of region). + pos = 0 + tic_len = len(tics) + while pos < tic_len: + try: + tic_size = tics[pos] - tic_points[pos][2] + if tic_size == 0: + raise ValueError + index = tics[pos + 1:].index(tic_size) + 1 + tic_region.append((tic_points[pos][0], tic_points[pos + index][1])) + pos += index + 1 + except ValueError: + pos += 1 + + # Resolve pipes. Check if they are within a tic pair region. + # Walk through pipes comparing them to each region. + # - If pipe position is less that a region, it isn't in a region + # - If it is within a region, we don't want it, so throw it out + # - If we didn't throw it out, it must be a table pipe + for pipe in pipes: + throw_out = False + for region in tic_region: + if pipe < region[0]: + # Pipe is not in a region + break + elif region[0] <= pipe <= region[1]: + # Pipe is within a code region. Throw it out. + throw_out = True + break + if not throw_out: + good_pipes.append(pipe) + + # Split row according to table delimeters. + pos = 0 + for pipe in good_pipes: + elements.append(row[pos:pipe]) + pos = pipe + 1 + elements.append(row[pos:]) return elements - def _row_has_unpaired_backticks(self, row): - count_total_backtick = row.count('`') - count_escaped_backtick = row.count('\`') - count_backtick = count_total_backtick - count_escaped_backtick - # odd number of backticks, - # we won't be able to build correct code blocks - return count_backtick & 1 - class TableExtension(Extension): """ Add tables to Markdown. """ def extendMarkdown(self, md, md_globals): """ Add an instance of TableProcessor to BlockParser. """ + if '|' not in md.ESCAPED_CHARS: + md.ESCAPED_CHARS.append('|') md.parser.blockprocessors.add('table', TableProcessor(md.parser), '<hashheader') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/inlinepatterns.py new/Markdown-2.6.8/markdown/inlinepatterns.py --- old/Markdown-2.6.7/markdown/inlinepatterns.py 2016-09-24 01:36:40.000000000 +0200 +++ new/Markdown-2.6.8/markdown/inlinepatterns.py 2017-01-25 23:05:42.000000000 +0100 @@ -87,6 +87,7 @@ inlinePatterns["emphasis2"] = SimpleTagPattern(EMPHASIS_2_RE, 'em') return inlinePatterns + """ The actual regular expressions for patterns ----------------------------------------------------------------------------- @@ -102,7 +103,7 @@ NOIMG = r'(?<!\!)' # `e=f()` or ``e=f("`")`` -BACKTICK_RE = r'(?<!\\)(`+)(.+?)(?<!`)\2(?!`)' +BACKTICK_RE = r'(?:(?<!\\)((?:\\{2})+)(?=`+)|(?<!\\)(`+)(.+?)(?<!`)\3(?!`))' # \< ESCAPE_RE = r'\\(.)' @@ -301,12 +302,16 @@ """ Return a `<code>` element containing the matching text. """ def __init__(self, pattern): Pattern.__init__(self, pattern) - self.tag = "code" + self.ESCAPED_BSLASH = '%s%s%s' % (util.STX, ord('\\'), util.ETX) + self.tag = 'code' def handleMatch(self, m): - el = util.etree.Element(self.tag) - el.text = util.AtomicString(m.group(3).strip()) - return el + if m.group(4): + el = util.etree.Element(self.tag) + el.text = util.AtomicString(m.group(4).strip()) + return el + else: + return m.group(2).replace('\\\\', self.ESCAPED_BSLASH) class DoubleTagPattern(SimpleTagPattern): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/preprocessors.py new/Markdown-2.6.8/markdown/preprocessors.py --- old/Markdown-2.6.7/markdown/preprocessors.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/markdown/preprocessors.py 2017-01-25 23:05:42.000000000 +0100 @@ -258,7 +258,13 @@ else: items.append(block) - right_tag, data_index = self._get_right_tag(left_tag, 0, block) + # Need to evaluate all items so we can calculate relative to the left index. + right_tag, data_index = self._get_right_tag(left_tag, left_index, ''.join(items)) + # Adjust data_index: relative to items -> relative to last block + prev_block_length = 0 + for item in items[:-1]: + prev_block_length += len(item) + data_index -= prev_block_length if self._equal_tags(left_tag, right_tag): # if find closing tag diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/treeprocessors.py new/Markdown-2.6.8/markdown/treeprocessors.py --- old/Markdown-2.6.7/markdown/treeprocessors.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/markdown/treeprocessors.py 2016-11-11 23:41:49.000000000 +0100 @@ -358,14 +358,14 @@ self._prettifyETree(root) # Do <br />'s seperately as they are often in the middle of # inline content and missed by _prettifyETree. - brs = root.getiterator('br') + brs = root.iter('br') for br in brs: if not br.tail or not br.tail.strip(): br.tail = '\n' else: br.tail = '\n%s' % br.tail # Clean up extra empty lines at end of code blocks. - pres = root.getiterator('pre') + pres = root.iter('pre') for pre in pres: if len(pre) and pre[0].tag == 'code': pre[0].text = util.AtomicString(pre[0].text.rstrip() + '\n') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/markdown/util.py new/Markdown-2.6.8/markdown/util.py --- old/Markdown-2.6.7/markdown/util.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/markdown/util.py 2017-01-25 23:05:42.000000000 +0100 @@ -32,7 +32,7 @@ "|hr|hr/|style|li|dt|dd|thead|tbody" "|tr|th|td|section|footer|header|group|figure" "|figcaption|aside|article|canvas|output" - "|progress|video|nav)$", + "|progress|video|nav|main)$", re.IGNORECASE ) # Placeholders diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/setup.py new/Markdown-2.6.8/setup.py --- old/Markdown-2.6.7/setup.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/setup.py 2017-01-04 06:33:56.000000000 +0100 @@ -22,6 +22,7 @@ finally: fp.close() + version, version_info = get_version() # Get development Status for classifiers @@ -210,6 +211,7 @@ sub_commands = build.sub_commands + [('build_docs', has_docs)] + long_description = ''' This is a Python implementation of John Gruber's Markdown_. It is almost completely compliant with the reference implementation, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/extensions/extra/footnote.html new/Markdown-2.6.8/tests/extensions/extra/footnote.html --- old/Markdown-2.6.7/tests/extensions/extra/footnote.html 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/extensions/extra/footnote.html 2017-01-25 23:05:42.000000000 +0100 @@ -1,5 +1,10 @@ <p>This is the body with a footnote<sup id="fnref:1"><a class="footnote-ref" href="#fn:1" rel="footnote">1</a></sup> or two<sup id="fnref:2"><a class="footnote-ref" href="#fn:2" rel="footnote">2</a></sup> or more<sup id="fnref:3"><a class="footnote-ref" href="#fn:3" rel="footnote">3</a></sup> <sup id="fnref:4"><a class="footnote-ref" href="#fn:4" rel="footnote">4</a></sup> <sup id="fnref:5"><a class="footnote-ref" href="#fn:5" rel="footnote">5</a></sup>.</p> <p>Also a reference that does not exist[^6].</p> +<p>Duplicate<sup id="fnref:a"><a class="footnote-ref" href="#fn:a" rel="footnote">6</a></sup> footnotes<sup id="fnref2:a"><a class="footnote-ref" href="#fn:a" rel="footnote">6</a></sup> test<sup id="fnref3:a"><a class="footnote-ref" href="#fn:a" rel="footnote">6</a></sup>.</p> +<p>Duplicate<sup id="fnref:b"><a class="footnote-ref" href="#fn:b" rel="footnote">7</a></sup> footnotes<sup id="fnref2:b"><a class="footnote-ref" href="#fn:b" rel="footnote">7</a></sup> test<sup id="fnref3:b"><a class="footnote-ref" href="#fn:b" rel="footnote">7</a></sup>.</p> +<p>Single after duplicates<sup id="fnref:c"><a class="footnote-ref" href="#fn:c" rel="footnote">8</a></sup>.</p> +<p>Test emphasis at end of footnote<sup id="fnref:d"><a class="footnote-ref" href="#fn:d" rel="footnote">9</a></sup></p> +<p>Complex footnote content<sup id="fnref:e"><a class="footnote-ref" href="#fn:e" rel="footnote">10</a></sup></p> <div class="footnote"> <hr /> <ol> @@ -29,5 +34,38 @@ Second line of first paragraph is not intended. Nor is third... <a class="footnote-backref" href="#fnref:5" rev="footnote" title="Jump back to footnote 5 in the text">↩</a></p> </li> +<li id="fn:a"> +<p>1 <a class="footnote-backref" href="#fnref:a" rev="footnote" title="Jump back to footnote 6 in the text">↩</a><a class="footnote-backref" href="#fnref2:a" rev="footnote" title="Jump back to footnote 6 in the text">↩</a><a class="footnote-backref" href="#fnref3:a" rev="footnote" title="Jump back to footnote 6 in the text">↩</a></p> +</li> +<li id="fn:b"> +<p>2 <a class="footnote-backref" href="#fnref:b" rev="footnote" title="Jump back to footnote 7 in the text">↩</a><a class="footnote-backref" href="#fnref2:b" rev="footnote" title="Jump back to footnote 7 in the text">↩</a><a class="footnote-backref" href="#fnref3:b" rev="footnote" title="Jump back to footnote 7 in the text">↩</a></p> +</li> +<li id="fn:c"> +<p>3 <a class="footnote-backref" href="#fnref:c" rev="footnote" title="Jump back to footnote 8 in the text">↩</a></p> +</li> +<li id="fn:d"> +<p><em>emphasis works</em></p> +<p><em>emphasis still works</em> <a class="footnote-backref" href="#fnref:d" rev="footnote" title="Jump back to footnote 9 in the text">↩</a></p> +</li> +<li id="fn:e"> +<ol> +<li> +<p>The top couple half figure, contrary sides and hands across with bottom couple,</p> +<p>Half figure back on your own sides, and turn partner to places,</p> +<p>Swing partners with right hands into straight line long-ways, as in a reel, and</p> +<p>Set,</p> +<p>Hey and return to places,</p> +<p>The other three couples do the same.</p> +</li> +<li> +<p>Top and bottom couples meet and set,</p> +<p>Then each gentleman leas the opposite lady to the couple on his left, and set,</p> +<p>Aach four right and left,</p> +<p>Swing side couples to places, and turn partners all eight,</p> +<p>The other two couple o the same.</p> +</li> +</ol> +<p><a class="footnote-backref" href="#fnref:e" rev="footnote" title="Jump back to footnote 10 in the text">↩</a></p> +</li> </ol> </div> \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/extensions/extra/footnote.txt new/Markdown-2.6.8/tests/extensions/extra/footnote.txt --- old/Markdown-2.6.7/tests/extensions/extra/footnote.txt 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/extensions/extra/footnote.txt 2017-01-25 23:05:42.000000000 +0100 @@ -2,6 +2,16 @@ Also a reference that does not exist[^6]. +Duplicate[^a] footnotes[^a] test[^a]. + +Duplicate[^b] footnotes[^b] test[^b]. + +Single after duplicates[^c]. + +Test emphasis at end of footnote[^d] + +Complex footnote content[^e] + [^1]: Footnote that ends with a list: * item 1 @@ -18,3 +28,35 @@ [^5]: First line of first paragraph. Second line of first paragraph is not intended. Nor is third... + +[^a]: 1 +[^b]: 2 +[^c]: 3 + +[^d]: + _emphasis works_ + + _emphasis still works_ + +[^e]: + 1. The top couple half figure, contrary sides and hands across with bottom couple, + + Half figure back on your own sides, and turn partner to places, + + Swing partners with right hands into straight line long-ways, as in a reel, and + + Set, + + Hey and return to places, + + The other three couples do the same. + + 2. Top and bottom couples meet and set, + + Then each gentleman leas the opposite lady to the couple on his left, and set, + + Aach four right and left, + + Swing side couples to places, and turn partners all eight, + + The other two couple o the same. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/extensions/extra/tables.html new/Markdown-2.6.8/tests/extensions/extra/tables.html --- old/Markdown-2.6.7/tests/extensions/extra/tables.html 2016-09-24 01:36:40.000000000 +0200 +++ new/Markdown-2.6.8/tests/extensions/extra/tables.html 2017-01-25 23:05:42.000000000 +0100 @@ -250,4 +250,129 @@ <td>(<code>bar</code>) and <code>baz</code>.</td> </tr> </tbody> +</table> +<p>Lists are not tables</p> +<ul> +<li>this | should | not</li> +<li>be | a | table</li> +</ul> +<p>Add tests for issue #449</p> +<table> +<thead> +<tr> +<th>Odd backticks</th> +<th>Even backticks</th> +</tr> +</thead> +<tbody> +<tr> +<td><code>[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~]</code></td> +<td><code>[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^`_`{|}~]</code></td> +</tr> +</tbody> +</table> +<table> +<thead> +<tr> +<th>Escapes</th> +<th>More Escapes</th> +</tr> +</thead> +<tbody> +<tr> +<td><code>`\</code></td> +<td><code>\</code></td> +</tr> +</tbody> +</table> +<p>Only the first backtick can be escaped</p> +<table> +<thead> +<tr> +<th>Escaped</th> +<th>Bacticks</th> +</tr> +</thead> +<tbody> +<tr> +<td>`<code>\</code></td> +<td>``</td> +</tr> +</tbody> +</table> +<p>Test escaped pipes</p> +<table> +<thead> +<tr> +<th>Column 1</th> +<th>Column 2</th> +</tr> +</thead> +<tbody> +<tr> +<td><code>|</code> |</td> +<td>Pipes are okay in code and escaped. |</td> +</tr> +</tbody> +</table> +<table> +<thead> +<tr> +<th>Column 1</th> +<th>Column 2</th> +</tr> +</thead> +<tbody> +<tr> +<td>row1</td> +<td>row1 |</td> +</tr> +<tr> +<td>row2</td> +<td>row2</td> +</tr> +</tbody> +</table> +<p>Test header escapes</p> +<table> +<thead> +<tr> +<th><code>`\</code> |</th> +<th><code>\</code> |</th> +</tr> +</thead> +<tbody> +<tr> +<td>row1</td> +<td>row1</td> +</tr> +<tr> +<td>row2</td> +<td>row2</td> +</tr> +</tbody> +</table> +<p>Escaped pipes in format row should not be a table</p> +<p>| Column1 | Column2 | +| ------- || ------- | +| row1 | row1 | +| row2 | row2 |</p> +<p>Test escaped code in Table</p> +<table> +<thead> +<tr> +<th>Should not be code</th> +<th>Should be code</th> +</tr> +</thead> +<tbody> +<tr> +<td>`Not code`</td> +<td>\<code>code</code></td> +</tr> +<tr> +<td>\`Not code\`</td> +<td>\\<code>code</code></td> +</tr> +</tbody> </table> \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/extensions/extra/tables.txt new/Markdown-2.6.8/tests/extensions/extra/tables.txt --- old/Markdown-2.6.7/tests/extensions/extra/tables.txt 2015-12-30 00:31:55.000000000 +0100 +++ new/Markdown-2.6.8/tests/extensions/extra/tables.txt 2017-01-25 23:05:42.000000000 +0100 @@ -45,7 +45,7 @@ | Content Cell | Content Cell | Four spaces is a code block: - + First Header | Second Header ------------ | ------------- Content Cell | Content Cell @@ -74,4 +74,57 @@ foo | bar --- | --- -foo | (`bar`) and `baz`. \ No newline at end of file +foo | (`bar`) and `baz`. + +Lists are not tables + + - this | should | not + - be | a | table + +Add tests for issue #449 + +Odd backticks | Even backticks +------------ | ------------- +``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~]`` | ``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^`_`{|}~]`` + +Escapes | More Escapes +------- | ------ +`` `\`` | `\` + +Only the first backtick can be escaped + +Escaped | Bacticks +------- | ------ +\`` \` | \`\` + +Test escaped pipes + +Column 1 | Column 2 +-------- | -------- +`|` \| | Pipes are okay in code and escaped. \| + +| Column 1 | Column 2 | +| -------- | -------- | +| row1 | row1 \| +| row2 | row2 | + +Test header escapes + +| `` `\`` \| | `\` \| +| ---------- | ---- | +| row1 | row1 | +| row2 | row2 | + +Escaped pipes in format row should not be a table + +| Column1 | Column2 | +| ------- \|| ------- | +| row1 | row1 | +| row2 | row2 | + +Test escaped code in Table + +Should not be code | Should be code +------------------ | -------------- +\`Not code\` | \\`code` +\\\`Not code\\\` | \\\\`code` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/misc/backtick-escape.html new/Markdown-2.6.8/tests/misc/backtick-escape.html --- old/Markdown-2.6.7/tests/misc/backtick-escape.html 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/misc/backtick-escape.html 2017-01-25 23:05:42.000000000 +0100 @@ -1,3 +1,4 @@ -<p>\`This should not be in code.\` -`This also should not be in code.` +<p>`This should not be in code.` +\<code>This should be in code.\\</code> +\`This should not be in code.\` `And finally this should not be in code.`</p> \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/misc/backtick-escape.txt new/Markdown-2.6.8/tests/misc/backtick-escape.txt --- old/Markdown-2.6.7/tests/misc/backtick-escape.txt 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/misc/backtick-escape.txt 2017-01-25 23:05:42.000000000 +0100 @@ -1,3 +1,4 @@ -\\`This should not be in code.\\` -\`This also should not be in code.\` +\`This should not be in code.\` +\\`This should be in code.\\` +\\\`This should not be in code.\\\` \`And finally this should not be in code.` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/misc/blockquote-hr.html new/Markdown-2.6.8/tests/misc/blockquote-hr.html --- old/Markdown-2.6.7/tests/misc/blockquote-hr.html 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/misc/blockquote-hr.html 2017-01-25 23:05:42.000000000 +0100 @@ -13,4 +13,13 @@ Even a lazy line.</p> <hr /> <p>The last line.</p> +</blockquote> +<p>foo</p> +<blockquote> +<p>bar</p> +<hr /> +</blockquote> +<hr /> +<blockquote> +<p>baz</p> </blockquote> \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/misc/blockquote-hr.txt new/Markdown-2.6.8/tests/misc/blockquote-hr.txt --- old/Markdown-2.6.7/tests/misc/blockquote-hr.txt 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/misc/blockquote-hr.txt 2017-01-25 23:05:42.000000000 +0100 @@ -19,3 +19,9 @@ > --- > The last line. + +foo +> bar +> *** +--- +> baz diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/misc/html.html new/Markdown-2.6.8/tests/misc/html.html --- old/Markdown-2.6.7/tests/misc/html.html 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/misc/html.html 2017-01-25 23:05:42.000000000 +0100 @@ -8,6 +8,17 @@ Html with various attributes. </div> +<div> + <div> + Div with a blank line + + in the middle. + </div> + <div> + This gets treated as HTML. + </div> +</div> + <p>And of course <script>blah</script>.</p> <p><a href="script>stuff</script">this <script>link</a></p> <p>Some funky <x\]> inline stuff with markdown escaping syntax.</p> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/misc/html.txt new/Markdown-2.6.8/tests/misc/html.txt --- old/Markdown-2.6.7/tests/misc/html.txt 2015-08-28 05:42:04.000000000 +0200 +++ new/Markdown-2.6.8/tests/misc/html.txt 2017-01-25 23:05:42.000000000 +0100 @@ -11,6 +11,17 @@ Html with various attributes. </div> +<div> + <div> + Div with a blank line + + in the middle. + </div> + <div> + This gets treated as HTML. + </div> +</div> + And of course <script>blah</script>. [this <script>link](<script>stuff</script>) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Markdown-2.6.7/tests/test_apis.py new/Markdown-2.6.8/tests/test_apis.py --- old/Markdown-2.6.7/tests/test_apis.py 2016-03-11 23:52:18.000000000 +0100 +++ new/Markdown-2.6.8/tests/test_apis.py 2017-01-25 23:05:42.000000000 +0100 @@ -758,3 +758,15 @@ """ self.create_config_file(config) self.assertRaises(yaml.YAMLError, parse_options, ['-c', self.tempfile]) + + +class TestEscapeAppend(unittest.TestCase): + """ Tests escape character append. """ + + def testAppend(self): + """ Test that appended escapes are only in the current instance. """ + md = markdown.Markdown() + md.ESCAPED_CHARS.append('|') + self.assertEqual('|' in md.ESCAPED_CHARS, True) + md2 = markdown.Markdown() + self.assertEqual('|' not in md2.ESCAPED_CHARS, True)
