Exploring Drupal 8 in Jupyter Notebook

Using Jupyter with Drupal 8Jupyter notebooks are used in data science for exploring / documenting / presenting data. If you haven't heard of Jupyter maybe you have by it's former name, iPython notebook. Since there are multiple "kernels" supported it was renamed to Jupyter ( for Julia-Python-R ). There is support for 3rd party kernels such as the Ruby kernel and thanks to the Jupyter-PHP project on github we can add PHP to the list.

Notebook results can be hosted on github as static HTML pages or hosted on a `nbviewer` server like https://nbviewer.jupyter.org. You can even host your own nbviewer server if you like.

Here is a brief walk through on getting it set up on a mac with homebrew.

Prerequisites

First you need a copy of php with the Zero MQ php library:

# Stick a tap in the homebrew php repository:
brew tap homebrew/homebrew-php

# Install a local version of php.
brew install php56

# Install the Zero MQ extension
brew install php56-zmq

# Install these extras if you like.
brew install php56-mcrypt php56-apcu php56-opcache php56-xdebug php56-xhprof php56-twig

Installing Jupyter

The easiest way to install Jupyter is with anaconda.

# Tap caskroom
brew tap caskroom/cask
# Install anaconda
brew cask install anaconda

Installing Jupyter-PHP

# Grab the installer.
wget https://litipk.github.io/Jupyter-PHP-Installer/dist/jupyter-php-installer.phar
# Get the ssh 512 signature via the browser or with:
curl https://litipk.github.io/Jupyter-PHP-Installer/dist/jupyter-php-installer.phar.sha512
# Compare the sha 512 digest of the download with the hosted hash.
openssl dgst -sha512 jupyter-php-installer.phar
# If they match you can install with:
./jupyter-php-installer.phar install

I also had to manually install the Jupyter-PHP library dependencies:

# Go to the jupyter-php folder.
cd ~/Library/jupyter-php/pkgs/
composer install

WhooHoo! Now you ready to run Jupyter notebook with Jupyter-PHP.

Starting Jupyter Notebook

# launch Jupyter notebook
jupyter notebook

If everything went well, it will open a browser browser window that looks like this:

Jupyter start screen

For an overview of using Jupyter notebooks see http://jupyter.readthedocs.io/en/latest/.

Exploring Drupal in a Jupyter notebook

Bootstrapping Drupal 8

Here we will go over bootstrapping Drupal 8. See the footnotes for bootstrapping Drupal 7.

// Load the autoloader.
$autoloader = isset($autoloader) ? $autoloader : require_once '/path/to/drupal_root/autoload.php';

You should see:

jupyter notebook 1

// Bootstrap drupal.
$request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
$kernel = \Drupal\Core\DrupalKernel::createFromRequest($request, $autoloader, 'prod');
// There are a couple of files not loaded by the autoloader.
$kernel->loadLegacyIncludes();
$kernel->boot();

jupyter notebook 2

Loading the entity type manager Drupal service.

$entity_manager = \Drupal::service('entity_type.manager');

jupyter notebook 3

Exporting entity data to a CSV file

// Load some entities.
$entities = $entity_manager->getStorage('node')->loadByProperties(['type'=>'page']);
// Open a file to write out a csv of entity data.
$file_path = __DIR__.'/entity-data.csv';
$f = fopen($file_path, 'w');
// Add a header to the file.
fputcsv($f, ['nid', 'type', 'created', 'owner']);
// Loop over each entity and add it's data to the file.
foreach ($entities as $entity) {
  fputcsv($f, [
   'nid' => $entity->id(),
   'type' => $entity->getType(),
   'created' => $entity->getCreatedTime(),
   'owner' => $entity->getOwner()->getUsername(),
  ]);
}
fclose($f);

jupyter notebook 4

Now you are ready to load the CSV in a python notebook for data exploration with:

import numpy as np
f = open("entity-data.csv")
# Skip the header
f.readline()
# Read the data into a Numpy array:
data = np.loadtxt(f)

Footnotes

Special thanks to open source software contributors

Installing php-zmq in php70 (experimental)

brew tap jenssegers/homebrew-custom
brew install --HEAD jenssegers/custom/php70-zmq

Bootstrapping Drupal 7

if(!defined('DRUPAL_ROOT')) { 
  define('DRUPAL_ROOT', '/path/to/drupal_root');
}
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);