fix: Fix incorrectly generated `Required-Dist` when specifying requirements with markers in extra_requires in py_wheel rule (#2200)

Currently, if extra requirements are provided via a file, it is allowed
to contain markers, but if it is passed via extra_requires field, it
will run into error since the extra in this case is blindly added in the
following line in `py_wheel.bzl`
```
metadata_contents.append(
    "Requires-Dist: %s; extra == '%s'" % (requirement, option),
)
```

Thus, this PR adds a post-process for this case, to make it possible to
pass something like
```
    extra_requires = {"example": [
        "pyyaml>=6.0.0,!=6.0.1",
        'toml; (python_version == "3.11" or python_version == "3.12") and python_version != "3.8"',
        'wheel; python_version == "3.11" or python_version == "3.12" ',
    ]},
```
to `py_wheel`
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d410575..e2c54e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -51,6 +51,8 @@
   {obj}`--bootstrap_impl=script`. This fixes invocations using non-sandboxed
   test execution with `--enable_runfiles=false --build_runfile_manifests=true`.
   ([#2186](https://github.com/bazelbuild/rules_python/issues/2186)).
+* (py_wheel) Fix incorrectly generated `Required-Dist` when specifying requirements with markers
+  in extra_requires in py_wheel rule.
 
 
 ### Added
diff --git a/examples/wheel/BUILD.bazel b/examples/wheel/BUILD.bazel
index aa063ce..1eaf035 100644
--- a/examples/wheel/BUILD.bazel
+++ b/examples/wheel/BUILD.bazel
@@ -333,6 +333,27 @@
     version = "0.0.1",
 )
 
+py_wheel(
+    name = "extra_requires",
+    distribution = "extra_requires",
+    extra_requires = {"example": [
+        "pyyaml>=6.0.0,!=6.0.1",
+        'toml; (python_version == "3.11" or python_version == "3.12") and python_version != "3.8"',
+        'wheel; python_version == "3.11" or python_version == "3.12" ',
+    ]},
+    python_tag = "py3",
+    # py_wheel can use text files to specify their requirements. This
+    # can be convenient for users of `compile_pip_requirements` who have
+    # granular `requirements.in` files per package.
+    requires = [
+        "tomli>=2.0.0",
+        "starlark",
+        'pytest; python_version != "3.8"',
+    ],
+    version = "0.0.1",
+    deps = [":example_pkg"],
+)
+
 py_test(
     name = "wheel_test",
     srcs = ["wheel_test.py"],
@@ -341,6 +362,7 @@
         ":custom_package_root_multi_prefix",
         ":custom_package_root_multi_prefix_reverse_order",
         ":customized",
+        ":extra_requires",
         ":filename_escaping",
         ":minimal_data_files",
         ":minimal_with_py_library",
diff --git a/examples/wheel/wheel_test.py b/examples/wheel/wheel_test.py
index 66ebd50..7212423 100644
--- a/examples/wheel/wheel_test.py
+++ b/examples/wheel/wheel_test.py
@@ -489,6 +489,36 @@
                 ],
             )
 
+    def test_extra_requires(self):
+        filename = self._get_path("extra_requires-0.0.1-py3-none-any.whl")
+
+        with zipfile.ZipFile(filename) as zf:
+            self.assertAllEntriesHasReproducibleMetadata(zf)
+            metadata_file = None
+            for f in zf.namelist():
+                if os.path.basename(f) == "METADATA":
+                    metadata_file = f
+            self.assertIsNotNone(metadata_file)
+
+            requires = []
+            with zf.open(metadata_file) as fp:
+                for line in fp:
+                    if line.startswith(b"Requires-Dist:"):
+                        requires.append(line.decode("utf-8").strip())
+
+            print(requires)
+            self.assertEqual(
+                [
+                    "Requires-Dist: tomli>=2.0.0",
+                    "Requires-Dist: starlark",
+                    'Requires-Dist: pytest; python_version != "3.8"',
+                    "Requires-Dist: pyyaml!=6.0.1,>=6.0.0; extra == 'example'",
+                    'Requires-Dist: toml; ((python_version == "3.11" or python_version == "3.12") and python_version != "3.8") and extra == \'example\'',
+                    'Requires-Dist: wheel; (python_version == "3.11" or python_version == "3.12") and extra == \'example\'',
+                ],
+                requires,
+            )
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/wheelmaker.py b/tools/wheelmaker.py
index 8fa3e02..68578b8 100644
--- a/tools/wheelmaker.py
+++ b/tools/wheelmaker.py
@@ -537,9 +537,34 @@
 
         # Search for any `Requires-Dist` entries that refer to other files and
         # expand them.
+
+        def get_new_requirement_line(reqs_text, extra):
+            req = Requirement(reqs_text.strip())
+            if req.marker:
+                if extra:
+                    return f"Requires-Dist: {req.name}{req.specifier}; ({req.marker}) and {extra}"
+                else:
+                    return f"Requires-Dist: {req.name}{req.specifier}; {req.marker}"
+            else:
+                return f"Requires-Dist: {req.name}{req.specifier}; {extra}".strip(" ;")
+
         for meta_line in metadata.splitlines():
-            if not meta_line.startswith("Requires-Dist: @"):
+            if not meta_line.startswith("Requires-Dist: "):
                 continue
+
+            if not meta_line[len("Requires-Dist: ") :].startswith("@"):
+                # This is a normal requirement.
+                package, _, extra = meta_line[len("Requires-Dist: ") :].rpartition(";")
+                if not package:
+                    # This is when the package requirement does not have markers.
+                    continue
+                extra = extra.strip()
+                metadata = metadata.replace(
+                    meta_line, get_new_requirement_line(package, extra)
+                )
+                continue
+
+            # This is a requirement that refers to a file.
             file, _, extra = meta_line[len("Requires-Dist: @") :].partition(";")
             extra = extra.strip()
 
@@ -552,20 +577,7 @@
                 # Strip any comments
                 reqs_text, _, _ = reqs_text.partition("#")
 
-                req = Requirement(reqs_text.strip())
-                if req.marker:
-                    if extra:
-                        reqs.append(
-                            f"Requires-Dist: {req.name}{req.specifier}; ({req.marker}) and {extra}"
-                        )
-                    else:
-                        reqs.append(
-                            f"Requires-Dist: {req.name}{req.specifier}; {req.marker}"
-                        )
-                else:
-                    reqs.append(
-                        f"Requires-Dist: {req.name}{req.specifier}; {extra}".strip(" ;")
-                    )
+                reqs.append(get_new_requirement_line(reqs_text, extra))
 
             metadata = metadata.replace(meta_line, "\n".join(reqs))