prompt: 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()
  
  ```
  
golden_diff: 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 = ""
  
verification_info: {"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"}]}