utils.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. // tslint:disable-next-line
  4. /// <reference path="./typings/json-to-html/json-to-html.d.ts"/>
  5. import json2html = require('json-to-html');
  6. import { simulate } from 'simulate-event';
  7. import { ServiceManager } from '@jupyterlab/services';
  8. import { ClientSession } from '@jupyterlab/apputils';
  9. import { nbformat } from '@jupyterlab/coreutils';
  10. import { UUID } from '@phosphor/coreutils';
  11. import {
  12. TextModelFactory,
  13. DocumentRegistry,
  14. Context
  15. } from '@jupyterlab/docregistry';
  16. import { INotebookModel, NotebookModelFactory } from '@jupyterlab/notebook';
  17. import {
  18. IRenderMime,
  19. RenderMimeRegistry,
  20. RenderedHTML,
  21. standardRendererFactories
  22. } from '@jupyterlab/rendermime';
  23. /**
  24. * Return a promise that resolves in the given milliseconds with the given value.
  25. */
  26. export function sleep<T>(milliseconds: number = 0, value?: T): Promise<T> {
  27. return new Promise((resolve, reject) => {
  28. setTimeout(() => {
  29. resolve(value);
  30. }, milliseconds);
  31. });
  32. }
  33. /**
  34. * Get a copy of the default rendermime instance.
  35. */
  36. export function defaultRenderMime(): RenderMimeRegistry {
  37. return Private.rendermime.clone();
  38. }
  39. /**
  40. * Create a client session object.
  41. */
  42. export async function createClientSession(
  43. options: Partial<ClientSession.IOptions> = {}
  44. ): Promise<ClientSession> {
  45. const manager = options.manager || Private.manager.sessions;
  46. await manager.ready;
  47. return new ClientSession({
  48. manager,
  49. path: options.path || UUID.uuid4(),
  50. name: options.name,
  51. type: options.type,
  52. kernelPreference: options.kernelPreference || {
  53. shouldStart: true,
  54. canStart: true,
  55. name: manager.specs.default
  56. }
  57. });
  58. }
  59. /**
  60. * Create a context for a file.
  61. */
  62. export function createFileContext(
  63. path?: string,
  64. manager?: ServiceManager.IManager
  65. ): Context<DocumentRegistry.IModel> {
  66. const factory = Private.textFactory;
  67. manager = manager || Private.manager;
  68. path = path || UUID.uuid4() + '.txt';
  69. return new Context({ manager, factory, path });
  70. }
  71. /**
  72. * Create a context for a notebook.
  73. */
  74. export async function createNotebookContext(
  75. path?: string,
  76. manager?: ServiceManager.IManager
  77. ): Promise<Context<INotebookModel>> {
  78. const factory = Private.notebookFactory;
  79. manager = manager || Private.manager;
  80. path = path || UUID.uuid4() + '.ipynb';
  81. await manager.ready;
  82. return new Context({
  83. manager,
  84. factory,
  85. path,
  86. kernelPreference: { name: manager.specs.default }
  87. });
  88. }
  89. /**
  90. * Wait for a dialog to be attached to an element.
  91. */
  92. export function waitForDialog(
  93. host?: HTMLElement,
  94. timeout?: number
  95. ): Promise<void> {
  96. return new Promise<void>((resolve, reject) => {
  97. let counter = 0;
  98. const interval = 25;
  99. const limit = Math.floor((timeout || 250) / interval);
  100. const seek = () => {
  101. if (++counter === limit) {
  102. reject(new Error('Dialog not found'));
  103. return;
  104. }
  105. if ((host || document.body).getElementsByClassName('jp-Dialog')[0]) {
  106. resolve(undefined);
  107. return;
  108. }
  109. setTimeout(seek, interval);
  110. };
  111. seek();
  112. });
  113. }
  114. /**
  115. * Accept a dialog after it is attached by accepting the default button.
  116. */
  117. export async function acceptDialog(
  118. host?: HTMLElement,
  119. timeout?: number
  120. ): Promise<void> {
  121. host = host || document.body;
  122. await waitForDialog(host, timeout);
  123. const node = host.getElementsByClassName('jp-Dialog')[0];
  124. if (node) {
  125. simulate(node as HTMLElement, 'keydown', { keyCode: 13 });
  126. }
  127. }
  128. /**
  129. * Dismiss a dialog after it is attached.
  130. *
  131. * #### Notes
  132. * This promise will always resolve successfully.
  133. */
  134. export async function dismissDialog(
  135. host?: HTMLElement,
  136. timeout?: number
  137. ): Promise<void> {
  138. host = host || document.body;
  139. try {
  140. await waitForDialog(host, timeout);
  141. } catch (error) {
  142. return; // Ignore calls to dismiss the dialog if there is no dialog.
  143. }
  144. const node = host.getElementsByClassName('jp-Dialog')[0];
  145. if (node) {
  146. simulate(node as HTMLElement, 'keydown', { keyCode: 27 });
  147. }
  148. }
  149. /**
  150. * A namespace for private data.
  151. */
  152. namespace Private {
  153. export const manager = new ServiceManager();
  154. export const textFactory = new TextModelFactory();
  155. export const notebookFactory = new NotebookModelFactory({});
  156. class JSONRenderer extends RenderedHTML {
  157. mimeType = 'text/html';
  158. renderModel(model: IRenderMime.IMimeModel): Promise<void> {
  159. let source = model.data['application/json'];
  160. model.setData({ data: { 'text/html': json2html(source) } });
  161. return super.renderModel(model);
  162. }
  163. }
  164. const jsonRendererFactory = {
  165. mimeTypes: ['application/json'],
  166. safe: true,
  167. createRenderer(
  168. options: IRenderMime.IRendererOptions
  169. ): IRenderMime.IRenderer {
  170. return new JSONRenderer(options);
  171. }
  172. };
  173. export const rendermime = new RenderMimeRegistry({
  174. initialFactories: standardRendererFactories
  175. });
  176. rendermime.addFactory(jsonRendererFactory, 10);
  177. }
  178. /**
  179. * The default outputs used for testing.
  180. */
  181. export const DEFAULT_OUTPUTS: nbformat.IOutput[] = [
  182. {
  183. name: 'stdout',
  184. output_type: 'stream',
  185. text: ['hello world\n', '0\n', '1\n', '2\n']
  186. },
  187. {
  188. name: 'stderr',
  189. output_type: 'stream',
  190. text: ['output to stderr\n']
  191. },
  192. {
  193. name: 'stderr',
  194. output_type: 'stream',
  195. text: ['output to stderr2\n']
  196. },
  197. {
  198. output_type: 'execute_result',
  199. execution_count: 1,
  200. data: { 'text/plain': 'foo' },
  201. metadata: {}
  202. },
  203. {
  204. output_type: 'display_data',
  205. data: { 'text/plain': 'hello, world' },
  206. metadata: {}
  207. },
  208. {
  209. output_type: 'error',
  210. ename: 'foo',
  211. evalue: 'bar',
  212. traceback: ['fizz', 'buzz']
  213. }
  214. ];