Repository: pypa/wheel

Issue:
convert_pkg_info raises an exception if the description is empty
`description_lines[0].lstrip()` raises a `list index out of range` exception if the description field is empty. Here's a minimal repro:

`Parser().parsestr('description:\n')['description'].splitlines()[0]`

The fix is to check if the description is empty before calling splitlines on it

Hints from issue comments:

Solution patch:
diff --git a/docs/news.rst b/docs/news.rst
index 08127b89..39618a1e 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -1,6 +1,11 @@
 Release Notes
 =============
 
+**UNRELEASED**
+
+- Fixed an exception when calling the ``convert`` command with an empty description
+  field
+
 **0.45.1 (2024-11-23)**
 
 - Fixed pure Python wheels converted from eggs and wininst files having the ABI tag in
diff --git a/src/wheel/cli/convert.py b/src/wheel/cli/convert.py
index 61d4775c..63ee9dc2 100644
--- a/src/wheel/cli/convert.py
+++ b/src/wheel/cli/convert.py
@@ -72,13 +72,17 @@ def convert_pkg_info(pkginfo: str, metadata: Message):
 
         if key_lower == "description":
             description_lines = value.splitlines()
-            value = "\n".join(
-                (
-                    description_lines[0].lstrip(),
-                    dedent("\n".join(description_lines[1:])),
-                    "\n",
+            if description_lines:
+                value = "\n".join(
+                    (
+                        description_lines[0].lstrip(),
+                        dedent("\n".join(description_lines[1:])),
+                        "\n",
+                    )
                 )
-            )
+            else:
+                value = "\n"
+
             metadata.set_payload(value)
         elif key_lower == "home-page":
             metadata.add_header("Project-URL", f"Homepage, {value}")


Test patch:
diff --git a/tests/cli/test_convert.py b/tests/cli/test_convert.py
index 62884c2d..3372bcca 100644
--- a/tests/cli/test_convert.py
+++ b/tests/cli/test_convert.py
@@ -2,6 +2,7 @@
 
 import os.path
 import zipfile
+from email.message import Message
 from pathlib import Path
 from textwrap import dedent
 
@@ -10,7 +11,7 @@
 from pytest import CaptureFixture, TempPathFactory
 
 import wheel
-from wheel.cli.convert import convert, egg_filename_re
+from wheel.cli.convert import convert, convert_pkg_info, egg_filename_re
 from wheel.wheelfile import WheelFile
 
 PKG_INFO = """\
@@ -262,3 +263,32 @@ def test_convert_bdist_wininst(
         assert wf.read("sampledist-1.0.0.dist-info/entry_points.txt") == b""
 
     assert capsys.readouterr().out == f"{bdist_wininst_path}...OK\n"
+
+
+def test_convert_pkg_info_with_empty_description():
+    # Regression test for https://github.com/pypa/wheel/issues/645
+    pkginfo = """\
+Metadata-Version: 2.1
+Name: Sampledist
+Version: 1.0.0
+Home-page: https://example.com
+Download-URL: https://example.com/sampledist
+Description:"""
+    message = Message()
+    convert_pkg_info(pkginfo, message)
+    assert message.get_all("Name") == ["Sampledist"]
+    assert message.get_payload() == "\n"
+
+
+def test_convert_pkg_info_with_one_line_description():
+    pkginfo = """\
+Metadata-Version: 2.1
+Name: Sampledist
+Version: 1.0.0
+Home-page: https://example.com
+Download-URL: https://example.com/sampledist
+Description:    My cool package"""
+    message = Message()
+    convert_pkg_info(pkginfo, message)
+    assert message.get_all("Name") == ["Sampledist"]
+    assert message.get_payload() == "My cool package\n\n\n"