Skip to content
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

blurb: replace spaces with underscores in news directory #499

Merged
merged 17 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 39 additions & 9 deletions blurb/blurb.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
## Licensed to the Python Software Foundation under a contributor agreement.
##


# TODO
#
# automatic git adds and removes
Expand Down Expand Up @@ -110,19 +109,46 @@
sections.append(section.strip())


_sanitize_section = {
"C API": "C_API",
"Core and Builtins": "Core_and_Builtins",
"Tools/Demos": "Tools-Demos",
}


def sanitize_section(section):
"""
Cleans up a section string, making it viable as a directory name.
Clean up a section string, making it viable as a directory name.
"""
return _sanitize_section.get(section, section)


def sanitize_section_legacy(section):
"""
Clean up a section string, making it viable as a directory name (allow spaces).
"""
return section.replace("/", "-")


_unsanitize_section = {
"C_API": "C API",
"Core_and_Builtins": "Core and Builtins",
hugovk marked this conversation as resolved.
Show resolved Hide resolved
"Tools-Demos": "Tools/Demos",
}


def unsanitize_section(section):
return _unsanitize_section.get(section, section)

def next_filename_unsanitize_sections(filename):
s = filename
for key, value in _unsanitize_section.items():
for separator in "/\\":
key = f"{separator}{key}{separator}"
value = f"{separator}{value}{separator}"
filename = filename.replace(key, value)
return filename


def textwrap_body(body, *, subsequent_indent=''):
"""
Expand Down Expand Up @@ -300,14 +326,18 @@ def glob_blurbs(version):
wildcard = base + ".rst"
filenames.extend(glob.glob(wildcard))
else:
for section in sections:
wildcard = os.path.join(base, sanitize_section(section), "*.rst")
sanitized_sections = (
{sanitize_section(section) for section in sections} |
{sanitize_section_legacy(section) for section in sections}
)
for section in sanitized_sections:
wildcard = os.path.join(base, section, "*.rst")
entries = glob.glob(wildcard)
entries.sort(reverse=True)
deletables = [x for x in entries if x.endswith("/README.rst")]
for filename in deletables:
entries.remove(filename)
filenames.extend(entries)
filenames.sort(reverse=True, key=next_filename_unsanitize_sections)
return filenames


Expand Down Expand Up @@ -537,8 +567,8 @@ def save(self, path):
@staticmethod
def _parse_next_filename(filename):
"""
Parses a "next" filename into its equivalent blurb metadata.
Returns a dict.
Parses a "next" filename into its equivalent blurb metadata.
Returns a dict.
"""
components = filename.split(os.sep)
section, filename = components[-2:]
Expand All @@ -552,7 +582,7 @@ def _parse_next_filename(filename):
metadata = {"date": fields[0], "nonce": fields[-2], "section": section}

for field in fields[1:-2]:
for name in ("gh-issue","bpo"):
for name in ("gh-issue", "bpo"):
_, got, value = field.partition(name + "-")
if got:
metadata[name] = value.strip()
Expand Down Expand Up @@ -589,7 +619,7 @@ def _extract_next_filename(self):
metadata, body = self[-1]
metadata['section'] = sanitize_section(metadata['section'])
metadata['root'] = root
if int(metadata["gh-issue"]) > 0 :
if int(metadata["gh-issue"]) > 0:
path = "{root}/Misc/NEWS.d/next/{section}/{date}.gh-issue-{gh-issue}.{nonce}.rst".format_map(metadata)
elif int(metadata["bpo"]) > 0:
# assume it's a GH issue number
Expand Down
85 changes: 63 additions & 22 deletions blurb/tests/test_blurb.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@


UNCHANGED_SECTIONS = (
"C API",
"Core and Builtins",
"Library",
)


@pytest.mark.parametrize("section", UNCHANGED_SECTIONS)
def test_sanitize_section_no_change(section: str) -> None:
def test_sanitize_section_no_change(section):
sanitized = blurb.sanitize_section(section)
assert sanitized == section


@pytest.mark.parametrize(
"section, expected",
(
("C API", "C_API"),
("Core and Builtins", "Core_and_Builtins"),
("Tools/Demos", "Tools-Demos"),
),
)
def test_sanitize_section_changed(section: str, expected: str) -> None:
def test_sanitize_section_changed(section, expected):
sanitized = blurb.sanitize_section(section)
assert sanitized == expected


@pytest.mark.parametrize("section", UNCHANGED_SECTIONS)
def test_unsanitize_section_no_change(section: str) -> None:
def test_unsanitize_section_no_change(section):
unsanitized = blurb.unsanitize_section(section)
assert unsanitized == section

Expand All @@ -40,12 +40,12 @@ def test_unsanitize_section_no_change(section: str) -> None:
("Tools-Demos", "Tools/Demos"),
),
)
def test_unsanitize_section_changed(section: str, expected: str) -> None:
def test_unsanitize_section_changed(section, expected):
unsanitized = blurb.unsanitize_section(section)
assert unsanitized == expected


def test_glob_blurbs_next(fs: FakeFilesystem) -> None:
def test_glob_blurbs_next(fs):
# Arrange
fake_news_entries = (
"Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.pC7gnM.rst",
Expand All @@ -69,28 +69,71 @@ def test_glob_blurbs_next(fs: FakeFilesystem) -> None:
assert set(filenames) == set(fake_news_entries)


def test_glob_blurbs_sort_order(fs):
"""
It shouldn't make a difference to sorting whether
section names have spaces or underscores.
"""
# Arrange
fake_news_entries = (
"Misc/NEWS.d/next/Core and Builtins/2023-07-23-12-01-00.gh-issue-33331.Pf_BI1.rst",
"Misc/NEWS.d/next/Core_and_Builtins/2023-07-23-12-02-00.gh-issue-33332.Pf_BI2.rst",
"Misc/NEWS.d/next/Core and Builtins/2023-07-23-12-03-00.gh-issue-33333.Pf_BI3.rst",
"Misc/NEWS.d/next/Core_and_Builtins/2023-07-23-12-04-00.gh-issue-33334.Pf_BI4.rst",
)
# As fake_news_entries, but reverse sorted by *filename* only
expected = [
"Misc/NEWS.d/next/Core_and_Builtins/2023-07-23-12-04-00.gh-issue-33334.Pf_BI4.rst",
"Misc/NEWS.d/next/Core and Builtins/2023-07-23-12-03-00.gh-issue-33333.Pf_BI3.rst",
"Misc/NEWS.d/next/Core_and_Builtins/2023-07-23-12-02-00.gh-issue-33332.Pf_BI2.rst",
"Misc/NEWS.d/next/Core and Builtins/2023-07-23-12-01-00.gh-issue-33331.Pf_BI1.rst",
]
fake_readmes = (
"Misc/NEWS.d/next/Library/README.rst",
"Misc/NEWS.d/next/Core and Builtins/README.rst",
"Misc/NEWS.d/next/Tools-Demos/README.rst",
"Misc/NEWS.d/next/C API/README.rst",
)
for fn in fake_news_entries + fake_readmes:
fs.create_file(fn)

# Act
filenames = blurb.glob_blurbs("next")

# Assert
assert filenames == expected


@pytest.mark.parametrize(
"news_entry, expected_section",
(
(
"Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-55555.pC7gnM.rst",
"Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-33333.pC7gnM.rst",
"Library",
),
(
"Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-33333.Pf_BI7.rst",
"Misc/NEWS.d/next/Core_and_Builtins/2023-03-17-12-09-45.gh-issue-44444.Pf_BI7.rst",
"Core and Builtins",
),
(
"Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-55555.Pf_BI7.rst",
"Core and Builtins",
),
(
"Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-44444.2F1Byz.rst",
"Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-66666.2F1Byz.rst",
"Tools/Demos",
),
(
"Misc/NEWS.d/next/C API/2023-03-27-22-09-07.gh-issue-66666.3SN8Bs.rst",
"Misc/NEWS.d/next/C_API/2023-03-27-22-09-07.gh-issue-77777.3SN8Bs.rst",
"C API",
),
(
"Misc/NEWS.d/next/C API/2023-03-27-22-09-07.gh-issue-88888.3SN8Bs.rst",
"C API",
),
),
)
def test_load_next(news_entry: str, expected_section: str, fs: FakeFilesystem) -> None:
def test_load_next(news_entry, expected_section, fs):
# Arrange
fs.create_file(news_entry, contents="testing")
blurbs = blurb.Blurbs()
Expand All @@ -107,26 +150,24 @@ def test_load_next(news_entry: str, expected_section: str, fs: FakeFilesystem) -
"news_entry, expected_path",
(
(
"Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-55555.pC7gnM.rst",
"root/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-55555.pC7gnM.rst",
"Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-33333.pC7gnM.rst",
"root/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-33333.pC7gnM.rst",
),
(
"Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-33333.Pf_BI7.rst",
"root/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-33333.Pf_BI7.rst",
"Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-44444.Pf_BI7.rst",
"root/Misc/NEWS.d/next/Core_and_Builtins/2023-03-17-12-09-45.gh-issue-44444.Pf_BI7.rst",
),
(
"Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-44444.2F1Byz.rst",
"root/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-44444.2F1Byz.rst",
"Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-55555.2F1Byz.rst",
"root/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-55555.2F1Byz.rst",
),
(
"Misc/NEWS.d/next/C API/2023-03-27-22-09-07.gh-issue-66666.3SN8Bs.rst",
"root/Misc/NEWS.d/next/C API/2023-03-27-22-09-07.gh-issue-66666.3SN8Bs.rst",
"root/Misc/NEWS.d/next/C_API/2023-03-27-22-09-07.gh-issue-66666.3SN8Bs.rst",
),
),
)
def test_extract_next_filename(
news_entry: str, expected_path: str, fs: FakeFilesystem
) -> None:
def test_extract_next_filename(news_entry, expected_path, fs):
# Arrange
fs.create_file(news_entry, contents="testing")
blurb.root = "root"
Expand Down