We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Infer model's name from folder's name
Currently, particularly in the case of MMS, MLServer requires models to specify their name in a `model-settings.json` file. This forces all models to ship that file alongside their model artifacts.

It would be good to, instead, infer the model's name from the folder name (if not present in env). This would reduce friction on adopting MLServer, the V2 protocol and MMS.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mlserver/repository.py`
Content:
```
1 import os
2 import glob
3 
4 from typing import List
5 
6 from .settings import ModelParameters, ModelSettings
7 from .errors import ModelNotFound
8 
9 DEFAULT_MODEL_SETTINGS_FILENAME = "model-settings.json"
10 
11 
12 class ModelRepository:
13     """
14     Model repository, responsible of the discovery of models which can be
15     loaded onto the model registry.
16     """
17 
18     def __init__(self, root: str = None):
19         self._root = root
20 
21     async def list(self) -> List[ModelSettings]:
22         all_model_settings = []
23 
24         # TODO: Use an async alternative for filesys ops
25         if self._root:
26             pattern = os.path.join(self._root, "**", DEFAULT_MODEL_SETTINGS_FILENAME)
27             matches = glob.glob(pattern, recursive=True)
28 
29             for model_settings_path in matches:
30                 model_settings = self._load_model_settings(model_settings_path)
31                 all_model_settings.append(model_settings)
32 
33         # If there were no matches, try to load model from environment
34         if not all_model_settings:
35             # return default
36             model_settings = ModelSettings()
37             model_settings.parameters = ModelParameters()
38             all_model_settings.append(model_settings)
39 
40         return all_model_settings
41 
42     def _load_model_settings(self, model_settings_path: str) -> ModelSettings:
43         model_settings = ModelSettings.parse_file(model_settings_path)
44 
45         if not model_settings.parameters:
46             model_settings.parameters = ModelParameters()
47 
48         if not model_settings.parameters.uri:
49             # If not specified, default to its own folder
50             default_model_uri = os.path.dirname(model_settings_path)
51             model_settings.parameters.uri = default_model_uri
52 
53         return model_settings
54 
55     async def find(self, name: str) -> ModelSettings:
56         all_settings = await self.list()
57         for model_settings in all_settings:
58             if model_settings.name == name:
59                 # TODO: Implement version policy
60                 return model_settings
61 
62         raise ModelNotFound(name)
63
```

Path: `mlserver/settings.py`
Content:
```
1 from typing import List, Optional
2 from pydantic import BaseSettings, PyObject
3 
4 from .version import __version__
5 from .types import MetadataTensor
6 
7 ENV_PREFIX_SETTINGS = "MLSERVER_"
8 ENV_PREFIX_MODEL_SETTINGS = "MLSERVER_MODEL_"
9 
10 
11 class Settings(BaseSettings):
12     class Config:
13         env_prefix = ENV_PREFIX_SETTINGS
14 
15     debug: bool = True
16 
17     # Model repository folder
18     model_repository_root: str = "."
19     load_models_at_startup: bool = True
20 
21     # Server metadata
22     server_name: str = "mlserver"
23     server_version: str = __version__
24     extensions: List[str] = []
25 
26     # Server settings
27     host: str = "0.0.0.0"
28     http_port: int = 8080
29     grpc_port: int = 8081
30     grpc_workers: int = 10
31 
32 
33 class ModelParameters(BaseSettings):
34     """
35     Parameters that apply only to a particular instance of a model.
36     This can include things like model weights.
37     The main difference with respect to ModelSettings is that parameters can
38     change on each instance (e.g. each version) of the model.
39     """
40 
41     class Config:
42         env_prefix = ENV_PREFIX_MODEL_SETTINGS
43 
44     uri: Optional[str] = None
45     version: Optional[str] = None
46     format: Optional[str] = None
47 
48 
49 class ModelSettings(BaseSettings):
50     class Config:
51         env_prefix = ENV_PREFIX_MODEL_SETTINGS
52 
53     name: str
54 
55     # Model metadata
56     platform: str = ""
57     versions: Optional[List[str]] = []
58     inputs: Optional[List[MetadataTensor]] = []
59     outputs: Optional[List[MetadataTensor]] = []
60 
61     # Custom model class implementation
62     implementation: PyObject = "mlserver.model.MLModel"  # type: ignore
63 
64     # Model parameters are meant to be set directly by the MLServer runtime.
65     # However, it's also possible to override them manually.
66     parameters: Optional[ModelParameters] = None
67
```
--- 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/mlserver/repository.py b/mlserver/repository.py
--- a/mlserver/repository.py
+++ b/mlserver/repository.py
@@ -42,6 +42,12 @@
     def _load_model_settings(self, model_settings_path: str) -> ModelSettings:
         model_settings = ModelSettings.parse_file(model_settings_path)
 
+        # TODO: Raise warning if name is different than folder's name
+        if not model_settings.name:
+            # If name not present, default to folder name
+            default_model_name = os.path.basename(os.path.dirname(model_settings_path))
+            model_settings.name = default_model_name
+
         if not model_settings.parameters:
             model_settings.parameters = ModelParameters()
 
diff --git a/mlserver/settings.py b/mlserver/settings.py
--- a/mlserver/settings.py
+++ b/mlserver/settings.py
@@ -50,7 +50,7 @@
     class Config:
         env_prefix = ENV_PREFIX_MODEL_SETTINGS
 
-    name: str
+    name: str = ""
 
     # Model metadata
     platform: str = ""

{"golden_diff": "diff --git a/mlserver/repository.py b/mlserver/repository.py\n--- a/mlserver/repository.py\n+++ b/mlserver/repository.py\n@@ -42,6 +42,12 @@\n     def _load_model_settings(self, model_settings_path: str) -> ModelSettings:\n         model_settings = ModelSettings.parse_file(model_settings_path)\n \n+        # TODO: Raise warning if name is different than folder's name\n+        if not model_settings.name:\n+            # If name not present, default to folder name\n+            default_model_name = os.path.basename(os.path.dirname(model_settings_path))\n+            model_settings.name = default_model_name\n+\n         if not model_settings.parameters:\n             model_settings.parameters = ModelParameters()\n \ndiff --git a/mlserver/settings.py b/mlserver/settings.py\n--- a/mlserver/settings.py\n+++ b/mlserver/settings.py\n@@ -50,7 +50,7 @@\n     class Config:\n         env_prefix = ENV_PREFIX_MODEL_SETTINGS\n \n-    name: str\n+    name: str = \"\"\n \n     # Model metadata\n     platform: str = \"\"\n", "issue": "Infer model's name from folder's name\nCurrently, particularly in the case of MMS, MLServer requires models to specify their name in a `model-settings.json` file. This forces all models to ship that file alongside their model artifacts.\r\n\r\nIt would be good to, instead, infer the model's name from the folder name (if not present in env). This would reduce friction on adopting MLServer, the V2 protocol and MMS.\n", "before_files": [{"content": "import os\nimport glob\n\nfrom typing import List\n\nfrom .settings import ModelParameters, ModelSettings\nfrom .errors import ModelNotFound\n\nDEFAULT_MODEL_SETTINGS_FILENAME = \"model-settings.json\"\n\n\nclass ModelRepository:\n    \"\"\"\n    Model repository, responsible of the discovery of models which can be\n    loaded onto the model registry.\n    \"\"\"\n\n    def __init__(self, root: str = None):\n        self._root = root\n\n    async def list(self) -> List[ModelSettings]:\n        all_model_settings = []\n\n        # TODO: Use an async alternative for filesys ops\n        if self._root:\n            pattern = os.path.join(self._root, \"**\", DEFAULT_MODEL_SETTINGS_FILENAME)\n            matches = glob.glob(pattern, recursive=True)\n\n            for model_settings_path in matches:\n                model_settings = self._load_model_settings(model_settings_path)\n                all_model_settings.append(model_settings)\n\n        # If there were no matches, try to load model from environment\n        if not all_model_settings:\n            # return default\n            model_settings = ModelSettings()\n            model_settings.parameters = ModelParameters()\n            all_model_settings.append(model_settings)\n\n        return all_model_settings\n\n    def _load_model_settings(self, model_settings_path: str) -> ModelSettings:\n        model_settings = ModelSettings.parse_file(model_settings_path)\n\n        if not model_settings.parameters:\n            model_settings.parameters = ModelParameters()\n\n        if not model_settings.parameters.uri:\n            # If not specified, default to its own folder\n            default_model_uri = os.path.dirname(model_settings_path)\n            model_settings.parameters.uri = default_model_uri\n\n        return model_settings\n\n    async def find(self, name: str) -> ModelSettings:\n        all_settings = await self.list()\n        for model_settings in all_settings:\n            if model_settings.name == name:\n                # TODO: Implement version policy\n                return model_settings\n\n        raise ModelNotFound(name)\n", "path": "mlserver/repository.py"}, {"content": "from typing import List, Optional\nfrom pydantic import BaseSettings, PyObject\n\nfrom .version import __version__\nfrom .types import MetadataTensor\n\nENV_PREFIX_SETTINGS = \"MLSERVER_\"\nENV_PREFIX_MODEL_SETTINGS = \"MLSERVER_MODEL_\"\n\n\nclass Settings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_SETTINGS\n\n    debug: bool = True\n\n    # Model repository folder\n    model_repository_root: str = \".\"\n    load_models_at_startup: bool = True\n\n    # Server metadata\n    server_name: str = \"mlserver\"\n    server_version: str = __version__\n    extensions: List[str] = []\n\n    # Server settings\n    host: str = \"0.0.0.0\"\n    http_port: int = 8080\n    grpc_port: int = 8081\n    grpc_workers: int = 10\n\n\nclass ModelParameters(BaseSettings):\n    \"\"\"\n    Parameters that apply only to a particular instance of a model.\n    This can include things like model weights.\n    The main difference with respect to ModelSettings is that parameters can\n    change on each instance (e.g. each version) of the model.\n    \"\"\"\n\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    uri: Optional[str] = None\n    version: Optional[str] = None\n    format: Optional[str] = None\n\n\nclass ModelSettings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    name: str\n\n    # Model metadata\n    platform: str = \"\"\n    versions: Optional[List[str]] = []\n    inputs: Optional[List[MetadataTensor]] = []\n    outputs: Optional[List[MetadataTensor]] = []\n\n    # Custom model class implementation\n    implementation: PyObject = \"mlserver.model.MLModel\"  # type: ignore\n\n    # Model parameters are meant to be set directly by the MLServer runtime.\n    # However, it's also possible to override them manually.\n    parameters: Optional[ModelParameters] = None\n", "path": "mlserver/settings.py"}], "after_files": [{"content": "import os\nimport glob\n\nfrom typing import List\n\nfrom .settings import ModelParameters, ModelSettings\nfrom .errors import ModelNotFound\n\nDEFAULT_MODEL_SETTINGS_FILENAME = \"model-settings.json\"\n\n\nclass ModelRepository:\n    \"\"\"\n    Model repository, responsible of the discovery of models which can be\n    loaded onto the model registry.\n    \"\"\"\n\n    def __init__(self, root: str = None):\n        self._root = root\n\n    async def list(self) -> List[ModelSettings]:\n        all_model_settings = []\n\n        # TODO: Use an async alternative for filesys ops\n        if self._root:\n            pattern = os.path.join(self._root, \"**\", DEFAULT_MODEL_SETTINGS_FILENAME)\n            matches = glob.glob(pattern, recursive=True)\n\n            for model_settings_path in matches:\n                model_settings = self._load_model_settings(model_settings_path)\n                all_model_settings.append(model_settings)\n\n        # If there were no matches, try to load model from environment\n        if not all_model_settings:\n            # return default\n            model_settings = ModelSettings()\n            model_settings.parameters = ModelParameters()\n            all_model_settings.append(model_settings)\n\n        return all_model_settings\n\n    def _load_model_settings(self, model_settings_path: str) -> ModelSettings:\n        model_settings = ModelSettings.parse_file(model_settings_path)\n\n        # TODO: Raise warning if name is different than folder's name\n        if not model_settings.name:\n            # If name not present, default to folder name\n            default_model_name = os.path.basename(os.path.dirname(model_settings_path))\n            model_settings.name = default_model_name\n\n        if not model_settings.parameters:\n            model_settings.parameters = ModelParameters()\n\n        if not model_settings.parameters.uri:\n            # If not specified, default to its own folder\n            default_model_uri = os.path.dirname(model_settings_path)\n            model_settings.parameters.uri = default_model_uri\n\n        return model_settings\n\n    async def find(self, name: str) -> ModelSettings:\n        all_settings = await self.list()\n        for model_settings in all_settings:\n            if model_settings.name == name:\n                # TODO: Implement version policy\n                return model_settings\n\n        raise ModelNotFound(name)\n", "path": "mlserver/repository.py"}, {"content": "from typing import List, Optional\nfrom pydantic import BaseSettings, PyObject\n\nfrom .version import __version__\nfrom .types import MetadataTensor\n\nENV_PREFIX_SETTINGS = \"MLSERVER_\"\nENV_PREFIX_MODEL_SETTINGS = \"MLSERVER_MODEL_\"\n\n\nclass Settings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_SETTINGS\n\n    debug: bool = True\n\n    # Model repository folder\n    model_repository_root: str = \".\"\n    load_models_at_startup: bool = True\n\n    # Server metadata\n    server_name: str = \"mlserver\"\n    server_version: str = __version__\n    extensions: List[str] = []\n\n    # Server settings\n    host: str = \"0.0.0.0\"\n    http_port: int = 8080\n    grpc_port: int = 8081\n    grpc_workers: int = 10\n\n\nclass ModelParameters(BaseSettings):\n    \"\"\"\n    Parameters that apply only to a particular instance of a model.\n    This can include things like model weights.\n    The main difference with respect to ModelSettings is that parameters can\n    change on each instance (e.g. each version) of the model.\n    \"\"\"\n\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    uri: Optional[str] = None\n    version: Optional[str] = None\n    format: Optional[str] = None\n\n\nclass ModelSettings(BaseSettings):\n    class Config:\n        env_prefix = ENV_PREFIX_MODEL_SETTINGS\n\n    name: str = \"\"\n\n    # Model metadata\n    platform: str = \"\"\n    versions: Optional[List[str]] = []\n    inputs: Optional[List[MetadataTensor]] = []\n    outputs: Optional[List[MetadataTensor]] = []\n\n    # Custom model class implementation\n    implementation: PyObject = \"mlserver.model.MLModel\"  # type: ignore\n\n    # Model parameters are meant to be set directly by the MLServer runtime.\n    # However, it's also possible to override them manually.\n    parameters: Optional[ModelParameters] = None\n", "path": "mlserver/settings.py"}]}