prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <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
  
  </issue>
  <code>
  [start of pyodide-build/pyodide_build/pypabuild.py]
  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 of pyodide-build/pyodide_build/pypabuild.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: 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
  
verification_info: {"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"}]}