We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Support importing model from subdirectories
This works:

```yaml
model: "predict.py:MyModel"
```

But this doesn't:

```yaml:
model: "mymodel/predict.py:MyModel"
```

It should.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `python/cog/predictor.py`
Content:
```
1 from abc import ABC, abstractmethod
2 import importlib
3 import os.path
4 from pathlib import Path
5 from typing import Dict, Any
6 
7 import yaml
8 
9 from .errors import ConfigDoesNotExist, PredictorNotSet
10 
11 
12 # TODO(andreas): handle directory input
13 # TODO(andreas): handle List[Dict[str, int]], etc.
14 # TODO(andreas): model-level documentation
15 
16 
17 class Predictor(ABC):
18     @abstractmethod
19     def setup(self):
20         pass
21 
22     @abstractmethod
23     def predict(self, **kwargs):
24         pass
25 
26     def get_type_signature(self):
27         """
28         Returns a dict describing the inputs of the model.
29         """
30         from .input import (
31             get_type_name,
32             UNSPECIFIED,
33         )
34 
35         inputs = []
36         if hasattr(self.predict, "_inputs"):
37             input_specs = self.predict._inputs
38             for spec in input_specs:
39                 arg: Dict[str, Any] = {
40                     "name": spec.name,
41                     "type": get_type_name(spec.type),
42                 }
43                 if spec.help:
44                     arg["help"] = spec.help
45                 if spec.default is not UNSPECIFIED:
46                     arg["default"] = str(spec.default)  # TODO: don't string this
47                 if spec.min is not None:
48                     arg["min"] = str(spec.min)  # TODO: don't string this
49                 if spec.max is not None:
50                     arg["max"] = str(spec.max)  # TODO: don't string this
51                 if spec.options is not None:
52                     arg["options"] = [str(o) for o in spec.options]
53                 inputs.append(arg)
54         return {"inputs": inputs}
55 
56 
57 def run_prediction(predictor, inputs, cleanup_functions):
58     """
59     Run the predictor on the inputs, and append resulting paths
60     to cleanup functions for removal.
61     """
62     result = predictor.predict(**inputs)
63     if isinstance(result, Path):
64         cleanup_functions.append(result.unlink)
65     return result
66 
67 
68 def load_predictor():
69     # Assumes the working directory is /src
70     config_path = os.path.abspath("cog.yaml")
71     try:
72         with open(config_path) as fh:
73             config = yaml.safe_load(fh)
74     except FileNotFoundError:
75         raise ConfigDoesNotExist(
76             f"Could not find {config_path}",
77         )
78 
79     if "predict" not in config:
80         raise PredictorNotSet(
81             "Can't run predictions: 'predict' option not found in cog.yaml"
82         )
83 
84     # TODO: handle predict scripts in subdirectories
85     predict_string = config["predict"]
86     module_name, class_name = predict_string.split(".py:", 1)
87     module = importlib.import_module(module_name)
88     predictor_class = getattr(module, class_name)
89     return predictor_class()
90
```
--- 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/python/cog/predictor.py b/python/cog/predictor.py
--- a/python/cog/predictor.py
+++ b/python/cog/predictor.py
@@ -81,9 +81,11 @@
             "Can't run predictions: 'predict' option not found in cog.yaml"
         )
 
-    # TODO: handle predict scripts in subdirectories
     predict_string = config["predict"]
-    module_name, class_name = predict_string.split(".py:", 1)
-    module = importlib.import_module(module_name)
+    module_path, class_name = predict_string.split(":", 1)
+    module_name = os.path.basename(module_path).split(".py", 1)[0]
+    spec = importlib.util.spec_from_file_location(module_name, module_path)
+    module = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(module)
     predictor_class = getattr(module, class_name)
     return predictor_class()

{"golden_diff": "diff --git a/python/cog/predictor.py b/python/cog/predictor.py\n--- a/python/cog/predictor.py\n+++ b/python/cog/predictor.py\n@@ -81,9 +81,11 @@\n             \"Can't run predictions: 'predict' option not found in cog.yaml\"\n         )\n \n-    # TODO: handle predict scripts in subdirectories\n     predict_string = config[\"predict\"]\n-    module_name, class_name = predict_string.split(\".py:\", 1)\n-    module = importlib.import_module(module_name)\n+    module_path, class_name = predict_string.split(\":\", 1)\n+    module_name = os.path.basename(module_path).split(\".py\", 1)[0]\n+    spec = importlib.util.spec_from_file_location(module_name, module_path)\n+    module = importlib.util.module_from_spec(spec)\n+    spec.loader.exec_module(module)\n     predictor_class = getattr(module, class_name)\n     return predictor_class()\n", "issue": "Support importing model from subdirectories\nThis works:\r\n\r\n```yaml\r\nmodel: \"predict.py:MyModel\"\r\n```\r\n\r\nBut this doesn't:\r\n\r\n```yaml:\r\nmodel: \"mymodel/predict.py:MyModel\"\r\n```\r\n\r\nIt should.\n", "before_files": [{"content": "from abc import ABC, abstractmethod\nimport importlib\nimport os.path\nfrom pathlib import Path\nfrom typing import Dict, Any\n\nimport yaml\n\nfrom .errors import ConfigDoesNotExist, PredictorNotSet\n\n\n# TODO(andreas): handle directory input\n# TODO(andreas): handle List[Dict[str, int]], etc.\n# TODO(andreas): model-level documentation\n\n\nclass Predictor(ABC):\n    @abstractmethod\n    def setup(self):\n        pass\n\n    @abstractmethod\n    def predict(self, **kwargs):\n        pass\n\n    def get_type_signature(self):\n        \"\"\"\n        Returns a dict describing the inputs of the model.\n        \"\"\"\n        from .input import (\n            get_type_name,\n            UNSPECIFIED,\n        )\n\n        inputs = []\n        if hasattr(self.predict, \"_inputs\"):\n            input_specs = self.predict._inputs\n            for spec in input_specs:\n                arg: Dict[str, Any] = {\n                    \"name\": spec.name,\n                    \"type\": get_type_name(spec.type),\n                }\n                if spec.help:\n                    arg[\"help\"] = spec.help\n                if spec.default is not UNSPECIFIED:\n                    arg[\"default\"] = str(spec.default)  # TODO: don't string this\n                if spec.min is not None:\n                    arg[\"min\"] = str(spec.min)  # TODO: don't string this\n                if spec.max is not None:\n                    arg[\"max\"] = str(spec.max)  # TODO: don't string this\n                if spec.options is not None:\n                    arg[\"options\"] = [str(o) for o in spec.options]\n                inputs.append(arg)\n        return {\"inputs\": inputs}\n\n\ndef run_prediction(predictor, inputs, cleanup_functions):\n    \"\"\"\n    Run the predictor on the inputs, and append resulting paths\n    to cleanup functions for removal.\n    \"\"\"\n    result = predictor.predict(**inputs)\n    if isinstance(result, Path):\n        cleanup_functions.append(result.unlink)\n    return result\n\n\ndef load_predictor():\n    # Assumes the working directory is /src\n    config_path = os.path.abspath(\"cog.yaml\")\n    try:\n        with open(config_path) as fh:\n            config = yaml.safe_load(fh)\n    except FileNotFoundError:\n        raise ConfigDoesNotExist(\n            f\"Could not find {config_path}\",\n        )\n\n    if \"predict\" not in config:\n        raise PredictorNotSet(\n            \"Can't run predictions: 'predict' option not found in cog.yaml\"\n        )\n\n    # TODO: handle predict scripts in subdirectories\n    predict_string = config[\"predict\"]\n    module_name, class_name = predict_string.split(\".py:\", 1)\n    module = importlib.import_module(module_name)\n    predictor_class = getattr(module, class_name)\n    return predictor_class()\n", "path": "python/cog/predictor.py"}], "after_files": [{"content": "from abc import ABC, abstractmethod\nimport importlib\nimport os.path\nfrom pathlib import Path\nfrom typing import Dict, Any\n\nimport yaml\n\nfrom .errors import ConfigDoesNotExist, PredictorNotSet\n\n\n# TODO(andreas): handle directory input\n# TODO(andreas): handle List[Dict[str, int]], etc.\n# TODO(andreas): model-level documentation\n\n\nclass Predictor(ABC):\n    @abstractmethod\n    def setup(self):\n        pass\n\n    @abstractmethod\n    def predict(self, **kwargs):\n        pass\n\n    def get_type_signature(self):\n        \"\"\"\n        Returns a dict describing the inputs of the model.\n        \"\"\"\n        from .input import (\n            get_type_name,\n            UNSPECIFIED,\n        )\n\n        inputs = []\n        if hasattr(self.predict, \"_inputs\"):\n            input_specs = self.predict._inputs\n            for spec in input_specs:\n                arg: Dict[str, Any] = {\n                    \"name\": spec.name,\n                    \"type\": get_type_name(spec.type),\n                }\n                if spec.help:\n                    arg[\"help\"] = spec.help\n                if spec.default is not UNSPECIFIED:\n                    arg[\"default\"] = str(spec.default)  # TODO: don't string this\n                if spec.min is not None:\n                    arg[\"min\"] = str(spec.min)  # TODO: don't string this\n                if spec.max is not None:\n                    arg[\"max\"] = str(spec.max)  # TODO: don't string this\n                if spec.options is not None:\n                    arg[\"options\"] = [str(o) for o in spec.options]\n                inputs.append(arg)\n        return {\"inputs\": inputs}\n\n\ndef run_prediction(predictor, inputs, cleanup_functions):\n    \"\"\"\n    Run the predictor on the inputs, and append resulting paths\n    to cleanup functions for removal.\n    \"\"\"\n    result = predictor.predict(**inputs)\n    if isinstance(result, Path):\n        cleanup_functions.append(result.unlink)\n    return result\n\n\ndef load_predictor():\n    # Assumes the working directory is /src\n    config_path = os.path.abspath(\"cog.yaml\")\n    try:\n        with open(config_path) as fh:\n            config = yaml.safe_load(fh)\n    except FileNotFoundError:\n        raise ConfigDoesNotExist(\n            f\"Could not find {config_path}\",\n        )\n\n    if \"predict\" not in config:\n        raise PredictorNotSet(\n            \"Can't run predictions: 'predict' option not found in cog.yaml\"\n        )\n\n    predict_string = config[\"predict\"]\n    module_path, class_name = predict_string.split(\":\", 1)\n    module_name = os.path.basename(module_path).split(\".py\", 1)[0]\n    spec = importlib.util.spec_from_file_location(module_name, module_path)\n    module = importlib.util.module_from_spec(spec)\n    spec.loader.exec_module(module)\n    predictor_class = getattr(module, class_name)\n    return predictor_class()\n", "path": "python/cog/predictor.py"}]}