Skip to content

Commit

Permalink
Prefer pathlib for read/write operations (#591)
Browse files Browse the repository at this point in the history
* Rely on pathlib when reading and writing simple text.

* Universal newlines is the default, so remove the comment.

* Add news fragment.

* Add compatibility shim for Python 3.9 and earlier.

* Suppress coverage check for line 20 as it emits a spurious failure.

* Only exclude branch coverage (regular coverage is fine)

Co-authored-by: Adi Roiban <[email protected]>

* Add comment explaining motivation for the compatibility shim.

---------

Co-authored-by: Adi Roiban <[email protected]>
  • Loading branch information
jaraco and adiroiban authored Apr 29, 2024
1 parent 7221d5d commit db10a4d
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/towncrier/_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import textwrap

from collections import defaultdict
from pathlib import Path
from typing import Any, DefaultDict, Iterable, Iterator, Mapping, Sequence

from jinja2 import Template
Expand Down Expand Up @@ -111,8 +112,7 @@ def find_fragments(

full_filename = os.path.join(section_dir, basename)
fragment_filenames.append(full_filename)
with open(full_filename, "rb") as f:
data = f.read().decode("utf-8", "replace")
data = Path(full_filename).read_text(encoding="utf-8", errors="replace")

if (ticket, category, counter) in file_content:
raise ValueError(
Expand Down
36 changes: 25 additions & 11 deletions src/towncrier/_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,22 @@

from __future__ import annotations

import sys

from pathlib import Path
from typing import Any


if sys.version_info < (3, 10):
# Compatibility shim for newline parameter to write_text, added in 3.10
def _newline_write_text(path: Path, content: str, **kwargs: Any) -> None:
with path.open("w", **kwargs) as strm: # pragma: no branch
strm.write(content)

else:

def _newline_write_text(path: Path, content: str, **kwargs: Any) -> None:
path.write_text(content, **kwargs)


def append_to_newsfile(
Expand Down Expand Up @@ -37,15 +52,17 @@ def append_to_newsfile(
if top_line and top_line in prev_body:
raise ValueError("It seems you've already produced newsfiles for this version?")

# Leave newlines alone. This probably leads to inconsistent newlines,
# because we've loaded existing content with universal newlines, but that's
# the original behavior.
with news_file.open("w", encoding="utf-8", newline="") as f:
if header:
f.write(header)
_newline_write_text(
news_file,
# If there is no previous body that means we're writing a brand new news file.
# We don't want extra whitespace at the end of this new file.
f.write(content + prev_body if prev_body else content.rstrip() + "\n")
header + (content + prev_body if prev_body else content.rstrip() + "\n"),
encoding="utf-8",
# Leave newlines alone. This probably leads to inconsistent newlines,
# because we've loaded existing content with universal newlines, but that's
# the original behavior.
newline="",
)


def _figure_out_existing_content(
Expand All @@ -64,10 +81,7 @@ def _figure_out_existing_content(
# Non-existent files have no existing content.
return "", ""

# If we didn't use universal newlines here, we wouldn't find *start_string*
# which usually contains a `\n`.
with news_file.open(encoding="utf-8") as f:
content = f.read()
content = Path(news_file).read_text(encoding="utf-8")

t = content.split(start_string, 1)
if len(t) == 2:
Expand Down
5 changes: 2 additions & 3 deletions src/towncrier/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
Build a combined news file from news fragments.
"""


from __future__ import annotations

import os
import sys

from datetime import date
from pathlib import Path

import click

Expand Down Expand Up @@ -171,8 +171,7 @@ def __main(
.read_text(encoding="utf-8")
)
else:
with open(config.template, encoding="utf-8") as tmpl:
template = tmpl.read()
template = Path(config.template).read_text(encoding="utf-8")

click.echo("Finding news fragments...", err=to_err)

Expand Down
10 changes: 6 additions & 4 deletions src/towncrier/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import os

from pathlib import Path

import click

from ._settings import config_option_help, load_config_from_options
Expand Down Expand Up @@ -170,10 +172,10 @@ def __main(
click.echo("Aborted creating news fragment due to empty message.")
ctx.exit(1)

with open(segment_file, "w", encoding="utf-8") as f:
f.write(content)
if config.create_eof_newline and content and not content.endswith("\n"):
f.write("\n")
add_newline = bool(
config.create_eof_newline and content and not content.endswith("\n")
)
Path(segment_file).write_text(content + "\n" * add_newline, encoding="utf-8")

click.echo(f"Created news fragment at {segment_file}")

Expand Down
1 change: 1 addition & 0 deletions src/towncrier/newsfragments/591.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Leveraged pathlib in most file operations.

0 comments on commit db10a4d

Please sign in to comment.