| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9862c6a commit c027287
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,6 +7,7 @@ | |||
| 7 | 7 | from datascience.daemon.daemon_python import ( | |
| 8 | 8 | error_decorator, | |
| 9 | 9 | PythonDaemon as BasePythonDaemon, | |
| 10 | + change_exec_context, | ||
| 10 | 11 | ) | |
| 11 | 12 | ||
| 12 | 13 | log = logging.getLogger(__name__) | |
@@ -24,7 +25,7 @@ def __getitem__(self, item): | |||
| 24 | 25 | ||
| 25 | 26 | @error_decorator | |
| 26 | 27 | def m_exec_module(self, module_name, args=[], cwd=None, env=None): | |
| 27 | - log.info("Exec in child class %s with args %s", module_name, args) | ||
| 28 | + log.info("Exec in DS Daemon %s with args %s", module_name, args) | ||
| 28 | 29 | args = [] if args is None else args | |
| 29 | 30 | ||
| 30 | 31 | if module_name == "jupyter" and args == ["kernelspec", "list"]: | |
@@ -35,6 +36,37 @@ def m_exec_module(self, module_name, args=[], cwd=None, env=None): | |||
| 35 | 36 | log.info("check base class stuff") | |
| 36 | 37 | return super().m_exec_module(module_name, args, cwd, env) | |
| 37 | 38 | ||
| 39 | + @error_decorator | ||
| 40 | + def m_exec_module_observable(self, module_name, args=None, cwd=None, env=None): | ||
| 41 | + log.info("Exec in DS Daemon (observable) %s with args %s", module_name, args) | ||
| 42 | + args = [] if args is None else args | ||
| 43 | + | ||
| 44 | + # Assumption is that `python -m jupyter notebook` or `python -m notebook` with observable output | ||
| 45 | + # will only ever be used to start a notebook and nothing else. | ||
| 46 | + # E.g. `python -m jupyter notebook --version` wouldn't require the use of exec_module_observable, | ||
| 47 | + # In such cases, we can get the output immediately. | ||
| 48 | + if (module_name == "jupyter" and args[0] == "notebook") or ( | ||
| 49 | + module_name == "notebook" | ||
| 50 | + ): | ||
| 51 | + # Args must not have ['notebook'] in the begining. Drop the `notebook` subcommand when using `jupyter` | ||
| 52 | + args = args[1:] if args[0] == "notebook" else args | ||
| 53 | + log.info("Starting notebook with args %s", args) | ||
| 54 | + | ||
| 55 | + # When launching notebook always ensure the first argument is `notebook`. | ||
| 56 | + with change_exec_context(args, cwd, env): | ||
| 57 | + self._start_notebook(args) | ||
| 58 | + else: | ||
| 59 | + return super().m_exec_module_observable(module_name, args, cwd, env) | ||
| 60 | + | ||
| 61 | + def _print_kernelspec_version(self): | ||
| 62 | + import jupyter_client | ||
| 63 | + | ||
| 64 | + # Check whether kernelspec module exists. | ||
| 65 | + import jupyter_client.kernelspec | ||
| 66 | + | ||
| 67 | + sys.stdout.write(jupyter_client.__version__) | ||
| 68 | + sys.stdout.flush() | ||
| 69 | + | ||
| 38 | 70 | def _print_kernelspec_version(self): | |
| 39 | 71 | import jupyter_client | |
| 40 | 72 | ||
@@ -55,9 +87,8 @@ def _print_kernel_list(self): | |||
| 55 | 87 | ) | |
| 56 | 88 | sys.stdout.flush() | |
| 57 | 89 | ||
| 58 | - def m_hello(self, rootUri=None, **kwargs): | ||
| 59 | - from notebook.notebookapp import main | ||
| 90 | + def _start_notebook(self, args): | ||
| 91 | + from notebook import notebookapp as app | ||
| 60 | 92 | ||
| 61 | - sys.argv = ["notebook", "--no-browser"] | ||
| 62 | - main() | ||
| 63 | - return {} | ||
| 93 | + sys.argv = [""] + args | ||
| 94 | + app.launch_new_instance() | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -199,14 +199,19 @@ export class PythonDaemonExecutionService implements IPythonDaemonExecutionServi | |||
| 199 | 199 | const subject = new Subject<Output<string>>(); | |
| 200 | 200 | const start = async () => { | |
| 201 | 201 | type ExecResponse = ErrorResponse & { stdout: string; stderr?: string }; | |
| 202 | + let response: ExecResponse; | ||
| 202 | 203 | if ('fileName' in moduleOrFile) { | |
| 203 | 204 | // tslint:disable-next-line: no-any | |
| 204 | 205 | const request = new RequestType<{ file_name: string; args: string[]; cwd?: string; env?: any }, ExecResponse, void, void>('exec_file_observable'); | |
| 205 | - await this.connection.sendRequest(request, { file_name: moduleOrFile.fileName, args, cwd: options.cwd, env: options.env }); | ||
| 206 | + response = await this.connection.sendRequest(request, { file_name: moduleOrFile.fileName, args, cwd: options.cwd, env: options.env }); | ||
| 206 | 207 | } else { | |
| 207 | 208 | // tslint:disable-next-line: no-any | |
| 208 | 209 | const request = new RequestType<{ module_name: string; args: string[]; cwd?: string; env?: any }, ExecResponse, void, void>('exec_module_observable'); | |
| 209 | - await this.connection.sendRequest(request, { module_name: moduleOrFile.moduleName, args, cwd: options.cwd, env: options.env }); | ||
| 210 | + response = await this.connection.sendRequest(request, { module_name: moduleOrFile.moduleName, args, cwd: options.cwd, env: options.env }); | ||
| 211 | + } | ||
| 212 | + // Might not get a response object back, as its observable. | ||
| 213 | + if (response && response.error){ | ||
| 214 | + throw new StdErrError(response.error); | ||
| 210 | 215 | } | |
| 211 | 216 | }; | |
| 212 | 217 | let stdErr = ''; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,6 +15,7 @@ import { traceError } from '../logger'; | |||
| 15 | 15 | import { IConfigurationService, IDisposableRegistry } from '../types'; | |
| 16 | 16 | import { sleep } from '../utils/async'; | |
| 17 | 17 | import { ProcessService } from './proc'; | |
| 18 | + import { PythonDaemonExecutionService } from './pythonDaemon'; | ||
| 18 | 19 | import { PythonExecutionService } from './pythonProcess'; | |
| 19 | 20 | import { | |
| 20 | 21 | DaemonExecutionFactoryCreationOptions, | |
@@ -67,7 +68,8 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { | |||
| 67 | 68 | env.PYTHONPATH = envPythonPath; | |
| 68 | 69 | } | |
| 69 | 70 | env.PYTHONUNBUFFERED = '1'; | |
| 70 | - const daemonProc = activatedProc!.execModuleObservable('datascience.daemon', [`--daemon-module=${options.daemonModule}`], { env }); | ||
| 71 | + const args = options.daemonModule ? [`--daemon-module=${options.daemonModule}`] : []; | ||
| 72 | + const daemonProc = activatedProc!.execModuleObservable('datascience.daemon', args, { env }); | ||
| 71 | 73 | if (!daemonProc.proc) { | |
| 72 | 74 | throw new Error('Failed to create Daemon Proc'); | |
| 73 | 75 | } | |
@@ -92,7 +94,8 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { | |||
| 92 | 94 | if (result.pong !== 'hello') { | |
| 93 | 95 | throw new Error(`Daemon did not reply to the ping, received: ${result.pong}`); | |
| 94 | 96 | } | |
| 95 | - return new options.daemonClass(activatedProc, pythonPath, daemonProc.proc, connection); | ||
| 97 | + const cls = options.daemonClass ? options.daemonClass : PythonDaemonExecutionService; | ||
| 98 | + return new cls(activatedProc!, pythonPath, daemonProc.proc, connection); | ||
| 96 | 99 | } catch (ex) { | |
| 97 | 100 | traceError('Failed to start the Daemon, StdErr: ', stdError); | |
| 98 | 101 | traceError('Failed to start the Daemon, ProcEndEx', procEndEx || ex); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -70,8 +70,8 @@ export type DaemonExecutionFactoryCreationOptions = ExecutionFactoryCreationOpti | |||
| 70 | 70 | * | |
| 71 | 71 | * @type {string} | |
| 72 | 72 | */ | |
| 73 | - daemonModule: string; | ||
| 74 | - daemonClass: Newable<IPythonDaemonExecutionService>; | ||
| 73 | + daemonModule?: string; | ||
| 74 | + daemonClass?: Newable<IPythonDaemonExecutionService>; | ||
| 75 | 75 | }; | |
| 76 | 76 | export type ExecutionFactoryCreateWithEnvironmentOptions = { | |
| 77 | 77 | resource?: Uri; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,6 +14,7 @@ import { | |||
| 14 | 14 | } from '../../common/process/types'; | |
| 15 | 15 | import { IEnvironmentActivationService } from '../../interpreter/activation/types'; | |
| 16 | 16 | import { IInterpreterService, PythonInterpreter } from '../../interpreter/contracts'; | |
| 17 | + import { JupyterCommands } from '../constants'; | ||
| 17 | 18 | import { IJupyterCommand, IJupyterCommandFactory } from '../types'; | |
| 18 | 19 | ||
| 19 | 20 | // JupyterCommand objects represent some process that can be launched that should be guaranteed to work because it | |
@@ -64,14 +65,12 @@ class ProcessJupyterCommand implements IJupyterCommand { | |||
| 64 | 65 | } | |
| 65 | 66 | ||
| 66 | 67 | class InterpreterJupyterCommand implements IJupyterCommand { | |
| 67 | - private requiredArgs: string[]; | ||
| 68 | - private interpreterPromise: Promise<PythonInterpreter | undefined>; | ||
| 68 | + protected interpreterPromise: Promise<PythonInterpreter | undefined>; | ||
| 69 | 69 | private pythonLauncher: Promise<IPythonExecutionService>; | |
| 70 | 70 | ||
| 71 | - constructor(args: string[], pythonExecutionFactory: IPythonExecutionFactory, interpreter: PythonInterpreter) { | ||
| 72 | - this.requiredArgs = args; | ||
| 73 | - this.interpreterPromise = Promise.resolve(interpreter); | ||
| 74 | - this.pythonLauncher = pythonExecutionFactory.createActivatedEnvironment({ resource: undefined, interpreter, allowEnvironmentFetchExceptions: true }); | ||
| 71 | + constructor(protected readonly moduleName: string, protected args: string[], pythonExecutionFactory: IPythonExecutionFactory, private readonly _interpreter: PythonInterpreter) { | ||
| 72 | + this.interpreterPromise = Promise.resolve(this._interpreter); | ||
| 73 | + this.pythonLauncher = pythonExecutionFactory.createActivatedEnvironment({ resource: undefined, interpreter: _interpreter, allowEnvironmentFetchExceptions: true }); | ||
| 75 | 74 | } | |
| 76 | 75 | public interpreter() : Promise<PythonInterpreter | undefined> { | |
| 77 | 76 | return this.interpreterPromise; | |
@@ -80,18 +79,32 @@ class InterpreterJupyterCommand implements IJupyterCommand { | |||
| 80 | 79 | public async execObservable(args: string[], options: SpawnOptions): Promise<ObservableExecutionResult<string>> { | |
| 81 | 80 | const newOptions = { ...options }; | |
| 82 | 81 | const launcher = await this.pythonLauncher; | |
| 83 | - const newArgs = [...this.requiredArgs, ...args]; | ||
| 82 | + const newArgs = [...this.args, ...args]; | ||
| 84 | 83 | return launcher.execObservable(newArgs, newOptions); | |
| 85 | 84 | } | |
| 86 | 85 | ||
| 87 | 86 | public async exec(args: string[], options: SpawnOptions): Promise<ExecutionResult<string>> { | |
| 88 | 87 | const newOptions = { ...options }; | |
| 89 | 88 | const launcher = await this.pythonLauncher; | |
| 90 | - const newArgs = [...this.requiredArgs, ...args]; | ||
| 89 | + const newArgs = [...this.args, ...args]; | ||
| 91 | 90 | return launcher.exec(newArgs, newOptions); | |
| 92 | 91 | } | |
| 93 | 92 | } | |
| 94 | 93 | ||
| 94 | + /** | ||
| 95 | + * This class is used to launch the notebook. | ||
| 96 | + * I.e. anything to do with the command `python -m jupyter notebook` or `python -m notebook`. | ||
| 97 | + * | ||
| 98 | + * @class InterpreterJupyterNotebookCommand | ||
| 99 | + * @implements {IJupyterCommand} | ||
| 100 | + */ | ||
| 101 | + class InterpreterJupyterNotebookCommand extends InterpreterJupyterCommand { | ||
| 102 | + constructor(moduleName: string, args: string[], pythonExecutionFactory: IPythonExecutionFactory, interpreter: PythonInterpreter) { | ||
| 103 | + super(moduleName, args, pythonExecutionFactory, interpreter); | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + // tslint:disable-next-line: max-classes-per-file | ||
| 95 | 108 | @injectable() | |
| 96 | 109 | export class JupyterCommandFactory implements IJupyterCommandFactory { | |
| 97 | 110 | ||
@@ -104,8 +117,11 @@ export class JupyterCommandFactory implements IJupyterCommandFactory { | |||
| 104 | 117 | ||
| 105 | 118 | } | |
| 106 | 119 | ||
| 107 | - public createInterpreterCommand(args: string[], interpreter: PythonInterpreter): IJupyterCommand { | ||
| 108 | - return new InterpreterJupyterCommand(args, this.executionFactory, interpreter); | ||
| 120 | + public createInterpreterCommand(command: JupyterCommands, moduleName: string, args: string[], interpreter: PythonInterpreter): IJupyterCommand { | ||
| 121 | + if (command === JupyterCommands.NotebookCommand){ | ||
| 122 | + return new InterpreterJupyterNotebookCommand(moduleName, args, this.executionFactory, interpreter); | ||
| 123 | + } | ||
| 124 | + return new InterpreterJupyterCommand(moduleName, args, this.executionFactory, interpreter); | ||
| 109 | 125 | } | |
| 110 | 126 | ||
| 111 | 127 | public createProcessCommand(exe: string, args: string[]): IJupyterCommand { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments