Browse Source

merge upstream

J Forde 7 years ago
parent
commit
c4abbee218

+ 3 - 3
CONTRIBUTING.md

@@ -26,7 +26,7 @@ All source code is written in [TypeScript](http://www.typescriptlang.org/Handboo
 ### Installing Node.js and jlpm
 
 Building JupyterLab from its GitHub source code requires Node.js version
-4+.
+5+.
 
 If you use ``conda``, you can get it with:
 
@@ -205,7 +205,7 @@ The JupyterLab application is made up of two major parts:
 - an npm package
 - a Jupyter server extension (Python package)
 
-Each part is named `jupyterlab`. The [developer tutorial documentation](https://jupyterlab-tutorial.readthedocs.io/en/latest/index.html)
+Each part is named `jupyterlab`. The [developer tutorial documentation](https://jupyterlab.readthedocs.io/en/latest/index.html)
 provides additional architecture information.
 
 ## The NPM Packages
@@ -316,7 +316,7 @@ run `jupyter lab --core-mode`.  This is the core application that will
 be shipped.
 
 - If working with extensions, see the extension documentation on
-https://jupyterlab-tutorial.readthedocs.io/en/latest/index.html.
+https://jupyterlab.readthedocs.io/en/latest/index.html.
 
 - The npm modules are fully compatible with Node/Babel/ES6/ES5. Simply
 omit the type declarations when using a language other than TypeScript.

+ 4 - 4
README.md

@@ -127,7 +127,7 @@ A tool like [postcss](http://postcss.org/) can be used to convert the CSS files
 
 ## Documentation
 
-Read our documentation on [ReadTheDocs](http://jupyterlab-tutorial.readthedocs.io/en/latest/).
+Read our documentation on [ReadTheDocs](http://jupyterlab.readthedocs.io/en/latest/).
 
 ----
 
@@ -143,7 +143,7 @@ JupyterLab follows the official [Jupyter Code of Conduct](https://github.com/jup
 
 JupyterLab can be extended using extensions that are [npm](https://www.npmjs.com/) packages
 and use our public APIs. See our documentation
-for [users](https://jupyterlab-tutorial.readthedocs.io/en/latest/user/extensions.html) and [developers](https://jupyterlab-tutorial.readthedocs.io/en/latest/developer/extension_dev.html).
+for [users](https://jupyterlab.readthedocs.io/en/latest/user/extensions.html) and [developers](https://jupyterlab.readthedocs.io/en/latest/developer/extension_dev.html).
 
 ### License
 
@@ -167,7 +167,7 @@ JupyterLab is part of [Project Jupyter](http://jupyter.org/) and is developed by
 * Cameron Oelsen, Cal Poly (UI/UX design).
 * Fernando Perez, UC Berkeley (co-creator, vision).
 * Ian Rose, UC Berkeley (Real-time collaboration, document architecture).
-* Steven Silvester, Project Jupyter (co-creator, release management, packaging,
+* Steven Silvester, Quansight (co-creator, release management, packaging,
   prolific contributions throughout the code base).
 
 This list is provided to help provide context about who we are and how our team functions.
@@ -185,7 +185,7 @@ and you may participate in development discussions or get live help on [Gitter](
 ## Resources
 
 - [Reporting Issues](https://github.com/jupyterlab/jupyterlab/issues)
-- [Architecture tutorial](https://jupyterlab-tutorial.readthedocs.io/en/latest/index.html)
+- [Architecture tutorial](https://jupyterlab.readthedocs.io/en/latest/index.html)
 - [API Docs](http://jupyterlab.github.io/jupyterlab/)
 - [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html) | [PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)
 - [Project Jupyter website](https://jupyter.org)

+ 4 - 0
jupyterlab/__main__.py

@@ -0,0 +1,4 @@
+from jupyterlab.labapp import main
+import sys
+
+sys.exit(main())

+ 9 - 2
jupyterlab/commands.py

@@ -298,7 +298,7 @@ def unlink_package(package, app_dir=None, logger=None):
 def get_app_version(app_dir=None):
     """Get the application version."""
     app_dir = app_dir or get_app_dir()
-    handler = _AppHandler(app_dir)
+    handler = _AppHandler(app_dir, node_check=False)
     return handler.info['version']
 
 
@@ -309,12 +309,19 @@ def get_app_version(app_dir=None):
 
 class _AppHandler(object):
 
-    def __init__(self, app_dir, logger=None, kill_event=None):
+    def __init__(self, app_dir, logger=None, kill_event=None, node_check=True):
         self.app_dir = app_dir or get_app_dir()
         self.sys_dir = get_app_dir()
         self.logger = logger or logging.getLogger('jupyterlab')
         self.info = self._get_app_info()
         self.kill_event = kill_event or Event()
+        if not node_check:
+            return
+        try:
+            self._run(['node', 'node-version-check.js'], cwd=HERE, quiet=True)
+        except Exception:
+            msg = 'Please install nodejs 5+ and npm before continuing installation. nodejs may be installed using conda or directly from the nodejs website.'
+            raise ValueError(msg)
 
     def install_extension(self, extension, existing=None):
         """Install an extension package into JupyterLab.

+ 1 - 1
jupyterlab/jlpmapp.py

@@ -55,7 +55,7 @@ def which(command, env=None):
     command_with_path = _which(command, path=path)
     if not command_with_path:
         if command in ['node', 'npm']:
-            msg = 'Please install nodejs and npm before continuing installation. nodejs may be installed using conda or directly from the nodejs website.'
+            msg = 'Please install nodejs 5+ and npm before continuing installation. nodejs may be installed using conda or directly from the nodejs website.'
             raise ValueError(msg)
         raise ValueError('The command was not found or was not ' +
                 'executable: %s.' % command)

+ 5 - 0
jupyterlab/node-version-check.js

@@ -0,0 +1,5 @@
+#!/usr/bin/env node
+var version = parseInt(process.version.replace('v', ''));
+if (version < 5) {
+  process.exit(1);
+}

+ 3 - 2
jupyterlab/process.py

@@ -42,7 +42,7 @@ class Process(object):
     _pool = None
 
     def __init__(self, cmd, logger=None, cwd=None, kill_event=None,
-                 env=None):
+                 env=None, quiet=False):
         """Start a subprocess that can be run asynchronously.
 
         Parameters
@@ -66,7 +66,8 @@ class Process(object):
 
         self.logger = logger = logger or logging.getLogger('jupyterlab')
         self._last_line = ''
-        self.logger.info('> ' + list2cmdline(cmd))
+        if not quiet:
+            self.logger.info('> ' + list2cmdline(cmd))
         self.cmd = cmd
 
         self.proc = self._create_process(cwd=cwd, env=env)

+ 5 - 0
packages/codemirror/src/editor.ts

@@ -1175,6 +1175,11 @@ namespace Private {
    */
   export
   function setOption<K extends keyof CodeMirrorEditor.IConfig>(editor: CodeMirror.Editor, option: K, value: CodeMirrorEditor.IConfig[K]): void {
+    // Don't bother setting the option if it is already the same.
+    const oldValue = getOption(editor, option);
+    if (oldValue === value) {
+      return;
+    }
     switch (option) {
     case 'lineWrap':
       editor.setOption('lineWrapping', value);

+ 1 - 1
packages/completer/src/handler.ts

@@ -272,7 +272,7 @@ class CompletionHandler implements IDisposable {
     }
 
     // If the part of the line before the cursor is white space, return.
-    if (line.slice(0, position.column).match(/^\W*$/)) {
+    if (line.slice(0, position.column).match(/^\s*$/)) {
       this._enabled = false;
       model.reset(true);
       host.classList.remove(COMPLETER_ENABLED_CLASS);

+ 3 - 7
packages/coreutils/src/url.ts

@@ -97,13 +97,9 @@ namespace URLExt {
    */
   export
   function isLocal(url: string): boolean {
-    switch (parse(url).host) {
-    case location.host:
-    case '':
-      return true;
-    default:
-      return false;
-    }
+    const { host, protocol } = parse(url);
+
+    return protocol !== 'data:' && host === location.host || host === '';
   }
 
   /**

+ 2 - 2
packages/faq-extension/faq.md

@@ -14,7 +14,7 @@
 
 ## General
 
-Welcome to the Frequently Asked Questions (FAQ) for the JupyterLab Beta 1 Release.
+Welcome to the Frequently Asked Questions (FAQ) for the JupyterLab Beta Release Series.
 
 ### What is JupyterLab?
 
@@ -52,7 +52,7 @@ for more detailed information about these and other features.
 
 ### How stable is JupyterLab?
 
-This Beta 1 version of JupyterLab is ready for you to use! Starting with this
+This Beta version of JupyterLab is ready for you to use! Starting with this
 release, the JupyterLab Beta series of releases are characterized by:
 
 * Stable and featureful enough for daily usage.

+ 1 - 1
packages/help-extension/src/index.ts

@@ -311,7 +311,7 @@ function activate(app: JupyterLab, mainMenu: IMainMenu, palette: ICommandPalette
       // Create the header of the about dialog
       let headerLogo = h.div({className: 'jp-About-header-logo'});
       let headerWordmark = h.div({className: 'jp-About-header-wordmark'});
-      let release = 'Beta 1 Release';
+      let release = 'Beta Release Series';
       let versionNumber = `Version ${info.version}`;
       let versionInfo = h.span({className: 'jp-About-version-info'},
         h.span({className: 'jp-About-release'}, release),

+ 13 - 4
packages/notebook-extension/src/index.ts

@@ -708,8 +708,6 @@ function addCommands(app: JupyterLab, services: ServiceManager, tracker: Noteboo
     if (!isEnabled()) { return false; }
     const { notebook } = tracker.currentWidget;
     const index = notebook.activeCellIndex;
-    // Can't run above if we are at the top of a notebook.
-    if (index === notebook.widgets.length - 1) { return false; }
     // If there are selections that are not the active cell,
     // this command is confusing, so disable it.
     for (let i = 0; i < notebook.widgets.length; ++i) {
@@ -783,7 +781,12 @@ function addCommands(app: JupyterLab, services: ServiceManager, tracker: Noteboo
         return NotebookActions.runAllAbove(notebook, context.session);
       }
     },
-    isEnabled: isEnabledAndSingleSelected
+    isEnabled: () => {
+      // Can't run above if there are multiple cells selected,
+      // or if we are at the top of the notebook.
+      return isEnabledAndSingleSelected() &&
+             tracker.currentWidget.notebook.activeCellIndex !== 0;
+    }
   });
   commands.addCommand(CommandIDs.runAllBelow, {
     label: 'Run Selected Cell and All Below',
@@ -796,7 +799,13 @@ function addCommands(app: JupyterLab, services: ServiceManager, tracker: Noteboo
         return NotebookActions.runAllBelow(notebook, context.session);
       }
     },
-    isEnabled: isEnabledAndSingleSelected
+    isEnabled: () => {
+      // Can't run below if there are multiple cells selected,
+      // or if we are at the bottom of the notebook.
+      return isEnabledAndSingleSelected() &&
+             tracker.currentWidget.notebook.activeCellIndex !==
+             tracker.currentWidget.notebook.widgets.length - 1;
+    }
   });
   commands.addCommand(CommandIDs.restart, {
     label: 'Restart Kernel…',

+ 2 - 3
packages/notebook/style/index.css

@@ -29,8 +29,8 @@
 
 
 .jp-NotebookPanel {
-  display: flex;
-  flex-direction: column;
+  display: block;
+  overflow: scroll;
   height: 100%;
 }
 
@@ -40,7 +40,6 @@
 }
 
 .jp-Notebook {
-  flex: 1 1 auto;
   padding: var(--jp-notebook-padding);
   outline: none;
   overflow: auto;

+ 4 - 1
packages/observables/src/modeldb.ts

@@ -10,7 +10,7 @@ import {
 } from '@phosphor/signaling';
 
 import {
-  JSONValue, JSONObject
+  JSONExt, JSONValue, JSONObject
 } from '@phosphor/coreutils';
 
 import {
@@ -319,6 +319,9 @@ class ObservableValue implements IObservableValue {
    */
   set(value: JSONValue): void {
     let oldValue = this._value;
+    if (JSONExt.deepEqual(oldValue, value)) {
+      return;
+    }
     this._value = value;
     this._changed.emit({
       oldValue: oldValue,

+ 2 - 6
packages/services/src/session/default.ts

@@ -281,12 +281,8 @@ class DefaultSession implements Session.ISession {
       return Promise.reject(new Error('Session is disposed'));
     }
     let data = JSON.stringify({ kernel: options });
-    if (this._kernel) {
-      return this._kernel.ready.then(() => {
-        this._kernel.dispose();
-        return this._patch(data);
-      }).then(() => this.kernel);
-    }
+    this._kernel.dispose();
+    this._statusChanged.emit('restarting');
     return this._patch(data).then(() => this.kernel);
   }
 

+ 8 - 4
packages/services/test/src/session/manager.spec.ts

@@ -131,8 +131,9 @@ describe('session/manager', () => {
         handleRequest(manager, 200, specs);
         manager.specsChanged.connect((sender, args) => {
           expect(sender).to.be(manager);
-          expect(args.default).to.be(specs.default);
-          done();
+          if (args.default === specs.default) {
+            done();
+          }
         });
         manager.refreshSpecs();
       });
@@ -185,6 +186,8 @@ describe('session/manager', () => {
           called = true;
         });
         return session.changeKernel({ name: session.kernel.name }).then(() => {
+          return manager.refreshRunning();
+        }).then(() => {
           expect(called).to.be(true);
         });
       });
@@ -286,8 +289,9 @@ describe('session/manager', () => {
         let called = false;
         return startNew(manager).then(s => {
           manager.runningChanged.connect((sender, args) => {
-            expect(s.isDisposed).to.be(true);
-            called = true;
+            if (s.isDisposed) {
+              called = true;
+            }
           });
           return manager.shutdown(s.id);
         }).then(() => {

+ 7 - 1
packages/services/test/src/terminal/terminal.spec.ts

@@ -7,6 +7,10 @@ import {
   PageConfig, uuid
 } from '@jupyterlab/coreutils';
 
+import {
+  Signal
+} from '@phosphor/signaling';
+
 import {
   TerminalSession
 } from '../../../lib/terminal';
@@ -120,14 +124,16 @@ describe('terminal', () => {
     describe('#messageReceived', () => {
 
       it('should be emitted when a message is received', (done) => {
+        const object = {};
         TerminalSession.startNew().then(s => {
           session = s;
           session.messageReceived.connect((sender, msg) => {
             expect(sender).to.be(session);
             if (msg.type === 'stdout') {
+              Signal.disconnectReceiver(object);
               done();
             }
-          });
+          }, object);
         }).catch(done);
       });
 

+ 2 - 15
packages/terminal-extension/src/index.ts

@@ -14,7 +14,7 @@ import {
 } from '@jupyterlab/launcher';
 
 import {
-  IMainMenu, IEditMenu
+  IMainMenu
 } from '@jupyterlab/mainmenu';
 
 import {
@@ -121,19 +121,6 @@ function activate(app: JupyterLab, mainMenu: IMainMenu, palette: ICommandPalette
   // Add terminal creation to the file menu.
   mainMenu.fileMenu.newMenu.addGroup([{ command: CommandIDs.createNew }], 20);
 
-  // Add terminal clearing to the edit menu.
-  mainMenu.editMenu.clearers.add({
-    tracker,
-    noun: 'Terminal',
-    clearCurrent: current => {
-      current.refresh().then(() => {
-        if (current) {
-          current.activate();
-        }
-      });
-    }
-  } as IEditMenu.IClearer<Terminal>);
-
   // Add a launcher item if the launcher is available.
   if (launcher) {
     launcher.add({
@@ -209,7 +196,7 @@ function addCommands(app: JupyterLab, services: ServiceManager, tracker: Instanc
   });
 
   commands.addCommand(CommandIDs.refresh, {
-    label: 'Clear Terminal',
+    label: 'Refresh Terminal',
     caption: 'Refresh the current terminal session',
     execute: () => {
       let current = tracker.currentWidget;

+ 1 - 1
setup.py

@@ -40,7 +40,7 @@ data_files_spec = [
 package_data_spec = dict()
 package_data_spec[NAME] = [
     'staging/*', 'staging/templates/*', 'static/**', 'tests/mock_packages/**',
-    'themes/**', 'schemas/**'
+    'themes/**', 'schemas/**', 'node-version-check.js'
 ]
 
 staging = pjoin(HERE, NAME, 'staging')