Repository: bentoml/BentoML
Pull request #3933 (2023-06-06 06:19:12)

feat: disable compression
Upload is tested and working, but image building isn't, pending money / default build issues.

/cc @ssheng @aarnphm 


Patch:
diff --git a/src/bentoml/_internal/utils/analytics/schemas.py b/src/bentoml/_internal/utils/analytics/schemas.py
index 2bc7fb9e..8ad5e4f7 100644
--- a/src/bentoml/_internal/utils/analytics/schemas.py
+++ b/src/bentoml/_internal/utils/analytics/schemas.py
@@ -190,6 +190,7 @@ class ServeInitEvent(EventMeta):
     serve_id: str
     production: bool
     serve_from_bento: bool
+    serve_from_server_api: bool
 
     bento_creation_timestamp: t.Optional[datetime]
     serve_kind: str = attr.field(validator=attr.validators.in_(SERVE_KIND))
@@ -209,6 +210,7 @@ class ServeUpdateEvent(EventMeta):
     triggered_at: datetime
     duration_in_seconds: int
     serve_kind: str = attr.field(validator=attr.validators.in_(SERVE_KIND))
+    serve_from_server_api: bool
     component: str = attr.field(
         validator=attr.validators.and_(
             attr.validators.instance_of(str), attr.validators.in_(COMPONENT_KIND)
diff --git a/src/bentoml/_internal/utils/analytics/usage_stats.py b/src/bentoml/_internal/utils/analytics/usage_stats.py
index ada306bf..b82b382b 100644
--- a/src/bentoml/_internal/utils/analytics/usage_stats.py
+++ b/src/bentoml/_internal/utils/analytics/usage_stats.py
@@ -40,11 +40,17 @@ if TYPE_CHECKING:
 logger = logging.getLogger(__name__)
 
 BENTOML_DO_NOT_TRACK = "BENTOML_DO_NOT_TRACK"
+BENTOML_SERVE_FROM_SERVER_API = "__BENTOML_SERVE_FROM_SERVER_API"
 USAGE_TRACKING_URL = "https://t.bentoml.com"
 SERVE_USAGE_TRACKING_INTERVAL_SECONDS = int(12 * 60 * 60)  # every 12 hours
 USAGE_REQUEST_TIMEOUT_SECONDS = 1
 
 
+@lru_cache(maxsize=None)
+def _bentoml_serve_from_server_api() -> bool:
+    return os.environ.get(BENTOML_SERVE_FROM_SERVER_API, str(False)).lower() == "true"
+
+
 @lru_cache(maxsize=1)
 def do_not_track() -> bool:  # pragma: no cover
     # Returns True if and only if the environment variable is defined and has value True.
@@ -126,6 +132,7 @@ def _track_serve_init(
     svc: Service,
     production: bool,
     serve_kind: str,
+    from_server_api: bool,
     serve_info: ServeInfo = Provide[BentoMLContainer.serve_info],
 ):
     if svc.bento is not None:
@@ -133,6 +140,7 @@ def _track_serve_init(
         event_properties = ServeInitEvent(
             serve_id=serve_info.serve_id,
             serve_from_bento=True,
+            serve_from_server_api=from_server_api,
             production=production,
             serve_kind=serve_kind,
             bento_creation_timestamp=bento.info.creation_time,
@@ -148,6 +156,7 @@ def _track_serve_init(
         event_properties = ServeInitEvent(
             serve_id=serve_info.serve_id,
             serve_from_bento=False,
+            serve_from_server_api=from_server_api,
             production=production,
             serve_kind=serve_kind,
             bento_creation_timestamp=None,
@@ -237,6 +246,7 @@ def track_serve(
     svc: Service,
     *,
     production: bool = False,
+    from_server_api: bool | None = None,
     serve_kind: str = "http",
     component: str = "standalone",
     metrics_client: PrometheusClient = Provide[BentoMLContainer.metrics_client],
@@ -246,7 +256,15 @@ def track_serve(
         yield
         return
 
-    _track_serve_init(svc=svc, production=production, serve_kind=serve_kind)
+    if from_server_api is None:
+        from_server_api = _bentoml_serve_from_server_api()
+
+    _track_serve_init(
+        svc=svc,
+        production=production,
+        serve_kind=serve_kind,
+        from_server_api=from_server_api,
+    )
 
     if _usage_event_debugging():
         tracking_interval = 5
@@ -267,6 +285,8 @@ def track_serve(
                 serve_kind=serve_kind,
                 # Current accept components are "standalone", "api_server" and "runner"
                 component=component,
+                # check if serve is running from server API or just normal CLI
+                serve_from_server_api=from_server_api,
                 triggered_at=now,
                 duration_in_seconds=int((now - last_tracked_timestamp).total_seconds()),
                 metrics=get_metrics_report(metrics_client, serve_kind=serve_kind),
diff --git a/src/bentoml/_internal/yatai_client/__init__.py b/src/bentoml/_internal/yatai_client/__init__.py
index 160d30db..2e7174e2 100644
--- a/src/bentoml/_internal/yatai_client/__init__.py
+++ b/src/bentoml/_internal/yatai_client/__init__.py
@@ -300,7 +300,7 @@ class YataiClient:
 
         with io.BytesIO() as tar_io:
             with self.spin(text=f'Creating tar archive for bento "{bento.tag}"..'):
-                with tarfile.open(fileobj=tar_io, mode="w:gz") as tar:
+                with tarfile.open(fileobj=tar_io, mode="w:") as tar:
 
                     def filter_(
                         tar_info: tarfile.TarInfo,
@@ -751,7 +751,7 @@ class YataiClient:
 
         with io.BytesIO() as tar_io:
             with self.spin(text=f'Creating tar archive for model "{model.tag}"..'):
-                with tarfile.open(fileobj=tar_io, mode="w:gz") as tar:
+                with tarfile.open(fileobj=tar_io, mode="w:") as tar:
                     tar.add(model.path, arcname="./")
             tar_io.seek(0, 0)
             with self.spin(text=f'Start uploading model "{model.tag}"..'):
diff --git a/src/bentoml/bentos.py b/src/bentoml/bentos.py
index 61a714c9..84f0762f 100644
--- a/src/bentoml/bentos.py
+++ b/src/bentoml/bentos.py
@@ -5,6 +5,7 @@ User facing python APIs for managing local bentos and build new bentos.
 from __future__ import annotations
 
 import os
+import re
 import typing as t
 import logging
 import tempfile
@@ -21,6 +22,7 @@ from ._internal.bento import Bento
 from ._internal.utils import resolve_user_filepath
 from ._internal.bento.build_config import BentoBuildConfig
 from ._internal.configuration.containers import BentoMLContainer
+from ._internal.utils.analytics.usage_stats import _usage_event_debugging
 
 if t.TYPE_CHECKING:
     from .server import Server
@@ -48,27 +50,27 @@ __all__ = [
 
 
 @inject
-def list(  # pylint: disable=redefined-builtin
-    tag: t.Optional[t.Union[Tag, str]] = None,
-    _bento_store: "BentoStore" = Provide[BentoMLContainer.bento_store],
-) -> "t.List[Bento]":
+def list(
+    tag: Tag | str | None = None,
+    _bento_store: BentoStore = Provide[BentoMLContainer.bento_store],
+) -> t.List[Bento]:
     return _bento_store.list(tag)
 
 
 @inject
 def get(
-    tag: t.Union[Tag, str],
+    tag: Tag | str,
     *,
-    _bento_store: "BentoStore" = Provide[BentoMLContainer.bento_store],
+    _bento_store: BentoStore = Provide[BentoMLContainer.bento_store],
 ) -> Bento:
     return _bento_store.get(tag)
 
 
 @inject
 def delete(
-    tag: t.Union[Tag, str],
+    tag: Tag | str,
     *,
-    _bento_store: "BentoStore" = Provide[BentoMLContainer.bento_store],
+    _bento_store: BentoStore = Provide[BentoMLContainer.bento_store],
 ):
     _bento_store.delete(tag)
 
@@ -76,13 +78,13 @@ def delete(
 @inject
 def import_bento(
     path: str,
-    input_format: t.Optional[str] = None,
+    input_format: str | None = None,
     *,
-    protocol: t.Optional[str] = None,
-    user: t.Optional[str] = None,
-    passwd: t.Optional[str] = None,
+    protocol: str | None = None,
+    user: str | None = None,
+    passwd: str | None = None,
     params: t.Optional[t.Dict[str, str]] = None,
-    subpath: t.Optional[str] = None,
+    subpath: str | None = None,
     _bento_store: "BentoStore" = Provide[BentoMLContainer.bento_store],
 ) -> Bento:
     """
@@ -156,16 +158,16 @@ def import_bento(
 
 @inject
 def export_bento(
-    tag: t.Union[Tag, str],
+    tag: Tag | str,
     path: str,
-    output_format: t.Optional[str] = None,
+    output_format: str | None = None,
     *,
-    protocol: t.Optional[str] = None,
-    user: t.Optional[str] = None,
-    passwd: t.Optional[str] = None,
-    params: t.Optional[t.Dict[str, str]] = None,
-    subpath: t.Optional[str] = None,
-    _bento_store: "BentoStore" = Provide[BentoMLContainer.bento_store],
+    protocol: str | None = None,
+    user: str | None = None,
+    passwd: str | None = None,
+    params: dict[str, str] | None = None,
+    subpath: str | None = None,
+    _bento_store: BentoStore = Provide[BentoMLContainer.bento_store],
 ) -> str:
     """
     Export a bento.
@@ -240,10 +242,10 @@ def export_bento(
 
 @inject
 def push(
-    tag: t.Union[Tag, str],
+    tag: Tag | str,
     *,
     force: bool = False,
-    _bento_store: "BentoStore" = Provide[BentoMLContainer.bento_store],
+    _bento_store: BentoStore = Provide[BentoMLContainer.bento_store],
     _yatai_client: YataiClient = Provide[BentoMLContainer.yatai_client],
 ):
     """Push Bento to a yatai server."""
@@ -255,10 +257,10 @@ def push(
 
 @inject
 def pull(
-    tag: t.Union[Tag, str],
+    tag: Tag | str,
     *,
     force: bool = False,
-    _bento_store: "BentoStore" = Provide[BentoMLContainer.bento_store],
+    _bento_store: BentoStore = Provide[BentoMLContainer.bento_store],
     _yatai_client: YataiClient = Provide[BentoMLContainer.yatai_client],
 ):
     _yatai_client.pull_bento(tag, force=force, bento_store=_bento_store)
@@ -377,7 +379,16 @@ def build(
             logger.error("Failed to build BentoService bundle: %s", e)
             raise
 
-    return get(output.decode("utf-8").strip().split("\n")[-1])
+    if _usage_event_debugging():
+        # NOTE: This usually only concern BentoML devs.
+        pattern = r"^__tag__:[^:\n]+:[^:\n]+"
+        matched = re.search(pattern, output.decode("utf-8").strip(), re.MULTILINE)
+        assert matched is not None, f"Failed to find tag from output: {output}"
+        _, _, tag = matched.group(0).partition(":")
+    else:
+        # This branch is the current behaviour that doesn't concern BentoML users.
+        tag = output.decode("utf-8").strip().split("\n")[-1]
+    return get(tag, _bento_store=_bento_store)
 
 
 @inject
@@ -419,7 +430,16 @@ def build_bentofile(
         logger.error("Failed to build BentoService bundle: %s", e)
         raise
 
-    return get(output.decode("utf-8").strip().split("\n")[-1])
+    if _usage_event_debugging():
+        # NOTE: This usually only concern BentoML devs.
+        pattern = r"^__tag__:[^:\n]+:[^:\n]+"
+        matched = re.search(pattern, output.decode("utf-8").strip(), re.MULTILINE)
+        assert matched is not None, f"Failed to find tag from output: {output}"
+        _, _, tag = matched.group(0).partition(":")
+    else:
+        # This branch is the current behaviour that doesn't concern BentoML users.
+        tag = output.decode("utf-8").strip().split("\n")[-1]
+    return get(tag, _bento_store=_bento_store)
 
 
 def containerize(bento_tag: Tag | str, **kwargs: t.Any) -> bool:
diff --git a/src/bentoml/server.py b/src/bentoml/server.py
index d0285db0..7a37c44a 100644
--- a/src/bentoml/server.py
+++ b/src/bentoml/server.py
@@ -1,5 +1,6 @@
 from __future__ import annotations
 
+import os
 import sys
 import typing as t
 import logging
@@ -17,6 +18,7 @@ from ._internal.tag import Tag
 from ._internal.bento import Bento
 from ._internal.service import Service
 from ._internal.configuration.containers import BentoMLContainer
+from ._internal.utils.analytics.usage_stats import BENTOML_SERVE_FROM_SERVER_API
 
 if TYPE_CHECKING:
     from types import TracebackType
@@ -145,6 +147,12 @@ class Server(ABC):
             stderr: The stderr to pass to the server. Default to ``None``.
             text: Whether to output as text or bytes for stdout and stderr. Default to ``None``.
         """
+        # NOTE: User shouldn't manually set this since this envvar will be managed by BentoML.
+        os.environ[BENTOML_SERVE_FROM_SERVER_API] = str(True)
+
+        if env is None:
+            env = {}
+        env.update(os.environ.copy())
 
         class _Manager:
             def __init__(__inner_self):
@@ -184,11 +192,50 @@ class Server(ABC):
 
         return _Manager()
 
-    @abstractmethod
     def get_client(self) -> Client | None:
+        if self.process is None:
+            # NOTE: if the process is None, we reset this envvar
+            del os.environ[BENTOML_SERVE_FROM_SERVER_API]
+            logger.warning(
+                "Attempted to get a client for a BentoML server that was not running! Try running 'bentoml.*Server.start()' first."
+            )
+            return
+        assert self.process is not None
+        out_code = self.process.poll()
+        if out_code == 0:
+            # NOTE: if the process is None, we reset this envvar
+            del os.environ[BENTOML_SERVE_FROM_SERVER_API]
+            logger.warning(
+                "Attempted to get a client from a BentoML server that has already exited! You can run '.start()' again to restart it."
+            )
+            return
+        elif out_code is not None:
+            # NOTE: if the process is None, we reset this envvar
+            del os.environ[BENTOML_SERVE_FROM_SERVER_API]
+            logs = "Attempted to get a client from a BentoML server that has already exited with an error!\nServer Output:\n"
+            if self.process.stdout is not None and not self.process.stdout.closed:
+                s = self.process.stdout.read()
+                logs += textwrap.indent(
+                    s.decode("utf-8") if isinstance(s, bytes) else s, " " * 4
+                )
+            if self.process.stderr is not None and not self.process.stderr.closed:
+                logs += "\nServer Error:\n"
+                s = self.process.stderr.read()
+                logs += textwrap.indent(
+                    s.decode("utf-8") if isinstance(s, bytes) else s, " " * 4
+                )
+            logger.warning(logs)
+            return
+        return self._get_client()
+
+    @abstractmethod
+    def _get_client(self) -> Client | None:
         pass
 
     def stop(self) -> None:
+        # NOTE: User shouldn't manually set this since this envvar will be managed by BentoML.
+        del os.environ[BENTOML_SERVE_FROM_SERVER_API]
+
         if self.process is None:
             logger.warning("Attempted to stop a BentoML server that was not running!")
             return
@@ -301,37 +348,9 @@ class HTTPServer(Server):
         logger.warning(
             "'Server.client()' is deprecated, use 'Server.get_client()' instead."
         )
-        return self.get_client()
-
-    def get_client(self) -> HTTPClient | None:
-        if self.process is None:
-            logger.warning(
-                "Attempted to get a client for a BentoML server that was not running! Try running 'bentoml.*Server.start()' first."
-            )
-            return
-        assert self.process is not None
-        out_code = self.process.poll()
-        if out_code == 0:
-            logger.warning(
-                "Attempted to get a client from a BentoML server that has already exited! You can run '.start()' again to restart it."
-            )
-            return
-        elif out_code is not None:
-            logs = "Attempted to get a client from a BentoML server that has already exited with an error!\nServer Output:\n"
-            if self.process.stdout is not None and not self.process.stdout.closed:
-                s = self.process.stdout.read()
-                logs += textwrap.indent(
-                    s.decode("utf-8") if isinstance(s, bytes) else s, " " * 4
-                )
-            if self.process.stderr is not None and not self.process.stderr.closed:
-                logs += "\nServer Error:\n"
-                s = self.process.stderr.read()
-                logs += textwrap.indent(
-                    s.decode("utf-8") if isinstance(s, bytes) else s, " " * 4
-                )
-            logger.warning(logs)
-            return
+        return t.cast("HTTPClient | None", self.get_client())
 
+    def _get_client(self) -> HTTPClient | None:
         if self._client is None:
             from .client import HTTPClient
 
@@ -401,35 +420,7 @@ class GrpcServer(Server):
         if grpc_protocol_version is not None:
             self.args.extend(["--protocol-version", str(grpc_protocol_version)])
 
-    def get_client(self) -> GrpcClient | None:
-        if self.process is None:
-            logger.warning(
-                "Attempted to get a client for a BentoML server that was not running! Try running 'bentoml.*Server.start()' first."
-            )
-            return
-        assert self.process is not None
-        out_code = self.process.poll()
-        if out_code == 0:
-            logger.warning(
-                "Attempted to get a client from a BentoML server that has already exited! You can run '.start()' again to restart it."
-            )
-            return
-        elif out_code is not None:
-            logs = "Attempted to get a client from a BentoML server that has already exited with an error!\nServer Output:\n"
-            if self.process.stdout is not None and not self.process.stdout.closed:
-                s = self.process.stdout.read()
-                logs += textwrap.indent(
-                    s.decode("utf-8") if isinstance(s, bytes) else s, " " * 4
-                )
-            if self.process.stderr is not None and not self.process.stderr.closed:
-                logs += "\nServer Error:\n"
-                s = self.process.stderr.read()
-                logs += textwrap.indent(
-                    s.decode("utf-8") if isinstance(s, bytes) else s, " " * 4
-                )
-            logger.warning(logs)
-            return
-
+    def _get_client(self) -> GrpcClient | None:
         if self._client is None:
             from .client import GrpcClient
 
diff --git a/src/bentoml_cli/bentos.py b/src/bentoml_cli/bentos.py
index d4fb76ca..c57afe08 100644
--- a/src/bentoml_cli/bentos.py
+++ b/src/bentoml_cli/bentos.py
@@ -64,6 +64,7 @@ def add_bento_management_commands(cli: Group):
     from bentoml._internal.configuration import get_quiet_mode
     from bentoml._internal.bento.build_config import BentoBuildConfig
     from bentoml._internal.configuration.containers import BentoMLContainer
+    from bentoml._internal.utils.analytics.usage_stats import _usage_event_debugging
 
     bento_store = BentoMLContainer.bento_store.get()
     yatai_client = BentoMLContainer.yatai_client.get()
@@ -311,7 +312,7 @@ def add_bento_management_commands(cli: Group):
         build_ctx: str,
         bentofile: str,
         version: str,
-        output: t.Literal["tag", "default"],
+        output: t.Literal["tag", "default", "yaml"],
         _bento_store: BentoStore = Provide[BentoMLContainer.bento_store],
     ):
         """Build a new Bento from current directory."""
@@ -334,7 +335,14 @@ def add_bento_management_commands(cli: Group):
         # NOTE: Don't remove the return statement here, since we will need this
         # for usage stats collection if users are opt-in.
         if output == "tag":
-            click.echo(bento.tag)
+            if _usage_event_debugging():
+                # NOTE: Since we are logging all of the trackintg id to stdout
+                # We will prefix the tag with __tag__ and we can use regex to correctly
+                # get the tag from 'bentoml.bentos.build|build_bentofile'
+                click.echo(f"__tag__:{bento.tag}")
+            else:
+                # Current behaviour
+                click.echo(bento.tag)
             return bento
 
         if not get_quiet_mode():
diff --git a/src/bentoml_cli/serve.py b/src/bentoml_cli/serve.py
index 416de059..077bbbf2 100644
--- a/src/bentoml_cli/serve.py
+++ b/src/bentoml_cli/serve.py
@@ -2,15 +2,50 @@ from __future__ import annotations
 
 import os
 import sys
+import typing as t
 import logging
 
 import click
 
+if t.TYPE_CHECKING:
+    P = t.ParamSpec("P")
+    F = t.Callable[P, t.Any]
+
+
 logger = logging.getLogger(__name__)
 
 DEFAULT_DEV_SERVER_HOST = "127.0.0.1"
 
 
+def deprecated_option(*param_decls: str, **attrs: t.Any):
+    """Marks a given options as deprecated, and omit a warning when it's used"""
+    deprecated = attrs.pop("deprecated", True)
+    new_behaviour = attrs.pop("current_behaviour", None)
+    assert new_behaviour is not None, "current_behaviour is required"
+
+    def show_deprecated_callback(
+        ctx: click.Context, param: click.Parameter, value: t.Any
+    ):
+        if value is not param.default and deprecated:
+            name = "'--%(name)s'" if attrs.get("is_flag", False) else "'%(name)s'"
+            DEPRECATION_WARNING = f"DeprecationWarning: The parameter {name} is deprecated and will be removed in the future. (Current behaviour: %(new_behaviour)s)"
+            click.secho(
+                DEPRECATION_WARNING
+                % {"name": param.name, "new_behaviour": new_behaviour},
+                fg="yellow",
+                err=True,
+            )
+
+    def decorator(f: F[t.Any]) -> t.Callable[[F[t.Any]], click.Command]:
+        msg = attrs.pop("help", "")
+        msg += " (Deprecated)" if msg else "(Deprecated)"
+        attrs.setdefault("help", msg)
+        attrs.setdefault("callback", show_deprecated_callback)
+        return click.option(*param_decls, **attrs)(f)
+
+    return decorator
+
+
 def add_serve_command(cli: click.Group) -> None:
     from bentoml.grpc.utils import LATEST_PROTOCOL_VERSION
     from bentoml._internal.log import configure_server_logging
@@ -27,13 +62,14 @@ def add_serve_command(cli: click.Group) -> None:
         default=False,
         show_default=True,
     )
-    @click.option(
+    @deprecated_option(
         "--production",
         type=click.BOOL,
-        help="Deprecated option, by default BentoServer will run in production mode",
+        help="Run BentoServer in production mode",
+        current_behaviour="This is enabled by default. To run in development mode, use '--development'.",
         is_flag=True,
         default=True,
-        show_default=True,
+        show_default=False,
     )
     @click.option(
         "-p",
@@ -135,13 +171,12 @@ def add_serve_command(cli: click.Group) -> None:
     def serve(  # type: ignore (unused warning)
         bento: str,
         development: bool,
-        production: bool,  # deprecated and ignored
         port: int,
         host: str,
         api_workers: int | None,
         backlog: int,
         reload: bool,
-        working_dir: str,
+        working_dir: str | None,
         ssl_certfile: str | None,
         ssl_keyfile: str | None,
         ssl_keyfile_password: str | None,
@@ -149,6 +184,7 @@ def add_serve_command(cli: click.Group) -> None:
         ssl_cert_reqs: int | None,
         ssl_ca_certs: str | None,
         ssl_ciphers: str | None,
+        **attrs: t.Any,
     ) -> None:
         """Start a HTTP BentoServer from a given 🍱
 
@@ -242,13 +278,14 @@ def add_serve_command(cli: click.Group) -> None:
         default=False,
         show_default=True,
     )
-    @click.option(
+    @deprecated_option(
         "--production",
         type=click.BOOL,
-        help="Deprecated option, by default BentoServer will run in production mode",
+        help="Run BentoServer in production mode",
+        current_behaviour="This is enabled by default. To run in development mode, use '--development'.",
         is_flag=True,
         default=True,
-        show_default=True,
+        show_default=False,
     )
     @click.option(
         "-p",
@@ -353,13 +390,12 @@ def add_serve_command(cli: click.Group) -> None:
     def serve_grpc(  # type: ignore (unused warning)
         bento: str,
         development: bool,
-        production: bool,  # deprecated and ignored
         port: int,
         host: str,
         api_workers: int | None,
         backlog: int,
         reload: bool,
-        working_dir: str,
+        working_dir: str | None,
         ssl_certfile: str | None,
         ssl_keyfile: str | None,
         ssl_ca_certs: str | None,
@@ -367,6 +403,7 @@ def add_serve_command(cli: click.Group) -> None:
         enable_channelz: bool,
         max_concurrent_streams: int | None,
         protocol_version: str,
+        **attrs: t.Any,
     ):
         """Start a gRPC BentoServer from a given 🍱
 


Test patch:
diff --git a/tests/unit/_internal/utils/test_analytics.py b/tests/unit/_internal/utils/test_analytics.py
index 180f07ff..e160292a 100644
--- a/tests/unit/_internal/utils/test_analytics.py
+++ b/tests/unit/_internal/utils/test_analytics.py
@@ -1,19 +1,15 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 
-import typing as t
 import logging
+import typing as t
 from typing import TYPE_CHECKING
-from unittest.mock import Mock
-from unittest.mock import patch
+from unittest.mock import Mock, patch
 
 import pytest
-from schema import Or
-from schema import And
-from schema import Schema
-from prometheus_client.parser import (
-    text_string_to_metric_families,  # type: ignore (no prometheus types)
-)
+from prometheus_client.parser import \
+    text_string_to_metric_families  # type: ignore (no prometheus types)
+from schema import And, Or, Schema
 
 import bentoml
 from bentoml._internal.utils import analytics
@@ -148,6 +144,7 @@ def test_track_serve_init(
         production=production,
         serve_info=analytics.usage_stats.get_serve_info(),
         serve_kind="http",
+        from_server_api=False,
     )
 
     assert mock_do_not_track.called
@@ -160,6 +157,7 @@ def test_track_serve_init(
             production=production,
             serve_info=analytics.usage_stats.get_serve_info(),
             serve_kind="http",
+            from_server_api=False,
         )
     assert "model_types" in caplog.text
 
@@ -184,6 +182,7 @@ def test_track_serve_init_no_bento(
             production=False,
             serve_info=analytics.usage_stats.get_serve_info(),
             serve_kind="http",
+            from_server_api=False,
         )
     assert "model_types" not in caplog.text