Repository: bentoml/BentoML
Pull request #4417 (2024-01-18 03:29:39)

refactor(bento): add entry_service to bento info
cc @frostming 
The bento name has to be DNS name, while we wanna keep the service name as is


Patch:
diff --git a/examples/quickstart/service.py b/examples/quickstart/service.py
index 27e64cdf..fb55253c 100644
--- a/examples/quickstart/service.py
+++ b/examples/quickstart/service.py
@@ -5,14 +5,14 @@ import bentoml
 from bentoml.validators import Shape
 
 
-@bentoml.service(resources={"cpu": "200m", "memory": "512Mi"})
+@bentoml.service(name="preprocessing", resources={"cpu": "200m", "memory": "512Mi"})
 class Preprocessing:
     @bentoml.api
     def preprocess(self, input_series: np.ndarray) -> np.ndarray:
         return input_series
 
 
-@bentoml.service(name="iris_classifier", resources={"cpu": "200m", "memory": "512Mi"})
+@bentoml.service(resources={"cpu": "200m", "memory": "512Mi"})
 class IrisClassifier:
     iris_model = bentoml.models.get("iris_sklearn:latest")
     preprocessing = bentoml.depends(Preprocessing)
diff --git a/src/_bentoml_sdk/service/factory.py b/src/_bentoml_sdk/service/factory.py
index 40cd3cd5..14a4747c 100644
--- a/src/_bentoml_sdk/service/factory.py
+++ b/src/_bentoml_sdk/service/factory.py
@@ -19,7 +19,6 @@ from bentoml._internal.bento.bento import Bento
 from bentoml._internal.configuration.containers import BentoMLContainer
 from bentoml._internal.context import ServiceContext
 from bentoml._internal.models import Model
-from bentoml._internal.tag import validate_tag_str
 from bentoml._internal.utils import dict_filter_none
 from bentoml.exceptions import BentoMLException
 
@@ -159,8 +158,7 @@ class Service(t.Generic[T]):
 
     @property
     def name(self) -> str:
-        name = self.config.get("name") or self.inner.__name__.lower()
-        validate_tag_str(name)
+        name = self.config.get("name") or self.inner.__name__
         return name
 
     @property
diff --git a/src/bentoml/_internal/bento/bento.py b/src/bentoml/_internal/bento/bento.py
index feff4277..8194ed6a 100644
--- a/src/bentoml/_internal/bento/bento.py
+++ b/src/bentoml/_internal/bento/bento.py
@@ -33,6 +33,7 @@ from ..runner import Runner
 from ..store import Store
 from ..store import StoreItem
 from ..tag import Tag
+from ..tag import to_snake_case
 from ..types import PathType
 from ..utils import bentoml_cattr
 from ..utils import copy_file_to_fs_folder
@@ -204,7 +205,18 @@ class Bento(StoreItem):
         # Apply default build options
         build_config = build_config.with_defaults()
 
-        bento_name = build_config.name if build_config.name is not None else svc.name
+        if isinstance(svc, Service):
+            # for < 1.2
+            bento_name = (
+                build_config.name if build_config.name is not None else svc.name
+            )
+        else:
+            # for >= 1.2
+            bento_name = (
+                build_config.name
+                if build_config.name is not None
+                else to_snake_case(svc.name)
+            )
         tag = Tag(bento_name, version)
         if version is None:
             tag = tag.make_new_version()
@@ -293,6 +305,7 @@ class Bento(StoreItem):
             BentoInfo(
                 tag=tag,
                 service=svc,  # type: ignore # attrs converters do not typecheck
+                entry_service=svc.name,
                 labels=build_config.labels,
                 models=[
                     BentoModelInfo.from_bento_model(
@@ -581,7 +594,9 @@ class BentoInfo:
     models: t.List[BentoModelInfo] = attr.field(factory=list)
     runners: t.List[BentoRunnerInfo] = attr.field(factory=list)
     # for BentoML 1.2+ SDK
+    entry_service: str = attr.field(factory=str)
     services: t.List[BentoServiceInfo] = attr.field(factory=list)
+
     apis: t.List[BentoApiInfo] = attr.field(factory=list)
     docker: DockerOptions = attr.field(factory=lambda: DockerOptions().with_defaults())
     python: PythonOptions = attr.field(factory=lambda: PythonOptions().with_defaults())
diff --git a/src/bentoml/_internal/cloud/bentocloud.py b/src/bentoml/_internal/cloud/bentocloud.py
index a4ea4fe8..04472d98 100644
--- a/src/bentoml/_internal/cloud/bentocloud.py
+++ b/src/bentoml/_internal/cloud/bentocloud.py
@@ -159,6 +159,7 @@ class BentoCloudClient(CloudClient):
         ]
         manifest = BentoManifestSchema(
             name=info.name,
+            entry_service=info.entry_service,
             service=info.service,
             bentoml_version=info.bentoml_version,
             apis=apis,
diff --git a/src/bentoml/_internal/cloud/schemas/modelschemas.py b/src/bentoml/_internal/cloud/schemas/modelschemas.py
index 3a3e9852..79d28d7c 100644
--- a/src/bentoml/_internal/cloud/schemas/modelschemas.py
+++ b/src/bentoml/_internal/cloud/schemas/modelschemas.py
@@ -74,6 +74,7 @@ class BentoRunnerSchema:
 @attr.define
 class BentoManifestSchema:
     service: str
+    entry_service: str
     bentoml_version: str
     size_bytes: int
     name: t.Optional[str] = attr.field(default=None)
diff --git a/src/bentoml/_internal/cloud/yatai.py b/src/bentoml/_internal/cloud/yatai.py
index 05f0b75d..efd47ed2 100644
--- a/src/bentoml/_internal/cloud/yatai.py
+++ b/src/bentoml/_internal/cloud/yatai.py
@@ -153,6 +153,7 @@ class YataiClient(CloudClient):
         ]
         manifest = BentoManifestSchema(
             name=info.name,
+            entry_service=info.entry_service,
             service=info.service,
             bentoml_version=info.bentoml_version,
             apis=apis,
diff --git a/src/bentoml/_internal/tag.py b/src/bentoml/_internal/tag.py
index 4494eafa..5188a1e8 100644
--- a/src/bentoml/_internal/tag.py
+++ b/src/bentoml/_internal/tag.py
@@ -21,6 +21,11 @@ tag_invalid_error_msg = "a tag's name or version must consist of lowercase alpha
 tag_regex = re.compile(f"^{tag_fmt}$")
 
 
+def to_snake_case(name: str) -> str:
+    snake_case = re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
+    return snake_case
+
+
 def validate_tag_str(value: str):
     """
     Validate that a tag value (either name or version) is a simple string that:


Test patch:
diff --git a/tests/unit/_internal/bento/test_bento.py b/tests/unit/_internal/bento/test_bento.py
index bbc70803..2daf0059 100644
--- a/tests/unit/_internal/bento/test_bento.py
+++ b/tests/unit/_internal/bento/test_bento.py
@@ -101,6 +101,7 @@ runners:
   - runner_a_model
   resource_config:
     cpu: 2
+entry_service: ''
 services: []
 apis:
 - name: predict
diff --git a/tests/unit/_internal/cloud/test_deployment.py b/tests/unit/_internal/cloud/test_deployment.py
index d79b1fc5..75abae07 100644
--- a/tests/unit/_internal/cloud/test_deployment.py
+++ b/tests/unit/_internal/cloud/test_deployment.py
@@ -86,6 +86,7 @@ def dummy_generate_deployment_schema(
         presigned_download_url="",
         manifest=BentoManifestSchema(
             service="",
+            entry_service="",
             bentoml_version="",
             size_bytes=0,
             apis={},