diff --git a/README.md b/README.md index 653c3e2..2e7a547 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,15 @@

Test code blocks in your READMEs.

-[![PyPi Version](https://img.shields.io/pypi/v/pytest-codeblocks.svg?style=flat-square)](https://pypi.org/project/pytest-codeblocks/) +[![PyPi Version](https://img.shields.io/pypi/v/pytest-codeblocks.svg?style=flat-square)](https://pypi.org/project/pytest_codeblocks/) [![Anaconda Cloud](https://anaconda.org/conda-forge/pytest-codeblocks/badges/version.svg?=style=flat-square)](https://anaconda.org/conda-forge/pytest-codeblocks/) -[![PyPI pyversions](https://img.shields.io/pypi/pyversions/pytest-codeblocks.svg?style=flat-square)](https://pypi.org/project/pytest-codeblocks/) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/pytest-codeblocks.svg?style=flat-square)](https://pypi.org/project/pytest_codeblocks/) [![GitHub stars](https://img.shields.io/github/stars/nschloe/pytest-codeblocks.svg?style=flat-square&logo=github&label=Stars&logoColor=white)](https://github.com/nschloe/pytest-codeblocks) -[![Downloads](https://pepy.tech/badge/pytest-codeblocks/month?style=flat-square)](https://pepy.tech/project/pytest-codeblocks) +[![Downloads](https://static.pepy.tech/badge/pytest-codeblocks/month?style=flat-square)](https://www.pepy.tech/projects/pytest-codeblocks) -[![gh-actions](https://img.shields.io/github/workflow/status/nschloe/pytest-codeblocks/ci?style=flat-square)](https://github.com/nschloe/pytest-codeblocks/actions?query=workflow%3Aci) +[![gh-actions](https://img.shields.io/github/actions/workflow/status/nschloe/pytest-codeblocks/tests?style=flat-square)](https://github.com/nschloe/pytest-codeblocks/actions?query=workflow%3Atests) [![codecov](https://img.shields.io/codecov/c/github/nschloe/pytest-codeblocks.svg?style=flat-square)](https://app.codecov.io/gh/nschloe/pytest-codeblocks) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square)](https://github.com/psf/black) @@ -156,5 +156,8 @@ gives ``` ```` +Use `expected-output-ignore-whitespace` if you'd like whitespace differences to +be ignored. + (Conditionally) Skipping the output verfication works by prepending the first block with `skip`/`skipif` (see [above](#skipping-code-blocks)). diff --git a/pyproject.toml b/pyproject.toml index 372149e..a728d17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,9 +2,6 @@ requires = ["setuptools>=61"] build-backend = "setuptools.build_meta" -[tool.isort] -profile = "black" - [project] name = "pytest_codeblocks" authors = [{name = "Nico Schlömer", email = "nico.schloemer@gmail.com"}] diff --git a/src/pytest_codeblocks/__about__.py b/src/pytest_codeblocks/__about__.py index 113af05..7f33bc0 100644 --- a/src/pytest_codeblocks/__about__.py +++ b/src/pytest_codeblocks/__about__.py @@ -1 +1 @@ -__version__ = "0.16.1" +__version__ = "0.16.2" diff --git a/src/pytest_codeblocks/main.py b/src/pytest_codeblocks/main.py index 742acaf..36060c2 100644 --- a/src/pytest_codeblocks/main.py +++ b/src/pytest_codeblocks/main.py @@ -18,6 +18,7 @@ class CodeBlock: lineno: int syntax: str | None = None expected_output: str | None = None + expected_output_ignore_whitespace: bool = False importorskip: str | None = None marks: list[str] = field(default_factory=lambda: []) @@ -34,6 +35,7 @@ def extract_from_buffer(f, max_num_lines: int = 10000) -> list[CodeBlock]: marks = [] continued_block = None expected_output_block = None + expected_output_ignore_whitespace = False importorskip = None k = 1 @@ -58,18 +60,21 @@ def extract_from_buffer(f, max_num_lines: int = 10000) -> list[CodeBlock]: if m is not None: keyword = m.group(1).strip("- ") # handle special tags - if keyword == "expected-output": + if keyword in {"expected-output", "expected-output-ignore-whitespace"}: if len(out) == 0: raise RuntimeError( - "Found " + f"Found " + "but no previous code block." ) if out[-1].expected_output is not None: raise RuntimeError( - "Found " + f"Found " + "but block already has expected_output." ) expected_output_block = out[-1] + if keyword == "expected-output-ignore-whitespace": + # \s: regex matches all whitespace characters + expected_output_ignore_whitespace = True elif keyword == "cont": if len(out) == 0: @@ -115,7 +120,7 @@ def extract_from_buffer(f, max_num_lines: int = 10000) -> list[CodeBlock]: marks.append("pytest.mark.xfail") else: - raise RuntimeError(f'Unknown pytest-codeblocks keyword "{keyword}."') + raise RuntimeError(f'Unknown pytest-codeblocks keyword "{keyword}"') continue @@ -162,6 +167,9 @@ def extract_from_buffer(f, max_num_lines: int = 10000) -> list[CodeBlock]: elif expected_output_block: expected_output_block.expected_output = code + expected_output_block.expected_output_ignore_whitespace = ( + expected_output_ignore_whitespace + ) expected_output_block = None else: diff --git a/src/pytest_codeblocks/plugin.py b/src/pytest_codeblocks/plugin.py index c26c569..84432f3 100644 --- a/src/pytest_codeblocks/plugin.py +++ b/src/pytest_codeblocks/plugin.py @@ -4,6 +4,7 @@ # import subprocess from pathlib import Path +import re import pytest @@ -103,7 +104,14 @@ def runtest(self): output = ret.stdout.decode() if output is not None and self.obj.expected_output is not None: - if self.obj.expected_output != output: + str0 = self.obj.expected_output + str1 = output + + if self.obj.expected_output_ignore_whitespace: + str0 = re.sub(r"^\s+", "", str0, flags=re.MULTILINE) + str1 = re.sub(r"^\s+", "", str1, flags=re.MULTILINE) + + if str0 != str1: raise RuntimeError( f"{self.name}, line {self.obj.lineno}:\n```\n" + f"Expected output\n```\n{self.obj.expected_output}```\n" diff --git a/tests/test_expected_output.py b/tests/test_expected_output.py index 15e82b8..0a68bc0 100644 --- a/tests/test_expected_output.py +++ b/tests/test_expected_output.py @@ -34,3 +34,25 @@ def test_expected_output_fail(testdir): testdir.makefile(".md", string) result = testdir.runpytest("--codeblocks") result.assert_outcomes(failed=1) + + +def test_expected_output_ignore_whitespace(testdir): + string = """ +Lorem ipsum +```python +print(1 + 3) +print(1 - 3) +print(1 * 3) +``` +dolor sit amet + +``` + 4 + -2 + + 3 +``` +""" + testdir.makefile(".md", string) + result = testdir.runpytest("--codeblocks") + result.assert_outcomes(passed=1)