Repository: Lightning-Universe/lightning-flash

Issue:
Add required dependencies error message to `available_*` methods.
## 🐛 Bug

<!-- A clear and concise description of what the bug is. -->

### To Reproduce

Code to reproduce the behavior:

```python
from flash.image import KeypointDetector

print(len(KeypointDetector.available_backbones())) # Output: 0
print(len(KeypointDetector.available_heads())) # Output: 0
```

### Expected behavior

I'm not sure what are all the available backbones and heads for `KeypointDetector`. However, from the source code of [KeypointDector](https://lightning-flash.readthedocs.io/en/stable/_modules/flash/image/keypoint_detection/model.html#KeypointDetector) (see the excerpt below) there should be at least 1 available backbones and heads, respectively.

```python
backbone: Optional[str] = "resnet18_fpn",
head: Optional[str] = "keypoint_rcnn",
```

### Environment

 - PyTorch Version (e.g., 1.0): 1.7.1+cu110
 - OS (e.g., Linux): Ubuntu 20.04
 - How you installed PyTorch (`conda`, `pip`, source): `pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 -f https://download.pytorch.org/whl/torch_stable.html`
 - Build command you used (if compiling from source): NA
 - Python version: 3.8.10
 - CUDA/cuDNN version: 
 - GPU models and configuration: RTX3090
 - Any other relevant information: Flash version 0.6.0

### Additional context

<!-- Add any other context about the problem here. -->



Discussion:
Hey @martin0258 in order for the backbones to be available you would need to install `icevision` and `lightning-flash[image]`. So you could do the following:
```
pip install --upgrade icevision lightning-flash[image]
```

Hope that helps :smiley:
Thank you @ethanwharris! It's working after I ran `pip install icevision==0.8.0`. Below is the result

```python
In [1]: from flash.image import KeypointDetector

In [2]: KeypointDetector.available_backbones()
Out[2]: 
['mobilenet',
 'resnet101',
 'resnet101_fpn',
 'resnet152',
 'resnet152_fpn',
 'resnet18',
 'resnet18_fpn',
 'resnet34',
 'resnet34_fpn',
 'resnet50',
 'resnet50_fpn',
 'resnext101_32x8d',
 'resnext101_32x8d_fpn',
 'resnext50_32x4d_fpn',
 'wide_resnet101_2_fpn',
 'wide_resnet50_2_fpn']

In [3]: KeypointDetector.available_heads()
Out[3]: ['keypoint_rcnn']
```

Just FYI: I installed icevision 0.8.0 because the latest icevision isn't compatible with my existing PyTorch 1.7.1+cu110. Also, previously I have already installed `lightning-flash[image]` with `pip install 'lightning-flash[image]'`. Your command `pip install lightning-flash[image]` would cause error `zsh: no matches found: lightning-flash[image]`.

My last question: Is it documented somewhere? I mean the knowledge of `in order for the backbones and heads to be available we would need to install icevision and lightning-flash[image]`.
Hi @martin0258 glad you got it working! 

> My last question: Is it documented somewhere? I mean the knowledge of `in order for the backbones and heads to be available we would need to install icevision and lightning-flash[image]`.

Great question! It should have been, for other methods you would receive an error message letting you know what to install, but it looks like we missed it for these (we should eventually also add support for optional dependencies that would add some backbones but are not requied for the task to run). I'll leave this issue open as a bug report to add the message. Hope that helps :smiley:



Resolving patch:
diff --git a/flash/core/model.py b/flash/core/model.py
--- a/flash/core/model.py
+++ b/flash/core/model.py
@@ -14,6 +14,7 @@
 import functools
 import inspect
 import pickle
+import re
 from abc import ABCMeta
 from copy import deepcopy
 from importlib import import_module
@@ -267,11 +268,11 @@ def __new__(mcs, *args, **kwargs):
         result = ABCMeta.__new__(mcs, *args, **kwargs)
         if result.required_extras is not None:
             result.__init__ = requires(result.required_extras)(result.__init__)
-            load_from_checkpoint = getattr(result, "load_from_checkpoint", None)
-            if load_from_checkpoint is not None:
-                result.load_from_checkpoint = classmethod(
-                    requires(result.required_extras)(result.load_from_checkpoint.__func__)
-                )
+
+            patterns = ["load_from_checkpoint", "available_*"]  # must match classmethods only
+            regex = "(" + ")|(".join(patterns) + ")"
+            for attribute_name, attribute_value in filter(lambda x: re.match(regex, x[0]), inspect.getmembers(result)):
+                setattr(result, attribute_name, classmethod(requires(result.required_extras)(attribute_value.__func__)))
         return result
 
 


Test patch:
diff --git a/tests/core/test_model.py b/tests/core/test_model.py
--- a/tests/core/test_model.py
+++ b/tests/core/test_model.py
@@ -36,6 +36,7 @@
 from flash.core.utilities.imports import (
     _AUDIO_TESTING,
     _GRAPH_TESTING,
+    _IMAGE_AVAILABLE,
     _IMAGE_TESTING,
     _TABULAR_TESTING,
     _TEXT_TESTING,
@@ -317,6 +318,12 @@ class Foo(ImageClassifier):
     assert Foo.available_backbones() == {}
 
 
+@pytest.mark.skipif(_IMAGE_AVAILABLE, reason="image libraries are installed.")
+def test_available_backbones_raises():
+    with pytest.raises(ModuleNotFoundError, match="Required dependencies not available."):
+        _ = ImageClassifier.available_backbones()
+
+
 @ClassificationTask.lr_schedulers
 def custom_steplr_configuration_return_as_instance(optimizer):
     return torch.optim.lr_scheduler.StepLR(optimizer, step_size=10)