We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add python version mismatch warning
**Is your feature request related to a problem? Please describe.**

Currently, when the user saves a BentoML bundle, the `bentoml.yml` file under the bundle directory contains the Python version in which the bundle was created.

When deploying with Docker, bentoml ensures that the python version matches the saved bundle python version. Although when the user is using a custom docker image, or when the user is loading directly with the `bentoml.load` API, there's no guarantee the python version matches.

This can cause issues in some cases, especially where PickleArtifact or PyTorchArtifact is being used.

We should add a warning when loading a BentoML saved bundle if the current Python version does not match the saved bundle's python version.


**Describe the solution you'd like**
Add a warning to tell the user about Python version mismatch

**Describe alternatives you've considered**
Instead of warning, raise an exception.  

We can still allow user to specifically set a config to allow loading BentoML bundle of a different python version, e.g.  'BENTOML__CORE__PYPASS_BUNDLE_PY_VERSION_CHECK=true' 

**Additional context**
n/a

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bentoml/saved_bundle/config.py`
Content:
```
1 # Copyright 2019 Atalaya Tech, Inc.
2 
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 
7 # http://www.apache.org/licenses/LICENSE-2.0
8 
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import os
16 import logging
17 from datetime import datetime
18 from pathlib import Path
19 
20 from ruamel.yaml import YAML
21 
22 from bentoml import __version__ as BENTOML_VERSION
23 from bentoml import config
24 from bentoml.configuration import get_bentoml_deploy_version
25 from bentoml.utils import dump_to_yaml_str
26 from bentoml.exceptions import BentoMLConfigException
27 
28 BENTOML_CONFIG_YAML_TEPMLATE = """\
29 version: {bentoml_version}
30 kind: {kind}
31 metadata:
32     created_at: {created_at}
33 """
34 
35 logger = logging.getLogger(__name__)
36 DEFAULT_MAX_LATENCY = config("marshal_server").getint("default_max_latency")
37 DEFAULT_MAX_BATCH_SIZE = config("marshal_server").getint("default_max_batch_size")
38 
39 
40 def _get_apis_list(bento_service):
41     result = []
42     for api in bento_service.inference_apis:
43         api_obj = {
44             "name": api.name,
45             "docs": api.doc,
46             "input_type": api.handler.__class__.__name__,
47             "output_type": api.handler.output_adapter.__class__.__name__,
48             "mb_max_batch_size": api.mb_max_batch_size,
49             "mb_max_latency": api.mb_max_latency,
50         }
51         if api.handler.config:
52             api_obj["input_config"] = api.handler.config
53         if api.output_adapter.config:
54             api_obj["output_config"] = api.output_adapter.config
55         result.append(api_obj)
56     return result
57 
58 
59 def _get_artifacts_list(bento_service):
60     result = []
61     for artifact_name, artifact in bento_service.artifacts.items():
62         result.append(
63             {'name': artifact_name, 'artifact_type': artifact.__class__.__name__}
64         )
65     return result
66 
67 
68 class SavedBundleConfig(object):
69     def __init__(self, bento_service=None, kind="BentoService"):
70         self.kind = kind
71         self._yaml = YAML()
72         self._yaml.default_flow_style = False
73         self.config = self._yaml.load(
74             BENTOML_CONFIG_YAML_TEPMLATE.format(
75                 kind=self.kind,
76                 bentoml_version=get_bentoml_deploy_version(),
77                 created_at=str(datetime.utcnow()),
78             )
79         )
80 
81         if bento_service is not None:
82             self.config["metadata"].update(
83                 {
84                     "service_name": bento_service.name,
85                     "service_version": bento_service.version,
86                 }
87             )
88             self.config["env"] = bento_service.env.to_dict()
89             self.config['apis'] = _get_apis_list(bento_service)
90             self.config['artifacts'] = _get_artifacts_list(bento_service)
91 
92     def write_to_path(self, path, filename="bentoml.yml"):
93         return self._yaml.dump(self.config, Path(os.path.join(path, filename)))
94 
95     @classmethod
96     def load(cls, filepath):
97         conf = cls()
98         with open(filepath, "rb") as config_file:
99             yml_content = config_file.read()
100         conf.config = conf._yaml.load(yml_content)
101         ver = str(conf["version"])
102 
103         if ver != BENTOML_VERSION:
104             msg = (
105                 "Saved BentoService bundle version mismatch: loading BentoService "
106                 "bundle create with BentoML version {}, but loading from BentoML "
107                 "version {}".format(conf["version"], BENTOML_VERSION)
108             )
109 
110             # If major version is different, then there could be incompatible API
111             # changes. Raise error in this case.
112             if ver.split(".")[0] != BENTOML_VERSION.split(".")[0]:
113                 if not BENTOML_VERSION.startswith('0+untagged'):
114                     raise BentoMLConfigException(msg)
115                 else:
116                     logger.warning(msg)
117             else:  # Otherwise just show a warning.
118                 logger.warning(msg)
119 
120         return conf
121 
122     def get_bento_service_metadata_pb(self):
123         from bentoml.yatai.proto.repository_pb2 import BentoServiceMetadata
124 
125         bento_service_metadata = BentoServiceMetadata()
126         bento_service_metadata.name = self.config["metadata"]["service_name"]
127         bento_service_metadata.version = self.config["metadata"]["service_version"]
128         bento_service_metadata.created_at.FromDatetime(
129             self.config["metadata"]["created_at"]
130         )
131 
132         if "env" in self.config:
133             if "setup_sh" in self.config["env"]:
134                 bento_service_metadata.env.setup_sh = self.config["env"]["setup_sh"]
135 
136             if "conda_env" in self.config["env"]:
137                 bento_service_metadata.env.conda_env = dump_to_yaml_str(
138                     self.config["env"]["conda_env"]
139                 )
140 
141             if "pip_dependencies" in self.config["env"]:
142                 bento_service_metadata.env.pip_dependencies = "\n".join(
143                     self.config["env"]["pip_dependencies"]
144                 )
145             if "python_version" in self.config["env"]:
146                 bento_service_metadata.env.python_version = self.config["env"][
147                     "python_version"
148                 ]
149             if "docker_base_image" in self.config["env"]:
150                 bento_service_metadata.env.docker_base_image = self.config["env"][
151                     "docker_base_image"
152                 ]
153 
154         if "apis" in self.config:
155             for api_config in self.config["apis"]:
156                 if 'handler_type' in api_config:
157                     # Convert handler type to input type for saved bundle created
158                     # before version 0.8.0
159                     input_type = api_config.get('handler_type')
160                 elif 'input_type' in api_config:
161                     input_type = api_config.get('input_type')
162                 else:
163                     input_type = "unknown"
164 
165                 if 'output_type' in api_config:
166                     output_type = api_config.get('output_type')
167                 else:
168                     output_type = "DefaultOutput"
169 
170                 api_metadata = BentoServiceMetadata.BentoServiceApi(
171                     name=api_config["name"],
172                     docs=api_config["docs"],
173                     input_type=input_type,
174                     output_type=output_type,
175                 )
176                 if "handler_config" in api_config:
177                     # Supports viewing API input config info for saved bundle created
178                     # before version 0.8.0
179                     for k, v in api_config["handler_config"].items():
180                         if k in {'mb_max_latency', 'mb_max_batch_size'}:
181                             setattr(api_metadata, k, v)
182                         else:
183                             api_metadata.input_config[k] = v
184                 else:
185                     if 'mb_max_latency' in api_config:
186                         api_metadata.mb_max_latency = api_config["mb_max_latency"]
187                     else:
188                         api_metadata.mb_max_latency = DEFAULT_MAX_LATENCY
189 
190                     if 'mb_max_batch_size' in api_config:
191                         api_metadata.mb_max_batch_size = api_config["mb_max_batch_size"]
192                     else:
193                         api_metadata.mb_max_batch_size = DEFAULT_MAX_BATCH_SIZE
194 
195                 if "input_config" in api_config:
196                     for k, v in api_config["input_config"].items():
197                         api_metadata.input_config[k] = v
198 
199                 if "output_config" in api_config:
200                     for k, v in api_config["output_config"].items():
201                         api_metadata.output_config[k] = v
202                 bento_service_metadata.apis.extend([api_metadata])
203 
204         if "artifacts" in self.config:
205             for artifact_config in self.config["artifacts"]:
206                 artifact_metadata = BentoServiceMetadata.BentoArtifact()
207                 if "name" in artifact_config:
208                     artifact_metadata.name = artifact_config["name"]
209                 if "artifact_type" in artifact_config:
210                     artifact_metadata.artifact_type = artifact_config["artifact_type"]
211                 bento_service_metadata.artifacts.extend([artifact_metadata])
212 
213         return bento_service_metadata
214 
215     def __getitem__(self, item):
216         return self.config[item]
217 
218     def __setitem__(self, key, value):
219         self.config[key] = value
220 
221     def __contains__(self, item):
222         return item in self.config
223
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bentoml/saved_bundle/config.py b/bentoml/saved_bundle/config.py
--- a/bentoml/saved_bundle/config.py
+++ b/bentoml/saved_bundle/config.py
@@ -16,6 +16,7 @@
 import logging
 from datetime import datetime
 from pathlib import Path
+from sys import version_info
 
 from ruamel.yaml import YAML
 
@@ -35,6 +36,7 @@
 logger = logging.getLogger(__name__)
 DEFAULT_MAX_LATENCY = config("marshal_server").getint("default_max_latency")
 DEFAULT_MAX_BATCH_SIZE = config("marshal_server").getint("default_max_batch_size")
+PYTHON_VERSION = f"{version_info.major}.{version_info.minor}.{version_info.micro}"
 
 
 def _get_apis_list(bento_service):
@@ -99,6 +101,7 @@
             yml_content = config_file.read()
         conf.config = conf._yaml.load(yml_content)
         ver = str(conf["version"])
+        py_ver = conf.config["env"]["python_version"]
 
         if ver != BENTOML_VERSION:
             msg = (
@@ -117,6 +120,13 @@
             else:  # Otherwise just show a warning.
                 logger.warning(msg)
 
+        if py_ver != PYTHON_VERSION:
+            logger.warning(
+                f"Saved BentoService Python version mismatch: loading "
+                f"BentoService bundle created with Python version {py_ver}, "
+                f"but current environment version is {PYTHON_VERSION}."
+            )
+
         return conf
 
     def get_bento_service_metadata_pb(self):

{"golden_diff": "diff --git a/bentoml/saved_bundle/config.py b/bentoml/saved_bundle/config.py\n--- a/bentoml/saved_bundle/config.py\n+++ b/bentoml/saved_bundle/config.py\n@@ -16,6 +16,7 @@\n import logging\n from datetime import datetime\n from pathlib import Path\n+from sys import version_info\n \n from ruamel.yaml import YAML\n \n@@ -35,6 +36,7 @@\n logger = logging.getLogger(__name__)\n DEFAULT_MAX_LATENCY = config(\"marshal_server\").getint(\"default_max_latency\")\n DEFAULT_MAX_BATCH_SIZE = config(\"marshal_server\").getint(\"default_max_batch_size\")\n+PYTHON_VERSION = f\"{version_info.major}.{version_info.minor}.{version_info.micro}\"\n \n \n def _get_apis_list(bento_service):\n@@ -99,6 +101,7 @@\n             yml_content = config_file.read()\n         conf.config = conf._yaml.load(yml_content)\n         ver = str(conf[\"version\"])\n+        py_ver = conf.config[\"env\"][\"python_version\"]\n \n         if ver != BENTOML_VERSION:\n             msg = (\n@@ -117,6 +120,13 @@\n             else:  # Otherwise just show a warning.\n                 logger.warning(msg)\n \n+        if py_ver != PYTHON_VERSION:\n+            logger.warning(\n+                f\"Saved BentoService Python version mismatch: loading \"\n+                f\"BentoService bundle created with Python version {py_ver}, \"\n+                f\"but current environment version is {PYTHON_VERSION}.\"\n+            )\n+\n         return conf\n \n     def get_bento_service_metadata_pb(self):\n", "issue": "Add python version mismatch warning\n**Is your feature request related to a problem? Please describe.**\r\n\r\nCurrently, when the user saves a BentoML bundle, the `bentoml.yml` file under the bundle directory contains the Python version in which the bundle was created.\r\n\r\nWhen deploying with Docker, bentoml ensures that the python version matches the saved bundle python version. Although when the user is using a custom docker image, or when the user is loading directly with the `bentoml.load` API, there's no guarantee the python version matches.\r\n\r\nThis can cause issues in some cases, especially where PickleArtifact or PyTorchArtifact is being used.\r\n\r\nWe should add a warning when loading a BentoML saved bundle if the current Python version does not match the saved bundle's python version.\r\n\r\n\r\n**Describe the solution you'd like**\r\nAdd a warning to tell the user about Python version mismatch\r\n\r\n**Describe alternatives you've considered**\r\nInstead of warning, raise an exception.  \r\n\r\nWe can still allow user to specifically set a config to allow loading BentoML bundle of a different python version, e.g.  'BENTOML__CORE__PYPASS_BUNDLE_PY_VERSION_CHECK=true' \r\n\r\n**Additional context**\r\nn/a\n", "before_files": [{"content": "# Copyright 2019 Atalaya Tech, Inc.\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n\n# http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport logging\nfrom datetime import datetime\nfrom pathlib import Path\n\nfrom ruamel.yaml import YAML\n\nfrom bentoml import __version__ as BENTOML_VERSION\nfrom bentoml import config\nfrom bentoml.configuration import get_bentoml_deploy_version\nfrom bentoml.utils import dump_to_yaml_str\nfrom bentoml.exceptions import BentoMLConfigException\n\nBENTOML_CONFIG_YAML_TEPMLATE = \"\"\"\\\nversion: {bentoml_version}\nkind: {kind}\nmetadata:\n    created_at: {created_at}\n\"\"\"\n\nlogger = logging.getLogger(__name__)\nDEFAULT_MAX_LATENCY = config(\"marshal_server\").getint(\"default_max_latency\")\nDEFAULT_MAX_BATCH_SIZE = config(\"marshal_server\").getint(\"default_max_batch_size\")\n\n\ndef _get_apis_list(bento_service):\n    result = []\n    for api in bento_service.inference_apis:\n        api_obj = {\n            \"name\": api.name,\n            \"docs\": api.doc,\n            \"input_type\": api.handler.__class__.__name__,\n            \"output_type\": api.handler.output_adapter.__class__.__name__,\n            \"mb_max_batch_size\": api.mb_max_batch_size,\n            \"mb_max_latency\": api.mb_max_latency,\n        }\n        if api.handler.config:\n            api_obj[\"input_config\"] = api.handler.config\n        if api.output_adapter.config:\n            api_obj[\"output_config\"] = api.output_adapter.config\n        result.append(api_obj)\n    return result\n\n\ndef _get_artifacts_list(bento_service):\n    result = []\n    for artifact_name, artifact in bento_service.artifacts.items():\n        result.append(\n            {'name': artifact_name, 'artifact_type': artifact.__class__.__name__}\n        )\n    return result\n\n\nclass SavedBundleConfig(object):\n    def __init__(self, bento_service=None, kind=\"BentoService\"):\n        self.kind = kind\n        self._yaml = YAML()\n        self._yaml.default_flow_style = False\n        self.config = self._yaml.load(\n            BENTOML_CONFIG_YAML_TEPMLATE.format(\n                kind=self.kind,\n                bentoml_version=get_bentoml_deploy_version(),\n                created_at=str(datetime.utcnow()),\n            )\n        )\n\n        if bento_service is not None:\n            self.config[\"metadata\"].update(\n                {\n                    \"service_name\": bento_service.name,\n                    \"service_version\": bento_service.version,\n                }\n            )\n            self.config[\"env\"] = bento_service.env.to_dict()\n            self.config['apis'] = _get_apis_list(bento_service)\n            self.config['artifacts'] = _get_artifacts_list(bento_service)\n\n    def write_to_path(self, path, filename=\"bentoml.yml\"):\n        return self._yaml.dump(self.config, Path(os.path.join(path, filename)))\n\n    @classmethod\n    def load(cls, filepath):\n        conf = cls()\n        with open(filepath, \"rb\") as config_file:\n            yml_content = config_file.read()\n        conf.config = conf._yaml.load(yml_content)\n        ver = str(conf[\"version\"])\n\n        if ver != BENTOML_VERSION:\n            msg = (\n                \"Saved BentoService bundle version mismatch: loading BentoService \"\n                \"bundle create with BentoML version {}, but loading from BentoML \"\n                \"version {}\".format(conf[\"version\"], BENTOML_VERSION)\n            )\n\n            # If major version is different, then there could be incompatible API\n            # changes. Raise error in this case.\n            if ver.split(\".\")[0] != BENTOML_VERSION.split(\".\")[0]:\n                if not BENTOML_VERSION.startswith('0+untagged'):\n                    raise BentoMLConfigException(msg)\n                else:\n                    logger.warning(msg)\n            else:  # Otherwise just show a warning.\n                logger.warning(msg)\n\n        return conf\n\n    def get_bento_service_metadata_pb(self):\n        from bentoml.yatai.proto.repository_pb2 import BentoServiceMetadata\n\n        bento_service_metadata = BentoServiceMetadata()\n        bento_service_metadata.name = self.config[\"metadata\"][\"service_name\"]\n        bento_service_metadata.version = self.config[\"metadata\"][\"service_version\"]\n        bento_service_metadata.created_at.FromDatetime(\n            self.config[\"metadata\"][\"created_at\"]\n        )\n\n        if \"env\" in self.config:\n            if \"setup_sh\" in self.config[\"env\"]:\n                bento_service_metadata.env.setup_sh = self.config[\"env\"][\"setup_sh\"]\n\n            if \"conda_env\" in self.config[\"env\"]:\n                bento_service_metadata.env.conda_env = dump_to_yaml_str(\n                    self.config[\"env\"][\"conda_env\"]\n                )\n\n            if \"pip_dependencies\" in self.config[\"env\"]:\n                bento_service_metadata.env.pip_dependencies = \"\\n\".join(\n                    self.config[\"env\"][\"pip_dependencies\"]\n                )\n            if \"python_version\" in self.config[\"env\"]:\n                bento_service_metadata.env.python_version = self.config[\"env\"][\n                    \"python_version\"\n                ]\n            if \"docker_base_image\" in self.config[\"env\"]:\n                bento_service_metadata.env.docker_base_image = self.config[\"env\"][\n                    \"docker_base_image\"\n                ]\n\n        if \"apis\" in self.config:\n            for api_config in self.config[\"apis\"]:\n                if 'handler_type' in api_config:\n                    # Convert handler type to input type for saved bundle created\n                    # before version 0.8.0\n                    input_type = api_config.get('handler_type')\n                elif 'input_type' in api_config:\n                    input_type = api_config.get('input_type')\n                else:\n                    input_type = \"unknown\"\n\n                if 'output_type' in api_config:\n                    output_type = api_config.get('output_type')\n                else:\n                    output_type = \"DefaultOutput\"\n\n                api_metadata = BentoServiceMetadata.BentoServiceApi(\n                    name=api_config[\"name\"],\n                    docs=api_config[\"docs\"],\n                    input_type=input_type,\n                    output_type=output_type,\n                )\n                if \"handler_config\" in api_config:\n                    # Supports viewing API input config info for saved bundle created\n                    # before version 0.8.0\n                    for k, v in api_config[\"handler_config\"].items():\n                        if k in {'mb_max_latency', 'mb_max_batch_size'}:\n                            setattr(api_metadata, k, v)\n                        else:\n                            api_metadata.input_config[k] = v\n                else:\n                    if 'mb_max_latency' in api_config:\n                        api_metadata.mb_max_latency = api_config[\"mb_max_latency\"]\n                    else:\n                        api_metadata.mb_max_latency = DEFAULT_MAX_LATENCY\n\n                    if 'mb_max_batch_size' in api_config:\n                        api_metadata.mb_max_batch_size = api_config[\"mb_max_batch_size\"]\n                    else:\n                        api_metadata.mb_max_batch_size = DEFAULT_MAX_BATCH_SIZE\n\n                if \"input_config\" in api_config:\n                    for k, v in api_config[\"input_config\"].items():\n                        api_metadata.input_config[k] = v\n\n                if \"output_config\" in api_config:\n                    for k, v in api_config[\"output_config\"].items():\n                        api_metadata.output_config[k] = v\n                bento_service_metadata.apis.extend([api_metadata])\n\n        if \"artifacts\" in self.config:\n            for artifact_config in self.config[\"artifacts\"]:\n                artifact_metadata = BentoServiceMetadata.BentoArtifact()\n                if \"name\" in artifact_config:\n                    artifact_metadata.name = artifact_config[\"name\"]\n                if \"artifact_type\" in artifact_config:\n                    artifact_metadata.artifact_type = artifact_config[\"artifact_type\"]\n                bento_service_metadata.artifacts.extend([artifact_metadata])\n\n        return bento_service_metadata\n\n    def __getitem__(self, item):\n        return self.config[item]\n\n    def __setitem__(self, key, value):\n        self.config[key] = value\n\n    def __contains__(self, item):\n        return item in self.config\n", "path": "bentoml/saved_bundle/config.py"}], "after_files": [{"content": "# Copyright 2019 Atalaya Tech, Inc.\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n\n# http://www.apache.org/licenses/LICENSE-2.0\n\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport logging\nfrom datetime import datetime\nfrom pathlib import Path\nfrom sys import version_info\n\nfrom ruamel.yaml import YAML\n\nfrom bentoml import __version__ as BENTOML_VERSION\nfrom bentoml import config\nfrom bentoml.configuration import get_bentoml_deploy_version\nfrom bentoml.utils import dump_to_yaml_str\nfrom bentoml.exceptions import BentoMLConfigException\n\nBENTOML_CONFIG_YAML_TEPMLATE = \"\"\"\\\nversion: {bentoml_version}\nkind: {kind}\nmetadata:\n    created_at: {created_at}\n\"\"\"\n\nlogger = logging.getLogger(__name__)\nDEFAULT_MAX_LATENCY = config(\"marshal_server\").getint(\"default_max_latency\")\nDEFAULT_MAX_BATCH_SIZE = config(\"marshal_server\").getint(\"default_max_batch_size\")\nPYTHON_VERSION = f\"{version_info.major}.{version_info.minor}.{version_info.micro}\"\n\n\ndef _get_apis_list(bento_service):\n    result = []\n    for api in bento_service.inference_apis:\n        api_obj = {\n            \"name\": api.name,\n            \"docs\": api.doc,\n            \"input_type\": api.handler.__class__.__name__,\n            \"output_type\": api.handler.output_adapter.__class__.__name__,\n            \"mb_max_batch_size\": api.mb_max_batch_size,\n            \"mb_max_latency\": api.mb_max_latency,\n        }\n        if api.handler.config:\n            api_obj[\"input_config\"] = api.handler.config\n        if api.output_adapter.config:\n            api_obj[\"output_config\"] = api.output_adapter.config\n        result.append(api_obj)\n    return result\n\n\ndef _get_artifacts_list(bento_service):\n    result = []\n    for artifact_name, artifact in bento_service.artifacts.items():\n        result.append(\n            {'name': artifact_name, 'artifact_type': artifact.__class__.__name__}\n        )\n    return result\n\n\nclass SavedBundleConfig(object):\n    def __init__(self, bento_service=None, kind=\"BentoService\"):\n        self.kind = kind\n        self._yaml = YAML()\n        self._yaml.default_flow_style = False\n        self.config = self._yaml.load(\n            BENTOML_CONFIG_YAML_TEPMLATE.format(\n                kind=self.kind,\n                bentoml_version=get_bentoml_deploy_version(),\n                created_at=str(datetime.utcnow()),\n            )\n        )\n\n        if bento_service is not None:\n            self.config[\"metadata\"].update(\n                {\n                    \"service_name\": bento_service.name,\n                    \"service_version\": bento_service.version,\n                }\n            )\n            self.config[\"env\"] = bento_service.env.to_dict()\n            self.config['apis'] = _get_apis_list(bento_service)\n            self.config['artifacts'] = _get_artifacts_list(bento_service)\n\n    def write_to_path(self, path, filename=\"bentoml.yml\"):\n        return self._yaml.dump(self.config, Path(os.path.join(path, filename)))\n\n    @classmethod\n    def load(cls, filepath):\n        conf = cls()\n        with open(filepath, \"rb\") as config_file:\n            yml_content = config_file.read()\n        conf.config = conf._yaml.load(yml_content)\n        ver = str(conf[\"version\"])\n        py_ver = conf.config[\"env\"][\"python_version\"]\n\n        if ver != BENTOML_VERSION:\n            msg = (\n                \"Saved BentoService bundle version mismatch: loading BentoService \"\n                \"bundle create with BentoML version {}, but loading from BentoML \"\n                \"version {}\".format(conf[\"version\"], BENTOML_VERSION)\n            )\n\n            # If major version is different, then there could be incompatible API\n            # changes. Raise error in this case.\n            if ver.split(\".\")[0] != BENTOML_VERSION.split(\".\")[0]:\n                if not BENTOML_VERSION.startswith('0+untagged'):\n                    raise BentoMLConfigException(msg)\n                else:\n                    logger.warning(msg)\n            else:  # Otherwise just show a warning.\n                logger.warning(msg)\n\n        if py_ver != PYTHON_VERSION:\n            logger.warning(\n                f\"Saved BentoService Python version mismatch: loading \"\n                f\"BentoService bundle created with Python version {py_ver}, \"\n                f\"but current environment version is {PYTHON_VERSION}.\"\n            )\n\n        return conf\n\n    def get_bento_service_metadata_pb(self):\n        from bentoml.yatai.proto.repository_pb2 import BentoServiceMetadata\n\n        bento_service_metadata = BentoServiceMetadata()\n        bento_service_metadata.name = self.config[\"metadata\"][\"service_name\"]\n        bento_service_metadata.version = self.config[\"metadata\"][\"service_version\"]\n        bento_service_metadata.created_at.FromDatetime(\n            self.config[\"metadata\"][\"created_at\"]\n        )\n\n        if \"env\" in self.config:\n            if \"setup_sh\" in self.config[\"env\"]:\n                bento_service_metadata.env.setup_sh = self.config[\"env\"][\"setup_sh\"]\n\n            if \"conda_env\" in self.config[\"env\"]:\n                bento_service_metadata.env.conda_env = dump_to_yaml_str(\n                    self.config[\"env\"][\"conda_env\"]\n                )\n\n            if \"pip_dependencies\" in self.config[\"env\"]:\n                bento_service_metadata.env.pip_dependencies = \"\\n\".join(\n                    self.config[\"env\"][\"pip_dependencies\"]\n                )\n            if \"python_version\" in self.config[\"env\"]:\n                bento_service_metadata.env.python_version = self.config[\"env\"][\n                    \"python_version\"\n                ]\n            if \"docker_base_image\" in self.config[\"env\"]:\n                bento_service_metadata.env.docker_base_image = self.config[\"env\"][\n                    \"docker_base_image\"\n                ]\n\n        if \"apis\" in self.config:\n            for api_config in self.config[\"apis\"]:\n                if 'handler_type' in api_config:\n                    # Convert handler type to input type for saved bundle created\n                    # before version 0.8.0\n                    input_type = api_config.get('handler_type')\n                elif 'input_type' in api_config:\n                    input_type = api_config.get('input_type')\n                else:\n                    input_type = \"unknown\"\n\n                if 'output_type' in api_config:\n                    output_type = api_config.get('output_type')\n                else:\n                    output_type = \"DefaultOutput\"\n\n                api_metadata = BentoServiceMetadata.BentoServiceApi(\n                    name=api_config[\"name\"],\n                    docs=api_config[\"docs\"],\n                    input_type=input_type,\n                    output_type=output_type,\n                )\n                if \"handler_config\" in api_config:\n                    # Supports viewing API input config info for saved bundle created\n                    # before version 0.8.0\n                    for k, v in api_config[\"handler_config\"].items():\n                        if k in {'mb_max_latency', 'mb_max_batch_size'}:\n                            setattr(api_metadata, k, v)\n                        else:\n                            api_metadata.input_config[k] = v\n                else:\n                    if 'mb_max_latency' in api_config:\n                        api_metadata.mb_max_latency = api_config[\"mb_max_latency\"]\n                    else:\n                        api_metadata.mb_max_latency = DEFAULT_MAX_LATENCY\n\n                    if 'mb_max_batch_size' in api_config:\n                        api_metadata.mb_max_batch_size = api_config[\"mb_max_batch_size\"]\n                    else:\n                        api_metadata.mb_max_batch_size = DEFAULT_MAX_BATCH_SIZE\n\n                if \"input_config\" in api_config:\n                    for k, v in api_config[\"input_config\"].items():\n                        api_metadata.input_config[k] = v\n\n                if \"output_config\" in api_config:\n                    for k, v in api_config[\"output_config\"].items():\n                        api_metadata.output_config[k] = v\n                bento_service_metadata.apis.extend([api_metadata])\n\n        if \"artifacts\" in self.config:\n            for artifact_config in self.config[\"artifacts\"]:\n                artifact_metadata = BentoServiceMetadata.BentoArtifact()\n                if \"name\" in artifact_config:\n                    artifact_metadata.name = artifact_config[\"name\"]\n                if \"artifact_type\" in artifact_config:\n                    artifact_metadata.artifact_type = artifact_config[\"artifact_type\"]\n                bento_service_metadata.artifacts.extend([artifact_metadata])\n\n        return bento_service_metadata\n\n    def __getitem__(self, item):\n        return self.config[item]\n\n    def __setitem__(self, key, value):\n        self.config[key] = value\n\n    def __contains__(self, item):\n        return item in self.config\n", "path": "bentoml/saved_bundle/config.py"}]}