{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import shutil\n",
    "import pandas as pd\n",
    "from seeq import spy\n",
    "\n",
    "# Set the compatibility option so that you maximize the chance that SPy will remain compatible with your notebook/script\n",
    "spy.options.compatibility = 193"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Logged in to <strong>http://localhost:34216</strong> as <strong>agent_api_key</strong>.<br>Seeq Server Version: <strong>R66.0.0-SNAPSHOT</strong><br>Seeq SDK Module Version: <strong>66.0.0</strong> @ C:\\git\\crab\\sdk\\pypi\\seeq\\sdk<br>Seeq SPy Module Version: <strong>193.0</strong> @ C:\\git\\crab\\sdk\\pypi\\seeq\\spy</div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Log into Seeq Server if you're not using Seeq Data Lab:\n",
    "spy.login(url='http://localhost:34216', credentials_file='../credentials.key', force=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# spy.workbooks\n",
    "\n",
    "The `spy.workbooks` module provides functions for importing and exporting _workbooks_. A workbook is either a _Workbench Analysis_ (colored green in the Seeq user interface) or an _Organizer Topic_ (colored blue).\n",
    "\n",
    "This functionality is helpful to:\n",
    "\n",
    "- Move content between two Seeq servers\n",
    "- Manage content by exporting and committing to a version control system like Git\n",
    "\n",
    "The process typically starts by searching for some content that you have created in Seeq and exporting it. However, since this documentation needs some pre-built content to illustrate how it works, there is a pre-built-and-exported set of workbooks alongside this documentation notebook. So we'll go in a non-typical order of operations in this example."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Export Format\n",
    "\n",
    "When content is exported from Seeq, each workbook is encapsulated in its own folder, including all its worksheets, calculated item definitions and all dependencies, journal/document images and anything else that is necessary to import that data into another server. Content is written to disk as either JSON, HTML or image files as appropriate. References to datasource items are also catalogued during export and default _datasource maps_ are created that facilitate identification of equivalent signals/conditions/scalars on the destination system so that the imported content gets \"hooked up\" to the right data."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Main Actions\n",
    "\n",
    "There are five main operations you can perform on workbooks:\n",
    "\n",
    "- **search** for workbooks whose content you want to *pull*\n",
    "- **pull** those workbooks into `Workbook` in-memory Python objects\n",
    "- **save** the `Workbook` Python objects to disk in the export format described above\n",
    "- **load** `Workbook` Python objects from disk into memory\n",
    "- **push** in-memory `Workbook` Python objects into a Seeq Server\n",
    "\n",
    "As mentioned, we're going to go out-of-order for illustration purposes: _load_, _push_, _search_, _pull_, _save_."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Importing\n",
    "\n",
    "This set of documentation comes with an _Example Export_ folder that contains an Analysis and a Topic for illustration purposes. First we **load** it into memory:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Success</div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "[Workbook \"Shared >> Example Export >> Example Analysis\" (D833DC83-9A38-48DE-BF45-EB787E9E8375),\n",
       " Workbook \"Shared >> Example Export >> Example Topic\" (811B1488-297A-4FD2-AE7C-A1FE0E3B3641)]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "workbooks = spy.workbooks.load('Support Files/Example Export.zip')\n",
    "workbooks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that the workbook definitions are in memory, we can push them into Seeq."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Push successful</div><table class=\"tex2jax_ignore\" style=\"color:black;\"><tr><td style=\"background-color: #EEFFEE;\"></td><td style=\"background-color: #EEFFEE; text-align: left;\">ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">Name</td><td style=\"background-color: #EEFFEE; text-align: left;\">Type</td><td style=\"background-color: #EEFFEE; text-align: left;\">Workbook Type</td><td style=\"background-color: #EEFFEE; text-align: left;\">Count</td><td style=\"background-color: #EEFFEE; text-align: left;\">Time</td><td style=\"background-color: #EEFFEE; text-align: left;\">Errors</td><td style=\"background-color: #EEFFEE; text-align: left;\">Result</td><td style=\"background-color: #EEFFEE; text-align: left;\">Pushed Workbook ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">URL</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">D833DC83-9A38-48DE-BF45-EB787E9E8375</td><td style=\"text-align: left; vertical-align: top;\">Example Analysis</td><td style=\"text-align: left; vertical-align: top;\">Workbook</td><td style=\"text-align: left; vertical-align: top;\">Analysis</td><td style=\"text-align: right; vertical-align: top;\">53</td><td style=\"vertical-align: top;\">00:00:08.06</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE8-D6DD-7160-A051-F4E478C8BB98</td><td style=\"text-align: left; vertical-align: top;\"><a target=\"_blank\" href=\"http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43/workbook/0EF5BFE8-D6DD-7160-A051-F4E478C8BB98/worksheet/0EF5BFE9-0E4F-66C0-AE96-D304CB5D85FD\">link</a></td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">1</td><td style=\"text-align: left; vertical-align: top;\">811B1488-297A-4FD2-AE7C-A1FE0E3B3641</td><td style=\"text-align: left; vertical-align: top;\">Example Topic</td><td style=\"text-align: left; vertical-align: top;\">Workbook</td><td style=\"text-align: left; vertical-align: top;\">Topic</td><td style=\"text-align: right; vertical-align: top;\">5</td><td style=\"vertical-align: top;\">00:00:02.36</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE9-2365-75F0-8696-71CB08978490</td><td style=\"text-align: left; vertical-align: top;\"><a target=\"_blank\" href=\"http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43/workbook/0EF5BFE9-2365-75F0-8696-71CB08978490/worksheet/0EF5BFE9-2501-FF80-9669-4EE79188B762\">link</a></td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Type</th>\n",
       "      <th>Workbook Type</th>\n",
       "      <th>Count</th>\n",
       "      <th>Time</th>\n",
       "      <th>Errors</th>\n",
       "      <th>Result</th>\n",
       "      <th>Pushed Workbook ID</th>\n",
       "      <th>URL</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>D833DC83-9A38-48DE-BF45-EB787E9E8375</td>\n",
       "      <td>Example Analysis</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>Analysis</td>\n",
       "      <td>53</td>\n",
       "      <td>0:00:08.057459</td>\n",
       "      <td>0</td>\n",
       "      <td>Success</td>\n",
       "      <td>0EF5BFE8-D6DD-7160-A051-F4E478C8BB98</td>\n",
       "      <td>http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>811B1488-297A-4FD2-AE7C-A1FE0E3B3641</td>\n",
       "      <td>Example Topic</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>Topic</td>\n",
       "      <td>5</td>\n",
       "      <td>0:00:02.356468</td>\n",
       "      <td>0</td>\n",
       "      <td>Success</td>\n",
       "      <td>0EF5BFE9-2365-75F0-8696-71CB08978490</td>\n",
       "      <td>http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                     ID              Name      Type  \\\n",
       "0  D833DC83-9A38-48DE-BF45-EB787E9E8375  Example Analysis  Workbook   \n",
       "1  811B1488-297A-4FD2-AE7C-A1FE0E3B3641     Example Topic  Workbook   \n",
       "\n",
       "  Workbook Type Count            Time Errors   Result  \\\n",
       "0      Analysis    53  0:00:08.057459      0  Success   \n",
       "1         Topic     5  0:00:02.356468      0  Success   \n",
       "\n",
       "                     Pushed Workbook ID  \\\n",
       "0  0EF5BFE8-D6DD-7160-A051-F4E478C8BB98   \n",
       "1  0EF5BFE9-2365-75F0-8696-71CB08978490   \n",
       "\n",
       "                                                 URL  \n",
       "0  http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...  \n",
       "1  http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...  "
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spy.workbooks.push(workbooks, path='SPy Documentation Examples >> My Import', errors='raise')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The workbooks have been imported into Seeq in a _My Import_ folder with you as the owner. Refresh Seeq Workbench in your browser and take a look."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exporting\n",
    "\n",
    "In Seeq Workbench, try changing the name of the _Example Analysis_ workbook to something like _My First Analysis Export_ so that you can tell that your changes get exported.\n",
    "\n",
    "Now we will **search** for the workbooks we want to export. The syntax for a workbook search query is very similar to an item metadata search via `spy.search()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Query successful.</div><table class=\"tex2jax_ignore\" style=\"color:black;\"><tr><td style=\"background-color: #EEFFEE;\"></td><td style=\"background-color: #EEFFEE; text-align: left;\">Time</td><td style=\"background-color: #EEFFEE; text-align: left;\">Count</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">Results</td><td style=\"vertical-align: top;\">00:00:00.16</td><td style=\"text-align: right; vertical-align: top;\">2</td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Archived</th>\n",
       "      <th>Created At</th>\n",
       "      <th>Creator ID</th>\n",
       "      <th>Creator Name</th>\n",
       "      <th>Creator Username</th>\n",
       "      <th>ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Owner ID</th>\n",
       "      <th>Owner Name</th>\n",
       "      <th>Owner Username</th>\n",
       "      <th>Path</th>\n",
       "      <th>Pinned</th>\n",
       "      <th>Search Folder ID</th>\n",
       "      <th>Type</th>\n",
       "      <th>Updated At</th>\n",
       "      <th>Workbook Type</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>NaN</td>\n",
       "      <td>2024-08-16 18:37:12.438219600+00:00</td>\n",
       "      <td>0EF58FC1-C55E-F990-AB3A-A59ED4E0F416</td>\n",
       "      <td>Agent API Key</td>\n",
       "      <td>agent_api_key</td>\n",
       "      <td>0EF5BFE8-D6DD-7160-A051-F4E478C8BB98</td>\n",
       "      <td>Example Analysis</td>\n",
       "      <td>0EF58FC1-C55E-F990-AB3A-A59ED4E0F416</td>\n",
       "      <td>Agent API Key</td>\n",
       "      <td>agent_api_key</td>\n",
       "      <td>SPy Documentation Examples &gt;&gt; My Import</td>\n",
       "      <td>NaN</td>\n",
       "      <td>0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>2024-08-16 18:37:22.922668100+00:00</td>\n",
       "      <td>Analysis</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>NaN</td>\n",
       "      <td>2024-08-16 18:37:20.463834900+00:00</td>\n",
       "      <td>0EF58FC1-C55E-F990-AB3A-A59ED4E0F416</td>\n",
       "      <td>Agent API Key</td>\n",
       "      <td>agent_api_key</td>\n",
       "      <td>0EF5BFE9-2365-75F0-8696-71CB08978490</td>\n",
       "      <td>Example Topic</td>\n",
       "      <td>0EF58FC1-C55E-F990-AB3A-A59ED4E0F416</td>\n",
       "      <td>Agent API Key</td>\n",
       "      <td>agent_api_key</td>\n",
       "      <td>SPy Documentation Examples &gt;&gt; My Import</td>\n",
       "      <td>NaN</td>\n",
       "      <td>0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>2024-08-16 18:37:22.992447600+00:00</td>\n",
       "      <td>Topic</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Archived                          Created At  \\\n",
       "0       NaN 2024-08-16 18:37:12.438219600+00:00   \n",
       "1       NaN 2024-08-16 18:37:20.463834900+00:00   \n",
       "\n",
       "                             Creator ID   Creator Name Creator Username  \\\n",
       "0  0EF58FC1-C55E-F990-AB3A-A59ED4E0F416  Agent API Key    agent_api_key   \n",
       "1  0EF58FC1-C55E-F990-AB3A-A59ED4E0F416  Agent API Key    agent_api_key   \n",
       "\n",
       "                                     ID              Name  \\\n",
       "0  0EF5BFE8-D6DD-7160-A051-F4E478C8BB98  Example Analysis   \n",
       "1  0EF5BFE9-2365-75F0-8696-71CB08978490     Example Topic   \n",
       "\n",
       "                               Owner ID     Owner Name Owner Username  \\\n",
       "0  0EF58FC1-C55E-F990-AB3A-A59ED4E0F416  Agent API Key  agent_api_key   \n",
       "1  0EF58FC1-C55E-F990-AB3A-A59ED4E0F416  Agent API Key  agent_api_key   \n",
       "\n",
       "                                      Path  Pinned  \\\n",
       "0  SPy Documentation Examples >> My Import     NaN   \n",
       "1  SPy Documentation Examples >> My Import     NaN   \n",
       "\n",
       "                       Search Folder ID      Type  \\\n",
       "0  0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43  Workbook   \n",
       "1  0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43  Workbook   \n",
       "\n",
       "                           Updated At Workbook Type  \n",
       "0 2024-08-16 18:37:22.922668100+00:00      Analysis  \n",
       "1 2024-08-16 18:37:22.992447600+00:00         Topic  "
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "workbooks_df = spy.workbooks.search({\n",
    "    'Path': 'SPy Documentation Examples >> My Import'\n",
    "})\n",
    "\n",
    "workbooks_df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see, the `spy.workbooks.search()` command returns a metadata DataFrame with the properties of the workbooks. We can now use that to **pull**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Pull successful</div><table class=\"tex2jax_ignore\" style=\"color:black;\"><tr><td style=\"background-color: #EEFFEE;\"></td><td style=\"background-color: #EEFFEE; text-align: left;\">ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">Path</td><td style=\"background-color: #EEFFEE; text-align: left;\">Name</td><td style=\"background-color: #EEFFEE; text-align: left;\">Workbook Type</td><td style=\"background-color: #EEFFEE; text-align: right;\">Count</td><td style=\"background-color: #EEFFEE; text-align: right;\">Time</td><td style=\"background-color: #EEFFEE; text-align: right;\">Errors</td><td style=\"background-color: #EEFFEE; text-align: left;\">Result</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE8-D6DD-7160-A051-F4E478C8BB98</td><td style=\"text-align: left; vertical-align: top;\">SPy Documentation Examples >> My Import</td><td style=\"text-align: left; vertical-align: top;\">Example Analysis</td><td style=\"text-align: left; vertical-align: top;\">Analysis</td><td style=\"text-align: right; vertical-align: top;\">54</td><td style=\"vertical-align: top;\">00:00:02.76</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">1</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE9-2365-75F0-8696-71CB08978490</td><td style=\"text-align: left; vertical-align: top;\">SPy Documentation Examples >> My Import</td><td style=\"text-align: left; vertical-align: top;\">Example Topic</td><td style=\"text-align: left; vertical-align: top;\">Topic</td><td style=\"text-align: right; vertical-align: top;\">9</td><td style=\"vertical-align: top;\">00:00:02.12</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "[Workbook \"My Folder >> SPy Documentation Examples >> My Import >> Example Topic\" (0EF5BFE9-2365-75F0-8696-71CB08978490),\n",
       " Workbook \"My Folder >> SPy Documentation Examples >> My Import >> Example Analysis\" (0EF5BFE8-D6DD-7160-A051-F4E478C8BB98)]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "workbooks = spy.workbooks.pull(workbooks_df)\n",
    "workbooks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These are the same type of in-memory Python objects that we had when we executed `spy.workbooks.load()`. Now we can **save** them to disk:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Success</div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if os.path.exists('../My First Export'):\n",
    "    shutil.rmtree('../My First Export')\n",
    "    \n",
    "spy.workbooks.save(workbooks, '../My First Export')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the parent folder of this documentation notebook, you'll find a new _My First Export_ folder that contains similar files to the _Example Export_ folder that's part of the documentation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Inspecting Worksheets\n",
    "\n",
    "With the in-memory Python objects that result from `spy.workbooks.pull()` or `spy.workbooks.load()`, you can inspect the worksheets to see what is displayed on them. For example, let's look at what's in the Details Pane of the second worksheet of _Example Analysis_:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Name</th>\n",
       "      <th>ID</th>\n",
       "      <th>Type</th>\n",
       "      <th>Color</th>\n",
       "      <th>Line Style</th>\n",
       "      <th>Line Width</th>\n",
       "      <th>Lane</th>\n",
       "      <th>Samples Display</th>\n",
       "      <th>Axis Auto Scale</th>\n",
       "      <th>Axis Align</th>\n",
       "      <th>Axis Group</th>\n",
       "      <th>Axis Show</th>\n",
       "      <th>Axis Max</th>\n",
       "      <th>Axis Min</th>\n",
       "      <th>Selected</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Area A_Temperature</td>\n",
       "      <td>0EF58FC2-8206-77F0-8519-ECD251B886A6</td>\n",
       "      <td>Signal</td>\n",
       "      <td>#068C45</td>\n",
       "      <td>Solid</td>\n",
       "      <td>1.0</td>\n",
       "      <td>2.0</td>\n",
       "      <td>Line</td>\n",
       "      <td>True</td>\n",
       "      <td>Left</td>\n",
       "      <td>A</td>\n",
       "      <td>True</td>\n",
       "      <td>120.433655</td>\n",
       "      <td>66.77846</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Smooth Temperature</td>\n",
       "      <td>0EF5BFE8-FE0C-FD30-89CF-1F3F2A7AB3D7</td>\n",
       "      <td>Signal</td>\n",
       "      <td>#9D248F</td>\n",
       "      <td>Solid</td>\n",
       "      <td>2.5</td>\n",
       "      <td>2.0</td>\n",
       "      <td>Line</td>\n",
       "      <td>True</td>\n",
       "      <td>Left</td>\n",
       "      <td>A</td>\n",
       "      <td>True</td>\n",
       "      <td>120.433655</td>\n",
       "      <td>66.77846</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Area A_Compressor Power</td>\n",
       "      <td>0EF58FC2-8C7F-6290-BEE8-1BE39219249E</td>\n",
       "      <td>Signal</td>\n",
       "      <td>#CE561B</td>\n",
       "      <td>Solid</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Line</td>\n",
       "      <td>True</td>\n",
       "      <td>Left</td>\n",
       "      <td>C</td>\n",
       "      <td>True</td>\n",
       "      <td>38.162385</td>\n",
       "      <td>0.002923</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Area C_Temperature</td>\n",
       "      <td>0EF58FC2-8A5C-6490-85CE-FD5BD9A25B54</td>\n",
       "      <td>Signal</td>\n",
       "      <td>#00A2DD</td>\n",
       "      <td>Solid</td>\n",
       "      <td>1.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>Line</td>\n",
       "      <td>True</td>\n",
       "      <td>Left</td>\n",
       "      <td>D</td>\n",
       "      <td>True</td>\n",
       "      <td>96.598636</td>\n",
       "      <td>-100.0</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>High Power</td>\n",
       "      <td>0EF5BFE9-0A44-6440-B624-1423E93F32CA</td>\n",
       "      <td>Condition</td>\n",
       "      <td>#4055A3</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Temperature Limit</td>\n",
       "      <td>0EF5BFE9-0087-F970-A74C-7FA9F5EE54CE</td>\n",
       "      <td>Scalar</td>\n",
       "      <td>#E1498E</td>\n",
       "      <td>Dash</td>\n",
       "      <td>1.0</td>\n",
       "      <td>2.0</td>\n",
       "      <td>NaN</td>\n",
       "      <td>True</td>\n",
       "      <td>Left</td>\n",
       "      <td>A</td>\n",
       "      <td>True</td>\n",
       "      <td>120.433655</td>\n",
       "      <td>66.77846</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                      Name                                    ID       Type  \\\n",
       "0       Area A_Temperature  0EF58FC2-8206-77F0-8519-ECD251B886A6     Signal   \n",
       "1       Smooth Temperature  0EF5BFE8-FE0C-FD30-89CF-1F3F2A7AB3D7     Signal   \n",
       "2  Area A_Compressor Power  0EF58FC2-8C7F-6290-BEE8-1BE39219249E     Signal   \n",
       "3       Area C_Temperature  0EF58FC2-8A5C-6490-85CE-FD5BD9A25B54     Signal   \n",
       "4               High Power  0EF5BFE9-0A44-6440-B624-1423E93F32CA  Condition   \n",
       "5        Temperature Limit  0EF5BFE9-0087-F970-A74C-7FA9F5EE54CE     Scalar   \n",
       "\n",
       "     Color Line Style Line Width Lane Samples Display Axis Auto Scale  \\\n",
       "0  #068C45      Solid        1.0  2.0            Line            True   \n",
       "1  #9D248F      Solid        2.5  2.0            Line            True   \n",
       "2  #CE561B      Solid        1.0  1.0            Line            True   \n",
       "3  #00A2DD      Solid        1.0  3.0            Line            True   \n",
       "4  #4055A3        NaN        NaN  NaN             NaN             NaN   \n",
       "5  #E1498E       Dash        1.0  2.0             NaN            True   \n",
       "\n",
       "  Axis Align Axis Group Axis Show    Axis Max  Axis Min Selected  \n",
       "0       Left          A      True  120.433655  66.77846    False  \n",
       "1       Left          A      True  120.433655  66.77846    False  \n",
       "2       Left          C      True   38.162385  0.002923    False  \n",
       "3       Left          D      True   96.598636    -100.0    False  \n",
       "4        NaN        NaN       NaN         NaN       NaN    False  \n",
       "5       Left          A      True  120.433655  66.77846    False  "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "worksheet_items = workbooks['Example Analysis'].worksheets['Calculated Items'].display_items\n",
    "worksheet_items"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now you can call `spy.pull()` to pull data for the items in the worksheet."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Pull successful from <strong>2019-01-01 00:00:00+00:00</strong> to <strong>2019-01-02 00:00:00+00:00</strong></div><table class=\"tex2jax_ignore\" style=\"color:black;\"><tr><td style=\"background-color: #EEFFEE;\"></td><td style=\"background-color: #EEFFEE; text-align: left;\">ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">Type</td><td style=\"background-color: #EEFFEE; text-align: left;\">Name</td><td style=\"background-color: #EEFFEE; text-align: right;\">Time</td><td style=\"background-color: #EEFFEE; text-align: right;\">Count</td><td style=\"background-color: #EEFFEE; text-align: right;\">Pages</td><td style=\"background-color: #EEFFEE; text-align: left;\">Data Processed</td><td style=\"background-color: #EEFFEE; text-align: left;\">Result</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">0EF58FC2-8206-77F0-8519-ECD251B886A6</td><td style=\"text-align: left; vertical-align: top;\">Signal</td><td style=\"text-align: left; vertical-align: top;\">Area A_Temperature</td><td style=\"vertical-align: top;\">00:00:01.24</td><td style=\"text-align: right; vertical-align: top;\">97</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">11 KB</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">1</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE8-FE0C-FD30-89CF-1F3F2A7AB3D7</td><td style=\"text-align: left; vertical-align: top;\">Signal</td><td style=\"text-align: left; vertical-align: top;\">Smooth Temperature</td><td style=\"vertical-align: top;\">00:00:01.24</td><td style=\"text-align: right; vertical-align: top;\">97</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">16 KB</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">2</td><td style=\"text-align: left; vertical-align: top;\">0EF58FC2-8C7F-6290-BEE8-1BE39219249E</td><td style=\"text-align: left; vertical-align: top;\">Signal</td><td style=\"text-align: left; vertical-align: top;\">Area A_Compressor Power</td><td style=\"vertical-align: top;\">00:00:01.24</td><td style=\"text-align: right; vertical-align: top;\">97</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">11 KB</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">3</td><td style=\"text-align: left; vertical-align: top;\">0EF58FC2-8A5C-6490-85CE-FD5BD9A25B54</td><td style=\"text-align: left; vertical-align: top;\">Signal</td><td style=\"text-align: left; vertical-align: top;\">Area C_Temperature</td><td style=\"vertical-align: top;\">00:00:01.24</td><td style=\"text-align: right; vertical-align: top;\">97</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">11 KB</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">4</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE9-0A44-6440-B624-1423E93F32CA</td><td style=\"text-align: left; vertical-align: top;\">Condition</td><td style=\"text-align: left; vertical-align: top;\">High Power</td><td style=\"vertical-align: top;\">00:00:00.24</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">46 KB</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">5</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE9-0087-F970-A74C-7FA9F5EE54CE</td><td style=\"text-align: left; vertical-align: top;\">Scalar</td><td style=\"text-align: left; vertical-align: top;\">Temperature Limit</td><td style=\"vertical-align: top;\">00:00:01.48</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: right; vertical-align: top;\">357 KB</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Area A_Temperature</th>\n",
       "      <th>Smooth Temperature</th>\n",
       "      <th>Area A_Compressor Power</th>\n",
       "      <th>Area C_Temperature</th>\n",
       "      <th>High Power</th>\n",
       "      <th>Temperature Limit</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2019-01-01 00:00:00+00:00</th>\n",
       "      <td>93.861500</td>\n",
       "      <td>95.094408</td>\n",
       "      <td>39.189300</td>\n",
       "      <td>102.017778</td>\n",
       "      <td>1.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 00:15:00+00:00</th>\n",
       "      <td>95.364050</td>\n",
       "      <td>95.257065</td>\n",
       "      <td>39.842881</td>\n",
       "      <td>89.474636</td>\n",
       "      <td>1.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 00:30:00+00:00</th>\n",
       "      <td>95.056341</td>\n",
       "      <td>95.548184</td>\n",
       "      <td>39.949065</td>\n",
       "      <td>87.157081</td>\n",
       "      <td>1.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 00:45:00+00:00</th>\n",
       "      <td>96.938340</td>\n",
       "      <td>96.005686</td>\n",
       "      <td>39.424393</td>\n",
       "      <td>83.497438</td>\n",
       "      <td>1.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 01:00:00+00:00</th>\n",
       "      <td>97.057959</td>\n",
       "      <td>96.521943</td>\n",
       "      <td>39.326496</td>\n",
       "      <td>82.098203</td>\n",
       "      <td>1.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 23:00:00+00:00</th>\n",
       "      <td>72.263661</td>\n",
       "      <td>71.274814</td>\n",
       "      <td>0.002923</td>\n",
       "      <td>87.940288</td>\n",
       "      <td>0.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 23:15:00+00:00</th>\n",
       "      <td>72.065032</td>\n",
       "      <td>71.352077</td>\n",
       "      <td>0.002923</td>\n",
       "      <td>88.873322</td>\n",
       "      <td>0.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 23:30:00+00:00</th>\n",
       "      <td>71.991097</td>\n",
       "      <td>71.814958</td>\n",
       "      <td>0.002923</td>\n",
       "      <td>90.710400</td>\n",
       "      <td>0.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-01 23:45:00+00:00</th>\n",
       "      <td>72.166508</td>\n",
       "      <td>72.622069</td>\n",
       "      <td>0.002923</td>\n",
       "      <td>89.150583</td>\n",
       "      <td>0.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-02 00:00:00+00:00</th>\n",
       "      <td>73.689557</td>\n",
       "      <td>74.064988</td>\n",
       "      <td>0.002923</td>\n",
       "      <td>85.146067</td>\n",
       "      <td>0.0</td>\n",
       "      <td>120.433655</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>97 rows × 6 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                           Area A_Temperature  Smooth Temperature  \\\n",
       "2019-01-01 00:00:00+00:00           93.861500           95.094408   \n",
       "2019-01-01 00:15:00+00:00           95.364050           95.257065   \n",
       "2019-01-01 00:30:00+00:00           95.056341           95.548184   \n",
       "2019-01-01 00:45:00+00:00           96.938340           96.005686   \n",
       "2019-01-01 01:00:00+00:00           97.057959           96.521943   \n",
       "...                                       ...                 ...   \n",
       "2019-01-01 23:00:00+00:00           72.263661           71.274814   \n",
       "2019-01-01 23:15:00+00:00           72.065032           71.352077   \n",
       "2019-01-01 23:30:00+00:00           71.991097           71.814958   \n",
       "2019-01-01 23:45:00+00:00           72.166508           72.622069   \n",
       "2019-01-02 00:00:00+00:00           73.689557           74.064988   \n",
       "\n",
       "                           Area A_Compressor Power  Area C_Temperature  \\\n",
       "2019-01-01 00:00:00+00:00                39.189300          102.017778   \n",
       "2019-01-01 00:15:00+00:00                39.842881           89.474636   \n",
       "2019-01-01 00:30:00+00:00                39.949065           87.157081   \n",
       "2019-01-01 00:45:00+00:00                39.424393           83.497438   \n",
       "2019-01-01 01:00:00+00:00                39.326496           82.098203   \n",
       "...                                            ...                 ...   \n",
       "2019-01-01 23:00:00+00:00                 0.002923           87.940288   \n",
       "2019-01-01 23:15:00+00:00                 0.002923           88.873322   \n",
       "2019-01-01 23:30:00+00:00                 0.002923           90.710400   \n",
       "2019-01-01 23:45:00+00:00                 0.002923           89.150583   \n",
       "2019-01-02 00:00:00+00:00                 0.002923           85.146067   \n",
       "\n",
       "                           High Power  Temperature Limit  \n",
       "2019-01-01 00:00:00+00:00         1.0         120.433655  \n",
       "2019-01-01 00:15:00+00:00         1.0         120.433655  \n",
       "2019-01-01 00:30:00+00:00         1.0         120.433655  \n",
       "2019-01-01 00:45:00+00:00         1.0         120.433655  \n",
       "2019-01-01 01:00:00+00:00         1.0         120.433655  \n",
       "...                               ...                ...  \n",
       "2019-01-01 23:00:00+00:00         0.0         120.433655  \n",
       "2019-01-01 23:15:00+00:00         0.0         120.433655  \n",
       "2019-01-01 23:30:00+00:00         0.0         120.433655  \n",
       "2019-01-01 23:45:00+00:00         0.0         120.433655  \n",
       "2019-01-02 00:00:00+00:00         0.0         120.433655  \n",
       "\n",
       "[97 rows x 6 columns]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spy.pull(worksheet_items, start='2019-01-01T00:00:00', end='2019-01-02T00:00:00')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that if you just wanted the full metadata for the items, you could execute `spy.search(worksheet_items[['ID']])`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Manipulating Worksheets\n",
    "\n",
    "In the example above, you saw how we can inspect the items that are displayed on the worksheet by accessing the `display_items` attribute on the worksheet object, which is a Pandas DataFrame.\n",
    "\n",
    "You can make changes by manipulating this DataFrame as shown below. Documentation on the various attributes of a worksheet is available in the [spy.workbooks.AnalysisWorksheet](https://python-docs.seeq.com/reference/submodules/workbooks.html#seeq.spy.workbooks.AnalysisWorksheet) online documentation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Query successful</div><table class=\"tex2jax_ignore\" style=\"color:black;\"><tr><td style=\"background-color: #EEFFEE;\"></td><td style=\"background-color: #EEFFEE; text-align: left;\">Datasource Name</td><td style=\"background-color: #EEFFEE; text-align: left;\">Name</td><td style=\"background-color: #EEFFEE; text-align: right;\">Time</td><td style=\"background-color: #EEFFEE; text-align: right;\">Count</td><td style=\"background-color: #EEFFEE; text-align: right;\">Pages</td><td style=\"background-color: #EEFFEE; text-align: left;\">Result</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Example Data</td><td style=\"text-align: left; vertical-align: top;\">Area E_Temperature</td><td style=\"vertical-align: top;\">00:00:00.04</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: right; vertical-align: top;\">1</td><td style=\"text-align: left; vertical-align: top;\">Success</td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Name</th>\n",
       "      <th>ID</th>\n",
       "      <th>Type</th>\n",
       "      <th>Color</th>\n",
       "      <th>Line Style</th>\n",
       "      <th>Line Width</th>\n",
       "      <th>Lane</th>\n",
       "      <th>Samples Display</th>\n",
       "      <th>Axis Auto Scale</th>\n",
       "      <th>Axis Align</th>\n",
       "      <th>Axis Group</th>\n",
       "      <th>Axis Show</th>\n",
       "      <th>Axis Max</th>\n",
       "      <th>Axis Min</th>\n",
       "      <th>Selected</th>\n",
       "      <th>Value Unit Of Measure</th>\n",
       "      <th>Datasource Name</th>\n",
       "      <th>Archived</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Area A_Temperature</td>\n",
       "      <td>9564A6B8-8A8F-4F6D-AC63-00EA38962B7A</td>\n",
       "      <td>Signal</td>\n",
       "      <td>#E1498E</td>\n",
       "      <td>Short Dash</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Line</td>\n",
       "      <td>False</td>\n",
       "      <td>Left</td>\n",
       "      <td>A</td>\n",
       "      <td>True</td>\n",
       "      <td>96.651042</td>\n",
       "      <td>69.006356</td>\n",
       "      <td>False</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Area A_Optimizer</td>\n",
       "      <td>47D091C1-1780-4EA0-BD54-AA6E13213EB8</td>\n",
       "      <td>Signal</td>\n",
       "      <td>#FF0000</td>\n",
       "      <td>Solid</td>\n",
       "      <td>1.0</td>\n",
       "      <td>2.0</td>\n",
       "      <td>Line</td>\n",
       "      <td>False</td>\n",
       "      <td>Left</td>\n",
       "      <td>B</td>\n",
       "      <td>True</td>\n",
       "      <td>6.60435</td>\n",
       "      <td>0.0</td>\n",
       "      <td>False</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Area E_Temperature</td>\n",
       "      <td>0EF58FC2-8D14-7160-9EE1-1EC3CA6EFB2C</td>\n",
       "      <td>Signal</td>\n",
       "      <td>#00FF00</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>2.0</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>D</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>°F</td>\n",
       "      <td>Example Data</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                 Name                                    ID    Type    Color  \\\n",
       "0  Area A_Temperature  9564A6B8-8A8F-4F6D-AC63-00EA38962B7A  Signal  #E1498E   \n",
       "1    Area A_Optimizer  47D091C1-1780-4EA0-BD54-AA6E13213EB8  Signal  #FF0000   \n",
       "2  Area E_Temperature  0EF58FC2-8D14-7160-9EE1-1EC3CA6EFB2C  Signal  #00FF00   \n",
       "\n",
       "   Line Style Line Width Lane Samples Display Axis Auto Scale Axis Align  \\\n",
       "0  Short Dash        1.0  1.0            Line           False       Left   \n",
       "1       Solid        1.0  2.0            Line           False       Left   \n",
       "2         NaN        NaN  2.0             NaN             NaN        NaN   \n",
       "\n",
       "  Axis Group Axis Show   Axis Max   Axis Min Selected Value Unit Of Measure  \\\n",
       "0          A      True  96.651042  69.006356    False                   NaN   \n",
       "1          B      True    6.60435        0.0    False                   NaN   \n",
       "2          D       NaN        NaN        NaN      NaN                    °F   \n",
       "\n",
       "  Datasource Name Archived  \n",
       "0             NaN      NaN  \n",
       "1             NaN      NaN  \n",
       "2    Example Data    False  "
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "workbooks = spy.workbooks.load('Support Files/Example Export.zip')\n",
    "\n",
    "worksheet = workbooks['Example Analysis'].worksheets['Details Pane']\n",
    "\n",
    "# Copy this into a variable where each row is indexed by Name for easy manipulation\n",
    "display_items = worksheet.display_items.set_index('Name')\n",
    "\n",
    "# Change Area A_Optimizer color to red\n",
    "display_items.at['Area A_Optimizer', 'Color'] = '#FF0000'\n",
    "\n",
    "# Change Area A_Temperature line style\n",
    "display_items.at['Area A_Temperature', 'Line Style'] = 'Short Dash'\n",
    "\n",
    "# Remove Area A_Compressor Stage\n",
    "display_items = display_items[~(display_items.index == 'Area A_Compressor Stage')]\n",
    "\n",
    "# Add Area E_Temperature\n",
    "area_e_temperature = spy.search({'Datasource Name': 'Example Data', 'Name': 'Area E_Temperature'}).set_index('Name')\n",
    "area_e_temperature.at['Area E_Temperature', 'Color'] = '#00FF00'\n",
    "area_e_temperature.at['Area E_Temperature', 'Lane'] = 2\n",
    "display_items = pd.concat([display_items, area_e_temperature])\n",
    "\n",
    "# Reset the index since the worksheet expects a Name column, then assign the manipulated DataFrame to the worksheet\n",
    "worksheet.display_items = display_items.reset_index()\n",
    "worksheet.display_items"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now push to the server and click the link to observe:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Push successful</div><table class=\"tex2jax_ignore\" style=\"color:black;\"><tr><td style=\"background-color: #EEFFEE;\"></td><td style=\"background-color: #EEFFEE; text-align: left;\">ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">Name</td><td style=\"background-color: #EEFFEE; text-align: left;\">Type</td><td style=\"background-color: #EEFFEE; text-align: left;\">Workbook Type</td><td style=\"background-color: #EEFFEE; text-align: left;\">Count</td><td style=\"background-color: #EEFFEE; text-align: left;\">Time</td><td style=\"background-color: #EEFFEE; text-align: left;\">Errors</td><td style=\"background-color: #EEFFEE; text-align: left;\">Result</td><td style=\"background-color: #EEFFEE; text-align: left;\">Pushed Workbook ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">URL</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">D833DC83-9A38-48DE-BF45-EB787E9E8375</td><td style=\"text-align: left; vertical-align: top;\">Example Analysis</td><td style=\"text-align: left; vertical-align: top;\">Workbook</td><td style=\"text-align: left; vertical-align: top;\">Analysis</td><td style=\"text-align: right; vertical-align: top;\">54</td><td style=\"vertical-align: top;\">00:00:04.47</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE8-D6DD-7160-A051-F4E478C8BB98</td><td style=\"text-align: left; vertical-align: top;\"><a target=\"_blank\" href=\"http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43/workbook/0EF5BFE8-D6DD-7160-A051-F4E478C8BB98/worksheet/0EF5BFE9-0E4F-66C0-AE96-D304CB5D85FD\">link</a></td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">1</td><td style=\"text-align: left; vertical-align: top;\">811B1488-297A-4FD2-AE7C-A1FE0E3B3641</td><td style=\"text-align: left; vertical-align: top;\">Example Topic</td><td style=\"text-align: left; vertical-align: top;\">Workbook</td><td style=\"text-align: left; vertical-align: top;\">Topic</td><td style=\"text-align: right; vertical-align: top;\">5</td><td style=\"vertical-align: top;\">00:00:01.71</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFE9-2365-75F0-8696-71CB08978490</td><td style=\"text-align: left; vertical-align: top;\"><a target=\"_blank\" href=\"http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD-794A2FED4C43/workbook/0EF5BFE9-2365-75F0-8696-71CB08978490/worksheet/0EF5BFE9-2501-FF80-9669-4EE79188B762\">link</a></td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Type</th>\n",
       "      <th>Workbook Type</th>\n",
       "      <th>Count</th>\n",
       "      <th>Time</th>\n",
       "      <th>Errors</th>\n",
       "      <th>Result</th>\n",
       "      <th>Pushed Workbook ID</th>\n",
       "      <th>URL</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>D833DC83-9A38-48DE-BF45-EB787E9E8375</td>\n",
       "      <td>Example Analysis</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>Analysis</td>\n",
       "      <td>54</td>\n",
       "      <td>0:00:04.468733</td>\n",
       "      <td>0</td>\n",
       "      <td>Success</td>\n",
       "      <td>0EF5BFE8-D6DD-7160-A051-F4E478C8BB98</td>\n",
       "      <td>http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>811B1488-297A-4FD2-AE7C-A1FE0E3B3641</td>\n",
       "      <td>Example Topic</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>Topic</td>\n",
       "      <td>5</td>\n",
       "      <td>0:00:01.705311</td>\n",
       "      <td>0</td>\n",
       "      <td>Success</td>\n",
       "      <td>0EF5BFE9-2365-75F0-8696-71CB08978490</td>\n",
       "      <td>http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                     ID              Name      Type  \\\n",
       "0  D833DC83-9A38-48DE-BF45-EB787E9E8375  Example Analysis  Workbook   \n",
       "1  811B1488-297A-4FD2-AE7C-A1FE0E3B3641     Example Topic  Workbook   \n",
       "\n",
       "  Workbook Type Count            Time Errors   Result  \\\n",
       "0      Analysis    54  0:00:04.468733      0  Success   \n",
       "1         Topic     5  0:00:01.705311      0  Success   \n",
       "\n",
       "                     Pushed Workbook ID  \\\n",
       "0  0EF5BFE8-D6DD-7160-A051-F4E478C8BB98   \n",
       "1  0EF5BFE9-2365-75F0-8696-71CB08978490   \n",
       "\n",
       "                                                 URL  \n",
       "0  http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...  \n",
       "1  http://localhost:34216/0EF5BFE8-D5DA-64C0-85AD...  "
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spy.workbooks.push(workbooks, path='SPy Documentation Examples >> My Import', errors='raise')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Re-importing and Labels\n",
    "\n",
    "If you **push** a set of workbooks more than once, then by default you will simply overwrite the existing workbooks with the saved content. This can be useful when you are \"backing up\" content to disk, perhaps for the purposes of version control.\n",
    "\n",
    "You can choose to **push** and supply a _label_, which will create a separate copy of all of the imported items instead of modifying the existing ones. This is useful when you want to import something that you are iterating on prior to affecting the \"published\" version. For example, let's push our workbooks with the label of `In Development`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"background-color: #EEFFEE;color:black; text-align: left;\">Push successful</div><table class=\"tex2jax_ignore\" style=\"color:black;\"><tr><td style=\"background-color: #EEFFEE;\"></td><td style=\"background-color: #EEFFEE; text-align: left;\">ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">Name</td><td style=\"background-color: #EEFFEE; text-align: left;\">Type</td><td style=\"background-color: #EEFFEE; text-align: left;\">Workbook Type</td><td style=\"background-color: #EEFFEE; text-align: left;\">Count</td><td style=\"background-color: #EEFFEE; text-align: left;\">Time</td><td style=\"background-color: #EEFFEE; text-align: left;\">Errors</td><td style=\"background-color: #EEFFEE; text-align: left;\">Result</td><td style=\"background-color: #EEFFEE; text-align: left;\">Pushed Workbook ID</td><td style=\"background-color: #EEFFEE; text-align: left;\">URL</td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">D833DC83-9A38-48DE-BF45-EB787E9E8375</td><td style=\"text-align: left; vertical-align: top;\">Example Analysis</td><td style=\"text-align: left; vertical-align: top;\">Workbook</td><td style=\"text-align: left; vertical-align: top;\">Analysis</td><td style=\"text-align: right; vertical-align: top;\">53</td><td style=\"vertical-align: top;\">00:00:03.54</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFEA-64D4-FF80-831F-74F857353197</td><td style=\"text-align: left; vertical-align: top;\"><a target=\"_blank\" href=\"http://localhost:34216/0EF5BFEA-63CF-FBD0-80F4-91A94FFBE4DA/workbook/0EF5BFEA-64D4-FF80-831F-74F857353197/worksheet/0EF5BFEA-7775-6090-852C-108DC39D6A20\">link</a></td></tr><tr style=\"background-color: #EEFFEE;\"><td style=\"vertical-align: top;\">1</td><td style=\"text-align: left; vertical-align: top;\">811B1488-297A-4FD2-AE7C-A1FE0E3B3641</td><td style=\"text-align: left; vertical-align: top;\">Example Topic</td><td style=\"text-align: left; vertical-align: top;\">Workbook</td><td style=\"text-align: left; vertical-align: top;\">Topic</td><td style=\"text-align: right; vertical-align: top;\">5</td><td style=\"vertical-align: top;\">00:00:00.64</td><td style=\"text-align: right; vertical-align: top;\">0</td><td style=\"text-align: left; vertical-align: top;\">Success</td><td style=\"text-align: left; vertical-align: top;\">0EF5BFEA-864E-64E0-89D3-9DB0E25804C1</td><td style=\"text-align: left; vertical-align: top;\"><a target=\"_blank\" href=\"http://localhost:34216/0EF5BFEA-63CF-FBD0-80F4-91A94FFBE4DA/workbook/0EF5BFEA-864E-64E0-89D3-9DB0E25804C1/worksheet/0EF5BFEA-878B-FB00-A1C0-6C7BAC20B64C\">link</a></td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ID</th>\n",
       "      <th>Name</th>\n",
       "      <th>Type</th>\n",
       "      <th>Workbook Type</th>\n",
       "      <th>Count</th>\n",
       "      <th>Time</th>\n",
       "      <th>Errors</th>\n",
       "      <th>Result</th>\n",
       "      <th>Pushed Workbook ID</th>\n",
       "      <th>URL</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>D833DC83-9A38-48DE-BF45-EB787E9E8375</td>\n",
       "      <td>Example Analysis</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>Analysis</td>\n",
       "      <td>53</td>\n",
       "      <td>0:00:03.537614</td>\n",
       "      <td>0</td>\n",
       "      <td>Success</td>\n",
       "      <td>0EF5BFEA-64D4-FF80-831F-74F857353197</td>\n",
       "      <td>http://localhost:34216/0EF5BFEA-63CF-FBD0-80F4...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>811B1488-297A-4FD2-AE7C-A1FE0E3B3641</td>\n",
       "      <td>Example Topic</td>\n",
       "      <td>Workbook</td>\n",
       "      <td>Topic</td>\n",
       "      <td>5</td>\n",
       "      <td>0:00:00.644468</td>\n",
       "      <td>0</td>\n",
       "      <td>Success</td>\n",
       "      <td>0EF5BFEA-864E-64E0-89D3-9DB0E25804C1</td>\n",
       "      <td>http://localhost:34216/0EF5BFEA-63CF-FBD0-80F4...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                     ID              Name      Type  \\\n",
       "0  D833DC83-9A38-48DE-BF45-EB787E9E8375  Example Analysis  Workbook   \n",
       "1  811B1488-297A-4FD2-AE7C-A1FE0E3B3641     Example Topic  Workbook   \n",
       "\n",
       "  Workbook Type Count            Time Errors   Result  \\\n",
       "0      Analysis    53  0:00:03.537614      0  Success   \n",
       "1         Topic     5  0:00:00.644468      0  Success   \n",
       "\n",
       "                     Pushed Workbook ID  \\\n",
       "0  0EF5BFEA-64D4-FF80-831F-74F857353197   \n",
       "1  0EF5BFEA-864E-64E0-89D3-9DB0E25804C1   \n",
       "\n",
       "                                                 URL  \n",
       "0  http://localhost:34216/0EF5BFEA-63CF-FBD0-80F4...  \n",
       "1  http://localhost:34216/0EF5BFEA-63CF-FBD0-80F4...  "
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "workbooks = spy.workbooks.load('Support Files/Example Export.zip')\n",
    "\n",
    "spy.workbooks.push(workbooks, path='SPy Documentation Examples >> My Development Folder', label='In Development')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you refresh Seeq Workbench, you'll notice that there is now a _My Development Folder_ and a separate copy of the Topic and Analysis that is independent of the original -- including all calculated items.\n",
    "\n",
    "Pushing with the same value for the `label` argument will overwrite the content for that label. Change the label again if you want yet another separate copy."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Mapping Items\n",
    "\n",
    "Sometimes you will have workbooks that are built upon a set of items (signals, conditions, scalars etc) and you would like to programmatically replace that set of items with a different set. For example, perhaps some of your workbooks are built using tags from an on-premise plant historian and you'd like to to switch to using the enterprise historian in the cloud.\n",
    "\n",
    "In order to achieve this, you must create a _Datasource Map Override_ folder, populate it with modified Datasource Map files, and then reference it via the `spy.workbooks.push(datasource_map_folder=<folder>)` argument.\n",
    "\n",
    "When you pull a set of workbooks and save them to disk, there will be a series of files in the save location that start with `Datasource_Map_`, one for each datasource that (any of) the workbooks touch. If you want to \"re-route\" any of the items in those datasources, copy the appropriate datasource map files to a new folder location and then edit them with a text editor. Note that Seeq Data Lab includes an editor:\n",
    "\n",
    "- In Advanced Mode, right-click on a file and select **Open With > Editor**.\n",
    "- In Non-Advanced Mode, click the checkbox to the left of the file and select **Edit** from the top set of action buttons."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tweaking the Datasource Map\n",
    "\n",
    "Each Datasource Map file is in the JSON format. Here's what the `Datasource_Map_Time Series CSV Files_Example Data_Example Data` looks like:\n",
    "\n",
    "```\n",
    "{\n",
    "    \"Datasource Class\": \"Time Series CSV Files\",\n",
    "    \"Datasource ID\": \"Example Data\",\n",
    "    \"Datasource Name\": \"Example Data\",\n",
    "    \"Item-Level Map Files\": [],\n",
    "    \"RegEx-Based Maps\": [\n",
    "        {\n",
    "            \"Old\": {\n",
    "                \"Type\": \"(?<type>.*)\",\n",
    "                \"Datasource Class\": \"Time Series CSV Files\",\n",
    "                \"Datasource Name\": \"Example Data\",\n",
    "                \"Data ID\": \"(?<data_id>.*)\"\n",
    "            },\n",
    "            \"New\": {\n",
    "                \"Type\": \"${type}\",\n",
    "                \"Datasource Class\": \"Time Series CSV Files\",\n",
    "                \"Datasource Name\": \"Example Data\",\n",
    "                \"Data ID\": \"${data_id}\"\n",
    "            }\n",
    "        }\n",
    "    ]\n",
    "}\n",
    "```\n",
    "\n",
    "You will generally start by focusing on the `RegEx-Based Maps` section. This is a list of _mapping directives_, each with an `Old` and a `New` dictionary. Each key in the dictionary is an item property. In the `Old` dictionary, the value for each key is a Regular Expression that is used to match on the item property's value. When `spy.workbooks.push()` is operating, it runs every item for this datasource through each of the `Old` sections to determine if they match.\n",
    "\n",
    "Let's take the value of `Type` for the map above: `(?<type>.*)`. Using [regex101.com](https://regex101.com) as an explanatory tool, we can copy and paste `(?<type>.*)` into the Regular Expression text box at the top of its user interface and it will explain what is happening on the far right:\n",
    "\n",
    "- A _Named Capture Group_ called `type` is being defined.\n",
    "- The `.*` matches on any character, any number of times.\n",
    "\n",
    "This effectively means that the entire value of the `Type` property is being assigned to the `type` _Named Capture Group_ (for use later, in the `New` section). The same thing is being done for `Data ID`. However, `Datasource Class` and `Datasource Name` are being explicitly matched to `Time Series CSV Files` and `Example Data`, respectively, and they are not being assigned to a capture group.\n",
    "\n",
    "Now let's focus on the `New` dictionary. The values in this dictionary are used to \"look up\" an item and use it in place of the item identified by the `Old` criteria. The default mapping is simple: It just finds items that are a 100% match of the `Type` and `Data ID` properties. (You can look at Item Properties for any item in Seeq Workbench by clicking the (i) button to the left of the item in the _Details_ pane.) If you are pulling and pushing within the same server without altering the map, this conveniently means that the old and new items are the same, and nothing changes.\n",
    "\n",
    "But what if you need to map to a different datasource and you want to use the `Name` property in a somewhat complex way? Let's look at a possible example:\n",
    "\n",
    "```\n",
    "{\n",
    "    \"Datasource Class\": \"OSIsoft PI\",\n",
    "    \"Datasource ID\": \"442A2678-A76F-49C4-A702-4CC494701D6C\",\n",
    "    \"Datasource Name\": \"PIPRDSRV012\",\n",
    "    \"Item-Level Map Files\": [],\n",
    "    \"RegEx-Based Maps\": [\n",
    "        {\n",
    "            \"Old\": {\n",
    "                \"Type\": \"(?<type>.*)\",\n",
    "                \"Datasource Class\": \"OSIsoft PI\",\n",
    "                \"Datasource Name\": \"PIPRDSRV012\",\n",
    "                \"Name\": \"(?<name>.*)\"\n",
    "            },\n",
    "            \"New\": {\n",
    "                \"Type\": \"${type}\",\n",
    "                \"Datasource Class\": \"ADX\",\n",
    "                \"Datasource Name\": \"PRDDATALAKE\",\n",
    "                \"Name\": \"PIPRDSRV012_${name}\"\n",
    "            }\n",
    "        }\n",
    "    ]\n",
    "}\n",
    "```\n",
    "\n",
    "Here we are mapping from an OSIsoft PI datasource (`PIPRDSRV012`) to a Microsoft ADX data lake (`PRDDATALAKE`), and we are using the `Name` property for mapping. When we are looking up the equivalent tag in the data lake, we are prepending `PIPRDSRV012_` to the name, because that is the (fictional) naming convention in this hypothetical data lake.\n",
    "\n",
    "In this way, you can specify a relatively complex set of rules for mapping. You can have as many Old/New dictionaries in the `RegEx-Based Maps` list as you want, and SPy will match against the `Old` dictionary in the order you specify them. You can only use the following properties in the `New` dictionary: `Datasource Class`, `Datasource ID`, `Datasource Name`, `Data ID`, `Type`, `Name`, `Description`, `Username`, `Path`, `Asset`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Importing to a Different Seeq Server\n",
    "\n",
    "You may wish to copy content to a new/different Seeq Server by exporting and then importing. For example, you might have a _development_ server where you iterate on content and a _production_ server that you publish to when finished.\n",
    "\n",
    "In order to accomplish this, you'll do one of two actions:\n",
    "\n",
    "- If you're using the SPy module within Seeq Data Lab, you'll copy the exported folder to the other version of Seeq Data Lab and then push it from there.\n",
    "- If you're using the SPy module with your own Python set up, you'll log in to the other server and push it.\n",
    "\n",
    "The default Datasource Map files that are part of the export may need to be tweaked if the destination server has differently-named datasources. See _Custom Datasource Mapping_ above."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Detailed Help\n",
    "\n",
    "All SPy functions have detailed documentation to help you use them. Just execute `help(spy.<func>)` like\n",
    "you see below.\n",
    "\n",
    "**Make sure you re-execute the cell below to see the latest documentation. It otherwise might be from an\n",
    "earlier version of SPy.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function search in module seeq.spy.workbooks._search:\n",
      "\n",
      "search(query, *, content_filter='owner', all_properties=False, recursive=False, include_archived=False, errors=None, quiet=None, status=None, session: 'Optional[Session]' = None)\n",
      "    Issues a query to the Seeq Server to retrieve metadata for workbooks.\n",
      "    This metadata can be used to pull workbook definitions into memory.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    query : dict\n",
      "        A mapping of property / match-criteria pairs. Match criteria uses\n",
      "        the same syntax as the Data tab in Seeq (contains, or glob, or regex).\n",
      "        Available options are:\n",
      "    \n",
      "        =================== ===================================================\n",
      "        Property            Description\n",
      "        =================== ===================================================\n",
      "        ID                  ID of the workbook, as seen in the URL.\n",
      "        Name                Name of the workbook.\n",
      "        Path                Path to the workbook through the folder hierarchy.\n",
      "        Description         Description of the workbook.\n",
      "        Workbook Type       Either 'Analysis' or 'Topic'.\n",
      "        =================== ===================================================\n",
      "    \n",
      "    content_filter : str, default 'owner'\n",
      "        Filters workbooks according to the following possible values:\n",
      "    \n",
      "        =================== ===================================================\n",
      "        Property            Description\n",
      "        =================== ===================================================\n",
      "        owner               Only content owned by the logged-in user.\n",
      "        shared              Only content shared specifically with the logged-in\n",
      "                            user. Note: To obtain the same results as you would\n",
      "                            when looking at the \"Shared\" tab in the Seeq home\n",
      "                            screen, use \"sharedorpublic\" (see below).\n",
      "        public              Only content shared with Everyone.\n",
      "        sharedorpublic      Content shared with Everyone or with the logged-in user\n",
      "        corporate           Only content in the Corporate folder\n",
      "        all                 All content, across all users (logged-in user must\n",
      "                            be admin).\n",
      "        users               Every user's home folder (logged-in user must be admin)\n",
      "        =================== ===================================================\n",
      "    \n",
      "    all_properties : bool, default False\n",
      "        True if all workbook properties should be retrieved. This currently makes\n",
      "        the search operation much slower as retrieval of properties for an item\n",
      "        requires a separate call.\n",
      "    \n",
      "    recursive : bool, default False\n",
      "        True if workbooks further down in the folder path should be returned.\n",
      "    \n",
      "    include_archived : bool, default False\n",
      "        True if archived (aka \"trashed\") folders/workbooks should be returned.\n",
      "    \n",
      "    errors : {'raise', 'catalog'}, default 'raise'\n",
      "        If 'raise', any errors encountered will cause an exception. If 'catalog',\n",
      "        errors will be added to a 'Result' column in the status.df DataFrame.\n",
      "    \n",
      "    quiet : bool, default False\n",
      "        If True, suppresses progress output. Note that when status is\n",
      "        provided, the quiet setting of the Status object that is passed\n",
      "        in takes precedence.\n",
      "    \n",
      "    status : spy.Status, optional\n",
      "        If specified, the supplied Status object will be updated as the command\n",
      "        progresses. It gets filled in with the same information you would see\n",
      "        in Jupyter in the blue/green/red table below your code while the\n",
      "        command is executed. The table itself is accessible as a DataFrame via\n",
      "        the status.df property.\n",
      "    \n",
      "    session : spy.Session, optional\n",
      "        If supplied, the Session object (and its Options) will be used to\n",
      "        store the login session state. This is useful to log in to different\n",
      "        Seeq servers at the same time or with different credentials.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    pandas.DataFrame\n",
      "        A DataFrame with rows for each workbook found and columns for each\n",
      "        property.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(spy.workbooks.search)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function pull in module seeq.spy.workbooks._pull:\n",
      "\n",
      "pull(workbooks_df: 'Union[pd.DataFrame, str]', *, include_referenced_workbooks: 'bool' = True, include_inventory: 'bool' = True, include_annotations: 'bool' = True, include_images: 'bool' = True, include_rendered_content: 'bool' = False, include_access_control: 'bool' = True, specific_worksheet_ids: 'Optional[List[str]]' = None, errors: 'Optional[str]' = None, quiet: 'Optional[bool]' = None, status: 'Optional[Status]' = None, session: 'Optional[Session]' = None) -> 'Optional[WorkbookList]'\n",
      "    Pulls the definitions for each workbook specified by workbooks_df into\n",
      "    memory as a list of Workbook items.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    workbooks_df : {str, pd.DataFrame}\n",
      "        A DataFrame containing 'ID', 'Type' and 'Workbook Type' columns that\n",
      "        can be used to identify the workbooks to pull. This is usually created\n",
      "        via a call to spy.workbooks.search(). Alternatively, you can supply a\n",
      "        workbook ID directly as a str or the URL of a Seeq Workbench worksheet\n",
      "        as a str.\n",
      "    \n",
      "    include_referenced_workbooks : bool, default True\n",
      "        If True, Analyses that are depended upon by Topics will be\n",
      "        automatically included in the resulting list even if they were not part\n",
      "        of the workbooks_df DataFrame.\n",
      "    \n",
      "    include_inventory : bool, default True\n",
      "        If True, all items that are referenced in worksheets, journals, topics\n",
      "        etc are included in the Workbook object's \"inventory\", along with\n",
      "        anything that is scoped to the workbook.\n",
      "    \n",
      "    include_annotations : bool, default True\n",
      "        If True, downloads the HTML for Journal and Organizer Topic content.\n",
      "    \n",
      "    include_images : bool, default True\n",
      "        If True, downloads all static images (not including embedded content --\n",
      "        see include_rendered_content for that).\n",
      "    \n",
      "    include_rendered_content : bool, default False\n",
      "        If True, any Organizer Topics pulled will include rendered content\n",
      "        images, which will cause spy.workbooks.save() to include a folder for\n",
      "        each Topic Document with its HTML and images such that it can be loaded\n",
      "        and viewed in a browser.\n",
      "    \n",
      "    include_access_control : bool, default True\n",
      "        If True, includes the access control information for the workbook and\n",
      "        all worksheets.\n",
      "    \n",
      "    specific_worksheet_ids : List[str], default None\n",
      "        If supplied, only the worksheets with IDs specified in the supplied\n",
      "        list will be pulled. This should be used when it would otherwise take\n",
      "        too long to pull all worksheets and you're only interested in a small\n",
      "        subset. Be careful not to push the resulting workbook(s) back because\n",
      "        the other worksheets will get archived.\n",
      "    \n",
      "    errors : {'raise', 'catalog'}, default 'raise'\n",
      "        If 'raise', any errors encountered will cause an exception. If\n",
      "        'catalog', errors will be added to a 'Result' column in the status.df\n",
      "        DataFrame (errors='catalog' must be combined with\n",
      "        status=<Status object>).\n",
      "    \n",
      "    quiet : bool\n",
      "        If True, suppresses progress output. Note that when status is\n",
      "        provided, the quiet setting of the Status object that is passed\n",
      "        in takes precedence.\n",
      "    \n",
      "    status : spy.Status, optional\n",
      "        If specified, the supplied Status object will be updated as the command\n",
      "        progresses. It gets filled in with the same information you would see\n",
      "        in Jupyter in the blue/green/red table below your code while the\n",
      "        command is executed. The table itself is accessible as a DataFrame via\n",
      "        the status.df property.\n",
      "    \n",
      "    session : spy.Session, optional\n",
      "        If supplied, the Session object (and its Options) will be used to\n",
      "        store the login session state. This is useful to log in to different\n",
      "        Seeq servers at the same time or with different credentials.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(spy.workbooks.pull)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function save in module seeq.spy.workbooks._save:\n",
      "\n",
      "save(workbooks, folder_or_zipfile: 'Optional[str]' = None, *, datasource_map_folder: 'Optional[str]' = None, include_rendered_content: 'bool' = False, pretty_print_html=False, overwrite: 'bool' = False, errors: 'Optional[str]' = None, quiet: 'Optional[bool]' = None, status: 'Optional[Status]' = None)\n",
      "    Saves a list of workbooks to a folder on disk from Workbook objects in\n",
      "    memory.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    workbooks : {Workbook, list[Workbook]}\n",
      "        A Workbook object or list of Workbook objects to save.\n",
      "    \n",
      "    folder_or_zipfile : str, default os.getcwd()\n",
      "        A folder or zip file on disk to which to save the workbooks. It will\n",
      "        be saved as a \"flat\" set of subfolders, no other hierarchy will be\n",
      "        created. The string must end in \".zip\" to cause a zip file to be\n",
      "        created instead of a folder.\n",
      "    \n",
      "    datasource_map_folder : str, default None\n",
      "        Specifies a curated set of datasource maps that should accompany the\n",
      "        workbooks (as opposed to the default maps that were created during the\n",
      "        spy.workbooks.pull call).\n",
      "    \n",
      "    include_rendered_content : bool, default False\n",
      "        If True, creates a folder called RenderedTopic within each Topic\n",
      "        Document folder that includes the embedded content such that you can\n",
      "        load it in an offline browser. You are required to have pulled the\n",
      "        workbooks with include_rendered_content=True.\n",
      "    \n",
      "    pretty_print_html : bool, default False\n",
      "        If True, this function will re-format the HTML of Topic Documents\n",
      "        and Journals so that it is easy to read in a text editor. If False, the\n",
      "        HTML will be written exactly as it is stored in Seeq Server. Note that\n",
      "        setting this to True can cause some minor deviations in rendering after\n",
      "        a round-trip (i.e. pull/save/load/push).\n",
      "    \n",
      "    overwrite : bool, default False\n",
      "        If True, will overwrite any existing folder or zip file.\n",
      "    \n",
      "    errors : {'raise', 'catalog'}, default 'raise'\n",
      "        If 'raise', any errors encountered will cause an exception. If\n",
      "        'catalog', errors will be added to a 'Result' column in the status.df\n",
      "        DataFrame (errors='catalog' must be combined with\n",
      "        status=<Status object>).\n",
      "    \n",
      "    quiet : bool\n",
      "        If True, suppresses progress output. Note that when status is\n",
      "        provided, the quiet setting of the Status object that is passed\n",
      "        in takes precedence.\n",
      "    \n",
      "    status : spy.Status, optional\n",
      "        If specified, the supplied Status object will be updated as the command\n",
      "        progresses. It gets filled in with the same information you would see\n",
      "        in Jupyter in the blue/green/red table below your code while the\n",
      "        command is executed.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(spy.workbooks.save)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function load in module seeq.spy.workbooks._load:\n",
      "\n",
      "load(folder_or_zipfile, *, as_template_with_label: 'str' = None, errors: 'Optional[str]' = None, quiet: 'Optional[bool]' = None, status: 'Optional[Status]' = None) -> 'WorkbookList'\n",
      "    Loads a list of workbooks from a folder on disk into Workbook objects in\n",
      "    memory.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    folder_or_zipfile : str\n",
      "        A folder or zip file on disk containing workbooks to be loaded. Note\n",
      "        that any subfolder structure will work -- this function will scan for\n",
      "        any subfolders that contain a Workbook.json file and assume they should\n",
      "        be loaded.\n",
      "    \n",
      "    as_template_with_label : str\n",
      "        Causes the workbooks to be loaded as templates (either AnalysisTemplate\n",
      "        or TopicTemplate) with the label specified. See the Workbook Templates\n",
      "        documentation notebook for more information about templates.\n",
      "    \n",
      "    errors : {'raise', 'catalog'}, default 'raise'\n",
      "        If 'raise', any errors encountered will cause an exception. If\n",
      "        'catalog', errors will be added to a 'Result' column in the status.df\n",
      "        DataFrame (errors='catalog' must be combined with\n",
      "        status=<Status object>).\n",
      "    \n",
      "    quiet : bool\n",
      "        If True, suppresses progress output. Note that when status is\n",
      "        provided, the quiet setting of the Status object that is passed\n",
      "        in takes precedence.\n",
      "    \n",
      "    status : spy.Status, optional\n",
      "        If specified, the supplied Status object will be updated as the command\n",
      "        progresses. It gets filled in with the same information you would see\n",
      "        in Jupyter in the blue/green/red table below your code while the\n",
      "        command is executed.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(spy.workbooks.load)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function push in module seeq.spy.workbooks._push:\n",
      "\n",
      "push(workbooks, *, path=None, owner=None, label=None, datasource=None, datasource_map_folder=None, use_full_path=False, access_control=None, override_max_interp=False, include_inventory=None, include_annotations: 'bool' = True, scope_globals_to_workbook=False, refresh=True, lookup_df: 'pd.DataFrame' = None, specific_worksheet_ids: 'Optional[List[str]]' = None, create_dummy_items_in_workbook=None, errors=None, quiet=None, status: 'Optional[Status]' = None, session: 'Optional[Session]' = None, item_map: 'Optional[ItemMap]' = None) -> 'pd.DataFrame'\n",
      "    Pushes workbooks into Seeq using a list of Workbook object definitions.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    workbooks : {Workbook, list[Workbook]}\n",
      "        A Workbook object or list of Workbook objects to be pushed into Seeq.\n",
      "    \n",
      "    path : str, default None\n",
      "        A '>>'-delimited folder path to create to contain the workbooks. Note\n",
      "        that a further subfolder hierarchy will be created to preserve the\n",
      "        relative paths that the folders were in when they were searched for\n",
      "        and pulled. If you specify None, then the workbook will stay where\n",
      "        it is (if it has already been pushed once).\n",
      "    \n",
      "        If you specify spy.workbooks.MY_FOLDER, it will be moved to the user's\n",
      "        home folder.\n",
      "    \n",
      "        If you specify a folder ID directly, it will be pushed to that folder.\n",
      "    \n",
      "        If you specify spy.workbooks.ORIGINAL_FOLDER, it will be pushed to the\n",
      "        folder it was in when it was originally pulled. The folder hierarchy\n",
      "        will be recreated on the target server if it doesn't already exist.\n",
      "        (You must be an admin to use this to ensure you have permissions to\n",
      "        put things where they need to go.)\n",
      "    \n",
      "    owner : str, default None\n",
      "        Determines the ownership of pushed workbooks and folders.\n",
      "    \n",
      "        By default, the current owner will be preserved. If the content doesn't\n",
      "        exist yet, the logged-in user will be the owner.\n",
      "    \n",
      "        All other options require that the logged-in user is an admin:\n",
      "    \n",
      "        If spy.workbooks.ORIGINAL_OWNER, ownership is assigned according to the\n",
      "        original owner of the pulled content. (You must be an admin to use\n",
      "        this.)\n",
      "    \n",
      "        If spy.workbooks.FORCE_ME_AS_OWNER, existing content will be\n",
      "        reassigned to the logged-in user.\n",
      "    \n",
      "        If a username or a user's Seeq ID is supplied, that user will be\n",
      "        assigned as owner.\n",
      "    \n",
      "        You may need to supply an appropriate datasource map if the usernames\n",
      "        are different between the original and the target servers.\n",
      "    \n",
      "    label : str\n",
      "        A user-defined label that differentiates this push operation from\n",
      "        others. By default, the label will be the logged-in user's username\n",
      "        OR the username from the 'owner' argument so that push activity will\n",
      "        generally be isolated by user. But you can override this with a label\n",
      "        of your choosing.\n",
      "    \n",
      "    datasource : str, optional, default 'Seeq Data Lab'\n",
      "        The name of the datasource within which to contain all the pushed items.\n",
      "        Items inherit access control permissions from their datasource unless it\n",
      "        has been overridden at a lower level. If you specify a datasource using\n",
      "        this argument, you can later manage access control (using spy.acl functions)\n",
      "        at the datasource level for all the items you have pushed.\n",
      "    \n",
      "        If you instead want access control for your items to be inherited from the\n",
      "        workbook they are scoped to, specify `spy.INHERIT_FROM_WORKBOOK`.\n",
      "    \n",
      "    datasource_map_folder : str, default None\n",
      "        A folder containing Datasource_Map_Xxxx_Yyyy_Zzzz.json files that can\n",
      "        provides a means to map stored items (i.e., those originating from\n",
      "        external datasources like OSIsoft PI) from one server to another or\n",
      "        from one datasource to another (i.e., for workbook swapping). A default\n",
      "        set of datasource map files is created during a pull/save sequence, and\n",
      "        you can copy these default files to a folder, alter them, and then\n",
      "        specify the folder as this argument.\n",
      "    \n",
      "    use_full_path : bool, default False\n",
      "        If True, the original full path for an item is reconstructed, as\n",
      "        opposed to the path that is relative to the Path property supplied to\n",
      "        the spy.workbooks.search() call that originally helped create these\n",
      "        workbook definitions. Note that this full path will still be inside\n",
      "        the folder specified by the 'path' argument, if supplied.\n",
      "    \n",
      "    access_control : str, default None\n",
      "        Specifies how Access Control Lists should be treated, via the\n",
      "        following keywords: add/replace,loose/strict\n",
      "    \n",
      "        - If None, then no access control entries are pushed.\n",
      "        - If 'add', then existing access control entries will not be disturbed\n",
      "          but new entries will be added.\n",
      "        - If 'replace', then existing access control entries will be removed\n",
      "          and replaced with the entries from workbook definitions.\n",
      "        - If 'loose', then any unmapped users/groups from the workbook\n",
      "          definitions will be silently ignored.\n",
      "        - If 'strict', then any unmapped users/groups will result in errors.\n",
      "    \n",
      "        Example: access_control='replace,loose'\n",
      "    \n",
      "    override_max_interp : bool, default False\n",
      "        If True, then the Maximum Interpolation overrides from the source\n",
      "        system will be written to the destination system.\n",
      "    \n",
      "    include_inventory : bool, optional\n",
      "        If True, then all calculated items that are scoped to the workbook\n",
      "        will be pushed as well.\n",
      "    \n",
      "        If omitted, SPy will push inventory in any non-template scenarios.\n",
      "    \n",
      "    include_annotations : bool, default True\n",
      "        If True, downloads the HTML for Journal and Organizer Topic content.\n",
      "    \n",
      "    scope_globals_to_workbook : bool, default False\n",
      "        If include_inventory=True and scope_globals_to_workbook=True, then\n",
      "        all globally-scoped (aka \"Available outside this analysis\") items\n",
      "        will be scoped to the workbook. False if you want to actually push\n",
      "        these items to the global scope.\n",
      "    \n",
      "    refresh : bool, default True\n",
      "        If True, then the Workbook objects that were supplied as input will\n",
      "        be updated to be \"fresh\" from the server after the push. All\n",
      "        identifiers will reflect the actual pushed IDs. Since refreshing\n",
      "        takes time, you can set this to False if you don't plan to make\n",
      "        further modifications to the Workbook objects or use the new IDs.\n",
      "    \n",
      "    lookup_df : pd.DataFrame, optional\n",
      "        A DataFrame of item metadata that can be used to look up identifiers\n",
      "        that correspond to template parameters (when pushing AnalysisTemplate\n",
      "        objects). This argument is automatically specified by the spy.push()\n",
      "        function.\n",
      "    \n",
      "    specific_worksheet_ids : List[str], default None\n",
      "        If supplied, only the worksheets with IDs specified in the supplied\n",
      "        list will be pushed. This should be used when it would otherwise take\n",
      "        too long to push all worksheets and you're interested in optimizing\n",
      "        the push operation. No existing worksheets will be archived or moved\n",
      "        in their ordering.\n",
      "    \n",
      "    create_dummy_items_in_workbook : str, optional\n",
      "        If specified, then \"dummy\" items will be created for any stored items\n",
      "        that are not successfully mapped to the target system. This is useful\n",
      "        when you want to push a workbook to a system that doesn't have the same\n",
      "        datasources/items as the source system. The dummy items will be\n",
      "        created in the target system's \"Seeq Data Lab\" datasource and will\n",
      "        have the same name as the original item, and no data. They will be\n",
      "        scoped to the workbook specified.\n",
      "    \n",
      "    errors : {'raise', 'catalog'}, default 'raise'\n",
      "        If 'raise', any errors encountered will cause an exception. If\n",
      "        'catalog', errors will be added to a 'Result' column in the status.df\n",
      "        DataFrame (errors='catalog' must be combined with\n",
      "        status=<Status object>).\n",
      "    \n",
      "    quiet : bool, default False\n",
      "        If True, suppresses progress output. Note that when status is\n",
      "        provided, the quiet setting of the Status object that is passed\n",
      "        in takes precedence.\n",
      "    \n",
      "    status : spy.Status, optional\n",
      "        If specified, the supplied Status object will be updated as the command\n",
      "        progresses. It gets filled in with the same information you would see\n",
      "        in Jupyter in the blue/green/red table below your code while the\n",
      "        command is executed. The table itself is accessible as a DataFrame via\n",
      "        the status.df property.\n",
      "    \n",
      "    session : spy.Session, optional\n",
      "        If supplied, the Session object (and its Options) will be used to\n",
      "        store the login session state. This is useful to log in to different\n",
      "        Seeq servers at the same time or with different credentials.\n",
      "    \n",
      "    item_map:\n",
      "        For internal use only.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    pandas.DataFrame\n",
      "        A DataFrame with status on the items pushed. The IDs for the pushed\n",
      "        workbooks are in the \"Pushed Workbook ID\" column.\n",
      "    \n",
      "        Additionally, the following properties are stored on the \"spy\"\n",
      "        attribute of the output DataFrame:\n",
      "    \n",
      "        =================== ===================================================\n",
      "        Property            Description\n",
      "        =================== ===================================================\n",
      "        func                A str value of 'spy.workbooks.push'\n",
      "        kwargs              A dict with the values of the input parameters\n",
      "                            passed to this function\n",
      "        input               The set of workbooks passed in to this function\n",
      "        output              The set of workbooks pulled from the server if\n",
      "                            refresh=True\n",
      "        datasource          The datasource that all pushed items will fall\n",
      "                            under (as a DatasourceOutputV1 object).\n",
      "        item_map            A dictionary of IDs that map from the input\n",
      "                            workbooks and inventory to the actual IDs as they\n",
      "                            were created/updated on the server\n",
      "        status              A spy.Status object with the status of the\n",
      "                            spy.push call\n",
      "        =================== ===================================================\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(spy.workbooks.push)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.11",
   "language": "python",
   "name": "python311"
  },
  "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.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
