From 036771539caa8682648c06deec2ce6634ece8ce3 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 28 Mar 2023 08:45:18 +0300 Subject: [PATCH 01/15] Remove unused code --- blurb/blurb.py | 68 -------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index 51f1087..0d920be 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -51,7 +51,6 @@ import io import inspect import itertools -import math import os from pathlib import Path import re @@ -249,40 +248,6 @@ def safe_mkdir(path): os.makedirs(path) -def which(cmd, path="PATH"): - """Find cmd on PATH.""" - if os.path.exists(cmd): - return cmd - if cmd[0] == '/': - return None - for segment in os.getenv(path).split(":"): - program = os.path.normpath(os.path.join(segment, cmd)) - if os.path.exists(program): - return program - return None - - -def strip_whitespace_lines(lines): - # strip from head - while lines: - if lines[0]: - break - lines.pop(0) - - # strip from tail - while lines: - if lines[-1]: - return - lines.pop() - - -def longest_line(lines): - longest = 0 - for line in lines: - longest = max(longest, len(line)) - return longest - - def version_key(element): fields = list(element.split(".")) if len(fields) == 1: @@ -632,31 +597,6 @@ def save_next(self): blurb.save(filename) return filename - def save_split_next(self): - """ - Save out blurbs created from "blurb split". - They don't have dates, so we have to get creative. - """ - filenames = [] - # the "date" MUST have a leading zero. - # this ensures these files sort after all - # newly created blurbs. - width = int(math.ceil(math.log(len(self), 10))) + 1 - i = 1 - blurb = Blurbs() - while self: - metadata, body = self.pop() - metadata['date'] = str(i).rjust(width, '0') - if 'release date' in metadata: - del metadata['release date'] - blurb.append((metadata, body)) - filename = blurb._extract_next_filename() - blurb.save(filename) - blurb.clear() - filenames.append(filename) - i += 1 - return filenames - tests_run = 0 @@ -694,13 +634,6 @@ def filename_test(self, filename): b.load(filename) - -def run(s): - process = subprocess.run(s.split(), capture_output=True) - process.check_returncode() - return process.stdout.decode('ascii') - - readme_re = re.compile(r"This is \w+ version \d+\.\d+").match def chdir_to_repo_root(): @@ -993,7 +926,6 @@ def release(version): metadata = {"no changes": "True", "gh-issue": "0", "section": "Library", "date": date, "nonce": nonceify(body)} blurbs.append((metadata, body)) else: - no_changes = None count = len(filenames) print(f'Merging {count} blurbs to "{output}".') From 535fc6a24f7d7cab160d60a925558b3eea5ac7ea Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 28 Mar 2023 08:49:04 +0300 Subject: [PATCH 02/15] Add tests --- .coveragerc | 15 +++++ .github/workflows/tests.yml | 18 ++++- blurb/tests/test_blurb.py | 127 ++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 .coveragerc create mode 100644 blurb/tests/test_blurb.py diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..38d0766 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,15 @@ +# .coveragerc to control coverage.py + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Have to re-enable the standard pragma: + pragma: no cover + + # Don't complain if non-runnable code isn't run: + if __name__ == .__main__.: + def main + +[run] +omit = + **/blurb/__main__.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cbb8cd2..5a25a05 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,6 +2,9 @@ name: Tests on: [push, pull_request, workflow_dispatch] +env: + FORCE_COLOR: 1 + jobs: build_ubuntu: strategy: @@ -21,10 +24,23 @@ jobs: python --version python -m pip install --upgrade pip python -m pip install --upgrade flit + python -m pip install --upgrade pytest pytest-cov pyfakefs - name: install run: | cd blurb - flit install + pip install -e . - name: test run: | blurb test + - name: pytest + # TODO Pending https://github.com/pytest-dev/pyfakefs/issues/770 + if: matrix.python-version != '3.12-dev' + run: | + pytest --cov blurb + - name: Upload coverage + # TODO Pending https://github.com/pytest-dev/pyfakefs/issues/770 + if: matrix.python-version != '3.12-dev' + uses: codecov/codecov-action@v3 + with: + flags: ${{ matrix.python-version }} + name: Python ${{ matrix.python-version }} diff --git a/blurb/tests/test_blurb.py b/blurb/tests/test_blurb.py new file mode 100644 index 0000000..b305cd8 --- /dev/null +++ b/blurb/tests/test_blurb.py @@ -0,0 +1,127 @@ +import pytest +from pyfakefs.fake_filesystem import FakeFilesystem + +import blurb + + +@pytest.mark.parametrize( + "section, expected", + ( + ("C API", "C API"), + ("Core and Builtins", "Core and Builtins"), + ("Library", "Library"), + ("Tools/Demos", "Tools-Demos"), + ), +) +def test_sanitize_section(section: str, expected: str) -> None: + sanitized = blurb.sanitize_section(section) + assert sanitized == expected + + +@pytest.mark.parametrize( + "section, expected", + ( + ("C API", "C API"), + ("Core and Builtins", "Core and Builtins"), + ("Library", "Library"), + ("Tools-Demos", "Tools/Demos"), + ), +) +def test_unsanitize_section(section: str, expected: str) -> None: + unsanitized = blurb.unsanitize_section(section) + assert unsanitized == expected + + +def test_glob_blurbs_next(fs: FakeFilesystem) -> None: + # Arrange + fake_news_entries = ( + "Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.pC7gnM.rst", + "Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-33333.Pf_BI7.rst", + "Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-44444.2F1Byz.rst", + "Misc/NEWS.d/next/C API/2023-03-27-22-09-07.gh-issue-66666.3SN8Bs.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 set(filenames) == set(fake_news_entries) + + +@pytest.mark.parametrize( + "news_entry, expected_section", + ( + ( + "Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.pC7gnM.rst", + "Library", + ), + ( + "Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-33333.Pf_BI7.rst", + "Core and Builtins", + ), + ( + "Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-44444.2F1Byz.rst", + "Tools/Demos", + ), + ( + "Misc/NEWS.d/next/C API/2023-03-27-22-09-07.gh-issue-66666.3SN8Bs.rst", + "C API", + ), + ), +) +def test_load_next(news_entry: str, expected_section: str, fs: FakeFilesystem) -> None: + # Arrange + fs.create_file(news_entry, contents="testing") + blurbs = blurb.Blurbs() + + # Act + blurbs.load_next(news_entry) + + # Assert + metadata = blurbs[0][0] + assert metadata["section"] == expected_section + + +@pytest.mark.parametrize( + "news_entry, expected_path", + ( + ( + "Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.pC7gnM.rst", + "root/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.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/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/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: + # Arrange + fs.create_file(news_entry, contents="testing") + blurb.root = "root" + blurbs = blurb.Blurbs() + blurbs.load_next(news_entry) + + # Act + path = blurbs._extract_next_filename() + + # Assert + assert path == expected_path From 3a84a69defd861359adefe207cb42e2ad99f7914 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 28 Mar 2023 11:02:32 +0300 Subject: [PATCH 03/15] Add some type annotations --- blurb/blurb.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index 0d920be..4588b28 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 """Command-line tool to manage CPython Misc/NEWS.d entries.""" +from __future__ import annotations __version__ = "1.1.0" ## @@ -110,17 +111,19 @@ sections.append(section.strip()) -def sanitize_section(section): +def sanitize_section(section: str) -> str: """ -Cleans up a section string, making it viable as a directory name. + Cleans up a section string, making it viable as a directory name. """ return section.replace("/", "-") + _unsanitize_section = { "Tools-Demos": "Tools/Demos", } -def unsanitize_section(section): + +def unsanitize_section(section: str) -> str: return _unsanitize_section.get(section, section) @@ -293,7 +296,7 @@ def glob_versions(): return versions -def glob_blurbs(version): +def glob_blurbs(version: str) -> list[str]: filenames = [] base = os.path.join("Misc", "NEWS.d", version) if version != "next": @@ -523,10 +526,10 @@ def save(self, path): file.write(text) @staticmethod - def _parse_next_filename(filename): + def _parse_next_filename(filename: str) -> dict[str, str]: """ -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:] @@ -540,7 +543,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() @@ -569,7 +572,7 @@ def ensure_metadata(self): if name not in metadata: metadata[name] = default - def _extract_next_filename(self): + def _extract_next_filename(self) -> str: """ changes metadata! """ @@ -577,7 +580,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 From 67869b30b17432354bd9b46190108dc75444e615 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 28 Mar 2023 17:31:36 +0300 Subject: [PATCH 04/15] Use dashes instead of spaces in paths --- blurb/blurb.py | 17 +++++++++++++++-- blurb/tests/test_blurb.py | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index 4588b28..84ddf5d 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -115,10 +115,19 @@ def sanitize_section(section: str) -> str: """ Cleans up a section string, making it viable as a directory name. """ + return section.replace("/", "-").replace(" ", "-") + + +def sanitize_section_legacy(section: str) -> str: + """ + Cleans 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", } @@ -303,8 +312,12 @@ def glob_blurbs(version: str) -> list[str]: 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")] diff --git a/blurb/tests/test_blurb.py b/blurb/tests/test_blurb.py index b305cd8..dc82c24 100644 --- a/blurb/tests/test_blurb.py +++ b/blurb/tests/test_blurb.py @@ -7,8 +7,8 @@ @pytest.mark.parametrize( "section, expected", ( - ("C API", "C API"), - ("Core and Builtins", "Core and Builtins"), + ("C API", "C-API"), + ("Core and Builtins", "Core-and-Builtins"), ("Library", "Library"), ("Tools/Demos", "Tools-Demos"), ), @@ -24,6 +24,22 @@ def test_sanitize_section(section: str, expected: str) -> None: ("C API", "C API"), ("Core and Builtins", "Core and Builtins"), ("Library", "Library"), + ("Tools/Demos", "Tools-Demos"), + ), +) +def test_sanitize_section_legacy(section: str, expected: str) -> None: + sanitized = blurb.sanitize_section_legacy(section) + assert sanitized == expected + + +@pytest.mark.parametrize( + "section, expected", + ( + ("C-API", "C API"), + ("C API", "C API"), + ("Core-and-Builtins", "Core and Builtins"), + ("Core and Builtins", "Core and Builtins"), + ("Library", "Library"), ("Tools-Demos", "Tools/Demos"), ), ) @@ -63,6 +79,10 @@ def test_glob_blurbs_next(fs: FakeFilesystem) -> None: "Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.pC7gnM.rst", "Library", ), + ( + "Misc/NEWS.d/next/Core-and-Builtins/2023-03-17-12-09-45.gh-issue-22222.Pf_BI7.rst", + "Core and Builtins", + ), ( "Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-33333.Pf_BI7.rst", "Core and Builtins", @@ -71,6 +91,10 @@ def test_glob_blurbs_next(fs: FakeFilesystem) -> None: "Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-44444.2F1Byz.rst", "Tools/Demos", ), + ( + "Misc/NEWS.d/next/C-API/2023-03-27-22-09-07.gh-issue-55555.3SN8Bs.rst", + "C API", + ), ( "Misc/NEWS.d/next/C API/2023-03-27-22-09-07.gh-issue-66666.3SN8Bs.rst", "C API", @@ -98,16 +122,16 @@ def test_load_next(news_entry: str, expected_section: str, fs: FakeFilesystem) - "root/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.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-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/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/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", + "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", ), ), ) From 36bd99f7c8e1b03c602b53bb56ac1250ebda4911 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 29 Mar 2023 22:38:30 +0300 Subject: [PATCH 05/15] Don't install flit Co-authored-by: C.A.M. Gerlach --- .github/workflows/tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5a25a05..df087ff 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,6 @@ jobs: run: | python --version python -m pip install --upgrade pip - python -m pip install --upgrade flit python -m pip install --upgrade pytest pytest-cov pyfakefs - name: install run: | From 66bc9e0acc507ffb8d1f2e2db7c2f52306378fbc Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 29 Mar 2023 22:47:43 +0300 Subject: [PATCH 06/15] Build and install package, then test installed package --- .github/workflows/tests.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index df087ff..81d17e5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,7 +27,8 @@ jobs: - name: install run: | cd blurb - pip install -e . + python -m build + echo dist/*.whl | xargs -I % python -m pip install % - name: test run: | blurb test @@ -35,7 +36,7 @@ jobs: # TODO Pending https://github.com/pytest-dev/pyfakefs/issues/770 if: matrix.python-version != '3.12-dev' run: | - pytest --cov blurb + python -I -m pytest --cov blurb - name: Upload coverage # TODO Pending https://github.com/pytest-dev/pyfakefs/issues/770 if: matrix.python-version != '3.12-dev' From e69848daa67f8c9fb81bd464a7f251d24796ceed Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 29 Mar 2023 22:50:01 +0300 Subject: [PATCH 07/15] Install build --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 81d17e5..e856e3b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,6 +8,7 @@ env: jobs: build_ubuntu: strategy: + fail-fast: false matrix: python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"] name: ${{ matrix.python-version }} @@ -23,7 +24,7 @@ jobs: run: | python --version python -m pip install --upgrade pip - python -m pip install --upgrade pytest pytest-cov pyfakefs + python -m pip install --upgrade build pytest pytest-cov pyfakefs - name: install run: | cd blurb From e68c9feb6574447bc91eb55ee5dc3f62ce92a4fc Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 30 Mar 2023 22:06:41 +0300 Subject: [PATCH 08/15] Install in place for easier test coverage --- .github/workflows/tests.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e856e3b..dcf5728 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,12 +24,11 @@ jobs: run: | python --version python -m pip install --upgrade pip - python -m pip install --upgrade build pytest pytest-cov pyfakefs + python -m pip install --upgrade pytest pytest-cov pyfakefs - name: install run: | cd blurb - python -m build - echo dist/*.whl | xargs -I % python -m pip install % + python -m pip install -e . - name: test run: | blurb test From 9bb59f49356660cc8b52e8f32cd4a3adb1e8bdbf Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 23 Jul 2023 14:10:55 +0200 Subject: [PATCH 09/15] Test on Python 3.12 --- .github/workflows/tests.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dcf5728..88ff525 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] name: ${{ matrix.python-version }} runs-on: ubuntu-latest steps: @@ -18,6 +18,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + allow-prereleases: true cache: pip cache-dependency-path: ".github/workflows/tests.yml" - name: setup @@ -33,13 +34,9 @@ jobs: run: | blurb test - name: pytest - # TODO Pending https://github.com/pytest-dev/pyfakefs/issues/770 - if: matrix.python-version != '3.12-dev' run: | python -I -m pytest --cov blurb - name: Upload coverage - # TODO Pending https://github.com/pytest-dev/pyfakefs/issues/770 - if: matrix.python-version != '3.12-dev' uses: codecov/codecov-action@v3 with: flags: ${{ matrix.python-version }} From 53ca53530a03e8581cfa0349a8287409a3751608 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 23 Jul 2023 14:23:35 +0200 Subject: [PATCH 10/15] Remove type hints --- blurb/blurb.py | 13 ++++++------- blurb/tests/test_blurb.py | 15 ++++++--------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index 84ddf5d..e7674a0 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 """Command-line tool to manage CPython Misc/NEWS.d entries.""" -from __future__ import annotations __version__ = "1.1.0" ## @@ -111,14 +110,14 @@ sections.append(section.strip()) -def sanitize_section(section: str) -> str: +def sanitize_section(section): """ Cleans up a section string, making it viable as a directory name. """ return section.replace("/", "-").replace(" ", "-") -def sanitize_section_legacy(section: str) -> str: +def sanitize_section_legacy(section): """ Cleans up a section string, making it viable as a directory name (allow spaces). """ @@ -132,7 +131,7 @@ def sanitize_section_legacy(section: str) -> str: } -def unsanitize_section(section: str) -> str: +def unsanitize_section(section): return _unsanitize_section.get(section, section) @@ -305,7 +304,7 @@ def glob_versions(): return versions -def glob_blurbs(version: str) -> list[str]: +def glob_blurbs(version): filenames = [] base = os.path.join("Misc", "NEWS.d", version) if version != "next": @@ -539,7 +538,7 @@ def save(self, path): file.write(text) @staticmethod - def _parse_next_filename(filename: str) -> dict[str, str]: + def _parse_next_filename(filename): """ Parses a "next" filename into its equivalent blurb metadata. Returns a dict. @@ -585,7 +584,7 @@ def ensure_metadata(self): if name not in metadata: metadata[name] = default - def _extract_next_filename(self) -> str: + def _extract_next_filename(self): """ changes metadata! """ diff --git a/blurb/tests/test_blurb.py b/blurb/tests/test_blurb.py index dc82c24..7fde38d 100644 --- a/blurb/tests/test_blurb.py +++ b/blurb/tests/test_blurb.py @@ -1,5 +1,4 @@ import pytest -from pyfakefs.fake_filesystem import FakeFilesystem import blurb @@ -13,7 +12,7 @@ ("Tools/Demos", "Tools-Demos"), ), ) -def test_sanitize_section(section: str, expected: str) -> None: +def test_sanitize_section(section, expected): sanitized = blurb.sanitize_section(section) assert sanitized == expected @@ -27,7 +26,7 @@ def test_sanitize_section(section: str, expected: str) -> None: ("Tools/Demos", "Tools-Demos"), ), ) -def test_sanitize_section_legacy(section: str, expected: str) -> None: +def test_sanitize_section_legacy(section, expected): sanitized = blurb.sanitize_section_legacy(section) assert sanitized == expected @@ -43,12 +42,12 @@ def test_sanitize_section_legacy(section: str, expected: str) -> None: ("Tools-Demos", "Tools/Demos"), ), ) -def test_unsanitize_section(section: str, expected: str) -> None: +def test_unsanitize_section(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", @@ -101,7 +100,7 @@ def test_glob_blurbs_next(fs: FakeFilesystem) -> None: ), ), ) -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() @@ -135,9 +134,7 @@ def test_load_next(news_entry: str, expected_section: str, fs: FakeFilesystem) - ), ), ) -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" From f98656d2f6630086fb1d022b0c0a5d6666f71786 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 23 Jul 2023 14:36:55 +0200 Subject: [PATCH 11/15] Use underscores instead of dashes for spaces --- blurb/blurb.py | 6 +++--- blurb/tests/test_blurb.py | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index e7674a0..0943c2e 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -114,7 +114,7 @@ def sanitize_section(section): """ Cleans up a section string, making it viable as a directory name. """ - return section.replace("/", "-").replace(" ", "-") + return section.replace("/", "-").replace(" ", "_") def sanitize_section_legacy(section): @@ -125,8 +125,8 @@ def sanitize_section_legacy(section): _unsanitize_section = { - "C-API": "C API", - "Core-and-Builtins": "Core and Builtins", + "C_API": "C API", + "Core_and_Builtins": "Core and Builtins", "Tools-Demos": "Tools/Demos", } diff --git a/blurb/tests/test_blurb.py b/blurb/tests/test_blurb.py index 7fde38d..8219c4a 100644 --- a/blurb/tests/test_blurb.py +++ b/blurb/tests/test_blurb.py @@ -6,8 +6,8 @@ @pytest.mark.parametrize( "section, expected", ( - ("C API", "C-API"), - ("Core and Builtins", "Core-and-Builtins"), + ("C API", "C_API"), + ("Core and Builtins", "Core_and_Builtins"), ("Library", "Library"), ("Tools/Demos", "Tools-Demos"), ), @@ -34,9 +34,9 @@ def test_sanitize_section_legacy(section, expected): @pytest.mark.parametrize( "section, expected", ( - ("C-API", "C API"), + ("C_API", "C API"), ("C API", "C API"), - ("Core-and-Builtins", "Core and Builtins"), + ("Core_and_Builtins", "Core and Builtins"), ("Core and Builtins", "Core and Builtins"), ("Library", "Library"), ("Tools-Demos", "Tools/Demos"), @@ -79,7 +79,7 @@ def test_glob_blurbs_next(fs): "Library", ), ( - "Misc/NEWS.d/next/Core-and-Builtins/2023-03-17-12-09-45.gh-issue-22222.Pf_BI7.rst", + "Misc/NEWS.d/next/Core_and_Builtins/2023-03-17-12-09-45.gh-issue-22222.Pf_BI7.rst", "Core and Builtins", ), ( @@ -91,7 +91,7 @@ def test_glob_blurbs_next(fs): "Tools/Demos", ), ( - "Misc/NEWS.d/next/C-API/2023-03-27-22-09-07.gh-issue-55555.3SN8Bs.rst", + "Misc/NEWS.d/next/C_API/2023-03-27-22-09-07.gh-issue-55555.3SN8Bs.rst", "C API", ), ( @@ -121,16 +121,16 @@ def test_load_next(news_entry, expected_section, fs): "root/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-11111.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-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/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/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", + "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", ), ), ) From 53cae5251f2e41c87099b95a549c4a52bc6be8fe Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sun, 23 Jul 2023 16:16:05 +0200 Subject: [PATCH 12/15] Sort the *normalized* filenames for blurb release. If we have "next" files in both "Core and Workflow" *and* "Core_and_Workflow", we need to merge those two directories together and sort by date. (Before this change, it would have had "Core and Workflow" entries sorted by date, and *then* "Core_and_Workflow" entries sorted by date.) --- blurb/blurb.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index 0943c2e..ce4b68d 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 @@ -134,6 +133,15 @@ def sanitize_section_legacy(section): 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=''): """ @@ -318,11 +326,11 @@ def glob_blurbs(version): 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 From 8e53d4a99f0c3d1d11066809f4de653e65584f62 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 23 Jul 2023 20:22:22 +0200 Subject: [PATCH 13/15] Add glob_blurbs test for sorting by filename --- blurb/tests/test_blurb.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/blurb/tests/test_blurb.py b/blurb/tests/test_blurb.py index 8219c4a..043266c 100644 --- a/blurb/tests/test_blurb.py +++ b/blurb/tests/test_blurb.py @@ -71,6 +71,41 @@ def test_glob_blurbs_next(fs): 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", ( From acc9e059b590e97260ff54bd65c1db2cb15ae11c Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 26 Jul 2023 18:14:52 +0300 Subject: [PATCH 14/15] Change docstring grammar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric --- blurb/blurb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index ce4b68d..fa1aad5 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -111,14 +111,14 @@ 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 section.replace("/", "-").replace(" ", "_") def sanitize_section_legacy(section): """ - Cleans up a section string, making it viable as a directory name (allow spaces). + Clean up a section string, making it viable as a directory name (allow spaces). """ return section.replace("/", "-") From f63fea1ddab33c8087c77fa222e59dadff37c67f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 17 Jan 2024 19:29:53 +0200 Subject: [PATCH 15/15] Replace replace.replace with dict.get --- blurb/blurb.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/blurb/blurb.py b/blurb/blurb.py index bfe53e6..3a21dab 100755 --- a/blurb/blurb.py +++ b/blurb/blurb.py @@ -109,11 +109,18 @@ sections.append(section.strip()) +_sanitize_section = { + "C API": "C_API", + "Core and Builtins": "Core_and_Builtins", + "Tools/Demos": "Tools-Demos", + } + + def sanitize_section(section): """ Clean up a section string, making it viable as a directory name. """ - return section.replace("/", "-").replace(" ", "_") + return _sanitize_section.get(section, section) def sanitize_section_legacy(section):