diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..b71b164 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,44 @@ +name: CI + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.12 + uses: actions/setup-python@v4 + with: + python-version: 3.12 + - name: Setup and install tools + run: | + python -m pip install --upgrade black flake8 + - name: black format check + run: black --check --line-length 120 pandoc_plantuml_filter.py tests setup.py + - name: flake8 format check + run: flake8 --max-line-length 120 pandoc_plantuml_filter.py tests setup.py + test: + strategy: + fail-fast: false + matrix: + python-version: [3.8, 3.12] + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Setup build and test environment + run: python -m pip install --upgrade pip setuptools wheel pytest pytest-mock + - name: Setup package + run: python -m pip install . + - name: run unit tests + run: pytest tests/test_unit.py + - name: install dependencies for integration tests + run: sudo apt update && sudo apt install -y pandoc plantuml + - name: run integration tests + run: pytest tests/test_integration.py + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..232ee03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.env/ +__pycache__/ +example.png +images/ +missfont.log +pandoc_plantuml_filter.egg-info/ +plantuml-images/ +sample.pdf diff --git a/pandoc_plantuml_filter.py b/pandoc_plantuml_filter.py index de79b17..53509ba 100755 --- a/pandoc_plantuml_filter.py +++ b/pandoc_plantuml_filter.py @@ -13,7 +13,7 @@ from pandocfilters import toJSONFilter, Para, Image from pandocfilters import get_filename4code, get_caption, get_extension -PLANTUML_BIN = os.environ.get('PLANTUML_BIN', 'plantuml') +PLANTUML_BIN = os.environ.get("PLANTUML_BIN", "plantuml") def rel_mkdir_symlink(src, dest): @@ -29,21 +29,21 @@ def rel_mkdir_symlink(src, dest): def plantuml(key, value, format_, meta): - if key == 'CodeBlock': + if key == "CodeBlock": [[ident, classes, keyvals], code] = value if "plantuml" in classes: caption, typef, keyvals = get_caption(keyvals) filename = get_filename4code("plantuml", code) - if meta.get('plantuml-format'): - pformat = meta.get('plantuml-format', None) - filetype = get_extension(format_, pformat['c'][0]['c']) + if meta.get("plantuml-format"): + pformat = meta.get("plantuml-format", None) + filetype = get_extension(format_, pformat["c"][0]["c"]) else: filetype = get_extension(format_, "png", html="svg", latex="png") - src = filename + '.uml' - dest = filename + '.' + filetype + src = filename + ".uml" + dest = filename + "." + filetype # Generate image only once if not os.path.isfile(dest): @@ -53,13 +53,12 @@ def plantuml(key, value, format_, meta): with open(src, "wb") as f: f.write(txt) - subprocess.check_call(PLANTUML_BIN.split() + - ["-t" + filetype, src]) - sys.stderr.write('Created image ' + dest + '\n') + subprocess.check_call(PLANTUML_BIN.split() + ["-t" + filetype, src]) + sys.stderr.write("Created image " + dest + "\n") # Update symlink each run for ind, keyval in enumerate(keyvals): - if keyval[0] == 'plantuml-filename': + if keyval[0] == "plantuml-filename": link = keyval[1] keyvals.pop(ind) rel_mkdir_symlink(dest, link) diff --git a/setup.py b/setup.py index 4c4aa35..1f1dc5e 100644 --- a/setup.py +++ b/setup.py @@ -15,21 +15,19 @@ sys.exit() -required = [ - 'pandocfilters' -] +required = ["pandocfilters"] class UploadCommand(Command): """Support setup.py upload.""" - description = 'Build and publish the package.' + description = "Build and publish the package." user_options = [] @staticmethod def status(s): """Prints things in bold.""" - print('\033[1m{0}\033[0m'.format(s)) + print("\033[1m{0}\033[0m".format(s)) def initialize_options(self): pass @@ -39,50 +37,49 @@ def finalize_options(self): def run(self): try: - self.status('Removing previous builds…') - rmtree(os.path.join(here, 'dist')) + self.status("Removing previous builds…") + rmtree(os.path.join(here, "dist")) except OSError: pass - self.status('Building Source and Wheel (universal) distribution…') - os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) + self.status("Building Source and Wheel (universal) distribution…") + os.system("{0} setup.py sdist bdist_wheel --universal".format(sys.executable)) - self.status('Uploading the package to PyPi via Twine…') - os.system('twine upload dist/*') + self.status("Uploading the package to PyPi via Twine…") + os.system("twine upload dist/*") sys.exit() setup( - name='pandoc-plantuml-filter', - version='0.1.2', - description='Pandoc filter for PlantUML code blocks', - long_description='Pandoc filter for PlantUML code blocks', - author='Timo Furrer', - author_email='tuxtimo@gmail.com', - url='https://github.com/timofurrer/pandoc-plantuml-filter', + name="pandoc-plantuml-filter", + version="0.1.2", + description="Pandoc filter for PlantUML code blocks", + long_description="Pandoc filter for PlantUML code blocks", + author="Timo Furrer", + author_email="tuxtimo@gmail.com", + url="https://github.com/timofurrer/pandoc-plantuml-filter", install_requires=required, - py_modules=['pandoc_plantuml_filter'], - entry_points={ - 'console_scripts': [ - 'pandoc-plantuml = pandoc_plantuml_filter:main' - ]}, - license='MIT', + py_modules=["pandoc_plantuml_filter"], + entry_points={"console_scripts": ["pandoc-plantuml = pandoc_plantuml_filter:main"]}, + license="MIT", classifiers=( - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: Implementation', - 'Programming Language :: Python :: Implementation :: CPython', - 'Topic :: Software Development :: Libraries :: Python Modules' + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Software Development :: Libraries :: Python Modules", ), cmdclass={ - 'upload': UploadCommand, + "upload": UploadCommand, }, ) diff --git a/tests/test_integration.py b/tests/test_integration.py new file mode 100644 index 0000000..41c17ca --- /dev/null +++ b/tests/test_integration.py @@ -0,0 +1,43 @@ +import os +import subprocess + +from pathlib import Path + +import pytest + +__TEST_BASE_DIR__ = Path(os.path.dirname(__file__)) / "testdata" + + +@pytest.mark.parametrize( + "filename, expected_content, expected_files", + [ + ("single-diagram", ["\\includegraphics{plantuml-images/"], []), + ("single-diagram-with-config", ["\\includegraphics", "width=0.6"], []), + ( + "single-diagram-with-filename-and-subdirectory", + ["\\includegraphics", "images/example.png"], + ["images/example.png"], + ), + ("single-diagram-with-filename-without-subdirectory", ["\\includegraphics", "example.png"], ["example.png"]), + ( + "single-diagram-reference", + ["\\includegraphics", "images/example.png", "\\includegraphics{images/example.png}"], + ["images/example.png"], + ), + ], +) +def test_digrams(mocker, tmp_path, filename, expected_content, expected_files): + input_file = str(__TEST_BASE_DIR__ / f"{filename}.md") + output_file = str(tmp_path / f"{filename}.tex") + + cmd = subprocess.run(["pandoc", input_file, "-o", output_file, "--filter", "pandoc-plantuml"]) + assert cmd.returncode == 0 + + with open(output_file) as f: + content = f.read() + + for line in expected_content: + assert line in content + + for file in expected_files: + assert os.path.exists(file) diff --git a/tests/test_unit.py b/tests/test_unit.py new file mode 100644 index 0000000..0a467bb --- /dev/null +++ b/tests/test_unit.py @@ -0,0 +1,14 @@ +from pandoc_plantuml_filter import plantuml + + +def test_call_plantuml_create_para_object(mocker): + mocker.patch("os.path.isfile", return_value=False) + mock = mocker.patch("subprocess.check_call") + + ret = plantuml(key="CodeBlock", value=[["", ["plantuml"], []], ""], format_=None, meta={}) + + assert isinstance(ret, dict) + assert "t" in ret.keys() + assert ret["t"] == "Para" + + mock.assert_called_once() diff --git a/tests/testdata/single-diagram-reference.md b/tests/testdata/single-diagram-reference.md new file mode 100644 index 0000000..6a8d6ad --- /dev/null +++ b/tests/testdata/single-diagram-reference.md @@ -0,0 +1,8 @@ +# Single PlantUML diagram which referenced later + +```{ .plantuml width=60% plantuml-filename=images/example.png } +[producer] -> [consumer]: data streaming +``` + +# Reference +![And here's the reference](images/example.png) diff --git a/tests/testdata/single-diagram-with-config.md b/tests/testdata/single-diagram-with-config.md new file mode 100644 index 0000000..9b9cd08 --- /dev/null +++ b/tests/testdata/single-diagram-with-config.md @@ -0,0 +1,5 @@ +# Single PlantUML diagram with config + +```{ .plantuml width=60% } +[producer] -> [consumer]: data streaming +``` diff --git a/tests/testdata/single-diagram-with-filename-and-subdirectory.md b/tests/testdata/single-diagram-with-filename-and-subdirectory.md new file mode 100644 index 0000000..3a88823 --- /dev/null +++ b/tests/testdata/single-diagram-with-filename-and-subdirectory.md @@ -0,0 +1,5 @@ +# Single PlantUML diagram with filename and sub-directory + +```{ .plantuml width=60% plantuml-filename=images/example.png } +[producer] -> [consumer]: data streaming +``` diff --git a/tests/testdata/single-diagram-with-filename-without-subdirectory.md b/tests/testdata/single-diagram-with-filename-without-subdirectory.md new file mode 100644 index 0000000..ba795d0 --- /dev/null +++ b/tests/testdata/single-diagram-with-filename-without-subdirectory.md @@ -0,0 +1,5 @@ +# Single PlantUML diagram with filename without sub-directory + +```{ .plantuml width=60% plantuml-filename=example.png } +[producer] -> [consumer]: data streaming +``` diff --git a/tests/testdata/single-diagram.md b/tests/testdata/single-diagram.md new file mode 100644 index 0000000..0f41fe4 --- /dev/null +++ b/tests/testdata/single-diagram.md @@ -0,0 +1,9 @@ +# Single PlantUML digaram + +```plantuml +Alice -> Bob: Authentication Request +Bob --> Alice: Authentication Response + +Alice -> Bob: Another authentication Request +Alice <-- Bob: another authentication Response +```