We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
pyodide_build buildpkg does not install Cython as a build dependency when it is spell with a lower case c
## 🐛 Bug

When trying to build [cftime](https://github.com/Unidata/cftime) the isolated env does not install cython.

### To Reproduce

`python -m pyodide_build buildpkg packages/cftime/meta.yaml` on [this meta.yaml](https://gist.github.com/ocefpaf/8b9a90bfa40d7dc27c63e3bf22ef335a)

### Expected behavior

Successful build :smile: 

### Environment

- Pyodide Version<!-- (e.g. 1.8.1) -->:
- Browser version<!-- (e.g. Chrome 95.0.4638.54) -->:
- Any other relevant information:


### Additional context

A patch to rename `cython` to `Cython` in the cftime pyproject.toml fixed it but we should not be case sensitive with PyPI names.

xref.: https://github.com/pyodide/pyodide/pull/2504

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyodide-build/pyodide_build/pypabuild.py`
Content:
```
1 import contextlib
2 import os
3 import sys
4 import traceback
5 from itertools import chain
6 from pathlib import Path
7 from typing import Mapping
8 
9 from build import BuildBackendException, ProjectBuilder  # type: ignore[import]
10 from build.__main__ import (  # type: ignore[import]
11     _STYLES,
12     _error,
13     _handle_build_error,
14     _IsolatedEnvBuilder,
15     _ProjectBuilder,
16 )
17 from build.env import IsolatedEnv  # type: ignore[import]
18 from packaging.requirements import Requirement
19 
20 from .common import get_hostsitepackages, get_pyversion
21 
22 UNISOLATED_PACKAGES = ["numpy", "scipy", "cffi", "pycparser", "pythran", "cython"]
23 
24 
25 def symlink_unisolated_packages(env: IsolatedEnv):
26     pyversion = get_pyversion()
27     site_packages_path = f"lib/{pyversion}/site-packages"
28     env_site_packages = Path(env._path) / site_packages_path
29     host_site_packages = Path(get_hostsitepackages())
30     for name in UNISOLATED_PACKAGES:
31         for path in chain(
32             host_site_packages.glob(f"{name}*"), host_site_packages.glob(f"_{name}*")
33         ):
34             (env_site_packages / path.name).unlink(missing_ok=True)
35             (env_site_packages / path.name).symlink_to(path)
36 
37 
38 def remove_unisolated_requirements(requires: set[str]) -> set[str]:
39     for reqstr in list(requires):
40         req = Requirement(reqstr)
41         for avoid_name in UNISOLATED_PACKAGES:
42             if avoid_name in req.name:
43                 requires.remove(reqstr)
44     return requires
45 
46 
47 @contextlib.contextmanager
48 def replace_env(build_env: Mapping[str, str]):
49     old_environ = dict(os.environ)
50     os.environ.clear()
51     os.environ.update(build_env)
52     try:
53         yield
54     finally:
55         os.environ.clear()
56         os.environ.update(old_environ)
57 
58 
59 def install_reqs(env: IsolatedEnv, reqs: set[str]):
60     env.install(remove_unisolated_requirements(reqs))
61 
62 
63 def _build_in_isolated_env(
64     build_env: Mapping[str, str],
65     builder: ProjectBuilder,
66     outdir: str,
67     distribution: str,
68 ) -> str:
69     with _IsolatedEnvBuilder() as env:
70         builder.python_executable = env.executable
71         builder.scripts_dir = env.scripts_dir
72         # first install the build dependencies
73         symlink_unisolated_packages(env)
74         install_reqs(env, builder.build_system_requires)
75         installed_requires_for_build = False
76         try:
77             build_reqs = builder.get_requires_for_build(distribution)
78         except BuildBackendException:
79             pass
80         else:
81             install_reqs(env, build_reqs)
82             installed_requires_for_build = True
83 
84         with replace_env(build_env):
85             if not installed_requires_for_build:
86                 install_reqs(env, builder.get_requires_for_build(distribution))
87             return builder.build(distribution, outdir, {})
88 
89 
90 def build(build_env: Mapping[str, str]):
91     srcdir = Path.cwd()
92     outdir = srcdir / "dist"
93     builder = _ProjectBuilder(srcdir)
94     distribution = "wheel"
95     try:
96         with _handle_build_error():
97             built = _build_in_isolated_env(
98                 build_env, builder, str(outdir), distribution
99             )
100             print("{bold}{green}Successfully built {}{reset}".format(built, **_STYLES))
101     except Exception as e:  # pragma: no cover
102         tb = traceback.format_exc().strip("\n")
103         print("\n{dim}{}{reset}\n".format(tb, **_STYLES))
104         _error(str(e))
105         sys.exit(1)
106
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyodide-build/pyodide_build/pypabuild.py b/pyodide-build/pyodide_build/pypabuild.py
--- a/pyodide-build/pyodide_build/pypabuild.py
+++ b/pyodide-build/pyodide_build/pypabuild.py
@@ -19,7 +19,7 @@
 
 from .common import get_hostsitepackages, get_pyversion
 
-UNISOLATED_PACKAGES = ["numpy", "scipy", "cffi", "pycparser", "pythran", "cython"]
+UNISOLATED_PACKAGES = ["numpy", "scipy", "cffi", "pycparser", "pythran"]
 
 
 def symlink_unisolated_packages(env: IsolatedEnv):
@@ -39,7 +39,7 @@
     for reqstr in list(requires):
         req = Requirement(reqstr)
         for avoid_name in UNISOLATED_PACKAGES:
-            if avoid_name in req.name:
+            if avoid_name in req.name.lower():
                 requires.remove(reqstr)
     return requires
 
@@ -58,6 +58,11 @@
 
 def install_reqs(env: IsolatedEnv, reqs: set[str]):
     env.install(remove_unisolated_requirements(reqs))
+    # Some packages (numcodecs) don't declare cython as a build dependency and
+    # only recythonize if it is present. We need them to always recythonize so
+    # we always install cython. If the reqs included some cython version already
+    # then this won't do anything.
+    env.install(["cython"])
 
 
 def _build_in_isolated_env(
@@ -66,6 +71,10 @@
     outdir: str,
     distribution: str,
 ) -> str:
+    # For debugging: The following line disables removal of the isolated venv.
+    # It will be left in the /tmp folder and can be inspected or entered as
+    # needed.
+    # _IsolatedEnvBuilder.__exit__ = lambda *args: None
     with _IsolatedEnvBuilder() as env:
         builder.python_executable = env.executable
         builder.scripts_dir = env.scripts_dir

{"golden_diff": "diff --git a/pyodide-build/pyodide_build/pypabuild.py b/pyodide-build/pyodide_build/pypabuild.py\n--- a/pyodide-build/pyodide_build/pypabuild.py\n+++ b/pyodide-build/pyodide_build/pypabuild.py\n@@ -19,7 +19,7 @@\n \n from .common import get_hostsitepackages, get_pyversion\n \n-UNISOLATED_PACKAGES = [\"numpy\", \"scipy\", \"cffi\", \"pycparser\", \"pythran\", \"cython\"]\n+UNISOLATED_PACKAGES = [\"numpy\", \"scipy\", \"cffi\", \"pycparser\", \"pythran\"]\n \n \n def symlink_unisolated_packages(env: IsolatedEnv):\n@@ -39,7 +39,7 @@\n     for reqstr in list(requires):\n         req = Requirement(reqstr)\n         for avoid_name in UNISOLATED_PACKAGES:\n-            if avoid_name in req.name:\n+            if avoid_name in req.name.lower():\n                 requires.remove(reqstr)\n     return requires\n \n@@ -58,6 +58,11 @@\n \n def install_reqs(env: IsolatedEnv, reqs: set[str]):\n     env.install(remove_unisolated_requirements(reqs))\n+    # Some packages (numcodecs) don't declare cython as a build dependency and\n+    # only recythonize if it is present. We need them to always recythonize so\n+    # we always install cython. If the reqs included some cython version already\n+    # then this won't do anything.\n+    env.install([\"cython\"])\n \n \n def _build_in_isolated_env(\n@@ -66,6 +71,10 @@\n     outdir: str,\n     distribution: str,\n ) -> str:\n+    # For debugging: The following line disables removal of the isolated venv.\n+    # It will be left in the /tmp folder and can be inspected or entered as\n+    # needed.\n+    # _IsolatedEnvBuilder.__exit__ = lambda *args: None\n     with _IsolatedEnvBuilder() as env:\n         builder.python_executable = env.executable\n         builder.scripts_dir = env.scripts_dir\n", "issue": "pyodide_build buildpkg does not install Cython as a build dependency when it is spell with a lower case c\n## \ud83d\udc1b Bug\r\n\r\nWhen trying to build [cftime](https://github.com/Unidata/cftime) the isolated env does not install cython.\r\n\r\n### To Reproduce\r\n\r\n`python -m pyodide_build buildpkg packages/cftime/meta.yaml` on [this meta.yaml](https://gist.github.com/ocefpaf/8b9a90bfa40d7dc27c63e3bf22ef335a)\r\n\r\n### Expected behavior\r\n\r\nSuccessful build :smile: \r\n\r\n### Environment\r\n\r\n- Pyodide Version<!-- (e.g. 1.8.1) -->:\r\n- Browser version<!-- (e.g. Chrome 95.0.4638.54) -->:\r\n- Any other relevant information:\r\n\r\n\r\n### Additional context\r\n\r\nA patch to rename `cython` to `Cython` in the cftime pyproject.toml fixed it but we should not be case sensitive with PyPI names.\r\n\r\nxref.: https://github.com/pyodide/pyodide/pull/2504\n", "before_files": [{"content": "import contextlib\nimport os\nimport sys\nimport traceback\nfrom itertools import chain\nfrom pathlib import Path\nfrom typing import Mapping\n\nfrom build import BuildBackendException, ProjectBuilder  # type: ignore[import]\nfrom build.__main__ import (  # type: ignore[import]\n    _STYLES,\n    _error,\n    _handle_build_error,\n    _IsolatedEnvBuilder,\n    _ProjectBuilder,\n)\nfrom build.env import IsolatedEnv  # type: ignore[import]\nfrom packaging.requirements import Requirement\n\nfrom .common import get_hostsitepackages, get_pyversion\n\nUNISOLATED_PACKAGES = [\"numpy\", \"scipy\", \"cffi\", \"pycparser\", \"pythran\", \"cython\"]\n\n\ndef symlink_unisolated_packages(env: IsolatedEnv):\n    pyversion = get_pyversion()\n    site_packages_path = f\"lib/{pyversion}/site-packages\"\n    env_site_packages = Path(env._path) / site_packages_path\n    host_site_packages = Path(get_hostsitepackages())\n    for name in UNISOLATED_PACKAGES:\n        for path in chain(\n            host_site_packages.glob(f\"{name}*\"), host_site_packages.glob(f\"_{name}*\")\n        ):\n            (env_site_packages / path.name).unlink(missing_ok=True)\n            (env_site_packages / path.name).symlink_to(path)\n\n\ndef remove_unisolated_requirements(requires: set[str]) -> set[str]:\n    for reqstr in list(requires):\n        req = Requirement(reqstr)\n        for avoid_name in UNISOLATED_PACKAGES:\n            if avoid_name in req.name:\n                requires.remove(reqstr)\n    return requires\n\n\n@contextlib.contextmanager\ndef replace_env(build_env: Mapping[str, str]):\n    old_environ = dict(os.environ)\n    os.environ.clear()\n    os.environ.update(build_env)\n    try:\n        yield\n    finally:\n        os.environ.clear()\n        os.environ.update(old_environ)\n\n\ndef install_reqs(env: IsolatedEnv, reqs: set[str]):\n    env.install(remove_unisolated_requirements(reqs))\n\n\ndef _build_in_isolated_env(\n    build_env: Mapping[str, str],\n    builder: ProjectBuilder,\n    outdir: str,\n    distribution: str,\n) -> str:\n    with _IsolatedEnvBuilder() as env:\n        builder.python_executable = env.executable\n        builder.scripts_dir = env.scripts_dir\n        # first install the build dependencies\n        symlink_unisolated_packages(env)\n        install_reqs(env, builder.build_system_requires)\n        installed_requires_for_build = False\n        try:\n            build_reqs = builder.get_requires_for_build(distribution)\n        except BuildBackendException:\n            pass\n        else:\n            install_reqs(env, build_reqs)\n            installed_requires_for_build = True\n\n        with replace_env(build_env):\n            if not installed_requires_for_build:\n                install_reqs(env, builder.get_requires_for_build(distribution))\n            return builder.build(distribution, outdir, {})\n\n\ndef build(build_env: Mapping[str, str]):\n    srcdir = Path.cwd()\n    outdir = srcdir / \"dist\"\n    builder = _ProjectBuilder(srcdir)\n    distribution = \"wheel\"\n    try:\n        with _handle_build_error():\n            built = _build_in_isolated_env(\n                build_env, builder, str(outdir), distribution\n            )\n            print(\"{bold}{green}Successfully built {}{reset}\".format(built, **_STYLES))\n    except Exception as e:  # pragma: no cover\n        tb = traceback.format_exc().strip(\"\\n\")\n        print(\"\\n{dim}{}{reset}\\n\".format(tb, **_STYLES))\n        _error(str(e))\n        sys.exit(1)\n", "path": "pyodide-build/pyodide_build/pypabuild.py"}], "after_files": [{"content": "import contextlib\nimport os\nimport sys\nimport traceback\nfrom itertools import chain\nfrom pathlib import Path\nfrom typing import Mapping\n\nfrom build import BuildBackendException, ProjectBuilder  # type: ignore[import]\nfrom build.__main__ import (  # type: ignore[import]\n    _STYLES,\n    _error,\n    _handle_build_error,\n    _IsolatedEnvBuilder,\n    _ProjectBuilder,\n)\nfrom build.env import IsolatedEnv  # type: ignore[import]\nfrom packaging.requirements import Requirement\n\nfrom .common import get_hostsitepackages, get_pyversion\n\nUNISOLATED_PACKAGES = [\"numpy\", \"scipy\", \"cffi\", \"pycparser\", \"pythran\"]\n\n\ndef symlink_unisolated_packages(env: IsolatedEnv):\n    pyversion = get_pyversion()\n    site_packages_path = f\"lib/{pyversion}/site-packages\"\n    env_site_packages = Path(env._path) / site_packages_path\n    host_site_packages = Path(get_hostsitepackages())\n    for name in UNISOLATED_PACKAGES:\n        for path in chain(\n            host_site_packages.glob(f\"{name}*\"), host_site_packages.glob(f\"_{name}*\")\n        ):\n            (env_site_packages / path.name).unlink(missing_ok=True)\n            (env_site_packages / path.name).symlink_to(path)\n\n\ndef remove_unisolated_requirements(requires: set[str]) -> set[str]:\n    for reqstr in list(requires):\n        req = Requirement(reqstr)\n        for avoid_name in UNISOLATED_PACKAGES:\n            if avoid_name in req.name.lower():\n                requires.remove(reqstr)\n    return requires\n\n\n@contextlib.contextmanager\ndef replace_env(build_env: Mapping[str, str]):\n    old_environ = dict(os.environ)\n    os.environ.clear()\n    os.environ.update(build_env)\n    try:\n        yield\n    finally:\n        os.environ.clear()\n        os.environ.update(old_environ)\n\n\ndef install_reqs(env: IsolatedEnv, reqs: set[str]):\n    env.install(remove_unisolated_requirements(reqs))\n    # Some packages (numcodecs) don't declare cython as a build dependency and\n    # only recythonize if it is present. We need them to always recythonize so\n    # we always install cython. If the reqs included some cython version already\n    # then this won't do anything.\n    env.install([\"cython\"])\n\n\ndef _build_in_isolated_env(\n    build_env: Mapping[str, str],\n    builder: ProjectBuilder,\n    outdir: str,\n    distribution: str,\n) -> str:\n    # For debugging: The following line disables removal of the isolated venv.\n    # It will be left in the /tmp folder and can be inspected or entered as\n    # needed.\n    # _IsolatedEnvBuilder.__exit__ = lambda *args: None\n    with _IsolatedEnvBuilder() as env:\n        builder.python_executable = env.executable\n        builder.scripts_dir = env.scripts_dir\n        # first install the build dependencies\n        symlink_unisolated_packages(env)\n        install_reqs(env, builder.build_system_requires)\n        installed_requires_for_build = False\n        try:\n            build_reqs = builder.get_requires_for_build(distribution)\n        except BuildBackendException:\n            pass\n        else:\n            install_reqs(env, build_reqs)\n            installed_requires_for_build = True\n\n        with replace_env(build_env):\n            if not installed_requires_for_build:\n                install_reqs(env, builder.get_requires_for_build(distribution))\n            return builder.build(distribution, outdir, {})\n\n\ndef build(build_env: Mapping[str, str]):\n    srcdir = Path.cwd()\n    outdir = srcdir / \"dist\"\n    builder = _ProjectBuilder(srcdir)\n    distribution = \"wheel\"\n    try:\n        with _handle_build_error():\n            built = _build_in_isolated_env(\n                build_env, builder, str(outdir), distribution\n            )\n            print(\"{bold}{green}Successfully built {}{reset}\".format(built, **_STYLES))\n    except Exception as e:  # pragma: no cover\n        tb = traceback.format_exc().strip(\"\\n\")\n        print(\"\\n{dim}{}{reset}\\n\".format(tb, **_STYLES))\n        _error(str(e))\n        sys.exit(1)\n", "path": "pyodide-build/pyodide_build/pypabuild.py"}]}