def test_pip_install_saved_bentoservice_bundle(bento_bundle_path, tmpdir): import subprocess install_path = str(tmpdir.mkdir("pip_local")) bentoml_path = os.path.abspath( os.path.join(os.path.dirname(__file__), "..")) stdout = subprocess.check_output([ "pip", "install", "-U", "--target={}".format(install_path), bento_bundle_path ]).decode('utf-8') assert format_path( "Processing {}".format(bento_bundle_path)) in format_path( format_path(stdout)) assert "Collecting bentoml=={}".format( get_bentoml_deploy_version()) in stdout assert "Successfully built ExampleBentoService" in stdout # ensure BentoML is installed as dependency if psutil.WINDOWS: assert os.path.isfile(os.path.join(install_path, "bin", "bentoml.exe")) else: assert os.path.isfile(os.path.join(install_path, "bin", "bentoml")) assert os.path.isdir(os.path.join(install_path, "bentoml")) sys.path.insert(0, install_path) ExampleBentoService = __import__("ExampleBentoService") sys.path.remove(install_path) svc = ExampleBentoService.load() res = svc.predict_dataframe( pd.DataFrame(pd.DataFrame([1], columns=["col1"]))) assert res == 1 # pip install should place cli entry script under target/bin directory if psutil.WINDOWS: cli_bin_path = os.path.join(install_path, "bin", "ExampleBentoService.exe") else: cli_bin_path = os.path.join(install_path, "bin", "ExampleBentoService") assert os.path.isfile(cli_bin_path) # add install_path and local bentoml module to PYTHONPATH to make them # available in subprocess call env = os.environ.copy() env["PYTHONPATH"] = ":".join(sys.path + [install_path, bentoml_path]) output = subprocess.check_output([cli_bin_path, "info", "--quiet"], env=env).decode() output = json.loads(output) assert output["name"] == "ExampleBentoService" assert output["version"] == svc.version assert "predict_dataframe" in map(lambda x: x["name"], output["apis"]) output = subprocess.check_output( [cli_bin_path, "open-api-spec", "--quiet"], env=env).decode() output = json.loads(output) assert output["info"]["version"] == svc.version
def __init__(self): bentoml_deploy_version = get_bentoml_deploy_version() self._conda_env = CondaEnv(bentoml_version=bentoml_deploy_version) self._pip_dependencies = ["bentoml=={}".format(bentoml_deploy_version)] self._python_version = PYTHON_VERSION self._setup_sh = None
def __init__( self, bento_service_name, setup_sh=None, pip_dependencies=None, conda_channels=None, conda_dependencies=None, ): self._python_version = PYTHON_VERSION self._conda_env = CondaEnv( "bentoml-" + bento_service_name, self._python_version ) bentoml_deploy_version = get_bentoml_deploy_version() self._pip_dependencies = ["bentoml=={}".format(bentoml_deploy_version)] if pip_dependencies: self._pip_dependencies += pip_dependencies self.set_setup_sh(setup_sh) if conda_channels: self.add_conda_channels(conda_channels) if conda_dependencies: self.add_conda_dependencies(conda_dependencies)
def __init__( self, bento_service_name, pip_dependencies=None, auto_pip_dependencies=False, requirements_txt_file=None, conda_channels=None, conda_dependencies=None, setup_sh=None, docker_base_image=None, ): self._python_version = PYTHON_VERSION self._conda_env = CondaEnv("bentoml-" + bento_service_name, self._python_version) bentoml_deploy_version = get_bentoml_deploy_version() self._pip_dependencies = ["bentoml=={}".format(bentoml_deploy_version)] if pip_dependencies: if auto_pip_dependencies: logger.warning( "auto_pip_dependencies enabled, it may override package versions " "specified in `pip_dependencies=%s`", pip_dependencies, ) else: self.add_pip_dependencies(pip_dependencies) if requirements_txt_file: if auto_pip_dependencies: logger.warning( "auto_pip_dependencies enabled, it may override package versions " "specified in `requirements_txt_file=%s`", requirements_txt_file, ) else: self._set_requirements_txt(requirements_txt_file) self._auto_pip_dependencies = auto_pip_dependencies self._set_setup_sh(setup_sh) if conda_channels: if not isinstance(conda_channels, list): conda_channels = [conda_channels] self.add_conda_channels(conda_channels) if conda_dependencies: if not isinstance(conda_dependencies, list): conda_dependencies = [conda_dependencies] self.add_conda_dependencies(conda_dependencies) if docker_base_image: self._docker_base_image = docker_base_image else: self._docker_base_image = config('core').get( 'default_docker_base_image') self._docker_gpu_base_image = config('core').get( 'default_docker_gpu_base_image')
def __init__(self, kind="BentoService"): self.kind = kind self._yaml = YAML() self._yaml.default_flow_style = False self.config = self._yaml.load( BENTOML_CONFIG_YAML_TEPMLATE.format( kind=self.kind, bentoml_version=get_bentoml_deploy_version(), created_at=str(datetime.utcnow()), ))
def save(self, path, bento_service): conda_yml_file = os.path.join(path, "environment.yml") self._conda_env.write_to_yaml_file(conda_yml_file) requirements_txt_file = os.path.join(path, "requirements.txt") with open(requirements_txt_file, "wb") as f: dependencies_map = {} for dep in self._pip_dependencies: name, version = parse_requirement_string(dep) dependencies_map[name] = version if self._auto_pip_dependencies: bento_service_module = sys.modules[bento_service.__class__.__module__] if hasattr(bento_service_module, "__file__"): bento_service_py_file_path = bento_service_module.__file__ reqs, unknown_modules = seek_pip_dependencies( bento_service_py_file_path ) dependencies_map.update(reqs) for module_name in unknown_modules: logger.warning( "unknown package dependency for module: %s", module_name ) # Reset bentoml to configured deploy version - this is for users using # customized BentoML branch for development but use a different stable # version for deployment # # For example, a BentoService created with local dirty branch will fail # to deploy with docker due to the version can't be found on PyPI, but # get_bentoml_deploy_version gives the user the latest released PyPI # version that's closest to the `dirty` branch dependencies_map['bentoml'] = get_bentoml_deploy_version() # Set self._pip_dependencies so it get writes to BentoService config file self._pip_dependencies = [] for pkg_name, pkg_version in dependencies_map.items(): self._pip_dependencies.append( "{}{}".format( pkg_name, "=={}".format(pkg_version) if pkg_version else "" ) ) pip_content = "\n".join(self._pip_dependencies).encode("utf-8") f.write(pip_content) if self._setup_sh: setup_sh_file = os.path.join(path, "setup.sh") with open(setup_sh_file, "wb") as f: f.write(self._setup_sh) # chmod +x setup.sh st = os.stat(setup_sh_file) os.chmod(setup_sh_file, st.st_mode | stat.S_IEXEC)
def __init__( self, bento_service_name, pip_dependencies=None, auto_pip_dependencies=False, requirements_txt_file=None, conda_channels=None, conda_dependencies=None, setup_sh=None, ): self._python_version = PYTHON_VERSION self._conda_env = CondaEnv( "bentoml-" + bento_service_name, self._python_version ) bentoml_deploy_version = get_bentoml_deploy_version() self._pip_dependencies = ["bentoml=={}".format(bentoml_deploy_version)] if pip_dependencies: if auto_pip_dependencies: logger.warning( "auto_pip_dependencies enabled, it may override package versions " "specified in `pip_dependencies=%s`", pip_dependencies, ) else: for dependency in pip_dependencies: self.check_dependency(dependency) self._pip_dependencies += pip_dependencies if requirements_txt_file: if auto_pip_dependencies: logger.warning( "auto_pip_dependencies enabled, it may override package versions " "specified in `requirements_txt_file=%s`", requirements_txt_file, ) else: self._set_requirements_txt(requirements_txt_file) self._auto_pip_dependencies = auto_pip_dependencies self._set_setup_sh(setup_sh) if conda_channels: self._add_conda_channels(conda_channels) if conda_dependencies: self._add_conda_dependencies(conda_dependencies)
def __init__( self, pip_packages: List[str] = None, pip_index_url: str = None, pip_trusted_host: str = None, pip_extra_index_url: str = None, infer_pip_packages: bool = False, requirements_txt_file: str = None, conda_channels: List[str] = None, conda_dependencies: List[str] = None, conda_env_yml_file: str = None, setup_sh: str = None, docker_base_image: str = None, ): self._python_version = PYTHON_VERSION self._pip_index_url = pip_index_url self._pip_trusted_host = pip_trusted_host self._pip_extra_index_url = pip_extra_index_url self._conda_env = CondaEnv( channels=conda_channels, dependencies=conda_dependencies, default_env_yaml_file=conda_env_yml_file, ) self._pip_packages = {} # add BentoML to pip packages list bentoml_deploy_version = get_bentoml_deploy_version() self.add_pip_package("bentoml=={}".format(bentoml_deploy_version)) if pip_packages: self.add_pip_packages(pip_packages) if requirements_txt_file: self.add_packages_from_requirements_txt_file(requirements_txt_file) self._infer_pip_packages = infer_pip_packages self.set_setup_sh(setup_sh) if docker_base_image: self._docker_base_image = docker_base_image else: self._docker_base_image = config('core').get( 'default_docker_base_image')
def __init__( self, name=CONDA_ENV_DEFAULT_NAME, python_version=PYTHON_VERSION, bentoml_version=None, ): self._yaml = YAML() self._yaml.default_flow_style = False if bentoml_version is None: bentoml_version = get_bentoml_deploy_version() self._conda_env = self._yaml.load( CONDA_ENV_BASE_YAML.format( name=name, python_version=python_version, bentoml_version=bentoml_version, ) )
def __init__(self, bento_service=None, kind="BentoService"): self.kind = kind self._yaml = YAML() self._yaml.default_flow_style = False self.config = self._yaml.load( BENTOML_CONFIG_YAML_TEMPLATE.format( kind=self.kind, bentoml_version=get_bentoml_deploy_version(), created_at=str(datetime.utcnow()), )) if bento_service is not None: self.config["metadata"].update({ "service_name": bento_service.name, "service_version": bento_service.version, }) self.config["env"] = bento_service.env.to_dict() self.config['apis'] = _get_apis_list(bento_service) self.config['artifacts'] = _get_artifacts_list(bento_service)
def infer_pip_dependencies_map(self): if not self.pip_dependencies_map: self.pip_dependencies_map = {} bento_service_module = sys.modules[self.__class__.__module__] if hasattr(bento_service_module, "__file__"): bento_service_py_file_path = bento_service_module.__file__ reqs, unknown_modules = seek_pip_packages( bento_service_py_file_path) self.pip_dependencies_map.update(reqs) for module_name in unknown_modules: logger.warning("unknown package dependency for module: %s", module_name) # Reset bentoml to configured deploy version - this is for users using # customized BentoML branch for development but use a different stable # version for deployment # # For example, a BentoService created with local dirty branch will fail # to deploy with docker due to the version can't be found on PyPI, but # get_bentoml_deploy_version gives the user the latest released PyPI # version that's closest to the `dirty` branch self.pip_dependencies_map['bentoml'] = get_bentoml_deploy_version() return self.pip_dependencies_map
def __init__( self, pip_packages: List[str] = None, pip_index_url: str = None, pip_trusted_host: str = None, pip_extra_index_url: str = None, infer_pip_packages: bool = False, requirements_txt_file: str = None, conda_channels: List[str] = None, conda_overwrite_channels: bool = False, conda_dependencies: List[str] = None, conda_env_yml_file: str = None, setup_sh: str = None, docker_base_image: str = None, zipimport_archives: List[str] = None, ): self._python_version = PYTHON_VERSION self._pip_index_url = pip_index_url self._pip_trusted_host = pip_trusted_host self._pip_extra_index_url = pip_extra_index_url self._requirements_txt_file = requirements_txt_file self._conda_env = CondaEnv( channels=conda_channels, dependencies=conda_dependencies, default_env_yaml_file=conda_env_yml_file, overwrite_channels=conda_overwrite_channels, ) self._pip_packages = {} # add BentoML to pip packages list bentoml_deploy_version = get_bentoml_deploy_version() self.add_pip_package("bentoml=={}".format(bentoml_deploy_version)) if pip_packages: self.add_pip_packages(pip_packages) self._infer_pip_packages = infer_pip_packages self.set_setup_sh(setup_sh) if docker_base_image: logger.info( f"Using user specified docker base image: `{docker_base_image}`, user" f"must make sure that the base image either has Python " f"{PYTHON_MINOR_VERSION} or conda installed." ) self._docker_base_image = docker_base_image elif config('core').get('default_docker_base_image'): logger.info( f"Using default docker base image: `{docker_base_image}` specified in" f"BentoML config file or env var. User must make sure that the docker " f"base image either has Python {PYTHON_MINOR_VERSION} or conda " f"installed." ) self._docker_base_image = config('core').get('default_docker_base_image') else: if PYTHON_MINOR_VERSION not in PYTHON_SUPPORTED_VERSIONS: self._docker_base_image = ( f"bentoml/model-server:{bentoml_deploy_version}" ) logger.warning( f"Python {PYTHON_VERSION} found in current environment is not " f"officially supported by BentoML. The docker base image used is" f"'{self._docker_base_image}' which will use conda to install " f"Python {PYTHON_VERSION} in the build process. Supported Python " f"versions are: f{', '.join(PYTHON_SUPPORTED_VERSIONS)}" ) else: # e.g. bentoml/model-server:0.8.6-py37 self._docker_base_image = ( f"bentoml/model-server:" f"{bentoml_deploy_version}-" f"py{PYTHON_MINOR_VERSION.replace('.', '')}" ) logger.debug( f"Using BentoML default docker base image " f"'{self._docker_base_image}'" ) self._zipimport_archives = zipimport_archives