diff --git a/src/mdformat/_api.py b/src/mdformat/_api.py index 18ec9e5..bffa4c2 100644 --- a/src/mdformat/_api.py +++ b/src/mdformat/_api.py @@ -7,13 +7,7 @@ from typing import Any from mdformat._conf import DEFAULT_OPTS -from mdformat._util import ( - EMPTY_MAP, - NULL_CTX, - atomic_write, - build_mdit, - detect_newline_type, -) +from mdformat._util import EMPTY_MAP, NULL_CTX, build_mdit, detect_newline_type from mdformat.renderer import MDRenderer @@ -75,4 +69,6 @@ def file( newline = detect_newline_type( original_md, options.get("end_of_line", DEFAULT_OPTS["end_of_line"]) ) - atomic_write(f, formatted_md, newline) + formatted_md = formatted_md.replace("\n", newline) + if formatted_md != original_md: + f.write_bytes(formatted_md.encode()) diff --git a/src/mdformat/_cli.py b/src/mdformat/_cli.py index 2e282d0..39491cd 100644 --- a/src/mdformat/_cli.py +++ b/src/mdformat/_cli.py @@ -6,7 +6,6 @@ import itertools import logging from pathlib import Path -import re import shutil import sys import textwrap @@ -14,13 +13,10 @@ import mdformat from mdformat._compat import importlib_metadata from mdformat._conf import DEFAULT_OPTS, InvalidConfError, read_toml_opts -from mdformat._util import atomic_write, detect_newline_type, is_md_equal +from mdformat._util import detect_newline_type, is_md_equal import mdformat.plugins import mdformat.renderer -# Match "\r" and "\n" characters that are not part of a "\r\n" sequence -RE_NON_CRLF_LINE_END = re.compile(r"(?:[^\r]|^)\n|\r(?:[^\n]|\Z)") - class RendererWarningPrinter(logging.Handler): def emit(self, record: logging.LogRecord) -> None: @@ -82,14 +78,10 @@ def run(cli_args: Sequence[str]) -> int: # noqa: C901 _filename=path_str, ) newline = detect_newline_type(original_str, opts["end_of_line"]) + formatted_str = formatted_str.replace("\n", newline) if opts["check"]: - original_str_lf_eol = original_str.replace("\r\n", "\n").replace("\r", "\n") - if ( - (formatted_str != original_str_lf_eol) - or (newline == "\n" and "\r" in original_str) - or (newline == "\r\n" and RE_NON_CRLF_LINE_END.search(original_str)) - ): + if formatted_str != original_str: format_errors_found = True print_error(f'File "{path_str}" is not formatted.') else: @@ -111,12 +103,10 @@ def run(cli_args: Sequence[str]) -> int: # noqa: C901 ) return 1 if path: - atomic_write(path, formatted_str, newline) + if formatted_str != original_str: + path.write_bytes(formatted_str.encode()) else: - with open( - sys.stdout.fileno(), "w", closefd=False, newline=newline - ) as stdout: - stdout.write(formatted_str) + sys.stdout.buffer.write(formatted_str.encode()) if format_errors_found: return 1 return 0 diff --git a/src/mdformat/_util.py b/src/mdformat/_util.py index e711fdf..a4d634f 100644 --- a/src/mdformat/_util.py +++ b/src/mdformat/_util.py @@ -2,11 +2,7 @@ from collections.abc import Iterable, Mapping from contextlib import nullcontext -import filecmp -import os -from pathlib import Path import re -import tempfile from types import MappingProxyType from typing import Any, Literal @@ -106,26 +102,6 @@ def is_md_equal( return html_texts["md1"] == html_texts["md2"] -def atomic_write(path: Path, text: str, newline: str) -> None: - """A function for atomic writes to a file. - - Writes a temporary file first and then replaces the original file - with the temporary one. This is to avoid a moment where only empty - or partial content exists on disk. - """ - fd, tmp_path = tempfile.mkstemp(dir=path.parent) - try: - with open(fd, "w", encoding="utf-8", newline=newline) as f: - f.write(text) - if filecmp.cmp(tmp_path, path, shallow=False): - os.remove(tmp_path) - else: - os.replace(tmp_path, path) - except BaseException: # pragma: no cover - os.remove(tmp_path) - raise - - def detect_newline_type(md: str, eol_setting: str) -> Literal["\n", "\r\n"]: """Returns the newline-character to be used for output.