From 7b145070503de84dedf09a6416c8d0c6b6ff16d9 Mon Sep 17 00:00:00 2001
From: zeryx <1892175+zeryx@users.noreply.github.com>
Date: Tue, 26 Jul 2022 05:47:32 -0300
Subject: [PATCH 1/3] added better error checking

---
 adk/mlops.py     | 10 +++++++++
 adk/modeldata.py | 55 ++++++++++++++++++++++++++----------------------
 2 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/adk/mlops.py b/adk/mlops.py
index 34d44e9..cd335a7 100644
--- a/adk/mlops.py
+++ b/adk/mlops.py
@@ -28,6 +28,16 @@ def __init__(self, api_token, path):
         if not os.path.exists(self.agent_dir):
             raise Exception("environment is not configured for mlops.\nPlease select a valid mlops enabled environment.")
 
+        if self.endpoint is None:
+            raise Exception("'no endpoint found, please add 'MLOPS_SERVICE_URL' environment variable, or create an "
+                            "mlops.json file")
+        if self.model_id is None:
+            raise Exception("no model_id found, please add 'MODEL_ID' environment variable, or create an mlops.json "
+                            "file")
+        if self.deployment_id is None:
+            raise Exception("no deployment_id found, please add 'DEPLOYMENT_ID' environment variable, or create an "
+                            "mlops.json file")
+
     def init(self):
         os.environ['MLOPS_DEPLOYMENT_ID'] = self.deployment_id
         os.environ['MLOPS_MODEL_ID'] = self.model_id
diff --git a/adk/modeldata.py b/adk/modeldata.py
index e2b49cd..893d28b 100644
--- a/adk/modeldata.py
+++ b/adk/modeldata.py
@@ -56,37 +56,42 @@ def initialize(self):
                 self.models[name] = FileData(real_hash, local_data_path)
 
     def get_model(self, model_name):
-        if model_name in self.models:
-            return self.models[model_name].file_path
-        elif len([optional for optional in self.manifest_data['optional_files'] if
-                  optional['name'] == model_name]) > 0:
-            self.find_optional_model(model_name)
-            return self.models[model_name].file_path
+        if self.available():
+            if model_name in self.models:
+                return self.models[model_name].file_path
+            elif len([optional for optional in self.manifest_data['optional_files'] if
+                      optional['name'] == model_name]) > 0:
+                self.find_optional_model(model_name)
+                return self.models[model_name].file_path
+            else:
+                raise Exception("model name " + model_name + " not found in manifest")
         else:
-            raise Exception("model name " + model_name + " not found in manifest")
+            raise Exception("unable to get model {}, model_manifest.json not found.".format(model_name))
 
     def find_optional_model(self, file_name):
-
-        found_models = [optional for optional in self.manifest_data['optional_files'] if
-                        optional['name'] == file_name]
-        if len(found_models) == 0:
-            raise Exception("file with name '" + file_name + "' not found in model manifest.")
-        model_info = found_models[0]
-        self.models[file_name] = {}
-        source_uri = model_info['source_uri']
-        fail_on_tamper = model_info.get("fail_on_tamper", False)
-        expected_hash = model_info.get('md5_checksum', None)
-        with self.client.file(source_uri).getFile() as f:
-            local_data_path = f.name
-        real_hash = md5_for_file(local_data_path)
-        if self.using_frozen:
-            if real_hash != expected_hash and fail_on_tamper:
-                raise Exception("Model File Mismatch for " + file_name +
-                                "\nexpected hash:  " + expected_hash + "\nreal hash: " + real_hash)
+        if self.available():
+            found_models = [optional for optional in self.manifest_data['optional_files'] if
+                            optional['name'] == file_name]
+            if len(found_models) == 0:
+                raise Exception("file with name '" + file_name + "' not found in model manifest.")
+            model_info = found_models[0]
+            self.models[file_name] = {}
+            source_uri = model_info['source_uri']
+            fail_on_tamper = model_info.get("fail_on_tamper", False)
+            expected_hash = model_info.get('md5_checksum', None)
+            with self.client.file(source_uri).getFile() as f:
+                local_data_path = f.name
+            real_hash = md5_for_file(local_data_path)
+            if self.using_frozen:
+                if real_hash != expected_hash and fail_on_tamper:
+                    raise Exception("Model File Mismatch for " + file_name +
+                                    "\nexpected hash:  " + expected_hash + "\nreal hash: " + real_hash)
+                else:
+                    self.models[file_name] = FileData(real_hash, local_data_path)
             else:
                 self.models[file_name] = FileData(real_hash, local_data_path)
         else:
-            self.models[file_name] = FileData(real_hash, local_data_path)
+            raise Exception("unable to get model {}, model_manifest.json not found.".format(model_name))
 
     def get_manifest(self):
         if os.path.exists(self.manifest_frozen_path):

From cb18c18cdeddde66ae72d8f5bcd542460fdb3d6a Mon Sep 17 00:00:00 2001
From: zeryx <1892175+zeryx@users.noreply.github.com>
Date: Tue, 26 Jul 2022 06:12:01 -0300
Subject: [PATCH 2/3] added better stack trace processing for both load time
 and runtime failures

---
 adk/io.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/adk/io.py b/adk/io.py
index be2045c..ccaabfc 100644
--- a/adk/io.py
+++ b/adk/io.py
@@ -57,7 +57,7 @@ def create_exception(exception, loading_exception=False):
     response = json.dumps({
         "error": {
             "message": str(exception),
-            "stacktrace": traceback.format_exc(),
+            "stacktrace": " ".join(traceback.format_exception(etype=type(exception), value=exception, tb=exception.__traceback__)),
             "error_type": error_type,
         }
     })

From 4c6b718d738f4ec6035e53712d96eaf8da3aca08 Mon Sep 17 00:00:00 2001
From: zeryx <1892175+zeryx@users.noreply.github.com>
Date: Tue, 26 Jul 2022 06:37:59 -0300
Subject: [PATCH 3/3] updated test case as we're now actually using
 stacktraces!

---
 tests/test_adk_local.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/tests/test_adk_local.py b/tests/test_adk_local.py
index 4b5585c..d4ed78a 100644
--- a/tests/test_adk_local.py
+++ b/tests/test_adk_local.py
@@ -135,17 +135,18 @@ def test_manifest_file_success(self):
         self.assertEqual(expected_output, actual_output)
 
     def test_manifest_file_tampered(self):
-        input = "Algorithmia"
+        input = 'Algorithmia'
         expected_output = {"error": {"error_type": "LoadingError",
                                      "message": "Model File Mismatch for squeezenet\n"
                                                 "expected hash:  f20b50b44fdef367a225d41f747a0963\n"
                                                 "real hash: 46a44d32d2c5c07f7f66324bef4c7266",
-                                     "stacktrace": "NoneType: None\n"}}
+                                     "stacktrace": ''}}
 
         actual_output = json.loads(self.execute_manifest_example(input, apply_successful_manifest_parsing,
                                                                  loading_with_manifest,
                                                                  manifest_path="tests/manifests/bad_model_manifest"
                                                                                ".json"))
+        actual_output['error']['stacktrace'] = ''
         self.assertEqual(expected_output, actual_output)
 
 
