Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-blurb for openSUSE:Factory 
checked in at 2025-01-28 14:59:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-blurb (Old)
 and      /work/SRC/openSUSE:Factory/.python-blurb.new.2316 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-blurb"

Tue Jan 28 14:59:48 2025 rev:6 rq:1240752 version:2.0.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-blurb/python-blurb.changes        
2024-12-11 21:09:27.585798934 +0100
+++ /work/SRC/openSUSE:Factory/.python-blurb.new.2316/python-blurb.changes      
2025-01-28 15:00:45.133961355 +0100
@@ -1,0 +2,12 @@
+Mon Jan 27 13:55:01 UTC 2025 - Nico Krapp <[email protected]>
+
+- Update to 2.0.0
+  * Move blurb test subcommand into test suite by @hugovk in #37
+  * Add support for Python 3.14 by @ezio-melotti in #40
+  * Validate gh-issue is int before checking range, and that gh-issue or bpo 
exists by @hugovk in #35
+  * Replace safe_mkdir(path) with os.makedirs(path, exist_ok=True) by @hugovk 
in #38
+  * Test version handling functions by @hugovk in #36
+  * Test textwrap_body, current_date and sortable_datetime by @hugovk in #42
+  * CI: Lint and test via uv by @hugovk in #32
+
+-------------------------------------------------------------------

Old:
----
  blurb-1.3.0.tar.gz

New:
----
  blurb-2.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-blurb.spec ++++++
--- /var/tmp/diff_new_pack.Jdoxgq/_old  2025-01-28 15:00:45.533977893 +0100
+++ /var/tmp/diff_new_pack.Jdoxgq/_new  2025-01-28 15:00:45.533977893 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-blurb
 #
-# Copyright (c) 2024 SUSE LLC
+# Copyright (c) 2025 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %define skip_python2 1
 %{?sle15_python_module_pythons}
 Name:           python-blurb
-Version:        1.3.0
+Version:        2.0.0
 Release:        0
 Summary:        Command-line tool to manage CPython Misc/NEWS.d entries
 License:        BSD-3-Clause
@@ -31,6 +31,7 @@
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module pyfakefs}
 BuildRequires:  %{python_module pytest}
+BuildRequires:  %{python_module time-machine}
 BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros

++++++ blurb-1.3.0.tar.gz -> blurb-2.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/.coveragerc new/blurb-2.0.0/.coveragerc
--- old/blurb-1.3.0/.coveragerc 2024-10-19 15:56:16.000000000 +0200
+++ new/blurb-2.0.0/.coveragerc 2025-01-15 13:44:34.000000000 +0100
@@ -10,3 +10,4 @@
 [run]
 omit =
     **/blurb/__main__.py
+    **/blurb/_version.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/.github/workflows/lint.yml 
new/blurb-2.0.0/.github/workflows/lint.yml
--- old/blurb-1.3.0/.github/workflows/lint.yml  2024-10-19 15:56:16.000000000 
+0200
+++ new/blurb-2.0.0/.github/workflows/lint.yml  2025-01-15 13:44:34.000000000 
+0100
@@ -14,8 +14,9 @@
 
     steps:
       - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
       - uses: actions/setup-python@v5
         with:
           python-version: "3.x"
-          cache: pip
-      - uses: pre-commit/[email protected]
+      - uses: tox-dev/action-pre-commit-uv@v1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/.github/workflows/release.yml 
new/blurb-2.0.0/.github/workflows/release.yml
--- old/blurb-1.3.0/.github/workflows/release.yml       2024-10-19 
15:56:16.000000000 +0200
+++ new/blurb-2.0.0/.github/workflows/release.yml       2025-01-15 
13:44:34.000000000 +0100
@@ -24,6 +24,7 @@
       - uses: actions/checkout@v4
         with:
           fetch-depth: 0
+          persist-credentials: false
 
       - uses: hynek/build-and-inspect-python-package@v2
 
@@ -50,7 +51,6 @@
       - name: Publish to Test PyPI
         uses: pypa/gh-action-pypi-publish@release/v1
         with:
-          attestations: true
           repository-url: https://test.pypi.org/legacy/
 
   # Publish to PyPI on GitHub Releases.
@@ -82,5 +82,3 @@
 
       - name: Publish to PyPI
         uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          attestations: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/.github/workflows/test.yml 
new/blurb-2.0.0/.github/workflows/test.yml
--- old/blurb-1.3.0/.github/workflows/test.yml  2024-10-19 15:56:16.000000000 
+0200
+++ new/blurb-2.0.0/.github/workflows/test.yml  2025-01-15 13:44:34.000000000 
+0100
@@ -14,30 +14,28 @@
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
 
     steps:
       - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
 
       - name: Set up Python ${{ matrix.python-version }}
         uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
           allow-prereleases: true
-          cache: pip
 
-      - name: Install dependencies
-        run: |
-          python --version
-          python -m pip install -U pip
-          python -m pip install -U tox
+      - name: Install uv
+        uses: hynek/setup-cached-uv@v2
 
       - name: Tox tests
         run: |
-          tox -e py
+          uvx --with tox-uv tox -e py
 
       - name: Upload coverage
-        uses: codecov/codecov-action@v4
+        uses: codecov/codecov-action@v5
         with:
           flags: ${{ matrix.python-version }}
           name: Python ${{ matrix.python-version }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/CHANGELOG.md new/blurb-2.0.0/CHANGELOG.md
--- old/blurb-1.3.0/CHANGELOG.md        2024-10-19 15:56:16.000000000 +0200
+++ new/blurb-2.0.0/CHANGELOG.md        2025-01-15 13:44:34.000000000 +0100
@@ -1,5 +1,14 @@
 # Changelog
 
+## 2.0.0
+
+* Move 'blurb test' subcommand into test suite by @hugovk in 
https://github.com/python/blurb/pull/37
+* Add support for Python 3.14 by @ezio-melotti in 
https://github.com/python/blurb/pull/40
+* Validate gh-issue is int before checking range, and that gh-issue or bpo 
exists by @hugovk in https://github.com/python/blurb/pull/35
+* Replace `safe_mkdir(path)` with `os.makedirs(path, exist_ok=True)` by 
@hugovk in https://github.com/python/blurb/pull/38
+* Test version handling functions by @hugovk in 
https://github.com/python/blurb/pull/36
+* CI: Lint and test via uv by @hugovk in 
https://github.com/python/blurb/pull/32
+
 ## 1.3.0
 
 * Add support for Python 3.13 by @hugovk in 
https://github.com/python/blurb/pull/26
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/PKG-INFO new/blurb-2.0.0/PKG-INFO
--- old/blurb-1.3.0/PKG-INFO    2024-10-19 15:56:16.000000000 +0200
+++ new/blurb-2.0.0/PKG-INFO    2025-01-15 13:44:34.000000000 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.3
+Metadata-Version: 2.4
 Name: blurb
-Version: 1.3.0
+Version: 2.0.0
 Summary: Command-line tool to manage CPython Misc/NEWS.d entries.
 Project-URL: Changelog, https://github.com/python/blurb/blob/main/CHANGELOG.md
 Project-URL: Homepage, https://github.com/python/blurb
@@ -16,11 +16,13 @@
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Requires-Python: >=3.9
 Provides-Extra: tests
 Requires-Dist: pyfakefs; extra == 'tests'
 Requires-Dist: pytest; extra == 'tests'
 Requires-Dist: pytest-cov; extra == 'tests'
+Requires-Dist: time-machine; extra == 'tests'
 Description-Content-Type: text/markdown
 
 # blurb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/pyproject.toml 
new/blurb-2.0.0/pyproject.toml
--- old/blurb-1.3.0/pyproject.toml      2024-10-19 15:56:16.000000000 +0200
+++ new/blurb-2.0.0/pyproject.toml      2025-01-15 13:44:34.000000000 +0100
@@ -25,6 +25,7 @@
   "Programming Language :: Python :: 3.11",
   "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: 3.13",
+  "Programming Language :: Python :: 3.14",
 ]
 dynamic = [
   "version",
@@ -33,6 +34,7 @@
   "pyfakefs",
   "pytest",
   "pytest-cov",
+  "time-machine",
 ]
 urls.Changelog = "https://github.com/python/blurb/blob/main/CHANGELOG.md";
 urls.Homepage = "https://github.com/python/blurb";
@@ -49,4 +51,4 @@
 local_scheme = "no-local-version"
 
 [tool.pyproject-fmt]
-max_supported_python = "3.13"
+max_supported_python = "3.14"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/src/blurb/_version.py 
new/blurb-2.0.0/src/blurb/_version.py
--- old/blurb-1.3.0/src/blurb/_version.py       2024-10-19 15:56:16.000000000 
+0200
+++ new/blurb-2.0.0/src/blurb/_version.py       2025-01-15 13:44:34.000000000 
+0100
@@ -12,5 +12,5 @@
 __version_tuple__: VERSION_TUPLE
 version_tuple: VERSION_TUPLE
 
-__version__ = version = '1.3.0'
-__version_tuple__ = version_tuple = (1, 3, 0)
+__version__ = version = '2.0.0'
+__version_tuple__ = version_tuple = (2, 0, 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/src/blurb/blurb.py 
new/blurb-2.0.0/src/blurb/blurb.py
--- old/blurb-1.3.0/src/blurb/blurb.py  2024-10-19 15:56:16.000000000 +0200
+++ new/blurb-2.0.0/src/blurb/blurb.py  2025-01-15 13:44:34.000000000 +0100
@@ -57,7 +57,6 @@
 import tempfile
 import textwrap
 import time
-import unittest
 
 from . import __version__
 
@@ -140,7 +139,6 @@
     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}"
@@ -268,11 +266,6 @@
         os.chdir(self.previous_cwd)
 
 
-def safe_mkdir(path):
-    if not os.path.exists(path):
-        os.makedirs(path)
-
-
 def version_key(element):
     fields = list(element.split("."))
     if len(fields) == 1:
@@ -482,14 +475,14 @@
                 # we'll complain about the *first* error
                 # we see in the blurb file, which is a
                 # better user experience.
-                if key == "gh-issue" and int(value) < 
lowest_possible_gh_issue_number:
-                    throw(f"The gh-issue number must be 
{lowest_possible_gh_issue_number} or above, not a PR number.")
-
                 if key in issue_keys:
                     try:
                         int(value)
                     except (TypeError, ValueError):
-                        throw(f"Invalid {issue_keys[key]} issue number! 
({value!r})")
+                        throw(f"Invalid {issue_keys[key]} number: {value!r}")
+
+                if key == "gh-issue" and int(value) < 
lowest_possible_gh_issue_number:
+                    throw(f"Invalid gh-issue number: {value!r} (must be >= 
{lowest_possible_gh_issue_number})")
 
                 if key == "section":
                     if no_changes:
@@ -497,7 +490,10 @@
                     if value not in sections:
                         throw(f"Invalid section {value!r}!  You must use one 
of the predefined sections.")
 
-            if not 'section' in metadata:
+            if "gh-issue" not in metadata and "bpo" not in metadata:
+                throw("'gh-issue:' or 'bpo:' must be specified in the 
metadata!")
+
+            if 'section' not in metadata:
                 throw("No 'section' specified.  You must provide one!")
 
             self.append((metadata, text))
@@ -557,7 +553,7 @@
 
     def save(self, path):
         dirname = os.path.dirname(path)
-        safe_mkdir(dirname)
+        os.makedirs(dirname, exist_ok=True)
 
         text = str(self)
         with open(path, "wt", encoding="utf-8") as file:
@@ -639,42 +635,6 @@
         return filename
 
 
-tests_run = 0
-
-class TestParserPasses(unittest.TestCase):
-    directory = "tests/pass"
-
-    def filename_test(self, filename):
-        b = Blurbs()
-        b.load(filename)
-        self.assertTrue(b)
-        if os.path.exists(filename + '.res'):
-            with open(filename + '.res', encoding='utf-8') as file:
-                expected = file.read()
-            self.assertEqual(str(b), expected)
-
-    def test_files(self):
-        global tests_run
-        with pushd(self.directory):
-            for filename in glob.glob("*"):
-                if filename[-4:] == '.res':
-                    self.assertTrue(os.path.exists(filename[:-4]), filename)
-                    continue
-                self.filename_test(filename)
-                print(".", end="")
-                sys.stdout.flush()
-                tests_run += 1
-
-
-class TestParserFailures(TestParserPasses):
-    directory = "tests/fail"
-
-    def filename_test(self, filename):
-        b = Blurbs()
-        with self.assertRaises(Exception):
-            b.load(filename)
-
-
 readme_re = re.compile(r"This is \w+ version \d+\.\d+").match
 
 def chdir_to_repo_root():
@@ -838,36 +798,6 @@
     return None
 
 
-@subcommand
-def test(*args):
-    """
-Run unit tests.  Only works inside source repo, not when installed.
-    """
-    # unittest.main doesn't work because this isn't a module
-    # so we'll do it ourselves
-
-    while (blurb_dir := _find_blurb_dir()) is None:
-        old_dir = os.getcwd()
-        os.chdir("..")
-        if old_dir == os.getcwd():
-            # we reached the root and never found it!
-            sys.exit("Error: Couldn't find the root of your blurb repo!")
-    os.chdir(blurb_dir)
-
-    print("-" * 79)
-
-    for clsname, cls in sorted(globals().items()):
-        if clsname.startswith("Test") and isinstance(cls, type):
-            o = cls()
-            for fnname in sorted(dir(o)):
-                if fnname.startswith("test"):
-                    fn = getattr(o, fnname)
-                    if callable(fn):
-                        fn()
-    print()
-    print(tests_run, "tests passed.")
-
-
 def find_editor():
     for var in 'GIT_EDITOR', 'EDITOR':
         editor = os.environ.get(var)
@@ -1175,12 +1105,12 @@
 Creates and populates the Misc/NEWS.d directory tree.
     """
     os.chdir("Misc")
-    safe_mkdir("NEWS.d/next")
+    os.makedirs("NEWS.d/next", exist_ok=True)
 
     for section in sections:
         dir_name = sanitize_section(section)
         dir_path = f"NEWS.d/next/{dir_name}"
-        safe_mkdir(dir_path)
+        os.makedirs(dir_path, exist_ok=True)
         readme_path = f"NEWS.d/next/{dir_name}/README.rst"
         with open(readme_path, "wt", encoding="utf-8") as readme:
             readme.write(f"Put news entry ``blurb`` files for the *{section}* 
section in this directory.\n")
@@ -1224,7 +1154,7 @@
     fn = get_subcommand(subcommand)
 
     # hack
-    if fn in (help, test, version):
+    if fn in (help, version):
         sys.exit(fn(*args))
 
     try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/tests/test_blurb.py 
new/blurb-2.0.0/tests/test_blurb.py
--- old/blurb-1.3.0/tests/test_blurb.py 2024-10-19 15:56:16.000000000 +0200
+++ new/blurb-2.0.0/tests/test_blurb.py 2025-01-15 13:44:34.000000000 +0100
@@ -1,5 +1,5 @@
 import pytest
-from pyfakefs.fake_filesystem import FakeFilesystem
+import time_machine
 
 from blurb import blurb
 
@@ -45,6 +45,116 @@
     assert unsanitized == expected
 
 
[email protected](
+    "body, subsequent_indent, expected",
+    (
+        (
+            "This is a test of the textwrap_body function with a string. It 
should wrap the text to 79 characters.",
+            "",
+            "This is a test of the textwrap_body function with a string. It 
should wrap\n"
+            "the text to 79 characters.\n",
+        ),
+        (
+            [
+                "This is a test of the textwrap_body function",
+                "with an iterable of strings.",
+                "It should wrap the text to 79 characters.",
+            ],
+            "",
+            "This is a test of the textwrap_body function with an iterable of 
strings. It\n"
+            "should wrap the text to 79 characters.\n",
+        ),
+        (
+            "This is a test of the textwrap_body function with a string and 
subsequent indent.",
+            "    ",
+            "This is a test of the textwrap_body function with a string and 
subsequent\n"
+            "    indent.\n",
+        ),
+        (
+            "This is a test of the textwrap_body function with a bullet list 
and subsequent indent. The list should not be wrapped.\n"
+            "\n"
+            "* Item 1\n"
+            "* Item 2\n",
+            "    ",
+            "This is a test of the textwrap_body function with a bullet list 
and\n"
+            "    subsequent indent. The list should not be wrapped.\n"
+            "\n"
+            "    * Item 1\n"
+            "    * Item 2\n",
+        ),
+    ),
+)
+def test_textwrap_body(body, subsequent_indent, expected):
+    assert blurb.textwrap_body(body, subsequent_indent=subsequent_indent) == 
expected
+
+
+@time_machine.travel("2025-01-07")
+def test_current_date():
+    assert blurb.current_date() == "2025-01-07"
+
+
+@time_machine.travel("2025-01-07 16:28:41")
+def test_sortable_datetime():
+    assert blurb.sortable_datetime() == "2025-01-07-16-28-41"
+
+
[email protected](
+    "version1, version2",
+    (
+        ("2", "3"),
+        ("3.5.0a1", "3.5.0b1"),
+        ("3.5.0a1", "3.5.0rc1"),
+        ("3.5.0a1", "3.5.0"),
+        ("3.6.0b1", "3.6.0b2"),
+        ("3.6.0b1", "3.6.0rc1"),
+        ("3.6.0b1", "3.6.0"),
+        ("3.7.0rc1", "3.7.0rc2"),
+        ("3.7.0rc1", "3.7.0"),
+        ("3.8", "3.8.1"),
+    ),
+)
+def test_version_key(version1, version2):
+    # Act
+    key1 = blurb.version_key(version1)
+    key2 = blurb.version_key(version2)
+
+    # Assert
+    assert key1 < key2
+
+
+def test_glob_versions(fs):
+    # Arrange
+    fake_version_blurbs = (
+        "Misc/NEWS.d/3.7.0.rst",
+        "Misc/NEWS.d/3.7.0a1.rst",
+        "Misc/NEWS.d/3.7.0a2.rst",
+        "Misc/NEWS.d/3.7.0b1.rst",
+        "Misc/NEWS.d/3.7.0b2.rst",
+        "Misc/NEWS.d/3.7.0rc1.rst",
+        "Misc/NEWS.d/3.7.0rc2.rst",
+        "Misc/NEWS.d/3.9.0b1.rst",
+        "Misc/NEWS.d/3.12.0a1.rst",
+    )
+    for fn in fake_version_blurbs:
+        fs.create_file(fn)
+
+    # Act
+    versions = blurb.glob_versions()
+
+    # Assert
+    assert versions == [
+        "3.12.0a1",
+        "3.9.0b1",
+        "3.7.0",
+        "3.7.0rc2",
+        "3.7.0rc1",
+        "3.7.0b2",
+        "3.7.0b1",
+        "3.7.0a2",
+        "3.7.0a1",
+    ]
+
+
 def test_glob_blurbs_next(fs):
     # Arrange
     fake_news_entries = (
@@ -105,6 +215,22 @@
 
 
 @pytest.mark.parametrize(
+    "version, expected",
+    (
+            ("next", "next"),
+            ("3.12.0a1", "3.12.0 alpha 1"),
+            ("3.12.0b2", "3.12.0 beta 2"),
+            ("3.12.0rc2", "3.12.0 release candidate 2"),
+            ("3.12.0", "3.12.0 final"),
+            ("3.12.1", "3.12.1 final"),
+    ),
+)
+def test_printable_version(version, expected):
+    # Act / Assert
+    assert blurb.printable_version(version) == expected
+
+
[email protected](
     "news_entry, expected_section",
     (
         (
@@ -188,3 +314,68 @@
     # Assert
     captured = capfd.readouterr()
     assert captured.out.startswith("blurb version ")
+
+
+def test_parse():
+    # Arrange
+    contents = ".. gh-issue: 123456\n.. section: IDLE\nHello world!"
+    blurbs = blurb.Blurbs()
+
+    # Act
+    blurbs.parse(contents)
+
+    # Assert
+    metadata, body = blurbs[0]
+    assert metadata["gh-issue"] == "123456"
+    assert metadata["section"] == "IDLE"
+    assert body == "Hello world!\n"
+
+
[email protected](
+    "contents, expected_error",
+    (
+        (
+            "",
+            r"Blurb 'body' text must not be empty!",
+        ),
+        (
+            "gh-issue: Hello world!",
+            r"Blurb 'body' can't start with 'gh-'!",
+        ),
+        (
+            ".. gh-issue: 1\n.. section: IDLE\nHello world!",
+            r"Invalid gh-issue number: '1' \(must be >= 32426\)",
+        ),
+        (
+            ".. bpo: one-two\n.. section: IDLE\nHello world!",
+            r"Invalid bpo number: 'one-two'",
+        ),
+        (
+            ".. gh-issue: one-two\n.. section: IDLE\nHello world!",
+            r"Invalid GitHub number: 'one-two'",
+        ),
+        (
+            ".. gh-issue: 123456\n.. section: Funky Kong\nHello world!",
+            r"Invalid section 'Funky Kong'!  You must use one of the 
predefined sections",
+        ),
+        (
+            ".. gh-issue: 123456\nHello world!",
+            r"No 'section' specified.  You must provide one!",
+        ),
+        (
+            ".. gh-issue: 123456\n.. section: IDLE\n.. section: IDLE\nHello 
world!",
+            r"Blurb metadata sets 'section' twice!",
+        ),
+        (
+            ".. section: IDLE\nHello world!",
+            r"'gh-issue:' or 'bpo:' must be specified in the metadata!",
+        ),
+    ),
+)
+def test_parse_no_body(contents, expected_error):
+    # Arrange
+    blurbs = blurb.Blurbs()
+
+    # Act / Assert
+    with pytest.raises(blurb.BlurbError, match=expected_error):
+        blurbs.parse(contents)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/tests/test_parser.py 
new/blurb-2.0.0/tests/test_parser.py
--- old/blurb-1.3.0/tests/test_parser.py        1970-01-01 01:00:00.000000000 
+0100
+++ new/blurb-2.0.0/tests/test_parser.py        2025-01-15 13:44:34.000000000 
+0100
@@ -0,0 +1,36 @@
+import glob
+import os
+
+import pytest
+
+from blurb.blurb import Blurbs, pushd
+
+
+class TestParserPasses:
+    directory = "tests/pass"
+
+    def filename_test(self, filename):
+        b = Blurbs()
+        b.load(filename)
+        assert b
+        if os.path.exists(filename + ".res"):
+            with open(filename + ".res", encoding="utf-8") as file:
+                expected = file.read()
+            assert str(b) == expected
+
+    def test_files(self):
+        with pushd(self.directory):
+            for filename in glob.glob("*"):
+                if filename.endswith(".res"):
+                    assert os.path.exists(filename[:-4]), filename
+                    continue
+                self.filename_test(filename)
+
+
+class TestParserFailures(TestParserPasses):
+    directory = "tests/fail"
+
+    def filename_test(self, filename):
+        b = Blurbs()
+        with pytest.raises(Exception):
+            b.load(filename)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/blurb-1.3.0/tox.ini new/blurb-2.0.0/tox.ini
--- old/blurb-1.3.0/tox.ini     2024-10-19 15:56:16.000000000 +0200
+++ new/blurb-2.0.0/tox.ini     2025-01-15 13:44:34.000000000 +0100
@@ -2,7 +2,7 @@
 requires =
     tox>=4.2
 env_list =
-    py{313, 312, 311, 310, 39}
+    py{314, 313, 312, 311, 310, 39}
 
 [testenv]
 extras =
@@ -17,9 +17,7 @@
       --cov-report term \
       --cov-report xml \
       {posargs}
-    blurb test
     blurb help
     blurb --version
-    {envpython} -I -m blurb test
     {envpython} -I -m blurb help
     {envpython} -I -m blurb version

Reply via email to