Skip to content

Commit

Permalink
add white_space_dot to config
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Nov 15, 2024
1 parent 0801b65 commit 4b8bffb
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 9 deletions.
2 changes: 2 additions & 0 deletions pytest_examples/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ExamplesConfig:
ruff_line_length: int | None = None
ruff_select: list[str] | None = None
ruff_ignore: list[str] | None = None
white_space_dot: bool = False
"""If True, replace spaces with `·` in example diffs."""

def black_mode(self):
return BlackMode(
Expand Down
14 changes: 10 additions & 4 deletions pytest_examples/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,22 @@ def black_format(source: str, config: ExamplesConfig, *, remove_double_blank: bo
def black_check(example: CodeExample, config: ExamplesConfig) -> None:
after_black = black_format(example.source, config, remove_double_blank=example.in_py_file())
if example.source != after_black:
diff = code_diff(example, after_black)
diff = code_diff(example, after_black, config.white_space_dot)
raise FormatError(f'black failed:\n{indent(diff, " ")}')


def code_diff(example: CodeExample, after: str) -> str:
diff = black_diff(example.source, after, 'before', 'after')
def code_diff(example: CodeExample, after: str, white_space_dot: bool) -> str:
diff = black_diff(sub_space(example.source, white_space_dot), sub_space(after, white_space_dot), 'before', 'after')

def replace_at_line(match: re.Match) -> str:
offset = re.sub(r'\d+', lambda m: str(int(m.group(0)) + example.start_line), match.group(2))
return f'{match.group(1)}{offset}{match.group(3)}'

# we could add `.replace(' ', '·')` to make white space easier to understand
return re.sub(r'^(@@\s*)(.*)(\s*@@)$', replace_at_line, diff, flags=re.M)


def sub_space(text: str, white_space_dot: bool) -> str:
if white_space_dot:
return text.replace(' ', '·')
else:
return text
11 changes: 6 additions & 5 deletions pytest_examples/run_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,16 @@ def __exit__(self, *args) -> None:
self.patch.stop()

def check_print_statements(self, example: CodeExample) -> None:
with_prints = self._insert_print_statements(example)
# we check against the raw `with_prints` and `with_prints` with trailing whitespace removed
if example.source != with_prints and example.source != re.sub(r'[ \t]+\n', '\n', with_prints):
diff = code_diff(example, with_prints)
new_code = self.updated_print_statements(example)
if new_code is not None:
diff = code_diff(example, new_code, self.config.white_space_dot)
pytest.fail(f'Print output changed code:\n{indent(diff, " ")}', pytrace=False)

def updated_print_statements(self, example: CodeExample) -> str | None:
with_prints = self._insert_print_statements(example)
if example.source != with_prints:
# we check against the raw `with_prints` and `with_prints` with trailing whitespace removed
# since trailing white space will have already been stripped by pre-commit in `example.source`
if example.source not in (with_prints, re.sub(r'[ \t]+\n', '\n', with_prints)):
return with_prints

def print_statements(self) -> list[PrintStatement]:
Expand Down
34 changes: 34 additions & 0 deletions tests/test_run_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,40 @@ def test_find_run_examples(example: CodeExample, eval_example: EvalExample):
]


def test_black_error_dot_space(pytester: pytest.Pytester):
pytester.makefile(
'.md',
my_file='line 1\nline 2\n```py\nx =[1,2, 3]\n```',
)
# language=Python
pytester.makepyfile(
"""
from pytest_examples import find_examples, CodeExample, EvalExample
import pytest
@pytest.mark.parametrize('example', find_examples('.'), ids=str)
def test_find_run_examples(example: CodeExample, eval_example: EvalExample):
eval_example.config.white_space_dot = True
eval_example.lint_black(example)
"""
)

result = pytester.runpytest('-p', 'no:pretty', '-v')
result.assert_outcomes(failed=1)

failures_start = next(index for index, line in enumerate(result.outlines) if 'FAILURES' in line)
failures_end = next(index for index, line in enumerate(result.outlines) if 'short test summary' in line)
e_lines = [line.strip() for line in result.outlines[failures_start + 2 : failures_end]]
assert e_lines == [
'black failed:',
'--- before',
'+++ after',
'@@ -4 +4 @@',
'-x·=[1,2,·3]',
'+x·=·[1,·2,·3]',
]


def test_black_error_multiline(pytester: pytest.Pytester):
pytester.makefile(
'.md',
Expand Down

0 comments on commit 4b8bffb

Please sign in to comment.