diff --git a/taiga/mdrender/extensions/autolink.py b/taiga/mdrender/extensions/autolink.py index 1dbf2b98..7faeb930 100644 --- a/taiga/mdrender/extensions/autolink.py +++ b/taiga/mdrender/extensions/autolink.py @@ -6,6 +6,7 @@ import re import markdown + # We can't re-use the built-in AutolinkPattern because we need to add protocols # to links without them. class AutolinkPattern(markdown.inlinepatterns.Pattern): @@ -20,6 +21,7 @@ class AutolinkPattern(markdown.inlinepatterns.Pattern): el.text = markdown.util.AtomicString(m.group(2)) return el + class AutolinkExtension(markdown.Extension): """An extension that turns all URLs into links. diff --git a/taiga/mdrender/extensions/automail.py b/taiga/mdrender/extensions/automail.py index f8c65f77..7c98520c 100644 --- a/taiga/mdrender/extensions/automail.py +++ b/taiga/mdrender/extensions/automail.py @@ -3,9 +3,9 @@ # for details. All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. -import re import markdown + # We can't re-use the built-in AutomailPattern because we need to add mailto:. # We also don't care about HTML-encoding the email. class AutomailPattern(markdown.inlinepatterns.Pattern): @@ -15,6 +15,7 @@ class AutomailPattern(markdown.inlinepatterns.Pattern): el.text = markdown.util.AtomicString(m.group(2)) return el + class AutomailExtension(markdown.Extension): """An extension that turns all email addresses into links.""" diff --git a/taiga/mdrender/extensions/emojify.py b/taiga/mdrender/extensions/emojify.py index c7b4a19c..502b0495 100644 --- a/taiga/mdrender/extensions/emojify.py +++ b/taiga/mdrender/extensions/emojify.py @@ -1,4 +1,4 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # Tested on Markdown 2.3.1 # @@ -26,7 +26,6 @@ import re -import os from markdown.extensions import Extension from markdown.preprocessors import Preprocessor @@ -167,7 +166,7 @@ class EmojifyPreprocessor(Preprocessor): def emojify(match): emoji = match.group(1) - if not emoji in emojis_set: + if emoji not in emojis_set: return match.group(0) url = emojis_path + emoji + u'.png' diff --git a/taiga/mdrender/extensions/mentions.py b/taiga/mdrender/extensions/mentions.py index f826b577..37468f66 100644 --- a/taiga/mdrender/extensions/mentions.py +++ b/taiga/mdrender/extensions/mentions.py @@ -1,4 +1,4 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # Tested on Markdown 2.3.1 # @@ -23,10 +23,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. - -import re -import os - from markdown.extensions import Extension from markdown.inlinepatterns import Pattern from markdown.util import etree @@ -39,9 +35,7 @@ class MentionsExtension(Extension): MENTION_RE = r'(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-]+)' mentionsPattern = MentionsPattern(MENTION_RE) mentionsPattern.md = md - md.inlinePatterns.add('mentions', - mentionsPattern, - '_begin') + md.inlinePatterns.add('mentions', mentionsPattern, '_begin') class MentionsPattern(Pattern): diff --git a/taiga/mdrender/extensions/references.py b/taiga/mdrender/extensions/references.py index eed3db3e..4861270a 100644 --- a/taiga/mdrender/extensions/references.py +++ b/taiga/mdrender/extensions/references.py @@ -1,4 +1,4 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # Tested on Markdown 2.3.1 # @@ -23,10 +23,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. - -import re -import os - from markdown.extensions import Extension from markdown.inlinepatterns import Pattern from markdown.util import etree @@ -43,9 +39,8 @@ class TaigaReferencesExtension(Extension): TAIGA_REFERENCE_RE = r'(?<=^|(?<=[^a-zA-Z0-9-\[]))#(\d+)' referencesPattern = TaigaReferencesPattern(TAIGA_REFERENCE_RE, self.project) referencesPattern.md = md - md.inlinePatterns.add('taiga-references', - referencesPattern, - '_begin') + md.inlinePatterns.add('taiga-references', referencesPattern, '_begin') + class TaigaReferencesPattern(Pattern): def __init__(self, pattern, project): @@ -73,7 +68,6 @@ class TaigaReferencesPattern(Pattern): else: return "#{}".format(obj_ref) - url = "/#/project/{}/{}/{}".format( self.project.slug, obj_section, diff --git a/taiga/mdrender/extensions/semi_sane_lists.py b/taiga/mdrender/extensions/semi_sane_lists.py index 477b8ef7..7eba07e7 100644 --- a/taiga/mdrender/extensions/semi_sane_lists.py +++ b/taiga/mdrender/extensions/semi_sane_lists.py @@ -2,15 +2,17 @@ # for details. All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. -import re import markdown + class SemiSaneOListProcessor(markdown.blockprocessors.OListProcessor): SIBLING_TAGS = ['ol'] + class SemiSaneUListProcessor(markdown.blockprocessors.UListProcessor): SIBLING_TAGS = ['ul'] + class SemiSaneListExtension(markdown.Extension): """An extension that causes lists to be treated the same way GitHub does. diff --git a/taiga/mdrender/extensions/spaced_link.py b/taiga/mdrender/extensions/spaced_link.py index c0d08d09..7f619cdb 100644 --- a/taiga/mdrender/extensions/spaced_link.py +++ b/taiga/mdrender/extensions/spaced_link.py @@ -20,6 +20,7 @@ SPACED_IMAGE_LINK_RE = markdown.inlinepatterns.IMAGE_LINK_RE.replace( SPACED_IMAGE_REFERENCE_RE = markdown.inlinepatterns.IMAGE_REFERENCE_RE.replace( r'\!' + BRK, r'\!' + BRK + SPACE) + class SpacedLinkExtension(markdown.Extension): """An extension that supports links and images with additional whitespace. diff --git a/taiga/mdrender/extensions/strikethrough.py b/taiga/mdrender/extensions/strikethrough.py index eabf87d2..c00a09d7 100644 --- a/taiga/mdrender/extensions/strikethrough.py +++ b/taiga/mdrender/extensions/strikethrough.py @@ -4,7 +4,8 @@ import markdown -STRIKE_RE = r'(~{2})(.+?)(~{2})' # ~~strike~~ +STRIKE_RE = r'(~{2})(.+?)(~{2})' # ~~strike~~ + class StrikethroughExtension(markdown.Extension): """An extension that supports PHP-Markdown style strikethrough. diff --git a/taiga/mdrender/extensions/wikilinks.py b/taiga/mdrender/extensions/wikilinks.py index 25a9d4d7..ea5cd3f9 100644 --- a/taiga/mdrender/extensions/wikilinks.py +++ b/taiga/mdrender/extensions/wikilinks.py @@ -5,20 +5,21 @@ from markdown.inlinepatterns import Pattern from markdown.util import etree import re + def build_url(label, base, end): """ Build a url from the label, a base, and an end. """ clean_label = re.sub(r'([ ]+_)|(_[ ]+)|([ ]+)', '_', label) - return '%s%s%s'% (base, clean_label, end) + return '%s%s%s' % (base, clean_label, end) class WikiLinkExtension(Extension): def __init__(self, configs): # set extension defaults self.config = { - 'base_url' : ['/', 'String to append to beginning or URL.'], - 'end_url' : ['/', 'String to append to end of URL.'], - 'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'], - 'build_url' : [build_url, 'Callable formats URL from label.'], + 'base_url': ['/', 'String to append to beginning or URL.'], + 'end_url': ['/', 'String to append to end of URL.'], + 'html_class': ['wikilink', 'CSS hook. Leave blank for none.'], + 'build_url': [build_url, 'Callable formats URL from label.'], } configs = dict(configs) or {} # Override defaults with user settings diff --git a/tests/unit/test_mdrender.py b/tests/unit/test_mdrender.py index af794ae7..90a91550 100644 --- a/tests/unit/test_mdrender.py +++ b/tests/unit/test_mdrender.py @@ -1,14 +1,8 @@ from unittest.mock import patch, MagicMock -import pytest - -import taiga.base -from taiga.mdrender.extensions import mentions from taiga.mdrender.extensions import emojify from taiga.mdrender.service import render, cache_by_sha, get_diff_of_htmls, render_and_extract -from taiga.projects.references import services - from taiga.users.models import User from datetime import datetime @@ -17,14 +11,17 @@ dummy_project = MagicMock() dummy_project.id = 1 dummy_project.slug = "test" + def test_proccessor_valid_emoji(): result = emojify.EmojifyPreprocessor().run(["**:smile:**"]) assert result == ["**![smile](http://localhost:8000/static/img/emojis/smile.png)**"] + def test_proccessor_invalid_emoji(): result = emojify.EmojifyPreprocessor().run(["**:notvalidemoji:**"]) assert result == ["**:notvalidemoji:**"] + def test_proccessor_valid_user_mention(): with patch("taiga.mdrender.extensions.mentions.User") as mock: instance = mock.objects.get.return_value @@ -33,6 +30,7 @@ def test_proccessor_valid_user_mention(): expected_result = "

@user1

" assert result == expected_result + def test_proccessor_invalid_user_mention(): with patch("taiga.mdrender.extensions.mentions.User") as mock: mock.DoesNotExist = User.DoesNotExist @@ -40,6 +38,7 @@ def test_proccessor_invalid_user_mention(): result = render(dummy_project, "**@notvaliduser**") assert result == '

@notvaliduser

' + def test_proccessor_valid_us_reference(): with patch("taiga.mdrender.extensions.references.get_instance_by_ref") as mock: instance = mock.return_value @@ -49,97 +48,117 @@ def test_proccessor_valid_us_reference(): expected_result = '

#1

' assert result == expected_result + def test_proccessor_valid_issue_reference(): with patch("taiga.mdrender.extensions.references.get_instance_by_ref") as mock: instance = mock.return_value instance.content_type.model = "issue" instance.content_object.subject = "test" - result = render(dummy_project, "**#1**") - expected_result = '

#1

' + result = render(dummy_project, "**#2**") + expected_result = '

#2

' assert result == expected_result + def test_proccessor_valid_task_reference(): with patch("taiga.mdrender.extensions.references.get_instance_by_ref") as mock: instance = mock.return_value instance.content_type.model = "task" instance.content_object.subject = "test" - result = render(dummy_project, "**#1**") - expected_result = '

#1

' + result = render(dummy_project, "**#3**") + expected_result = '

#3

' assert result == expected_result + def test_proccessor_invalid_type_reference(): with patch("taiga.mdrender.extensions.references.get_instance_by_ref") as mock: instance = mock.return_value instance.content_type.model = "other" instance.content_object.subject = "test" - result = render(dummy_project, "**#1**") - assert result == "

#1

" + result = render(dummy_project, "**#4**") + assert result == "

#4

" + def test_proccessor_invalid_reference(): with patch("taiga.mdrender.extensions.references.get_instance_by_ref") as mock: mock.return_value = None - result = render(dummy_project, "**#1**") - assert result == "

#1

" + result = render(dummy_project, "**#5**") + assert result == "

#5

" + def test_render_wiki_strong(): assert render(dummy_project, "**test**") == "

test

" assert render(dummy_project, "__test__") == "

test

" + def test_render_wiki_italic(): assert render(dummy_project, "*test*") == "

test

" assert render(dummy_project, "_test_") == "

test

" + def test_render_wiki_strike(): assert render(dummy_project, "~~test~~") == "

test

" + def test_render_absolute_link(): assert render(dummy_project, "[test](/test)") == "

test

" + def test_render_relative_link(): assert render(dummy_project, "[test](test)") == "

test

" + def test_render_wikilink(): expected_result = "

test

" assert render(dummy_project, "[[test]]") == expected_result + def test_render_wikilink_with_custom_title(): expected_result = "

custom

" assert render(dummy_project, "[[test|custom]]") == expected_result + def test_render_reference_links(): expected_result = "

An example of reference link

" source = "An [example][id] of reference link\n [id]: http://example.com/ \"Title\"" assert render(dummy_project, source) == expected_result + def test_render_url_autolinks(): expected_result = "

Test the http://example.com/ autolink

" source = "Test the http://example.com/ autolink" assert render(dummy_project, source) == expected_result + def test_render_url_autolinks_without_http(): expected_result = "

Test the www.example.com autolink

" source = "Test the www.example.com autolink" assert render(dummy_project, source) == expected_result + def test_render_url_automail(): expected_result = "

Test the example@example.com automail

" source = "Test the example@example.com automail" assert render(dummy_project, source) == expected_result + def test_render_absolute_image(): assert render(dummy_project, "![test](/test.png)") == "

\"test\"

" + def test_render_relative_image(): assert render(dummy_project, "![test](test.png)") == "

\"test\"

" + def test_render_triple_quote_code(): expected_result = "
print("test")\n
" assert render(dummy_project, "```\nprint(\"test\")\n```") == expected_result + def test_render_triple_quote_and_lang_code(): expected_result = "
print("test")\n
" assert render(dummy_project, "```python\nprint(\"test\")\n```") == expected_result + def test_cache_by_sha(): @cache_by_sha def test_cache(project, text): @@ -151,18 +170,22 @@ def test_cache_by_sha(): result3 = test_cache(dummy_project, "test") assert result1 == result3 + def test_get_diff_of_htmls_insertions(): result = get_diff_of_htmls("", "

test

") assert result == "<p>test</p>" + def test_get_diff_of_htmls_deletions(): result = get_diff_of_htmls("

test

", "") assert result == "<p>test</p>" + def test_get_diff_of_htmls_modifications(): result = get_diff_of_htmls("

test1

", "

1test

") assert result == "<p>1test1</p>" + def test_render_and_extract_references(): with patch("taiga.mdrender.extensions.references.get_instance_by_ref") as mock: instance = mock.return_value @@ -171,6 +194,7 @@ def test_render_and_extract_references(): (_, extracted) = render_and_extract(dummy_project, "**#1**") assert extracted['references'] == [instance.content_object] + def test_render_and_extract_mentions(): with patch("taiga.mdrender.extensions.mentions.User") as mock: instance = mock.objects.get.return_value