-
Notifications
You must be signed in to change notification settings - Fork 43
introduced option to specify file encoding #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cc0144a
a872339
f91f597
a15cea0
7940839
88eebb5
09979a3
2b56f2c
4a639d7
f0ec39e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -444,7 +444,7 @@ def parse(self, s, name=None): | |
| continue | ||
|
|
||
| if config.getoption('remote_data', 'none') != 'any': | ||
| if any(re.match(fr'{comment_char}\s+doctest-remote-data-all\s*::', x.strip()) | ||
| if any(re.match(fr'{comment_char}\s+doctest-remote-data-all\s*::', x.strip()) # noqa: E501 | ||
| for x in lines): | ||
| skip_all = True | ||
| continue | ||
|
|
@@ -912,13 +912,13 @@ def test_filter(test): | |
| return tests | ||
|
|
||
|
|
||
| def write_modified_file(fname, new_fname, changes): | ||
| def write_modified_file(fname, new_fname, changes, encoding=None): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the default here be consistent with addoption default (utf-8)?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it should be consistent, though I'm not sure if we should change the default to utf-8 or leave as is now?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to set From a developer's perspective, I would prefer using
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any changes required? i guess the default value of default value for cli option defaults to "utf-8" which will be passed on. |
||
| # Sort in reversed order to edit the lines: | ||
| bad_tests = [] | ||
| changes.sort(key=lambda x: (x["test_lineno"], x["example_lineno"]), | ||
| reverse=True) | ||
|
|
||
| with open(fname) as f: | ||
| with open(fname, encoding=encoding) as f: | ||
| text = f.readlines() | ||
|
|
||
| for change in changes: | ||
|
|
@@ -939,7 +939,7 @@ def write_modified_file(fname, new_fname, changes): | |
|
|
||
| text[lineno:lineno+want.count("\n")] = [got] | ||
|
|
||
| with open(new_fname, "w") as f: | ||
| with open(new_fname, "w", encoding=encoding) as f: | ||
| f.write("".join(text)) | ||
|
|
||
| return bad_tests | ||
|
|
@@ -954,6 +954,8 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config): | |
| if not diff_mode: | ||
| return # we do not report or apply diffs | ||
|
|
||
| encoding = config.getini("doctest_encoding") | ||
|
|
||
| if diff_mode != "overwrite": | ||
| # In this mode, we write a corrected file to a temporary folder in | ||
| # order to compare them (rather than modifying the file). | ||
|
|
@@ -974,14 +976,14 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config): | |
| new_fname = fname.replace(common_path, tmpdirname) | ||
| os.makedirs(os.path.split(new_fname)[0], exist_ok=True) | ||
|
|
||
| bad_tests = write_modified_file(fname, new_fname, changes) | ||
| bad_tests = write_modified_file(fname, new_fname, changes, encoding) | ||
| all_bad_tests.extend(bad_tests) | ||
|
|
||
| # git diff returns 1 to signal changes, so just ignore the | ||
| # exit status: | ||
| with subprocess.Popen( | ||
| ["git", "diff", "-p", "--no-index", fname, new_fname], | ||
| stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) as p: | ||
| stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding=encoding) as p: | ||
| p.wait() | ||
| # Diff should be fine, but write error if not: | ||
| diff = p.stderr.read() | ||
|
|
@@ -1013,7 +1015,7 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config): | |
| return | ||
| terminalreporter.write_line("Applied fix to the following files:") | ||
| for fname, changes in changesets.items(): | ||
| bad_tests = write_modified_file(fname, fname, changes) | ||
| bad_tests = write_modified_file(fname, fname, changes, encoding) | ||
| all_bad_tests.extend(bad_tests) | ||
| terminalreporter.write_line(f" {fname}") | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| import locale | ||
| import os | ||
| from pathlib import Path | ||
| from textwrap import dedent | ||
| from typing import Callable, Optional | ||
|
|
||
| import pytest | ||
|
|
||
| pytest_plugins = ["pytester"] | ||
|
|
||
|
|
||
| @pytest.fixture( | ||
| params=[ | ||
| ("A", "a", "utf-8"), | ||
| ("☆", "★", "utf-8"), | ||
| ("b", "B", "cp1252"), | ||
| ("☁", "☀", "utf-8"), | ||
| ], | ||
| ids=[ | ||
| "Aa-utf8", | ||
| "star-utf8", | ||
| "bB-cp1252", | ||
| "cloud-utf8", | ||
| ], | ||
| ) | ||
| def charset(request): | ||
| return request.param | ||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def basic_file(tmp_path: Path) -> Callable[[str, str, str], tuple[str, str, str]]: | ||
|
|
||
| def makebasicfile(a, b, encoding: str) -> tuple[str, str, str]: | ||
| """alternative implementation without the use of `testdir.makepyfile`.""" | ||
|
|
||
| content = """ | ||
| def f(): | ||
| ''' | ||
| >>> print('{}') | ||
| {} | ||
| ''' | ||
| pass | ||
| """ | ||
|
|
||
| original = dedent(content.format(a, b)) | ||
| expected_result = dedent(content.format(a, a)) | ||
|
|
||
| original_file = tmp_path.joinpath("test_basic.py") | ||
| original_file.write_text(original, encoding=encoding) | ||
|
|
||
| expected_diff = dedent( | ||
| f""" | ||
| >>> print('{a}') | ||
| - {b} | ||
| + {a} | ||
| """ | ||
| ).strip("\n") | ||
|
|
||
| return str(original_file), expected_diff, expected_result | ||
|
|
||
| return makebasicfile | ||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def ini_file(testdir) -> Callable[..., Path]: | ||
|
|
||
| def makeini( | ||
| encoding: Optional[str] = None, | ||
| ) -> Path: | ||
| """Create a pytest.ini file with the specified encoding.""" | ||
|
|
||
| ini = ["[pytest]"] | ||
|
|
||
| if encoding is not None: | ||
| ini.append(f"doctest_encoding = {encoding}") | ||
|
|
||
| ini.append("") | ||
|
|
||
| p = testdir.makefile(".ini", pytest="\n".join(ini)) | ||
|
|
||
| return Path(p) | ||
|
|
||
| return makeini | ||
|
|
||
|
|
||
| def test_basic_file_encoding_diff(testdir, capsys, basic_file, charset, ini_file): | ||
| """ | ||
| Test the diff from console output is as expected. | ||
| """ | ||
| a, b, encoding = charset | ||
|
|
||
| # create python file to test | ||
| file, diff, _ = basic_file(a, b, encoding) | ||
|
|
||
| # create pytest.ini file | ||
| ini = ini_file(encoding=encoding) | ||
| assert ini.is_file(), "setup pytest.ini not created/found" | ||
|
|
||
| testdir.inline_run( | ||
| file, | ||
| "--doctest-plus-generate-diff", | ||
| "-c", | ||
| str(ini), | ||
| ) | ||
|
|
||
| stdout, _ = capsys.readouterr() | ||
| assert diff in stdout | ||
|
|
||
|
|
||
| def test_basic_file_encoding_overwrite(testdir, basic_file, charset, ini_file): | ||
| """ | ||
| Test that the file is overwritten with the expected content. | ||
| """ | ||
|
|
||
| a, b, encoding = charset | ||
|
|
||
| # create python file to test | ||
| file, _, expected = basic_file(a, b, encoding) | ||
|
|
||
| # create pytest.ini file | ||
| ini = ini_file(encoding=encoding) | ||
| assert ini.is_file(), "setup pytest.ini not created/found" | ||
|
|
||
| testdir.inline_run( | ||
| file, | ||
| "--doctest-plus-generate-diff", | ||
| "overwrite", | ||
| "-c", | ||
| str(ini), | ||
| ) | ||
|
|
||
| assert expected in Path(file).read_text(encoding) | ||
|
|
||
|
|
||
| @pytest.mark.skipif(os.getenv("CI", False), reason="skip on CI") | ||
| def test_legacy_diff(testdir, capsys, basic_file, charset): | ||
| """ | ||
| Legacy test are supported to fail on Windows, when no encoding is provided. | ||
|
|
||
| On Windows this is cp1252, so "utf-8" are expected to fail while writing test files. | ||
| """ | ||
| a, b, _ = charset | ||
|
|
||
| try: | ||
| file, diff, _ = basic_file(a, b, None) | ||
| except UnicodeEncodeError: | ||
| encoding = locale.getpreferredencoding(False) | ||
| reason = f"could not encode {repr(charset)} with {encoding=}" | ||
| pytest.xfail(reason=reason) | ||
|
|
||
| testdir.inline_run( | ||
| file, | ||
| "--doctest-plus-generate-diff", | ||
| ) | ||
|
|
||
| stdout, _ = capsys.readouterr() | ||
|
|
||
| assert diff in stdout | ||
|
|
||
|
|
||
| @pytest.mark.skipif(os.getenv("CI", False), reason="skip on CI") | ||
| def test_legacy_overwrite(testdir, basic_file, charset): | ||
| """ | ||
| Legacy test are supported to fail on Windows, when no encoding is provided. | ||
|
|
||
| On Windows this is cp1252, so "utf-8" are expected to fail while writing test files. | ||
| """ | ||
|
|
||
| a, b, _encoding = charset | ||
|
|
||
| try: | ||
| file, _, expected = basic_file(a, b, None) | ||
| except UnicodeEncodeError: | ||
| encoding = locale.getpreferredencoding(False) | ||
| reason = f"could not encode {repr(charset)} with {encoding=}" | ||
| pytest.xfail(reason=reason) | ||
|
|
||
| testdir.inline_run( | ||
| file, | ||
| "--doctest-plus-generate-diff", | ||
| "overwrite", | ||
| ) | ||
|
|
||
| assert expected in Path(file).read_text(_encoding) |
Uh oh!
There was an error while loading. Please reload this page.