diff --git a/example_jobs/add.py b/example_jobs/add.py new file mode 100644 index 00000000..df669f5f --- /dev/null +++ b/example_jobs/add.py @@ -0,0 +1,10 @@ +# this code adds two numbers + +import time + +a = 123 +b = 123 + +time.sleep(60) + +print(a * 2 if a == b else a + b) diff --git a/example_jobs/complicated_addition.py b/example_jobs/complicated_addition.py new file mode 100644 index 00000000..6a2c8383 --- /dev/null +++ b/example_jobs/complicated_addition.py @@ -0,0 +1,28 @@ +# this is an absolute overkill for just adding two numbers but we will still do it + +from nbox import Instance +from pprint import pprint as peepee + +instance = Instance("GPT4NBX", url = "https://test-2.nimblebox.ai") +# instance = Instance.create("GPT4NBX", url = "https://test-2.nimblebox.ai") + +instance.compute_server.test("get") +instance.compute_server.get_files( + "post", {"dir_path": "/"}, verbose = True +) +out = instance.compute_server.run_script("post", {"script": "add.py"}, verbose = True) +print("RUN:") +peepee(out) +uid = out["uid"] + +out = instance.compute_server.get_script_status("post", {"uid": out["uid"]}, verbose = True) +print("STATUS:") +peepee(out) + +out = instance.compute_server.clear_jobs_db("get", verbose = True) +print("CLEAR:") +peepee(out) + +out = instance.compute_server.get_script_status("post", {"uid": uid}, verbose = True) +print("STATUS:") +peepee(out) diff --git a/example_jobs/simple_addition.py b/example_jobs/simple_addition.py index 89ff650c..01f52586 100644 --- a/example_jobs/simple_addition.py +++ b/example_jobs/simple_addition.py @@ -1,50 +1,11 @@ -# # this is an absolute overkill for just adding two numbers but we will -# # still do it - -import time - -from pprint import pprint as peepee +# this is an absolute overkill for just adding two numbers but we will still do it from nbox import Instance -from nbox.utils import nbox_session instance = Instance("GPT4NBX", url = "https://test-2.nimblebox.ai") # instance = Instance.create("GPT4NBX", url = "https://test-2.nimblebox.ai") -instance.start(True) -# instance("add.py") -# instance.stop() - -instance.compute_server.test("get").json() -instance.compute_server.get_files( - "post", {"dir_path": "/"}, verbose = True -).json() -out = instance.compute_server.run_script("post", {"script": "add.py"}, verbose = True).json() -print("RUN:") -peepee(out) -uid = out["uid"] - -out = instance.compute_server.get_script_status("post", {"uid": out["uid"]}, verbose = True).json() -print("STATUS:") -peepee(out) -out = instance.compute_server.clear_jobs_db("get", verbose = True).json() -print("CLEAR:") -peepee(out) - -out = instance.compute_server.get_script_status("post", {"uid": uid}, verbose = True).json() -print("STATUS:") -peepee(out) - -# class Sample(): -# def __init__(self): -# pass -# def __getattribute__(self, __name: str): -# print(__name) -# def __func(a, b): -# return a + b -# return __func - -# s = Sample() -# print(s.add) -# print(s.add(123, 123)) -# print(s.multiply(123, 123)) +instance.start(True) +my_uid = instance("add.py") +print("My UID:", my_uid) +instance(my_uid) diff --git a/nbox/jobs.py b/nbox/jobs.py index 2fea8011..914a5dae 100644 --- a/nbox/jobs.py +++ b/nbox/jobs.py @@ -27,12 +27,17 @@ def __repr__(self): return f"" def __getattr__(self, attr): + # https://stackoverflow.com/questions/3278077/difference-between-getattr-vs-getattribute def wrapper(method = "get", data = None, verbose = False): fn = getattr(nbox_session, method) url = f"{self.url}/{attr}" if verbose: logger.info(f"Calling {url}") - return fn(url, json = data) + r = fn(url, json = data) + if verbose: + logger.info(r.content.decode()) + r.raise_for_status() # good when server is good + return r.json() return wrapper @@ -133,8 +138,8 @@ def start(self, cpu_only = False, gpu_count = 1): if not self.state == "RUNNING": logger.info(f"Starting instance {self.instance_id}") - r = self.web_server.start_instance( - method = "post", + message = self.web_server.start_instance( + "post", data = { "instance_id": self.instance_id, "hw":"cpu" if cpu_only else "gpu", @@ -144,8 +149,7 @@ def start(self, cpu_only = False, gpu_count = 1): "gpuCount": gpu_count, } } - ) - message = r.json()["msg"] + )["msg"] if not message == "success": raise ValueError(message) @@ -164,9 +168,9 @@ def start(self, cpu_only = False, gpu_count = 1): # now the instance is running, we can open it, opening will assign a bunch of cookies and # then get us the exact location of the instance logger.info(f"Opening instance {self.instance_id}") - r = self.web_server.open_instance(method = "post", data = {"instance_id":self.instance_id}) - r.raise_for_status() - instance_url = r.json()["base_url"].lstrip("/").rstrip("/") + instance_url = self.web_server.open_instance( + "post", data = {"instance_id":self.instance_id} + )["base_url"].lstrip("/").rstrip("/") self.cs_url = f"{self.url}/{instance_url}/server" # create a subway @@ -175,42 +179,39 @@ def start(self, cpu_only = False, gpu_count = 1): # run a simple test and see if everything is working or not logger.info(f"Testing instance {self.instance_id}") - r = self.compute_server.test() - r.raise_for_status() - + self.compute_server.test() self.__opened = True - def __call__(self, path_or_func): + def __call__(self, path_or_func_or_uid): if not self.__opened: raise ValueError("Instance is not opened, please call .start() first") - if isinstance(path_or_func, str): - if path_or_func not in self.running_scripts: + if isinstance(path_or_func_or_uid, str): + if path_or_func_or_uid not in self.running_scripts: # this script is not running, so we will start it - logger.info(f"Running script {path_or_func} on instance {self.instance_id}") - r = self.compute_server.run_script(method = "post", data = {"script_path": path_or_func}) - r.raise_for_status() - message = r.json()["msg"] + logger.info(f"Running script {path_or_func_or_uid} on instance {self.instance_id}") + data = self.compute_server.run_script("post", data = {"script": path_or_func_or_uid}) + message = data["msg"] + self.running_scripts.append(data["uid"]) if not message == "success": raise ValueError(message) - self.running_scripts.append(path_or_func) + logger.info(f"Script {path_or_func_or_uid} started on instance {self.instance_id} with UID: {data['uid']}") + return data["uid"] else: # we already have this script running, so get the status of this script - logger.info(f"Getting status of script {path_or_func} on instance {self.instance_id}") - r = self.compute_server.get_script_status(method = "post", data = {"script": path_or_func}) - message = r.json()["msg"] - if not message == "script running": - raise ValueError(message) - elif "script not running" in message: - logger.info(f"Script {path_or_func} on instance {self.instance_id} is either completed or errored out.") + logger.info(f"Getting status of script {path_or_func_or_uid} on instance {self.instance_id}") + data = self.compute_server.get_script_status("post", data = {"uid": path_or_func_or_uid}) + if not data["msg"] == "success": + raise ValueError(data["msg"]) else: - raise ValueError(message) + status = "RUNNING" if data["status"] else "STOPPED" # /ERRORED + logger.info(f"Script {path_or_func_or_uid} on instance {self.instance_id} is {status}") - elif callable(path_or_func): + elif callable(path_or_func_or_uid): # this is the next generation power of nbox, we can pass a function to run on the instance (CasH step1) raise ValueError("callable methods are not supported yet, will be included in the next release") else: - raise ValueError("path_or_func must be a string or a function") + raise ValueError("path_or_func_or_uid must be a string or a function") def stop(self): if self.state == "STOPPED": @@ -218,8 +219,7 @@ def stop(self): return logger.info(f"Stopping instance {self.instance_id}") - r = self.web_server.stop_instance(method="post", data = {"instance_id":self.instance_id}) - message = r.json()["msg"] + message = self.web_server.stop_instance("post", data = {"instance_id":self.instance_id})["msg"] if not message == "success": raise ValueError(message) @@ -239,16 +239,13 @@ def delete(self, force = False): if self.__opened and not force: raise ValueError("Instance is still opened, please call .stop() first") - r = self.web_server.delete_instance(method = "post", data = {"instance_id":self.instance_id}) - r.raise_for_status() - message = r.json()["msg"] + message = self.web_server.delete_instance("post", data = {"instance_id":self.instance_id})["msg"] if not message == "success": raise ValueError(message) def update(self): - r = self.web_server.get_user_instances(method = "post", data = {"instance_id": self.instance_id}) - r.raise_for_status() - for k,v in r.json().items(): + out = self.web_server.get_user_instances("post", data = {"instance_id": self.instance_id}) + for k,v in out.items(): if k in self.useful_keys: setattr(self, k, v) - self.data = r.json() + self.data = out