Browse Source

Move example code for services into tested files.

Jason Grout 5 years ago
parent
commit
7bbc7e8863

+ 3 - 1
examples/chrome-example-test.js

@@ -20,9 +20,11 @@ async function main() {
 
   const handleMessage = async msg => {
     const text = msg.text();
-    console.log(`>> ${text}`);
     if (msg.type() === 'error') {
+      console.log(`ERROR>> ${text}`);
       errored = true;
+    } else {
+      console.log(`>> ${text}`);
     }
     const lower = text.toLowerCase();
     if (lower === 'example started!' || lower === 'test complete!') {

+ 25 - 16
examples/test_examples.py

@@ -5,46 +5,55 @@ This file is meant to be used to test all of the example here and and
 in ../packages/services/examples.  We import each of the applications
 and add instrument them with a puppeteer test that makes sure
 there are no console errors or uncaught errors prior to a sentinel
-string being printed.
+string being printed (see chrome-example-test.js for the sentinel strings
+checked before the browser.close() call).
 """
+import argparse
 import glob
 import os.path as osp
 import subprocess
 import sys
+import tempfile
 
 here = osp.abspath(osp.dirname(__file__))
 
-def header(path):
+def header(path, cwd = ''):
     test_name = osp.basename(path)
     print('\n'.join((
         '\n',
         '*' * 40,
-        'Starting %s test' % test_name,
+        'Starting %s test in %s' % (test_name, cwd),
         '*' * 40
     )), flush=True)
 
 def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--testPath", help="paths containing this string are tested")
+    args = parser.parse_args()
+
     paths = [i for i in glob.glob('%s/*' % here) if osp.isdir(i)]
 
     services_dir = osp.abspath(osp.join(here, '../packages/services/examples'))
     paths += [i for i in glob.glob('%s/*' % services_dir)]
+    if args.testPath:
+        paths = [p for p in paths if args.testPath in p]
+
+    print('Testing %s'%paths)
 
     count = 0
     for path in sorted(paths):
         if osp.basename(path) == 'node':
-            header(path)
-            runner = osp.join(path, 'main.py')
-            subprocess.check_call([sys.executable, runner])
-            count += 1
-            continue
-
-        if not osp.exists(osp.join(path, 'main.py')):
-            continue
-
-        count += 1
-        header(path)
-        runner = osp.join(here, 'example_check.py')
-        subprocess.check_call([sys.executable, runner, path])
+            with tempfile.TemporaryDirectory() as cwd:
+                header(path)
+                runner = osp.join(path, 'main.py')
+                subprocess.check_call([sys.executable, runner])
+                count += 1
+        elif osp.exists(osp.join(path, 'main.py')):
+            with tempfile.TemporaryDirectory() as cwd:
+                header(path)
+                runner = osp.join(here, 'example_check.py')
+                subprocess.check_call([sys.executable, runner, path], cwd=cwd)
+                count += 1
 
     print('\n\n%s tests complete!' % count)
 

+ 6 - 231
packages/services/README.md

@@ -114,237 +114,12 @@ examples below are written in TypeScript using ES6 syntax. Simply
 omit the type declarations when using a language other than TypeScript.
 A translator such as Babel can be used to convert from ES6 -> ES5.
 
-**Kernel**
-
-```typescript
-import { KernelMessage, Kernel } from '@jupyterlab/services';
-
-// Get a list of available kernels and connect to one.
-Kernel.listRunning().then(kernelModels => {
-  const kernel = Kernel.connectTo(kernelModels[0]);
-  console.log(kernel.name);
-});
-
-// Get info about the available kernels and start a new one.
-Kernel.getSpecs().then(kernelSpecs => {
-  console.log('Default spec:', kernelSpecs.default);
-  console.log('Available specs', Object.keys(kernelSpecs.kernelspecs));
-  // use the default name
-  let options: Kernel.IOptions = {
-    name: kernelSpecs.default
-  };
-  Kernel.startNew(options).then(kernel => {
-    // Execute and handle replies.
-    let future = kernel.requestExecute({ code: 'a = 1' });
-    future.done.then(() => {
-      console.log('Future is fulfilled');
-    });
-    future.onIOPub = msg => {
-      console.log(msg.content); // Print rich output data.
-    };
-
-    // Restart the kernel and then send an inspect message.
-    kernel.restart().then(() => {
-      let request: KernelMessage.IInspectRequest = {
-        code: 'hello',
-        cursor_pos: 4,
-        detail_level: 0
-      };
-      kernel.requestInspect(request).then(reply => {
-        console.log(reply.content.data);
-      });
-    });
-
-    // Interrupt the kernel and then send a complete message.
-    kernel.interrupt().then(() => {
-      kernel.requestComplete({ code: 'impor', cursor_pos: 4 }).then(reply => {
-        console.log(reply.content.matches);
-      });
-    });
-
-    // Register a callback for when the kernel changes state.
-    kernel.statusChanged.connect(status => {
-      console.log('status', status);
-    });
-
-    // Kill the kernel.
-    kernel.shutdown().then(() => {
-      console.log('Kernel shut down');
-    });
-  });
-});
-```
-
-**Session**
-
-```typescript
-import { Session } from '@jupyterlab/services';
-
-// Get a list of available sessions and connect to one.
-Session.listRunning().then(sessionModels => {
-  const session = Session.connectTo(sessionModels[0]);
-  console.log(session.kernel.name);
-});
-
-// Start a new session.
-let options = {
-  kernelName: 'python',
-  path: '/tmp/foo.ipynb'
-};
-
-Session.startNew(options).then(session => {
-  // Execute and handle replies on the kernel.
-  let future = session.kernel.requestExecute({ code: 'a = 1' });
-  future.done.then(() => {
-    console.log('Future is fulfilled');
-  });
-
-  // Rename the session.
-  session.setPath('/local/bar.ipynb').then(() => {
-    console.log('Session renamed to', session.path);
-  });
-
-  // Register a callback for when the session dies.
-  session.terminated.connect(() => {
-    console.log('session died');
-  });
-
-  // Kill the session.
-  session.shutdown().then(() => {
-    console.log('session closed');
-  });
-});
-```
-
-**Comm**
-
-```typescript
-import { Kernel } from '@jupyterlab/services';
-
-// Create a comm from the server side.
-//
-// Get info about the available kernels and connect to one.
-Kernel.getSpecs()
-  .then(kernelSpecs => {
-    return Kernel.startNew({
-      name: kernelSpecs.default
-    });
-  })
-  .then(kernel => {
-    let comm = kernel.createComm('test');
-    comm.open('initial state');
-    comm.send('test');
-    comm.close('bye');
-  });
-
-// Create a comm from the client side.
-Kernel.getSpecs()
-  .then(kernelSpecs => {
-    return Kernel.startNew({
-      name: kernelSpecs.default
-    });
-  })
-  .then(kernel => {
-    kernel.registerCommTarget('test2', (comm, commMsg) => {
-      if (commMsg.content.target_name !== 'test2') {
-        return;
-      }
-      comm.onMsg = msg => {
-        console.log(msg); // 'hello'
-      };
-      comm.onClose = msg => {
-        console.log(msg); // 'bye'
-      };
-    });
-
-    let code = [
-      'from ipykernel.comm import Comm',
-      'comm = Comm(target_name="test2")',
-      'comm.send(data="hello")',
-      'comm.close(data="bye")'
-    ].join('\n');
-    kernel.requestExecute({ code: code });
-  });
-```
-
-**Contents**
-
-```typescript
-import { ContentsManager } from '@jupyterlab/services';
-
-let contents = new ContentsManager();
-
-// Create a new python file.
-contents.newUntitled({ path: '/foo', type: 'file', ext: 'py' }).then(model => {
-  console.log('new file:', model.path);
-});
-
-// Get the contents of a directory.
-contents.get('/foo/bar').then(model => {
-  console.log('files:', model.content);
-});
-
-// Rename a file.
-contents.rename('/foo/bar.txt', '/foo/baz.txt');
-
-// Save a file.
-contents.save('/foo/test.ipynb');
-
-// Delete a file.
-contents.delete('/foo/bar.txt');
-
-// Copy a file.
-contents.copy('/foo/bar.txt', '/baz').then(model => {
-  console.log('new path', model.path);
-});
-
-// Create a checkpoint.
-contents.createCheckpoint('/foo/bar.ipynb').then(model => {
-  let checkpoint = model;
-
-  // Restore a checkpoint.
-  contents.restoreCheckpoint('/foo/bar.ipynb', checkpoint.id);
-
-  // Delete a checkpoint.
-  contents.deleteCheckpoint('/foo/bar.ipynb', checkpoint.id);
-});
-
-// List checkpoints for a file.
-contents.listCheckpoints('/foo/bar.txt').then(models => {
-  console.log(models[0].id);
-});
-```
-
-**Configuration**
-
-```typescript
-import { ConfigWithDefaults, ConfigSection } from '@jupyterlab/services';
-
-// The base url of the Jupyter server.
-
-ConfigSection.create({ name: 'notebook' }).then(section => {
-  let config = new ConfigWithDefaults({
-    section,
-    defaults: { default_cell_type: 'code' },
-    className: 'Notebook'
-  });
-  console.log(config.get('default_cell_type')); // 'code'
-  config.set('foo', 'bar').then(data => {
-    console.log(data); // "{ 'foo': 'bar' }"
-  });
-});
-```
-
-**Terminals**
-
-```typescript
-import { TerminalSession } from '@jupyterlab/services';
-
-// Create a named terminal session and send some data.
-TerminalSession.startNew().then(session => {
-  session.send({ type: 'stdin', content: ['foo'] });
-});
-```
+- [Comms](./examples/browser/src/comm.ts)
+- [Config](./examples/browser/src/config.ts)
+- [Contents](./examples/browser/src/contents.ts)
+- [Kernel](./examples/browser/src/kernel.ts)
+- [Session](./examples/browser/src/session.ts)
+- [Terminal](./examples/browser/src/terminal.ts)
 
 ## Overview
 

+ 2 - 1
packages/services/examples/browser/package.json

@@ -9,7 +9,8 @@
   },
   "dependencies": {
     "@jupyterlab/coreutils": "^4.0.0-alpha.4",
-    "@jupyterlab/services": "^5.0.0-alpha.4"
+    "@jupyterlab/services": "^5.0.0-alpha.4",
+    "@lumino/coreutils": "^1.4.0"
   },
   "devDependencies": {
     "rimraf": "~3.0.0",

+ 61 - 0
packages/services/examples/browser/src/comm.ts

@@ -0,0 +1,61 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { KernelManager } from '@jupyterlab/services';
+import { PromiseDelegate } from '@lumino/coreutils';
+
+import { log } from './log';
+
+export async function main() {
+  // Start a python kernel
+  let kernelManager = new KernelManager();
+  let kernel = await kernelManager.startNew({ name: 'python' });
+
+  log('Register a comm target in the kernel');
+  await kernel.requestExecute({
+    code: `
+kernel = get_ipython().kernel
+comm = None
+def comm_opened(comm, msg):
+    comm = comm
+kernel.comm_manager.register_target('test', comm_opened)
+`
+  }).done;
+
+  log('Create a comm');
+  let comm = kernel.createComm('test');
+
+  log('Open the comm');
+  await comm.open('initial state').done;
+  log('Send a test message');
+  await comm.send('test').done;
+  log('Close the comm');
+  await comm.close('bye').done;
+
+  log('Register a comm target in the browser');
+  let done = new PromiseDelegate();
+  kernel.registerCommTarget('test2', (comm, commMsg) => {
+    if (commMsg.content.target_name !== 'test2') {
+      return;
+    }
+    comm.onMsg = msg => {
+      console.log(msg.content.data);
+    };
+    comm.onClose = msg => {
+      console.log(msg.content.data);
+      done.resolve(undefined);
+    };
+  });
+
+  log('Create a corresponding comm from the kernel');
+  let code = `
+from ipykernel.comm import Comm
+comm = Comm(target_name="test2")
+comm.send(data="comm sent message")
+comm.close(data="closing comm")
+`;
+  await kernel.requestExecute({ code: code }).done;
+
+  // Wait for the comm to be closed on our side
+  await done.promise;
+}

+ 21 - 0
packages/services/examples/browser/src/config.ts

@@ -0,0 +1,21 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { ConfigWithDefaults, ConfigSection } from '@jupyterlab/services';
+
+import { log } from './log';
+
+export async function main() {
+  log('Config');
+  // The base url of the Jupyter server.
+
+  let section = await ConfigSection.create({ name: 'notebook' });
+  let config = new ConfigWithDefaults({
+    section,
+    defaults: { default_cell_type: 'code' },
+    className: 'Notebook'
+  });
+  log(config.get('default_cell_type')); // 'code'
+  let data = await config.set('foo', 'bar');
+  log(data);
+}

+ 54 - 0
packages/services/examples/browser/src/contents.ts

@@ -0,0 +1,54 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { ContentsManager } from '@jupyterlab/services';
+
+import { log } from './log';
+
+export async function main() {
+  let contents = new ContentsManager();
+
+  log('Create a new directory');
+  let model = await contents.newUntitled({ path: '/', type: 'directory' });
+  log(`Created directory ${model.path}`);
+
+  log('Move the new directory to /tmp');
+  await contents.rename(model.path, '/tmp');
+
+  log('Create new python file');
+  let model2 = await contents.newUntitled({
+    path: '/tmp',
+    type: 'file',
+    ext: 'py'
+  });
+  log(`Created ${model2.path}`);
+
+  log('Rename file');
+  await contents.rename(model2.path, '/tmp/foo.txt');
+
+  log('Get contents of /tmp');
+  await contents.get('/tmp');
+
+  log('Save a file');
+  await contents.save('/tmp/bar.txt');
+
+  log('Copy a file');
+  let model3 = await contents.copy('/tmp/bar.txt', '/tmp');
+  log(`Copied to ${model3.path}`);
+
+  log('Create a checkpoint');
+  let checkpoint = await contents.createCheckpoint('/tmp/bar.txt');
+
+  log('Restore a checkpoint');
+  await contents.restoreCheckpoint('/tmp/bar.txt', checkpoint.id);
+
+  log('List checkpoints for a file');
+  let models2 = await contents.listCheckpoints('/tmp/bar.txt');
+  log(models2[0].id);
+
+  log('Delete a checkpoint');
+  await contents.deleteCheckpoint('/tmp/bar.txt', checkpoint.id);
+
+  log('Delete a file');
+  await contents.delete('/tmp/bar.txt');
+}

+ 41 - 38
packages/services/examples/browser/src/index.ts

@@ -1,54 +1,57 @@
-/*-----------------------------------------------------------------------------
-| Copyright (c) 2014-2015, Jupyter Development Team.
-|
-| Distributed under the terms of the Modified BSD License.
-|----------------------------------------------------------------------------*/
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
 
 import { PageConfig, URLExt } from '@jupyterlab/coreutils';
 // @ts-ignore
 __webpack_public_path__ = URLExt.join(PageConfig.getBaseUrl(), 'example/');
 
-import { Session, KernelManager, SessionManager } from '@jupyterlab/services';
+import * as comm from './comm';
+import * as config from './config';
+import * as contents from './contents';
+import * as kernel from './kernel';
+import * as kernelspec from './kernelspec';
+import * as session from './session';
+import * as terminal from './terminal';
 
-function log(text: string): void {
-  let el = document.getElementById('output');
-  el.textContent = el.textContent + '\n' + text;
-  console.log(text);
-}
+import { log } from './log';
 
 async function main() {
-  let kernelManager = new KernelManager();
-  let sessionManager = new SessionManager({ kernelManager });
-
-  // Start a new session.
-  let options: Session.ISessionOptions = {
-    kernel: {
-      name: 'python'
-    },
-    path: 'foo.ipynb',
-    type: 'notebook',
-    name: 'foo.ipynb'
-  };
-
   try {
-    log('Starting session');
-    const sessionConnection = await sessionManager.startNew(options);
-    log('Session started');
-    await sessionConnection.setPath('bar.ipynb');
-    log(`Session renamed to ${sessionConnection.path}`);
-    let future = sessionConnection.kernel.requestExecute({ code: 'a = 1' });
-    future.onReply = reply => {
-      log('Got execute reply');
-    };
-    await future.done;
-    log('Future is fulfilled');
-    // Shut down the session.
-    await sessionConnection.shutdown();
-    log('Session shut down');
+    log('Starting tests');
+
+    log('Executing kernel spec example');
+    await kernelspec.main();
+    log('kernel spec example complete!');
+
+    log('Executing kernel example');
+    await kernel.main();
+    log('kernel example complete!');
+
+    log('Executing comm example');
+    await comm.main();
+    log('comm example complete!');
+
+    log('Executing session example');
+    await session.main();
+    log('session example complete!');
+
+    log('Executing contents example');
+    await contents.main();
+    log('contents example complete!');
+
+    log('Executing config example');
+    await config.main();
+    log('config example complete!');
+
+    log('Executing terminal example');
+    await terminal.main();
+    log('terminal example complete!');
+
     log('Test Complete!');
   } catch (err) {
     console.error(err);
     log('Test Failed! See the console output for details');
+    throw err;
   }
 }
 

+ 64 - 0
packages/services/examples/browser/src/kernel.ts

@@ -0,0 +1,64 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { KernelAPI, KernelManager, KernelMessage } from '@jupyterlab/services';
+
+import { log } from './log';
+
+export async function main() {
+  // Start a python kernel
+  let kernelManager = new KernelManager();
+  let kernel = await kernelManager.startNew({ name: 'python' });
+
+  // Register a callback for when the kernel changes state.
+  kernel.statusChanged.connect((_, status) => {
+    log(`Status: ${status}`);
+  });
+
+  log('Executing code');
+  let future = kernel.requestExecute({ code: 'a = 1' });
+  // Handle iopub messages
+  future.onIOPub = msg => {
+    if (msg.header.msg_type !== 'status') {
+      log(msg.content);
+    }
+  };
+  await future.done;
+  log('Execution is done');
+
+  log('Send an inspect message');
+  let request: KernelMessage.IInspectRequestMsg['content'] = {
+    code: 'hello',
+    cursor_pos: 4,
+    detail_level: 0
+  };
+  let inspectReply = await kernel.requestInspect(request);
+  log('Looking at reply');
+  if (inspectReply.content.status === 'ok') {
+    log('Inspect reply:');
+    log(inspectReply.content.data);
+  }
+
+  log('Interrupting the kernel');
+  await kernel.interrupt();
+
+  log('Send an completion message');
+  let reply = await kernel.requestComplete({ code: 'impor', cursor_pos: 4 });
+  if (reply.content.status === 'ok') {
+    log(reply.content.matches);
+  }
+
+  log('Restarting kernel');
+  await kernel.restart();
+
+  log('Shutting down kernel');
+  await kernel.shutdown();
+
+  log('Finding all existing kernels');
+  let kernelModels = await KernelAPI.listRunning();
+  log(kernelModels);
+  if (kernelModels.length > 0) {
+    log(`Connecting to ${kernelModels[0].name}`);
+    kernelManager.connectTo({ model: kernelModels[0] });
+  }
+}

+ 15 - 0
packages/services/examples/browser/src/kernelspec.ts

@@ -0,0 +1,15 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { KernelSpecManager } from '@jupyterlab/services';
+
+import { log } from './log';
+
+export async function main() {
+  log('Get the list of kernel specs');
+  let kernelSpecManager = new KernelSpecManager();
+  await kernelSpecManager.ready;
+  let kernelSpecs = kernelSpecManager.specs;
+  log(`Default spec: ${kernelSpecs.default}`);
+  log(`Available specs: ${Object.keys(kernelSpecs.kernelspecs)}`);
+}

+ 11 - 0
packages/services/examples/browser/src/log.ts

@@ -0,0 +1,11 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+export function log(content: any): void {
+  let el = document.getElementById('output');
+  if (typeof content !== 'string') {
+    content = JSON.stringify(content);
+  }
+  el.textContent = el.textContent + '\n' + content;
+  console.log(content);
+}

+ 48 - 0
packages/services/examples/browser/src/session.ts

@@ -0,0 +1,48 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  Session,
+  SessionAPI,
+  KernelManager,
+  SessionManager
+} from '@jupyterlab/services';
+
+import { log } from './log';
+
+export async function main() {
+  log('Starting session manager');
+  let kernelManager = new KernelManager();
+  let sessionManager = new SessionManager({ kernelManager });
+
+  log('Start a new session');
+  let options: Session.ISessionOptions = {
+    kernel: {
+      name: 'python'
+    },
+    path: 'foo.ipynb',
+    type: 'notebook',
+    name: 'foo.ipynb'
+  };
+  const sessionConnection = await sessionManager.startNew(options);
+
+  log('Change the session path to "bar.ipynb"');
+  await sessionConnection.setPath('bar.ipynb');
+
+  log('Execute "a=1"');
+  let future = sessionConnection.kernel.requestExecute({ code: 'a = 1' });
+  future.onReply = reply => {
+    log(`Got execute reply with status ${reply.content.status}`);
+  };
+  await future.done;
+
+  log('Shut down session');
+  await sessionConnection.shutdown();
+
+  log('Get a list of session models and connect to one if any exist');
+  let sessionModels = await SessionAPI.listRunning();
+  if (sessionModels.length > 0) {
+    let session = sessionManager.connectTo({ model: sessionModels[0] });
+    log(`Connected to ${session.kernel.name}`);
+  }
+}

+ 17 - 0
packages/services/examples/browser/src/terminal.ts

@@ -0,0 +1,17 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { TerminalSession } from '@jupyterlab/services';
+
+import { log } from './log';
+
+export async function main() {
+  log('Terminal');
+
+  // See if terminals are available
+  if (TerminalSession.isAvailable()) {
+    // Create a named terminal session and send some data.
+    let session = await TerminalSession.startNew();
+    session.send({ type: 'stdin', content: ['foo'] });
+  }
+}

+ 1 - 1
packages/services/package.json

@@ -35,7 +35,7 @@
   "typings": "lib/index.d.ts",
   "scripts": {
     "build": "tsc -b",
-    "clean": "rimraf docs && rimraf lib && rimraf test/build && rimraf test/coverage",
+    "clean": "rimraf docs && rimraf lib",
     "docs": "typedoc src",
     "prepublishOnly": "jlpm run build && webpack",
     "watch": "tsc -b --watch"