diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 41240f8..000c0b2 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -16,14 +16,14 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up Python 3.6 + - name: Set up Python 3.8 uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: 3.8 - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8==2.5.4 pytest + pip install flake8==3.8.4 pytest if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 run: | diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 1a03a7b..9e3a349 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.x' + python-version: '3.8' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/README.rst b/README.rst index 4d21411..1e245c1 100644 --- a/README.rst +++ b/README.rst @@ -75,6 +75,18 @@ bullets lists are nested. Otherwise, the bullet will alternate based on nesting level. Defaults to ``'*+-'``. +strong_em_symbol + In markdown, both ``*`` and ``_`` are used to encode **strong** or + *emphasized* texts. Either of these symbols can be chosen by the options + ``ASTERISK`` (default) or ``UNDERSCORE`` respectively. + +newline_style + Defines the style of marking linebreaks (``
``) in markdown. The default + value ``SPACES`` of this option will adopt the usual two spaces and a newline, + while ``BACKSLASH`` will convert a linebreak to ``\\n`` (a backslash an a + newline). While the latter convention is non-standard, it is commonly + preferred and supported by a lot of interpreters. + Options may be specified as kwargs to the ``markdownify`` function, or as a nested ``Options`` class in ``MarkdownConverter`` subclasses. diff --git a/markdownify/__init__.py b/markdownify/__init__.py index 8200ca7..0b2a620 100644 --- a/markdownify/__init__.py +++ b/markdownify/__init__.py @@ -15,6 +15,14 @@ ATX_CLOSED = 'atx_closed' UNDERLINED = 'underlined' SETEXT = UNDERLINED +# Newline style +SPACES = 'spaces' +BACKSLASH = 'backslash' + +# Strong and emphasis style +ASTERISK = '*' +UNDERSCORE = '_' + def escape(text): if not text: @@ -46,6 +54,8 @@ class MarkdownConverter(object): autolinks = True heading_style = UNDERLINED bullets = '*+-' # An iterable of bullet types. + strong_em_symbol = ASTERISK + newline_style = SPACES class Options(DefaultOptions): pass @@ -148,25 +158,29 @@ class MarkdownConverter(object): if convert_as_inline: return text - return '\n' + line_beginning_re.sub('> ', text) if text else '' + return '\n' + (line_beginning_re.sub('> ', text) + '\n\n') if text else '' def convert_br(self, el, text, convert_as_inline): if convert_as_inline: return "" - return ' \n' + if self.options['newline_style'].lower() == BACKSLASH: + return '\\\n' + else: + return ' \n' def convert_em(self, el, text, convert_as_inline): + em_tag = self.options['strong_em_symbol'] prefix, suffix, text = chomp(text) if not text: return '' - return '%s*%s*%s' % (prefix, text, suffix) + return '%s%s%s%s%s' % (prefix, em_tag, text, em_tag, suffix) def convert_hn(self, n, el, text, convert_as_inline): if convert_as_inline: return text - style = self.options['heading_style'] + style = self.options['heading_style'].lower() text = text.rstrip() if style == UNDERLINED and n <= 2: line = '=' if n == 1 else '-' @@ -222,10 +236,11 @@ class MarkdownConverter(object): return '%s\n\n' % text if text else '' def convert_strong(self, el, text, convert_as_inline): + strong_tag = 2 * self.options['strong_em_symbol'] prefix, suffix, text = chomp(text) if not text: return '' - return '%s**%s**%s' % (prefix, text, suffix) + return '%s%s%s%s%s' % (prefix, strong_tag, text, strong_tag, suffix) def convert_img(self, el, text, convert_as_inline): alt = el.attrs.get('alt', None) or '' diff --git a/setup.py b/setup.py index ec7dea2..db71182 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ read = lambda filepath: codecs.open(filepath, 'r', 'utf-8').read() pkgmeta = { '__title__': 'markdownify', '__author__': 'Matthew Tretter', - '__version__': '0.6.1', + '__version__': '0.6.6', } @@ -50,7 +50,7 @@ class LintCommand(Command): yield "%s.py" % filename def run(self): - from flake8.engine import get_style_guide + from flake8.api.legacy import get_style_guide flake8_style = get_style_guide(config_file='setup.cfg') paths = self.distribution_files() report = flake8_style.check_files(paths) @@ -70,13 +70,13 @@ setup( zip_safe=False, include_package_data=True, setup_requires=[ - 'flake8', + 'flake8>=3.8,<4', ], tests_require=[ - 'pytest', + 'pytest>=6.2,<7', ], install_requires=[ - 'beautifulsoup4', 'six' + 'beautifulsoup4>=4.9,<5', 'six>=1.15,<2' ], classifiers=[ 'Environment :: Web Environment', @@ -87,6 +87,9 @@ setup( 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Topic :: Utilities' ], cmdclass={ diff --git a/tests/test_conversions.py b/tests/test_conversions.py index bf09506..6dcf9a6 100644 --- a/tests/test_conversions.py +++ b/tests/test_conversions.py @@ -1,4 +1,4 @@ -from markdownify import markdownify as md, ATX, ATX_CLOSED +from markdownify import markdownify as md, ATX, ATX_CLOSED, BACKSLASH, UNDERSCORE import re @@ -145,12 +145,16 @@ def test_b_spaces(): def test_blockquote(): - assert md('
Hello
').strip() == '> Hello' + assert md('
Hello
') == '\n> Hello\n\n' + + +def test_blockquote_with_paragraph(): + assert md('
Hello

handsome

') == '\n> Hello\n\nhandsome\n\n' def test_nested_blockquote(): - text = md('
And she was like
Hello
').strip() - assert text == '> And she was like \n> > Hello' + text = md('
And she was like
Hello
') + assert text == '\n> And she was like \n> > Hello\n> \n> \n\n' def test_br(): @@ -292,3 +296,14 @@ def test_table(): assert md(table) == '| Firstname | Lastname | Age |\n| --- | --- | --- |\n| Jill | Smith | 50 |\n| Eve | Jackson | 94 |' assert md(table_head_body) == '| Firstname | Lastname | Age |\n| --- | --- | --- |\n| Jill | Smith | 50 |\n| Eve | Jackson | 94 |' assert md(table_missing_text) == '| | Lastname | Age |\n| --- | --- | --- |\n| Jill | | 50 |\n| Eve | Jackson | 94 |' + + +def test_strong_em_symbol(): + assert md('Hello', strong_em_symbol=UNDERSCORE) == '__Hello__' + assert md('Hello', strong_em_symbol=UNDERSCORE) == '__Hello__' + assert md('Hello', strong_em_symbol=UNDERSCORE) == '_Hello_' + assert md('Hello', strong_em_symbol=UNDERSCORE) == '_Hello_' + + +def test_newline_style(): + assert md('a
b
c', newline_style=BACKSLASH) == 'a\\\nb\\\nc' diff --git a/tests/test_escaping.py b/tests/test_escaping.py index 9b0d4fa..23a828c 100644 --- a/tests/test_escaping.py +++ b/tests/test_escaping.py @@ -2,7 +2,7 @@ from markdownify import markdownify as md def test_underscore(): - assert md('_hey_dude_') == '\_hey\_dude\_' + assert md('_hey_dude_') == r'\_hey\_dude\_' def test_xml_entities():