diff --git a/fix-test.patch b/fix-test.patch deleted file mode 100644 index afd1707..0000000 --- a/fix-test.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -ur pypandoc-1.5/tests.py pypandoc-1.5b/tests.py ---- pypandoc-1.5/tests.py 2020-04-12 18:41:24.000000000 -0600 -+++ pypandoc-1.5b/tests.py 2020-12-26 20:43:28.293871252 -0700 -@@ -293,7 +293,7 @@ - - def test_unicode_input(self): - # make sure that pandoc always returns unicode and does not mishandle it -- expected = u'üäöîôû{0}======{0}{0}'.format(os.linesep) -+ expected = u'# üäöîôû{0}{0}'.format(os.linesep) - written = pypandoc.convert_text(u'

üäöîôû

', 'md', format='html') - self.assertTrue(isinstance(written, unicode_type)) - self.assertEqualExceptForNewlineEnd(expected, written) -@@ -303,7 +303,7 @@ - self.assertTrue(isinstance(written, unicode_type)) - - # Only use german umlauts in th next test, as iso-8859-15 covers that -- expected = u'üäö€{0}===={0}{0}'.format(os.linesep) -+ expected = u'# üäö€{0}{0}'.format(os.linesep) - bytes = u'

üäö€

'.encode("iso-8859-15") - - # Without encoding, this fails as we expect utf-8 per default diff --git a/pypandoc-1.5.tar.gz b/pypandoc-1.5.tar.gz deleted file mode 100644 index 925fbbd..0000000 --- a/pypandoc-1.5.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:14a49977ab1fbc9b14ef3087dcb101f336851837fca55ca79cf33846cc4976ff -size 26494 diff --git a/pypandoc-1.6.4.tar.gz b/pypandoc-1.6.4.tar.gz new file mode 100644 index 0000000..b1a3325 --- /dev/null +++ b/pypandoc-1.6.4.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9184c512c5aef9fb8eeb6ea3f22446f067eb44ab924f7372475e49b6f283006b +size 36386 diff --git a/python-pypandoc.changes b/python-pypandoc.changes index 664905e..2702daa 100644 --- a/python-pypandoc.changes +++ b/python-pypandoc.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Sat Dec 4 23:33:35 UTC 2021 - John Vandenberg + +- Update to v1.6.4 +- Remove no longer needed fix-test.patch +- Add tests.py from upstream master to workaround failures + ------------------------------------------------------------------- Sun Dec 27 03:51:58 UTC 2020 - Jason Craig diff --git a/python-pypandoc.spec b/python-pypandoc.spec index 5bad503..07561a9 100644 --- a/python-pypandoc.spec +++ b/python-pypandoc.spec @@ -18,22 +18,19 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pypandoc -Version: 1.5 +Version: 1.6.4 Release: 0 Summary: Thin wrapper for pandoc License: MIT Group: Development/Languages/Python URL: https://github.com/bebraw/pypandoc -Source: https://pypi.org/packages/source/p/pypandoc/pypandoc-%{version}.tar.gz -# PATCH-FIX-UPSTREAM fix-test.patch -- ATX-style headings are default for -# markdown, see https://pandoc.org/MANUAL#option--markdown-headings -Patch1: fix-test.patch +Source: https://github.com/NicklasTegner/pypandoc/archive/refs/tags/v%{version}.tar.gz#/pypandoc-%{version}.tar.gz +Source1: https://raw.githubusercontent.com/NicklasTegner/pypandoc/master/tests.py BuildRequires: %{python_module pip} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module wheel} BuildRequires: fdupes -BuildRequires: ghc-citeproc BuildRequires: pandoc BuildRequires: python-rpm-macros BuildRequires: texlive-latex-bin @@ -49,9 +46,8 @@ pypandoc provides a thin wrapper for pandoc, a universal document converter. %prep %setup -q -n pypandoc-%{version} -%autopatch -p1 -# Disable test that requires internet -sed -i 's/\(test_basic_conversion_from_http_url\)/_\1/' tests.py + +cp %{SOURCE1} tests.py %build %python_build @@ -61,9 +57,8 @@ sed -i 's/\(test_basic_conversion_from_http_url\)/_\1/' tests.py %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -# test_conversion_with_citeproc_filter depends on ghc-pandoc-citeproc -# which was removed from factory -%pytest tests.py -k 'not test_conversion_with_citeproc_filter' +# test_basic_conversion_from_http_url needs network +%pytest tests.py -k 'not test_basic_conversion_from_http_url' %files %{python_files} %license LICENSE diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..c6c7eb5 --- /dev/null +++ b/tests.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import contextlib +import io +import os +import shutil +import subprocess +import sys +import tempfile +import unittest +import warnings + +import pypandoc +from pypandoc.py3compat import path2url, string_types, unicode_type + + +@contextlib.contextmanager +def closed_tempfile(suffix, text=None, dir_name=None): + file_name = None + try: + if dir_name: + dir_name = tempfile.mkdtemp(suffix=dir_name) + + with tempfile.NamedTemporaryFile('w+t', suffix=suffix, delete=False, dir=dir_name) as test_file: + file_name = test_file.name + if text: + test_file.write(text) + test_file.flush() + yield file_name + finally: + if dir_name: + shutil.rmtree(dir_name, ignore_errors=True) + elif file_name: + os.remove(file_name) + + +# Stolen from pandas +def is_list_like(arg): + return (hasattr(arg, '__iter__') and + not isinstance(arg, string_types)) + + +@contextlib.contextmanager +def assert_produces_warning(expected_warning=Warning, filter_level="always", + clear=None, check_stacklevel=True): + """ + Context manager for running code that expects to raise (or not raise) + warnings. Checks that code raises the expected warning and only the + expected warning. Pass ``False`` or ``None`` to check that it does *not* + raise a warning. Defaults to ``exception.Warning``, baseclass of all + Warnings. (basically a wrapper around ``warnings.catch_warnings``). + >>> import warnings + >>> with assert_produces_warning(): + ... warnings.warn(UserWarning()) + ... + >>> with assert_produces_warning(False): + ... warnings.warn(RuntimeWarning()) + ... + Traceback (most recent call last): + ... + AssertionError: Caused unexpected warning(s): ['RuntimeWarning']. + >>> with assert_produces_warning(UserWarning): + ... warnings.warn(RuntimeWarning()) + Traceback (most recent call last): + ... + AssertionError: Did not see expected warning of class 'UserWarning'. + ..warn:: This is *not* thread-safe. + """ + with warnings.catch_warnings(record=True) as w: + + if clear is not None: + # make sure that we are clearing these warnings + # if they have happened before + # to guarantee that we will catch them + if not is_list_like(clear): + clear = [clear] + for m in clear: + try: + m.__warningregistry__.clear() + except Exception as e: + # ignore... + print(str(e)) + + saw_warning = False + warnings.simplefilter(filter_level) + yield w + extra_warnings = [] + + for actual_warning in w: + if (expected_warning and issubclass(actual_warning.category, + expected_warning)): + saw_warning = True + + if check_stacklevel and issubclass(actual_warning.category, + (FutureWarning, + DeprecationWarning)): + from inspect import getframeinfo, stack + caller = getframeinfo(stack()[2][0]) + msg = (("Warning not set with correct stacklevel. " + + "File where warning is raised: {0} != {1}. " + + "Warning message: {2}").format( + actual_warning.filename, caller.filename, + actual_warning.message)) + assert actual_warning.filename == caller.filename, msg + else: + extra_warnings.append(actual_warning.category.__name__) + if expected_warning: + assert saw_warning, ("Did not see expected warning of class %r." + % expected_warning.__name__) + assert not extra_warnings, ("Caused unexpected warning(s): %r." + % extra_warnings) + + +class TestPypandoc(unittest.TestCase): + + # Python 2 compatibility + if not hasattr(unittest.TestCase, 'assertRaisesRegex'): + assertRaisesRegex = unittest.TestCase.assertRaisesRegexp + + def setUp(self): + if 'HOME' not in os.environ: + # if this is used with older versions of pandoc-citeproc + # https://github.com/jgm/pandoc-citeproc/issues/35 + if 'TRAVIS_BUILD_DIR' in os.environ: + os.environ["HOME"] = os.environ["TRAVIS_BUILD_DIR"] + print("Using TRAVIS_BUILD_DIR as HOME") + else: + os.environ["HOME"] = str(os.getcwd()) + print("Using current dir as HOME") + print(os.environ["HOME"]) + + def test_get_pandoc_formats(self): + inputs, outputs = pypandoc.get_pandoc_formats() + self.assertTrue("markdown" in inputs) + self.assertTrue("json" in inputs) + self.assertTrue("twiki" in inputs) + self.assertTrue("markdown" in outputs) + + def test_get_pandoc_version(self): + assert "HOME" in os.environ, "No HOME set, this will error..." + version = pypandoc.get_pandoc_version() + self.assertTrue(isinstance(version, pypandoc.string_types)) + major = int(version.split(".")[0]) + # according to http://pandoc.org/releases.html there were only two versions 0.x ... + self.assertTrue(major in [0, 1, 2]) + + def test_converts_valid_format(self): + self.assertEqualExceptForNewlineEnd(pypandoc.convert_text("ok", format='md', to='rest'), 'ok') + + def test_does_not_convert_to_invalid_format(self): + def f(): + pypandoc.convert_text("ok", format='md', to='invalid') + + with self.assertRaisesRegex(RuntimeError, "Invalid output format! Got invalid but "): + f() + + def test_does_not_convert_from_invalid_format(self): + def f(): + pypandoc.convert_text("ok", format='invalid', to='rest') + + with self.assertRaisesRegex(RuntimeError, 'Invalid input format! Got "invalid" but '): + f() + + def test_basic_conversion_from_file(self): + with closed_tempfile('.md', text='# some title\n') as file_name: + expected = u'some title{0}=========={0}{0}'.format(os.linesep) + received = pypandoc.convert_file(file_name, 'rst') + self.assertEqualExceptForNewlineEnd(expected, received) + + @unittest.skipIf(sys.platform.startswith("win"), "File based urls do not work on windows: " + "https://github.com/jgm/pandoc/issues/4613") + def test_basic_conversion_from_file_url(self): + with closed_tempfile('.md', text='# some title\n') as file_name: + expected = u'some title{0}=========={0}{0}'.format(os.linesep) + # this keeps the : (which should be '|' on windows but pandoc + # doesn't like it + file_url = path2url(file_name) + assert pypandoc._identify_path(file_url) + + received = pypandoc.convert_file(file_url, 'rst') + self.assertEqualExceptForNewlineEnd(expected, received) + + def test_basic_conversion_from_http_url(self): + url = 'https://raw.githubusercontent.com/bebraw/pypandoc/master/README.md' + received = pypandoc.convert_file(url, 'html') + assert "GPL2 license" in received + + def test_convert_with_custom_writer(self): + lua_file_content = self.create_sample_lua() + with closed_tempfile('.md', text='# title\n') as file_name: + with closed_tempfile('.lua', text=lua_file_content, dir_name="foo-bar+baz") as lua_file_name: + expected = u'

title

{0}'.format(os.linesep) + received = pypandoc.convert_file(file_name, lua_file_name) + self.assertEqualExceptForNewlineEnd(expected, received) + + def test_basic_conversion_from_file_with_format(self): + with closed_tempfile('.md', text='# some title\n') as file_name: + expected = u'some title{0}=========={0}{0}'.format(os.linesep) + received = pypandoc.convert_file(file_name, 'rst', format='md') + self.assertEqualExceptForNewlineEnd(expected, received) + + received = pypandoc.convert_file(file_name, 'rst', format='md') + self.assertEqualExceptForNewlineEnd(expected, received) + + def test_basic_conversion_from_string(self): + expected = u'some title{0}=========={0}{0}'.format(os.linesep) + received = pypandoc.convert_text('# some title', 'rst', format='md') + self.assertEqualExceptForNewlineEnd(expected, received) + + expected = u'some title{0}=========={0}{0}'.format(os.linesep) + received = pypandoc.convert_text('# some title', 'rst', format='md') + self.assertEqualExceptForNewlineEnd(expected, received) + + def test_conversion_with_markdown_extensions(self): + input = 'strike' + expected_with_extension = u'~~strike~~' + expected_without_extension = u'strike' + received_with_extension = pypandoc.convert_text(input, 'markdown+strikeout', + format='html') + received_without_extension = pypandoc.convert_text(input, + 'markdown-strikeout', + format='html') + self.assertEqualExceptForNewlineEnd(expected_with_extension, received_with_extension) + self.assertEqualExceptForNewlineEnd(expected_without_extension, received_without_extension) + + def test_conversion_from_markdown_with_extensions(self): + # Apparently without the extension, ~~ gets turned into different code + # depending on the pandoc version. So we do not test for that anymore... + input = u'~~strike~~' + expected_with_extension = u'

strike

' + received_with_extension = pypandoc.convert_text(input, 'html', format=u'markdown+strikeout') + self.assertEqualExceptForNewlineEnd(expected_with_extension, received_with_extension) + + def test_basic_conversion_to_file(self): + with closed_tempfile('.rst', ) as file_name: + expected = u'some title{0}=========={0}{0}'.format(os.linesep) + received = pypandoc.convert_text('# some title\n', to='rst', format='md', outputfile=file_name) + self.assertEqualExceptForNewlineEnd("", received) + with io.open(file_name) as f: + written = f.read() + self.assertEqualExceptForNewlineEnd(expected, written) + + # to odf does not work without a file + def f(): + pypandoc.convert_text('# some title\n', to='odf', format='md', + outputfile=None) + + with self.assertRaisesRegex(RuntimeError, "Invalid output format! Got odf but "): + f() + + def test_conversion_with_empty_filter(self): + # we just want to get a temp file name, where we can write to + filters = '' + written = pypandoc.convert_file('./filter_test.md', to='html', format='md', + outputfile=None, filters=filters) + import re as re + # This should not use the pandoc-citeproc module and will not find the + # strings + found = re.search(r'Fenner', written) + self.assertTrue(found is None) + found = re.search(r'10.1038', written) + self.assertTrue(found is None) + + def test_conversion_error(self): + # pandoc dies on wrong commandline arguments + def f(): + pypandoc.convert_text('

Primary Heading

', 'md', format='html', extra_args=["--blah"]) + + with self.assertRaisesRegex(RuntimeError, 'Pandoc died with exitcode "6" during conversion: Unknown option --blah'): + f() + + def test_unicode_input(self): + # make sure that pandoc always returns unicode and does not mishandle it + expected = u'üäöîôû{0}'.format(os.linesep) + written = pypandoc.convert_text(u'

üäöîôû

', 'md', format='html') + self.assertTrue(isinstance(written, unicode_type)) + self.assertEqualExceptForNewlineEnd(expected, written) + bytes = u'

üäöîôû

'.encode("utf-8") + written = pypandoc.convert_text(bytes, 'md', format='html') + self.assertTrue(expected == written) + self.assertTrue(isinstance(written, unicode_type)) + + # Only use german umlauts in the next test, as iso-8859-15 covers that + expected = u'äüäö{0}'.format(os.linesep) + bytes = u'

äüäö

'.encode("iso-8859-15") + + # Without encoding, this fails as we expect utf-8 per default + + def f(): + written = pypandoc.convert_text(bytes, 'md', format='html') + + assert expected != written + + def f(): + # we have to use something which interprets '\xa4', so latin and -1 does not work :-/ + written = pypandoc.convert_text(bytes, 'md', format='html', encoding="utf-16") + + assert expected != written + # with the right encoding it should work... + written = pypandoc.convert_text(bytes, 'md', format='html', encoding="iso-8859-15") + self.assertEqualExceptForNewlineEnd(expected, written) + self.assertTrue(isinstance(written, unicode_type)) + + def test_conversion_from_non_plain_text_file(self): + with closed_tempfile('.docx') as file_name: + expected = u'some title{0}=========={0}{0}'.format(os.linesep) + # let's just test conversion (to and) from docx, testing e.g. odt + # as well would really be testing pandoc rather than pypandoc + received = pypandoc.convert_text('# some title\n', to='docx', format='md', outputfile=file_name) + self.assertEqualExceptForNewlineEnd("", received) + received = pypandoc.convert_file(file_name, to='rst') + self.assertEqualExceptForNewlineEnd(expected, received) + + def test_pdf_conversion(self): + with closed_tempfile('.pdf') as file_name: + ret = pypandoc.convert_text('# some title\n', to='pdf', format='md', outputfile=file_name) + assert ret == "" + with io.open(file_name, mode='rb') as f: + written = f.read() + assert written[:4] == b"%PDF" + # TODO: find a test for the content? + + def f(): + # needs an outputfile + pypandoc.convert_text('# some title\n', to='pdf', format='md') + + with self.assertRaisesRegex(RuntimeError, "Output to pdf only works by using a outputfile"): + f() + + # outputfile needs to end in pdf + with closed_tempfile('.WRONG') as file_name: + def f(): + pypandoc.convert_text('# some title\n', to='pdf', format='md', outputfile=file_name) + + with self.assertRaisesRegex(RuntimeError, 'PDF output needs an outputfile with ".pdf" as a fileending'): + f() + + # no extensions allowed + with closed_tempfile('.pdf') as file_name: + def f(): + pypandoc.convert_text('# some title\n', to='pdf+somethign', format='md', outputfile=file_name) + + with self.assertRaisesRegex(RuntimeError, r"PDF output can't contain any extensions: pdf\+somethign"): + f() + + def test_get_pandoc_path(self): + result = pypandoc.get_pandoc_path() + assert "pandoc" in result + + def test_call_with_nonexisting_file(self): + files = ['/file/does/not/exists.md', + 'file:///file/does/not/exists.md' + '', + 42, + None + ] + + def f(filepath): + pypandoc.convert_file(filepath, 'rst') + + for filepath in files: + with self.assertRaisesRegex(RuntimeError, "source_file is not a valid path"): + f(filepath) + + def test_convert_text_with_existing_file(self): + with closed_tempfile('.md', text='# some title\n') as file_name: + received = pypandoc.convert_text(file_name, 'rst', format='md') + self.assertTrue("title" not in received) + + # The following is a problematic case + received = pypandoc.convert_file(file_name, 'rst', format='md') + self.assertTrue("title" in received) + + def test_depreaction_warnings(self): + # convert itself is deprecated... + with assert_produces_warning(DeprecationWarning): + pypandoc.convert('# some title\n', to='rst', format='md') + + def create_sample_lua(self): + args = [pypandoc.get_pandoc_path(), '--print-default-data-file', 'sample.lua'] + p = subprocess.Popen(args, stdout=subprocess.PIPE) + out, err = p.communicate() + return out.decode('utf-8') + + def assertEqualExceptForNewlineEnd(self, expected, received): # noqa + # output written to a file does not seem to have os.linesep + # handle everything here by replacing the os linesep by a simple \n + expected = expected.replace(os.linesep, "\n") + received = received.replace(os.linesep, "\n") + self.assertEqual(expected.rstrip('\n'), received.rstrip('\n')) + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(TestPypandoc) + ret = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(0 if ret.wasSuccessful() else 1)