diff --git a/blurb/blurb.py b/blurb/blurb.py index fd5c0fa..3a21dab 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -38,7 +38,6 @@ ## Licensed to the Python Software Foundation under a contributor agreement. ## - # TODO # # automatic git adds and removes @@ -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", "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=''): """ @@ -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 @@ -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:] @@ -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() @@ -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 diff --git a/blurb/tests/test_blurb.py b/blurb/tests/test_blurb.py index b2d06b5..515f6b2 100644 --- a/blurb/tests/test_blurb.py +++ b/blurb/tests/test_blurb.py @@ -5,14 +5,12 @@ 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 @@ -20,16 +18,18 @@ def test_sanitize_section_no_change(section: str) -> None: @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 @@ -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", @@ -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() @@ -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"
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: