code: def write_to_bento(self, bento_fs: FS, build_ctx: str) -> None:
      py_folder = fs.path.join("env", "python")
      wheels_folder = fs.path.join(py_folder, "wheels")
      bento_fs.makedirs(py_folder, recreate=True)
  
      # Save the python version of current build environment
      with bento_fs.open(
          fs.path.join(py_folder, "version.txt"), "w"
      ) as f:
          f.write(
              f"{version_info.major}.{version_info.minor}.{version_info.micro}"
          )
  
      # Build BentoML whl from local source if BENTOML_BUNDLE_LOCAL_BUILD=True
      build_bentoml_editable_wheel(bento_fs.getsyspath(wheels_folder))
  
      # Move over required wheel files
      if self.wheels:
          bento_fs.makedirs(wheels_folder, recreate=True)
          for (
              whl_file
          ) in self.wheels:  # pylint: disable=not-an-iterable
              whl_file = resolve_user_filepath(whl_file, build_ctx)
              copy_file_to_fs_folder(whl_file, bento_fs, wheels_folder)
  
      pip_compile_compat: t.List[str] = []
      if self.index_url:
          pip_compile_compat.extend(["--index-url", self.index_url])
      if self.trusted_host:
          for host in self.trusted_host:
              pip_compile_compat.extend(["--trusted-host", host])
      if self.find_links:
          for link in self.find_links:
              pip_compile_compat.extend(["--find-links", link])
      if self.extra_index_url:
          for url in self.extra_index_url:
              pip_compile_compat.extend(["--extra-index-url", url])
  
      # add additional pip args that does not apply to pip-compile
      pip_args: t.List[str] = []
      pip_args.extend(pip_compile_compat)
      if self.no_index:
          pip_args.append("--no-index")
      if self.pip_args:
          pip_args.extend(self.pip_args.split())
  
      with bento_fs.open(
          fs.path.combine(py_folder, "install.sh"), "w"
      ) as f:
          args = ["--no-warn-script-location"]
          if pip_args:
              args.extend(pip_args)
          install_sh = (
              """\
  #!/usr/bin/env bash
  set -exuo pipefail
  
  # Parent directory https://stackoverflow.com/a/246128/8643197
  BASEDIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )"
  
  PIP_ARGS=("""
              + " ".join(map(quote, args))
              + """)
  
  # BentoML by default generates two requirement files:
  #  - ./env/python/requirements.lock.txt: all dependencies locked to its version presented during `build`
  #  - ./env/python/requirements.txt: all dependencies as user specified in code or requirements.txt file
  REQUIREMENTS_TXT="$BASEDIR/requirements.txt"
  REQUIREMENTS_LOCK="$BASEDIR/requirements.lock.txt"
  WHEELS_DIR="$BASEDIR/wheels"
  BENTOML_VERSION=${BENTOML_VERSION:-"""
              + clean_bentoml_version(BENTOML_VERSION)
              + """}
  # Install python packages, prefer installing the requirements.lock.txt file if it exist
  if [ -f "$REQUIREMENTS_LOCK" ]; then
      echo "Installing pip packages from 'requirements.lock.txt'.."
      pip3 install -r "$REQUIREMENTS_LOCK" "${PIP_ARGS[@]}"
  else
      if [ -f "$REQUIREMENTS_TXT" ]; then
          echo "Installing pip packages from 'requirements.txt'.."
          pip3 install -r "$REQUIREMENTS_TXT" "${PIP_ARGS[@]}"
      fi
  fi
  
  # Install user-provided wheels
  if [ -d "$WHEELS_DIR" ]; then
      echo "Installing wheels packaged in Bento.."
      pip3 install "$WHEELS_DIR"/*.whl "${PIP_ARGS[@]}"
  fi
  
  # Install the BentoML from PyPI if it's not already installed
  if python3 -c "import bentoml" &> /dev/null; then
      existing_bentoml_version=$(python3 -c "import bentoml; print(bentoml.__version__)")
      if [ "$existing_bentoml_version" != "$BENTOML_VERSION" ]; then
          echo "WARNING: using BentoML version ${existing_bentoml_version}"
      fi
  else
      pip3 install bentoml=="$BENTOML_VERSION"
  fi
  """
          )
          f.write(install_sh)
  
      if self.requirements_txt is not None:
          from pip_requirements_parser import RequirementsFile
  
          requirements_txt = RequirementsFile.from_file(
              resolve_user_filepath(self.requirements_txt, build_ctx),
              include_nested=True,
          )
          # We need to make sure that we don't write any file references
          # back into the final `requirements.txt` file. We've already
          # resolved them and included their contents so we can discard
          # them.
          for option_line in requirements_txt.options:
              option_line.options.pop("constraints", None)
              option_line.options.pop("requirements", None)
  
          with bento_fs.open(
              fs.path.combine(py_folder, "requirements.txt"), "w"
          ) as f:
              f.write(
                  requirements_txt.dumps(preserve_one_empty_line=True)
              )
      elif self.packages is not None:
          with bento_fs.open(
              fs.path.join(py_folder, "requirements.txt"), "w"
          ) as f:
              f.write("\n".join(self.packages))
      else:
          # Return early if no python packages were specified
          return
  
      if self.lock_packages and not self.is_empty():
          # Note: "--allow-unsafe" is required for including setuptools in the
          # generated requirements.lock.txt file, and setuptool is required by
          # pyfilesystem2. Once pyfilesystem2 drop setuptools as dependency, we can
          # remove the "--allow-unsafe" flag here.
  
          # Note: "--generate-hashes" is purposefully not used here because it will
          # break if user includes PyPI package from version control system
  
          pip_compile_in = bento_fs.getsyspath(
              fs.path.combine(py_folder, "requirements.txt")
          )
          pip_compile_out = bento_fs.getsyspath(
              fs.path.combine(py_folder, "requirements.lock.txt")
          )
          pip_compile_args = [pip_compile_in]
          pip_compile_args.extend(pip_compile_compat)
          pip_compile_args.extend(
              [
                  "--quiet",
                  "--allow-unsafe",
                  "--no-header",
                  f"--output-file={pip_compile_out}",
                  "--resolver=backtracking",
                  "--no-annotate",
              ]
          )
          logger.info("Locking PyPI package versions.")
          cmd = [sys.executable, "-m", "piptools", "compile"]
          cmd.extend(pip_compile_args)
          try:
              subprocess.check_call(
                  cmd,
                  text=True,
                  stderr=subprocess.PIPE if get_quiet_mode() else None,
              )
          except subprocess.CalledProcessError as e:
              if not get_quiet_mode():
                  logger.error(
                      "Failed to lock PyPI packages: %s", e, exc_info=e
                  )
                  logger.error(
                      "Falling back to using the user-provided package requirement specifiers, which is equivalent to 'lock_packages=false'."
                  )
  
imports: from __future__ import annotations
  import logging
  import os
  import re
  import subprocess
  import sys
  import typing
  from shlex import quote
  from sys import version_info
  import attr
  import fs
  import fs.copy
  import psutil
  import yaml
  from pathspec import PathSpec
  from ...exceptions import BentoMLException
  from ...exceptions import InvalidArgument
  from ..configuration import BENTOML_VERSION
  from ..configuration import clean_bentoml_version
  from ..configuration import get_quiet_mode
  from ..container import generate_containerfile
  from ..container.frontend.dockerfile import ALLOWED_CUDA_VERSION_ARGS
  from ..container.frontend.dockerfile import CONTAINER_SUPPORTED_DISTROS
  from ..container.frontend.dockerfile import SUPPORTED_CUDA_VERSIONS
  from ..container.frontend.dockerfile import DistroSpec
  from ..container.frontend.dockerfile import get_supported_spec
  from ..container.generate import BENTO_PATH
  from ..utils import bentoml_cattr
  from ..utils import copy_file_to_fs_folder
  from ..utils import resolve_user_filepath
  from ..utils.dotenv import parse_dotenv
  from .build_dev_bentoml_whl import build_bentoml_editable_wheel
label_desc: Use image node_id 3 for calling the PythonOptions obj's underlying member method code with example usage: obj.write_to_bento(bento_fs, build_ctx) without return types