{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Quickstart\n",
    "\n",
    "## Using the Compute Service\n",
    "\n",
    "Using the notebook utilities provided by `evo-sdk-common`, we can easily interact with the Compute Service in a Jupyter notebook environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from evo.notebooks import ServiceManagerWidget\n",
    "\n",
    "manager = await ServiceManagerWidget.with_auth_code(\n",
    "    client_id=\"your-client-id\", cache_location=\"./notebook-data\"\n",
    ").login()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## JobClient\n",
    "\n",
    "The `JobClient` wraps endpoint functionality to provide a cohesive interface to the underlying API implementation.\n",
    "\n",
    "First we need an `APIConnector` and an `Environment` to scope the requests to a specific workspace within an organisation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "environment = manager.get_environment()  # Organization ID is in the environment.\n",
    "connector = manager.get_connector()  # The connector is used to authenticate requests."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Submit a Task\n",
    "\n",
    "The `JobClient` provides an asynchronous `submit` factory method to submit tasks to the Compute Service.\n",
    "The returned `JobClient` instance can be used to monitor the task status and retrieve the results.\n",
    "\n",
    "Tasks are referenced by `topic` and a human-readable `task` name.\n",
    "Required parameters are task-dependent, so task submissions accept any mapping as the `parameters` argument.\n",
    "\n",
    "The optional `result_type` argument can be used to specify the expected result type.\n",
    "The default is `dict`, which means job results will be returned as a python dictionary.\n",
    "Internally, `JobClient` uses a pydantic `TypeAdapter` to parse the job results into the specified type."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from evo.compute import JobClient\n",
    "\n",
    "break_ties = await JobClient.submit(\n",
    "    connector=connector,\n",
    "    org_id=environment.org_id,\n",
    "    topic=\"geostatistics\",\n",
    "    task=\"break-ties\",\n",
    "    parameters={\n",
    "        \"source\": {\n",
    "            \"type\": \"geoscience-object-reference\",\n",
    "            \"object_reference\": \"geoscience_object_ref\",\n",
    "            \"object_element\": [{\"type\": \"element\", \"path\": \"/cell_attributes/@name=attr-name\"}],\n",
    "        },\n",
    "        \"target\": {\n",
    "            \"type\": \"geoscience-object-reference\",\n",
    "            \"object_reference\": \"geoscience_object_ref\",\n",
    "            \"object_element\": [{\"type\": \"element\", \"path\": \"/cell_attributes/@name=attr-name\"}],\n",
    "        },\n",
    "        \"random_seed\": \"123456789\",\n",
    "    },\n",
    "    additional_headers={\"API-Preview\": \"opt-in\"},\n",
    "    result_type=dict,\n",
    ")\n",
    "print(break_ties)  # The Job status URL is used as the string representation of a job."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Get Job Status\n",
    "\n",
    "`JobClient.get_status()` returns the current status of the job."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "response = await break_ties.get_status()\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Get Job Results\n",
    "\n",
    "Once the job is completed, the results can be retrieved using `JobClient.get_results()`.\n",
    "\n",
    "If the job completed with an error, a `JobError` exception will be raised when calling `get_results()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "from evo.compute.exceptions import JobError, JobPendingError\n",
    "\n",
    "try:\n",
    "    results = await break_ties.get_results()\n",
    "except (JobPendingError, JobError) as e:\n",
    "    print(e)\n",
    "else:\n",
    "    print(json.dumps(results, indent=4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cancel a Job\n",
    "\n",
    "`JobClient.cancel()` can be used to request the cancellation of a running job.\n",
    "The job isn't always immediately cancelled and may take some time, so it's recommended to check the job status after calling `cancel()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "await break_ties.cancel()\n",
    "print(await break_ties.get_status())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Job Identifiers\n",
    "\n",
    "Sometimes it may be useful to serialize and deserialize job identifiers. The job status URL may be used for this purpose.\n",
    "\n",
    "An `APIConnector` instance is required to create a `JobClient` instance from a job status URL.\n",
    "The base URL of the `APIConnector` _MUST_ match the base URL of the job status URL.\n",
    "\n",
    "The `result_type` argument is the same as for `JobClient.submit()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "break_ties_copy = JobClient.from_url(\n",
    "    connector=connector,\n",
    "    url=break_ties.url,\n",
    "    result_type=dict,\n",
    ")\n",
    "print(break_ties_copy)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
