Snippets

Lance E Sloan Jupyter Notebook: Not supported by Bitbucket 🙁

Created by Lance E Sloan last modified

{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Caliper: Basic Example\n",
    "By [Lance E Sloan](https://gist.github.com/lsloan)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prerequisites\n",
    "\n",
    "1. **Jupyter Notebook** – If you're not already reading this document in Jupyter Notebook, I recommend it be installed by following the steps listed in the \"Installing Jupyter using Anaconda\" section of the \"[Project Jupyter | Install](http://jupyter.org/install)\" page.\n",
    "    \n",
    "   > 💡***Note:***  When installing Anaconda on macOS, its installer may use the \"install for all users of this computer\" option by default.  That installs Anaconda in a strange place, so it's recommended to explicitly specify the \"install for the current user only\" option.  When I first looked at the options, the \"current user\" one appeared to be selected and an error message was also shown that the installation couldn't be completed.  However, after I clicked the \"current user\" option, the error message was removed and the installation completed successfully.\n",
    "   \n",
    "1. **Caliper** – Get \"caliper-python\" and install it in the Anaconda environment so it will be accessible by Jupyter Notebook:\n",
    "    \n",
    "    1. Clone a copy of [IMSGlobal/caliper-python](https://github.com/IMSGlobal/caliper-python) from GitHub.  (Those that aren't familiar with git may download caliper-php as a ZIP file instead.  Expand the ZIP file before continuing to the next step.)\n",
    "    \n",
    "    1. In the ***same directory*** where caliper-python was downloaded (i.e., do **not** enter that directory before continuing) enter the following commands at a shell prompt:\n",
    "    \n",
    "        1. `source activate base`\n",
    "        \n",
    "        1. `pip install -e caliper-python`\n",
    "        \n",
    "    1. If Jupyter Notebook was already running as Caliper was installed, it may be necessary to stop Jupyter Notebook and start it again before continuing.\n",
    "    \n",
    "After the prerequisites have been satisfied, you may download and run **[this notebook](https://gist.github.com/lsloan/a1e56e2c1f1f27200ac0b0c9b41ced3d)** in your own instance of Jupyter Notebook."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize Environment\n",
    "\n",
    "Import the Caliper sensor module and other useful modules."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.1.0\n",
      "http://purl.imsglobal.org/ctx/caliper/v1p1\n"
     ]
    }
   ],
   "source": [
    "import caliper\n",
    "from datetime import datetime, timezone\n",
    "import getpass\n",
    "\n",
    "print(caliper.__version__)\n",
    "print(caliper.constants.CALIPER_VERSION)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Definitions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Endpoint\n",
    "\n",
    "For this example, the \"Caliper Event Store\" testing endpoint provided by the [ceLTIc project](http://celtic-project.org/) will be used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sensorId = getpass.getuser() + '_caliper_python_example'\n",
    "endpointUrl = 'https://lti.tools/caliper/event?key=' + sensorId\n",
    "\n",
    "'Your personal endpoint is at: ' + endpointUrl + ' '"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The events sent by this example code may be seen in the endpoint at the URL shown above.  (You'll need to run this notebook on your computer to see the URL.  This gist doesn't include one.)  The \"`key`\" part of the URL will be ***your*** login name followed by \"`_caliper_python_example`\".  If you run the code in this notebook multiple times, you will need to reload that endpoint page to see the newly sent events."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "scrolled": true
   },
   "source": [
    "### Caliper Sensor Objects\n",
    "These are the objects that represent the Caliper sensor and its configuation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "sensorConfiguration = caliper.HttpOptions(\n",
    "      host=endpointUrl,\n",
    "      auth_scheme='Bearer',\n",
    "      api_key='no-key-required-for-lti.tools',)\n",
    "\n",
    "sensor = caliper.build_sensor_from_config(\n",
    "        sensor_id = 'urn:' + sensorId,\n",
    "        config_options = sensorConfiguration,)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Event Timestamp\n",
    "Make a timestamp for the event using the current time in the UTC time \"zone\" and express it in ISO 8601 format."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-05-25T19:22:20.341114+00:00\n"
     ]
    }
   ],
   "source": [
    "eventTime = datetime.now(timezone.utc).isoformat()\n",
    "\n",
    "print(eventTime)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that in ISO 8601 format, the `+00:00` offset used for UTC could also be abbreviated as `Z`.  However, Python's `datetime` module doesn't use that abbreviation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Caliper Entities\n",
    "\n",
    "These definitions of Caliper entity objects will be used as part of the Caliper event created later.  Entities represent various pieces of information, like people, resources, courses, groups, membership, sessions, etc."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "aPerson = caliper.entities.Person(\n",
    "    id='urn:/user/193828',)\n",
    "\n",
    "aCourse = caliper.entities.CourseSection(\n",
    "    id='urn:/course/4077',\n",
    "    courseNumber='SSED514',\n",
    "    name='Economy and Society',\n",
    "    category='lecture',)\n",
    "\n",
    "aResource = caliper.entities.DigitalResource(\n",
    "    id='urn:/course/4077/resource/1',\n",
    "    name='Lecture Introduction',\n",
    "    description='Lecture Introduction',)\n",
    "\n",
    "aPersonCourseMembership = caliper.entities.Membership(\n",
    "    id='urn:/course/4077/member/193828',\n",
    "    member=aPerson,\n",
    "    organization=aCourse,\n",
    "    roles=[caliper.constants.CALIPER_ROLES['LEARNER']],\n",
    "    status=caliper.constants.CALIPER_STATUS['ACTIVE'],)\n",
    "\n",
    "aPersonSession = caliper.entities.Session(\n",
    "    id='urn:/session/379053173489041',\n",
    "    user=aPerson,)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All of the IDs used in the entities above are just random values.  (In fact, they're not even valid URNs.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Caliper Event\n",
    "\n",
    "Finally, a Caliper event object is defined using the entities from the previous steps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "navEvent = caliper.events.NavigationEvent(\n",
    "    actor=aPerson, \n",
    "    action=caliper.constants.BASIC_EVENT_ACTIONS['NAVIGATED_TO'],\n",
    "    object=aResource,\n",
    "    eventTime = eventTime,\n",
    "    membership=aPersonCourseMembership,\n",
    "    session=aPersonSession,)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Send\n",
    "The `send()` function serializes and sends a Caliper event and all of the entities it contains to the endpoint.\n",
    "\n",
    "The return value from `send()` contains a list of event and entity IDs that were sent to the endpoint."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'default': ['urn:/user/193828',\n",
       "  'urn:uuid:8a1cca39-1ff6-4c25-8e20-d86eddc17c61',\n",
       "  'urn:/course/4077/member/193828',\n",
       "  'urn:/user/193828',\n",
       "  'urn:/course/4077',\n",
       "  'urn:/course/4077/resource/1',\n",
       "  'urn:/session/379053173489041',\n",
       "  'urn:/user/193828']}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sensor.send(navEvent)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice that one of the IDs in the list begins with \"`urn:uuid:`\".  That's a UUID used as the ID of the event.  Because the event definition didn't already include an ID, Caliper added one to the event just before sending it."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Describe\n",
    "The `describe()` function serializes and sends a Caliper entity to the endpoint.  Note that it is not a complete event.\n",
    "\n",
    "In this example, the actor (a `Person` object) from the example event is sent to the endpoint.  Later, that `Person` may be referenced by other events and entities, allowing them to contain less data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'default': ['urn:/user/193828']}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "actorDescribe = sensor.describe(navEvent.actor)\n",
    "\n",
    "actorDescribe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Send with References\n",
    "Using the reference from the previous call to `describe()`, the same event is sent again, but the amount of data used to express the event is much smaller.\n",
    "\n",
    "Notice that the list of event and entity IDs is much shorter than the one returned by the earlier call to `send()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'default': ['urn:uuid:8a1cca39-1ff6-4c25-8e20-d86eddc17c61',\n",
       "  'urn:/course/4077/member/193828',\n",
       "  'urn:/course/4077',\n",
       "  'urn:/course/4077/resource/1',\n",
       "  'urn:/session/379053173489041']}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sensor.send(navEvent, described_objects=actorDescribe['default'])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.