Repository: augerai/a2ml
Issue: Python API calls should return the 404 rest api call error message from provider

If azureml returns a 404 on predict (and possibly on other functions as well), the error returned to the user doesn't indicate that a 404 happened:

```
AttributeError: 'AutoMLRun' object has no attribute '_client'
```

The logs show that a 404 actually happened:

```
[2020-06-20 19:10:47,678: WARNING/MainProcess] During handling of the above exception, another exception occurred:
[2020-06-20 19:10:47,678: WARNING/MainProcess] Traceback (most recent call last):
[2020-06-20 19:10:47,678: WARNING/MainProcess] File "/app/a2ml/api/utils/decorators.py", line 4, in wrapper
    return decorated(self, *args, **kwargs)
[2020-06-20 19:10:47,678: WARNING/MainProcess] File "/app/a2ml/api/utils/decorators.py", line 20, in wrapper
    return decorated(self, *args, **kwargs)
[2020-06-20 19:10:47,678: WARNING/MainProcess] File "/app/a2ml/api/azure/model.py", line 186, in predict
    self._predict_locally(ds.df, model_id, threshold) if locally else self._predict_remotely(ds.df, model_id, threshold)
[2020-06-20 19:10:47,678: WARNING/MainProcess] File "/app/a2ml/api/azure/model.py", line 334, in _predict_remotely
    remote_run = AutoMLRun(experiment = experiment, run_id = model_id)
[2020-06-20 19:10:47,678: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/train/automl/run.py", line 113, in __init__
    logging_utilities.log_traceback(e, self._get_logger(None))
[2020-06-20 19:10:47,678: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/train/automl/run.py", line 925, in _get_logger
    parent_run_uuid=self._run_dto.get("parent_run_uuid", None),
[2020-06-20 19:10:47,679: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_run_impl/run_base.py", line 99, in _run_dto
    run_dto = self._client.run_dto
[2020-06-20 19:10:47,679: WARNING/MainProcess] AttributeError: 'AutoMLRun' object has no attribute '_client'
[2020-06-20 19:10:47,679: INFO/MainProcess] [azure]  'AutoMLRun' object has no attribute '_client'
[2020-06-20 19:10:47,682: WARNING/MainProcess] Traceback (most recent call last):
[2020-06-20 19:10:47,683: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/workspace_client.py", line 86, in _execute_with_arguments
    return self._call_api(func, *args_list, **kwargs)
[2020-06-20 19:10:47,683: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/clientbase.py", line 230, in _call_api
    return self._execute_with_base_arguments(func, *args, **kwargs)
[2020-06-20 19:10:47,683: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/clientbase.py", line 306, in _execute_with_base_arguments
    back_off, total_retry, self._logger, func, _noop_reset, *args, **kwargs)
[2020-06-20 19:10:47,684: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/clientbase.py", line 321, in _execute_func_internal
    left_retry = cls._handle_retry(back_off, left_retry, total_retry, error, logger, func)
[2020-06-20 19:10:47,685: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/clientbase.py", line 370, in _handle_retry
    raise error
[2020-06-20 19:10:47,685: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/clientbase.py", line 319, in _execute_func_internal
    return func(*args, **kwargs)
[2020-06-20 19:10:47,685: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/operations/run_operations.py", line 302, in get
    raise models.ErrorResponseException(self._deserialize, response)
[2020-06-20 19:10:47,686: WARNING/MainProcess] azureml._restclient.models.error_response.ErrorResponseException: (UserError) Run AutoML7578738a70 was not found
[2020-06-20 19:10:47,686: WARNING/MainProcess] During handling of the above exception, another exception occurred:
[2020-06-20 19:10:47,686: WARNING/MainProcess] Traceback (most recent call last):
[2020-06-20 19:10:47,687: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/train/automl/run.py", line 111, in __init__
    **kwargs)
[2020-06-20 19:10:47,687: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/core/run.py", line 164, in __init__
    super(Run, self).__init__(experiment, run_id, outputs=outputs, **kwargs)
[2020-06-20 19:10:47,687: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_run_impl/run_base.py", line 69, in __init__
    _batch_upload_metrics=_batch_upload_metrics, flush_eager=flush_eager)
[2020-06-20 19:10:47,687: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_run_impl/run_history_facade.py", line 87, in __init__
    self.run_dto = run_dto if run_dto is not None else self.run.get_run()
[2020-06-20 19:10:47,688: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/run_client.py", line 74, in get_run
    return super(RunClient, self).get_run(self._run_id, **kwargs)
[2020-06-20 19:10:47,688: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/experiment_client.py", line 123, in get_run
    self._client.run.get, run_id=run_id, **kwargs)
[2020-06-20 19:10:47,688: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/experiment_client.py", line 252, in _execute_with_experiment_arguments
    return self._execute_with_arguments(func, copy.deepcopy(self._experiment_arguments), *args, **kwargs)
[2020-06-20 19:10:47,688: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_restclient/workspace_client.py", line 88, in _execute_with_arguments
    raise ServiceException(e)
[2020-06-20 19:10:47,689: WARNING/MainProcess] azureml._restclient.exceptions.ServiceException: ServiceException:
     Code: 404
     Message: (UserError) Run AutoML7578738a70 was not found
     Details:

     Headers: {
         "Date": "Sat, 20 Jun 2020 19:10:47 GMT",
         "Content-Type": "application/json; charset=utf-8",
         "Transfer-Encoding": "chunked",
         "Connection": "keep-alive",
         "Vary": "Accept-Encoding",
         "x-ms-response-type": "error",
         "x-ms-client-session-id": "",
         "Strict-Transport-Security": "max-age=15724800; includeSubDomains; preload",
         "Content-Encoding": "gzip"
     }
     InnerException: {
    "additional_properties": {
        "componentName": "run-history"
    },
    "error": {
        "additional_properties": {},
        "code": "UserError",
        "message": "Run AutoML7578738a70 was not found",
        "details_uri": null,
        "target": null,
        "details": [],
        "inner_error": {
            "additional_properties": {},
            "code": "NotFoundError",
            "inner_error": null
        },
        "debug_info": null,
        "message_format": null,
        "message_parameters": null,
        "reference_code": null
    },
    "correlation": {
        "operation": "5300c6c3092d214f97d9060995afa2d9",
        "request": "14dc36ce7fbc75ea"
    },
    "environment": "eastus2",
    "location": "eastus2",
    "time": {}
}
[2020-06-20 19:10:47,689: WARNING/MainProcess] During handling of the above exception, another exception occurred:
[2020-06-20 19:10:47,689: WARNING/MainProcess] Traceback (most recent call last):
[2020-06-20 19:10:47,690: WARNING/MainProcess] File "/app/a2ml/api/utils/provider_runner.py", line 74, in execute_provider
    result = getattr(provider, operation_name)(*args, **kwargs)
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/app/a2ml/api/azure/a2ml.py", line 33, in predict
    filename, model_id, threshold, locally, data, columns, output)
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/app/a2ml/api/utils/decorators.py", line 12, in wrapper
    raise exc
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/app/a2ml/api/utils/decorators.py", line 4, in wrapper
    return decorated(self, *args, **kwargs)
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/app/a2ml/api/utils/decorators.py", line 20, in wrapper
    return decorated(self, *args, **kwargs)
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/app/a2ml/api/azure/model.py", line 186, in predict
    self._predict_locally(ds.df, model_id, threshold) if locally else self._predict_remotely(ds.df, model_id, threshold)
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/app/a2ml/api/azure/model.py", line 334, in _predict_remotely
    remote_run = AutoMLRun(experiment = experiment, run_id = model_id)
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/train/automl/run.py", line 113, in __init__
    logging_utilities.log_traceback(e, self._get_logger(None))
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/train/automl/run.py", line 925, in _get_logger
    parent_run_uuid=self._run_dto.get("parent_run_uuid", None),
[2020-06-20 19:10:47,691: WARNING/MainProcess] File "/usr/local/lib/python3.7/site-packages/azureml/_run_impl/run_base.py", line 99, in _run_dto
    run_dto = self._client.run_dto
[2020-06-20 19:10:47,692: WARNING/MainProcess] AttributeError: 'AutoMLRun' object has no attribute '_client'
```

**Expected Behavior**
Return something that wraps the underlying provider exception which was this:

```
azureml._restclient.exceptions.ServiceException: ServiceException:
     Code: 404
     Message: (UserError) Run AutoML7578738a70 was not found
```

**Steps to Reproduce the Issue**
1. Call `predict()` method against a non-existent azure model


Changed files:
a2ml/api/utils/decorators.py

diff --git a/a2ml/api/utils/decorators.py b/a2ml/api/utils/decorators.py
index 0e68860..5a7d456 100644
--- a/a2ml/api/utils/decorators.py
+++ b/a2ml/api/utils/decorators.py
@@ -6,6 +6,10 @@ def error_handler(decorated):
             if self.ctx.debug:
                 import traceback
                 traceback.print_exc()
+
+            if "ServiceException" in str(type(exc)):
+                exc = Exception(exc.message)
+                
             self.ctx.log(str(exc))
             if not hasattr(self.ctx, 'not_reraise_exceptions')\\
                or not self.ctx.not_reraise_exceptions: