class_docstr: Model wrapper that executes learn/predict in venv
      
class_docstr_tok: ["Model","wrapper","that","executes","learn\/predict","in","venv"]
code: def prepare_env(self, modules, engine_id, engine_version: int):
      try:
          import virtualenv
  
          base_path = self.config.get("byom", {}).get("venv_path")
          if base_path is None:
              # create in root path
              base_path = Path(self.config.paths["root"]) / "venvs"
          else:
              base_path = Path(base_path)
          base_path.mkdir(parents=True, exist_ok=True)
  
          env_folder_name = f"env_{engine_id}"
          if isinstance(engine_version, int) and engine_version > 1:
              env_folder_name = f"{env_folder_name}_{engine_version}"
  
          self.env_storage_path = base_path / env_folder_name
          if self.is_cloud:
              bese_env_path = (
                  Path(tempfile.gettempdir()) / "mindsdb" / "venv"
              )
              bese_env_path.mkdir(parents=True, exist_ok=True)
              self.env_path = bese_env_path / env_folder_name
              tar_path = self.env_storage_path.with_suffix(".tar")
              if (
                  self.env_path.exists() is False
                  and tar_path.exists() is True
              ):
                  with tarfile.open(tar_path) as tar:
                      tar.extractall(path=bese_env_path)
          else:
              self.env_path = self.env_storage_path
  
          pip_cmd = self.env_path / "bin" / "pip"
  
          self.python_path = self.env_path / "bin" / "python"
  
          if self.env_path.exists():
              # already exists. it means requirements are already installed
              return
  
          # create
          logger.info(f"Creating new environment: {self.env_path}")
          virtualenv.cli_run(["-p", sys.executable, str(self.env_path)])
          logger.info(f"Created new environment: {self.env_path}")
  
          if len(modules) > 0:
              self.install_modules(modules, pip_cmd=pip_cmd)
      except Exception:
          # DANGER !!! VENV MUST BE CREATED
          logger.info(
              "Can't create virtual environment. venv module should be installed"
          )
  
          if self.is_cloud:
              raise
  
          self.python_path = Path(sys.executable)
  
          # try to install modules everytime
          self.install_modules(modules, pip_cmd=pip_cmd)
  
      # fastest way to copy files if destination is NFS
      if self.is_cloud and self.env_storage_path != self.env_path:
          old_cwd = os.getcwd()
          os.chdir(str(bese_env_path))
          tar_path = self.env_path.with_suffix(".tar")
          with tarfile.open(name=str(tar_path), mode="w") as tar:
              tar.add(str(self.env_path.name))
          os.chdir(old_cwd)
          subprocess.run(
              [
                  "cp",
                  "-R",
                  "--no-preserve=mode,ownership",
                  str(tar_path),
                  str(base_path / tar_path.name),
              ],
              check=True,
              shell=False,
          )
          tar_path.unlink()
  
imports: import os
  import re
  import sys
  import shutil
  import pickle
  import tarfile
  import tempfile
  import traceback
  import subprocess
  from enum import Enum
  from pathlib import Path
  from datetime import datetime
  from typing import Optional, Dict, Union
  from collections import OrderedDict
  import pandas
  from pandas.api import types
  from mindsdb.utilities import log
  from mindsdb.utilities.config import Config
  from mindsdb.interfaces.storage import db
  from mindsdb.integrations.libs.base import BaseMLEngine
  from mindsdb.integrations.libs.const import PREDICTOR_STATUS
  from mindsdb.integrations.utilities.utils import format_exception_error
  from mindsdb.integrations.libs.const import HANDLER_CONNECTION_ARG_TYPE
  import mindsdb.utilities.profiler
  from .proc_wrapper import pd_decode, pd_encode, encode, decode, BYOM_METHOD, import_string, find_model_class
  from .__about__ import __version__
label_desc: Use image node_id 2 for calling the ModelWrapperSafe obj's underlying member method code with example usage: obj.prepare_env(modules, engine_id, engine_version) without return types