From bcc11366f56544a22296ce6745a0d48a2d260422 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 9 Aug 2023 10:35:40 +1000 Subject: [PATCH] Use module Augmentation to merge API types (#14082) * Move display names into Jupyter Server Uri storage * fix formatting * Avoid validation of Jupyter Server providers * Stop using display name from Uri storage * Use module Augmentation to merge API types * Fix linter * fix formatting --- src/api.proposed.d.ts | 2 +- src/api.pythonIntegration.d.ts | 14 +- src/api.unstable.d.ts | 751 +++++++++--------- .../jupyter/connection/jupyterConnection.ts | 2 +- .../connection/jupyterConnection.unit.test.ts | 2 +- .../jupyterUriProviderRegistration.ts | 2 +- ...upyterUriProviderRegistration.unit.test.ts | 2 +- .../jupyter/connection/serverSelector.ts | 2 +- .../connection/serverUriStorage.unit.test.ts | 2 +- src/kernels/jupyter/jupyterUtils.ts | 2 +- src/kernels/jupyter/types.ts | 2 +- src/standalone/api/api.ts | 7 +- src/standalone/api/kernelApi.ts | 2 +- .../serverSelectorForTests.ts | 2 +- .../userServerUrlProvider.ts | 2 +- src/telemetry.ts | 2 +- src/test/client/api.vscode.test.ts | 2 +- 17 files changed, 400 insertions(+), 400 deletions(-) diff --git a/src/api.proposed.d.ts b/src/api.proposed.d.ts index 122fea339d3..4ae69672ed7 100644 --- a/src/api.proposed.d.ts +++ b/src/api.proposed.d.ts @@ -1,4 +1,4 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export interface JupyterAPI {} +// diff --git a/src/api.pythonIntegration.d.ts b/src/api.pythonIntegration.d.ts index 50c8f09d59a..884c20acaa9 100644 --- a/src/api.pythonIntegration.d.ts +++ b/src/api.pythonIntegration.d.ts @@ -3,10 +3,12 @@ import { PythonApi } from './platform/api/types'; -/** - * These types are not required for any other extension, except for the Python extension. - * Hence the reason to keep this separate. This way we can keep the API stable for other extensions (which would be the majority case). - */ -export interface JupyterAPI { - registerPythonApi(pythonApi: PythonApi): void; +declare module './api' { + /** + * These types are not required for any other extension, except for the Python extension. + * Hence the reason to keep this separate. This way we can keep the API stable for other extensions (which would be the majority case). + */ + export interface JupyterAPI { + registerPythonApi(pythonApi: PythonApi): void; + } } diff --git a/src/api.unstable.d.ts b/src/api.unstable.d.ts index 147aa815ebb..36ae6ee9326 100644 --- a/src/api.unstable.d.ts +++ b/src/api.unstable.d.ts @@ -8,399 +8,400 @@ import type { Kernel } from '@jupyterlab/services/lib/kernel'; import type { Session } from '@jupyterlab/services'; import { IDataViewerDataProvider } from './webviews/extension-side/dataviewer/types'; -export interface JupyterAPI { - /** - * Promise indicating whether all parts of the extension have completed loading or not. - * @type {Promise} - * @memberof IExtensionApi - */ - ready: Promise; - /** - * Launches Data Viewer component. - * @param {IDataViewerDataProvider} dataProvider Instance that will be used by the Data Viewer component to fetch data. - * @param {string} title Data Viewer title - */ - showDataViewer(dataProvider: IDataViewerDataProvider, title: string): Promise; - /** - * Returns the suggested controller for a give Jupyter server and notebook. - */ - getSuggestedController( - providerId: string, - handle: string, - notebook: NotebookDocument - ): Promise; +declare module './api' { + export interface JupyterAPI { + /** + * Promise indicating whether all parts of the extension have completed loading or not. + * @type {Promise} + * @memberof IExtensionApi + */ + ready: Promise; + /** + * Launches Data Viewer component. + * @param {IDataViewerDataProvider} dataProvider Instance that will be used by the Data Viewer component to fetch data. + * @param {string} title Data Viewer title + */ + showDataViewer(dataProvider: IDataViewerDataProvider, title: string): Promise; + /** + * Returns the suggested controller for a give Jupyter server and notebook. + */ + getSuggestedController( + providerId: string, + handle: string, + notebook: NotebookDocument + ): Promise; - /** - * Registers a remote server provider component that's used to pick remote jupyter server URIs - * @param serverProvider object called back when picking jupyter server URI - */ - registerRemoteServerProvider(serverProvider: IJupyterUriProvider): Disposable; - /** - * Adds a remote Jupyter Server to the list of Remote Jupyter servers. - * This will result in the Jupyter extension listing kernels from this server as items in the kernel picker. - */ - addRemoteJupyterServer(providerId: string, handle: string): Promise; - /** - * Gets the service that provides access to kernels. - * Returns `undefined` if the calling extension is not allowed to access this API. This could - * happen either when user doesn't allow this or the extension doesn't allow this. - * There are a specific set of extensions that are currently allowed to access this API. - */ - getKernelService(): Promise; - /** - * Opens a notebook with a specific kernel as the active kernel. - * @param {Uri} uri Uri of the notebook to open. - * @param {String} kernelId Id of the kernel, retrieved from getKernelService().getKernelSpecifications() - * @returns {Promise} Promise that resolves to the notebook document. - */ - openNotebook(uri: Uri, kernelId: string): Promise; -} -//#region Jupyter Server Providers -export interface IJupyterServerUri { - baseUrl: string; - /** - * Jupyter auth Token - */ - token: string; - /** - * Authorization header to be used when connecting to the server. - */ - authorizationHeader?: Record; - displayName: string; - /** - * The local directory that maps to the remote directory of the Jupyter Server. - * E.g. assume you start Jupyter Notebook with --notebook-dir=/foo/bar, - * and you have a file named /foo/bar/sample.ipynb, /foo/bar/sample2.ipynb and the like. - * Then assume the mapped local directory will be /users/xyz/remoteServer and the files sample.ipynb and sample2.ipynb - * are in the above local directory. - * - * Using this setting one can map the local directory to the remote directory. - * In this case the value of this property would be /users/xyz/remoteServer. - * - * Note: A side effect of providing this value is the session names are generated the way they are in Jupyter Notebook/Lab. - * I.e. the session names map to the relative path of the notebook file. - * As a result when attempting to create a new session for a notebook/file, Jupyter will - * first check if a session already exists for the same file and same kernel, and if so, will re-use that session. - */ - mappedRemoteNotebookDir?: string; - /** - * Returns the sub-protocols to be used. See details of `protocols` here https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket - * Useful if there is a custom authentication scheme that needs to be used for WebSocket connections. - * Note: The client side npm package @jupyterlab/services uses WebSockets to connect to remote Kernels. - */ - webSocketProtocols?: string[]; -} + /** + * Registers a remote server provider component that's used to pick remote jupyter server URIs + * @param serverProvider object called back when picking jupyter server URI + */ + registerRemoteServerProvider(serverProvider: IJupyterUriProvider): Disposable; + /** + * Adds a remote Jupyter Server to the list of Remote Jupyter servers. + * This will result in the Jupyter extension listing kernels from this server as items in the kernel picker. + */ + addRemoteJupyterServer(providerId: string, handle: string): Promise; + /** + * Gets the service that provides access to kernels. + * Returns `undefined` if the calling extension is not allowed to access this API. This could + * happen either when user doesn't allow this or the extension doesn't allow this. + * There are a specific set of extensions that are currently allowed to access this API. + */ + getKernelService(): Promise; + /** + * Opens a notebook with a specific kernel as the active kernel. + * @param {Uri} uri Uri of the notebook to open. + * @param {String} kernelId Id of the kernel, retrieved from getKernelService().getKernelSpecifications() + * @returns {Promise} Promise that resolves to the notebook document. + */ + openNotebook(uri: Uri, kernelId: string): Promise; + } + //#region Jupyter Server Providers + export interface IJupyterServerUri { + baseUrl: string; + /** + * Jupyter auth Token + */ + token: string; + /** + * Authorization header to be used when connecting to the server. + */ + authorizationHeader?: Record; + displayName: string; + /** + * The local directory that maps to the remote directory of the Jupyter Server. + * E.g. assume you start Jupyter Notebook with --notebook-dir=/foo/bar, + * and you have a file named /foo/bar/sample.ipynb, /foo/bar/sample2.ipynb and the like. + * Then assume the mapped local directory will be /users/xyz/remoteServer and the files sample.ipynb and sample2.ipynb + * are in the above local directory. + * + * Using this setting one can map the local directory to the remote directory. + * In this case the value of this property would be /users/xyz/remoteServer. + * + * Note: A side effect of providing this value is the session names are generated the way they are in Jupyter Notebook/Lab. + * I.e. the session names map to the relative path of the notebook file. + * As a result when attempting to create a new session for a notebook/file, Jupyter will + * first check if a session already exists for the same file and same kernel, and if so, will re-use that session. + */ + mappedRemoteNotebookDir?: string; + /** + * Returns the sub-protocols to be used. See details of `protocols` here https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket + * Useful if there is a custom authentication scheme that needs to be used for WebSocket connections. + * Note: The client side npm package @jupyterlab/services uses WebSockets to connect to remote Kernels. + */ + webSocketProtocols?: string[]; + } -export interface IJupyterUriProvider { - /** - * Should be a unique string (like a guid) - */ - readonly id: string; - readonly displayName?: string; - readonly detail?: string; - onDidChangeHandles?: Event; - getQuickPickEntryItems?(): - | Promise< - (QuickPickItem & { + export interface IJupyterUriProvider { + /** + * Should be a unique string (like a guid) + */ + readonly id: string; + readonly displayName?: string; + readonly detail?: string; + onDidChangeHandles?: Event; + getQuickPickEntryItems?(): + | Promise< + (QuickPickItem & { + /** + * If this is the only quick pick item in the list and this is true, then this item will be selected by default. + */ + default?: boolean; + })[] + > + | (QuickPickItem & { /** * If this is the only quick pick item in the list and this is true, then this item will be selected by default. */ default?: boolean; - })[] - > - | (QuickPickItem & { - /** - * If this is the only quick pick item in the list and this is true, then this item will be selected by default. - */ - default?: boolean; - })[]; - handleQuickPick?(item: QuickPickItem, backEnabled: boolean): Promise; - /** - * Given the handle, returns the Jupyter Server information. - */ - getServerUri(handle: string): Promise; - /** - * Gets a list of all valid Jupyter Server handles that can be passed into the `getServerUri` method. - */ - getHandles?(): Promise; - /** - * Users request to remove a handle. - */ - removeHandle?(handle: string): Promise; -} -//#endregion + })[]; + handleQuickPick?(item: QuickPickItem, backEnabled: boolean): Promise; + /** + * Given the handle, returns the Jupyter Server information. + */ + getServerUri(handle: string): Promise; + /** + * Gets a list of all valid Jupyter Server handles that can be passed into the `getServerUri` method. + */ + getHandles?(): Promise; + /** + * Users request to remove a handle. + */ + removeHandle?(handle: string): Promise; + } + //#endregion -//#region Python Env Information (soon to be deprecated in favour of Python Extensions new Environments API) -/** - * The supported Python environment types. - */ -export enum EnvironmentType { - Unknown = 'Unknown', - Conda = 'Conda', - VirtualEnv = 'VirtualEnv', - Pipenv = 'PipEnv', - Pyenv = 'Pyenv', - Venv = 'Venv', - Poetry = 'Poetry', - VirtualEnvWrapper = 'VirtualEnvWrapper' -} + //#region Python Env Information (soon to be deprecated in favour of Python Extensions new Environments API) + /** + * The supported Python environment types. + */ + export enum EnvironmentType { + Unknown = 'Unknown', + Conda = 'Conda', + VirtualEnv = 'VirtualEnv', + Pipenv = 'PipEnv', + Pyenv = 'Pyenv', + Venv = 'Venv', + Poetry = 'Poetry', + VirtualEnvWrapper = 'VirtualEnvWrapper' + } -/** - * A representation of a Python runtime's version. - */ -export type PythonVersion = { /** - * The original version string. - */ - raw: string; - major: number; - minor: number; - patch: number; -}; -export type PythonEnvironment = { - id: string; - displayName?: string; - uri: Uri; - version?: PythonVersion; - sysPrefix: string; - envType?: EnvironmentType; - envName?: string; - envPath?: Uri; -}; -//#endregion + * A representation of a Python runtime's version. + */ + export type PythonVersion = { + /** + * The original version string. + */ + raw: string; + major: number; + minor: number; + patch: number; + }; + export type PythonEnvironment = { + id: string; + displayName?: string; + uri: Uri; + version?: PythonVersion; + sysPrefix: string; + envType?: EnvironmentType; + envName?: string; + envPath?: Uri; + }; + //#endregion -//#region Kernel Information (Kernel Specs, connections) -/** - * Details of the kernel spec. - * See https://jupyter-client.readthedocs.io/en/stable/kernels.html#kernel-specs - */ -export interface IJupyterKernelSpec { - /** - * Id of an existing (active) Kernel from an active session. - */ - id?: string; - name: string; - /** - * The name of the language of the kernel - */ - language?: string; - path: string; - /** - * A dictionary of environment variables to set for the kernel. - * These will be added to the current environment variables before the kernel is started. - */ - env?: NodeJS.ProcessEnv | undefined; - /** - * Kernel display name. - */ - readonly display_name: string; - /** - * A dictionary of additional attributes about this kernel; used by clients to aid in kernel selection. - * Optionally storing the interpreter information in the metadata (helping extension search for kernels that match an interpreter). - * Metadata added here should be namespaced for the tool reading and writing that metadata. - */ - readonly metadata?: Record & { interpreter?: Partial }; - /** - * A list of command line arguments used to start the kernel. - * The text {connection_file} in any argument will be replaced with the path to the connection file. - */ - readonly argv: string[]; - /** - * Optionally where this kernel spec json is located on the local FS. - */ - specFile?: string; - /** - * Optionally the Interpreter this kernel spec belongs to. - * You can have kernel specs that are scoped to an interpreter. - * E.g. if you have Python in `c:\Python\Python3.8` - * Then you could have kernels in `\share\jupyter\kernels` - * Plenty of conda packages ship kernels in this manner (beakerx, java, etc). - */ - interpreterPath?: string; - /** - * May be either signal or message and specifies how a client is supposed to interrupt cell execution on this kernel, - * either by sending an interrupt signal via the operating system’s signalling facilities (e.g. SIGINT on POSIX systems), - * or by sending an interrupt_request message on the control channel. - * If this is not specified the client will default to signal mode. - */ - readonly interrupt_mode?: 'message' | 'signal'; -} -/** - * Connection metadata for Kernels started using kernelspec (JSON). - * This could be a raw kernel (spec might have path to executable for .NET or the like). - * If the executable is not defined in kernelspec json, & it is a Python kernel, then we'll use the provided python interpreter. - */ -export type LocalKernelSpecConnectionMetadata = Readonly<{ - kernelModel?: undefined; - kernelSpec: IJupyterKernelSpec; - /** - * Indicates the interpreter that may be used to start the kernel. - * If possible to start a kernel without this Python interpreter, then this Python interpreter will be used for intellisense & the like. - * This interpreter could also be the interpreter associated with the kernel spec that we are supposed to start. - */ - interpreter?: PythonEnvironment; - kind: 'startUsingLocalKernelSpec'; - id: string; -}>; -/** - * Connection metadata for Remote Kernels started using kernelspec (JSON). - * This could be a raw kernel (spec might have path to executable for .NET or the like). - * If the executable is not defined in kernelspec json, & it is a Python kernel, then we'll use the provided python interpreter. - */ -export type RemoteKernelSpecConnectionMetadata = Readonly<{ - kernelModel?: undefined; - interpreter?: undefined; - kernelSpec: IJupyterKernelSpec; - kind: 'startUsingRemoteKernelSpec'; - baseUrl: string; - id: string; -}>; -/** - * Connection metadata for Kernels started using Python interpreter. - * These are not necessarily raw (it could be plain old Jupyter Kernels, where we register Python interpreter as a kernel). - * We can have KernelSpec information here as well, however that is totally optional. - * We will always start this kernel using old Jupyter style (provided we first register this interpreter as a kernel) or raw. - */ -export type PythonKernelConnectionMetadata = Readonly<{ - kernelSpec: IJupyterKernelSpec; - interpreter: PythonEnvironment; - kind: 'startUsingPythonInterpreter'; - id: string; -}>; -interface IJupyterKernel { - /** - * Id of an existing (active) Kernel from an active session. - */ - id?: string; - name: string; -} + //#region Kernel Information (Kernel Specs, connections) + /** + * Details of the kernel spec. + * See https://jupyter-client.readthedocs.io/en/stable/kernels.html#kernel-specs + */ + export interface IJupyterKernelSpec { + /** + * Id of an existing (active) Kernel from an active session. + */ + id?: string; + name: string; + /** + * The name of the language of the kernel + */ + language?: string; + path: string; + /** + * A dictionary of environment variables to set for the kernel. + * These will be added to the current environment variables before the kernel is started. + */ + env?: NodeJS.ProcessEnv | undefined; + /** + * Kernel display name. + */ + readonly display_name: string; + /** + * A dictionary of additional attributes about this kernel; used by clients to aid in kernel selection. + * Optionally storing the interpreter information in the metadata (helping extension search for kernels that match an interpreter). + * Metadata added here should be namespaced for the tool reading and writing that metadata. + */ + readonly metadata?: Record & { interpreter?: Partial }; + /** + * A list of command line arguments used to start the kernel. + * The text {connection_file} in any argument will be replaced with the path to the connection file. + */ + readonly argv: string[]; + /** + * Optionally where this kernel spec json is located on the local FS. + */ + specFile?: string; + /** + * Optionally the Interpreter this kernel spec belongs to. + * You can have kernel specs that are scoped to an interpreter. + * E.g. if you have Python in `c:\Python\Python3.8` + * Then you could have kernels in `\share\jupyter\kernels` + * Plenty of conda packages ship kernels in this manner (beakerx, java, etc). + */ + interpreterPath?: string; + /** + * May be either signal or message and specifies how a client is supposed to interrupt cell execution on this kernel, + * either by sending an interrupt signal via the operating system’s signalling facilities (e.g. SIGINT on POSIX systems), + * or by sending an interrupt_request message on the control channel. + * If this is not specified the client will default to signal mode. + */ + readonly interrupt_mode?: 'message' | 'signal'; + } + /** + * Connection metadata for Kernels started using kernelspec (JSON). + * This could be a raw kernel (spec might have path to executable for .NET or the like). + * If the executable is not defined in kernelspec json, & it is a Python kernel, then we'll use the provided python interpreter. + */ + export type LocalKernelSpecConnectionMetadata = Readonly<{ + kernelModel?: undefined; + kernelSpec: IJupyterKernelSpec; + /** + * Indicates the interpreter that may be used to start the kernel. + * If possible to start a kernel without this Python interpreter, then this Python interpreter will be used for intellisense & the like. + * This interpreter could also be the interpreter associated with the kernel spec that we are supposed to start. + */ + interpreter?: PythonEnvironment; + kind: 'startUsingLocalKernelSpec'; + id: string; + }>; + /** + * Connection metadata for Remote Kernels started using kernelspec (JSON). + * This could be a raw kernel (spec might have path to executable for .NET or the like). + * If the executable is not defined in kernelspec json, & it is a Python kernel, then we'll use the provided python interpreter. + */ + export type RemoteKernelSpecConnectionMetadata = Readonly<{ + kernelModel?: undefined; + interpreter?: undefined; + kernelSpec: IJupyterKernelSpec; + kind: 'startUsingRemoteKernelSpec'; + baseUrl: string; + id: string; + }>; + /** + * Connection metadata for Kernels started using Python interpreter. + * These are not necessarily raw (it could be plain old Jupyter Kernels, where we register Python interpreter as a kernel). + * We can have KernelSpec information here as well, however that is totally optional. + * We will always start this kernel using old Jupyter style (provided we first register this interpreter as a kernel) or raw. + */ + export type PythonKernelConnectionMetadata = Readonly<{ + kernelSpec: IJupyterKernelSpec; + interpreter: PythonEnvironment; + kind: 'startUsingPythonInterpreter'; + id: string; + }>; + interface IJupyterKernel { + /** + * Id of an existing (active) Kernel from an active session. + */ + id?: string; + name: string; + } -export type LiveKernelModel = IJupyterKernel & - Partial & { model: Session.IModel | undefined; notebook?: { path?: string } }; + export type LiveKernelModel = IJupyterKernel & + Partial & { model: Session.IModel | undefined; notebook?: { path?: string } }; -/** - * Connection metadata for Live Kernels. - * With this we are able connect to an existing kernel (instead of starting a new session). - */ -export type LiveRemoteKernelConnectionMetadata = Readonly<{ - kernelModel: LiveKernelModel; /** - * Python interpreter will be used for intellisense & the like. - */ - interpreter?: PythonEnvironment; - baseUrl: string; - kind: 'connectToLiveRemoteKernel'; - id: string; -}>; + * Connection metadata for Live Kernels. + * With this we are able connect to an existing kernel (instead of starting a new session). + */ + export type LiveRemoteKernelConnectionMetadata = Readonly<{ + kernelModel: LiveKernelModel; + /** + * Python interpreter will be used for intellisense & the like. + */ + interpreter?: PythonEnvironment; + baseUrl: string; + kind: 'connectToLiveRemoteKernel'; + id: string; + }>; -export type KernelConnectionMetadata = - | LocalKernelSpecConnectionMetadata - | RemoteKernelSpecConnectionMetadata - | PythonKernelConnectionMetadata - | LiveRemoteKernelConnectionMetadata; -export type ActiveKernel = LiveRemoteKernelConnectionMetadata; -//#endregion + export type KernelConnectionMetadata = + | LocalKernelSpecConnectionMetadata + | RemoteKernelSpecConnectionMetadata + | PythonKernelConnectionMetadata + | LiveRemoteKernelConnectionMetadata; + export type ActiveKernel = LiveRemoteKernelConnectionMetadata; + //#endregion -//#region Kernel API + //#region Kernel API -/** - * Data represents the message payload received over the WebSocket. - */ -export type WebSocketData = string | Buffer | ArrayBuffer | Buffer[]; - -export interface IKernelSocket { - /** - * Whether the kernel socket is read & available for use. - * Use `onDidChange` to be notified when this changes. - */ - ready: boolean; - /** - * Event fired when the underlying socket state changes. - * E.g. when the socket is connected/available or changes to another socket. - */ - onDidChange: Event; - /** - * Sends data to the underlying Jupyter kernel over the socket connection. - * This bypasses all of the jupyter kernel comms infrastructure. - */ - sendToRealKernel(data: any, cb?: (err?: Error) => void): void; - /** - * Adds a listener to a socket that will be called before the socket's onMessage is called. This - * allows waiting for a callback before processing messages - */ - addReceiveHook(hook: (data: WebSocketData) => Promise): void; /** - * Removes a listener for the socket. When no listeners are present, the socket no longer blocks + * Data represents the message payload received over the WebSocket. */ - removeReceiveHook(hook: (data: WebSocketData) => Promise): void; - /** - * Adds a hook to the sending of data from a websocket. Hooks can block sending so be careful. - */ - addSendHook(hook: (data: any, cb?: (err?: Error) => void) => Promise): void; - /** - * Removes a send hook from the socket. - */ - removeSendHook(hook: (data: any, cb?: (err?: Error) => void) => Promise): void; -} + export type WebSocketData = string | Buffer | ArrayBuffer | Buffer[]; -export type IKernelConnectionInfo = { - /** - * Gives access to the jupyterlab Kernel.IKernelConnection object. - */ - connection: Kernel.IKernelConnection; - /** - * Underlying socket used by jupyterlab/services to communicate with kernel. - * See jupyterlab/services/kernel/default.ts - */ - kernelSocket: IKernelSocket; -}; + export interface IKernelSocket { + /** + * Whether the kernel socket is read & available for use. + * Use `onDidChange` to be notified when this changes. + */ + ready: boolean; + /** + * Event fired when the underlying socket state changes. + * E.g. when the socket is connected/available or changes to another socket. + */ + onDidChange: Event; + /** + * Sends data to the underlying Jupyter kernel over the socket connection. + * This bypasses all of the jupyter kernel comms infrastructure. + */ + sendToRealKernel(data: any, cb?: (err?: Error) => void): void; + /** + * Adds a listener to a socket that will be called before the socket's onMessage is called. This + * allows waiting for a callback before processing messages + */ + addReceiveHook(hook: (data: WebSocketData) => Promise): void; + /** + * Removes a listener for the socket. When no listeners are present, the socket no longer blocks + */ + removeReceiveHook(hook: (data: WebSocketData) => Promise): void; + /** + * Adds a hook to the sending of data from a websocket. Hooks can block sending so be careful. + */ + addSendHook(hook: (data: any, cb?: (err?: Error) => void) => Promise): void; + /** + * Removes a send hook from the socket. + */ + removeSendHook(hook: (data: any, cb?: (err?: Error) => void) => Promise): void; + } -export interface IExportedKernelService { - readonly status: 'discovering' | 'idle'; - /** - * Changes in kernel state (e.g. discovered kernels, not discovering kernel, etc). - */ - onDidChangeStatus: Event; - /** - * List of running kernels changed. - */ - onDidChangeKernels: Event; - /** - * List of kernel specs changed. - */ - onDidChangeKernelSpecifications: Event; - /** - * Gets a list of all kernel specifications that can be used to start a new kernel or to connect to an existing kernel. - * Local, remote kernels are returned, including Python interpreters that - * are treated as kernelspecs (as we can start Kernels for Python interpreters without Jupyter). - */ - getKernelSpecifications(): Promise; - /** - * Gets a list of all active kernel connections. - * If `uri` is undefined, then the kernel is not associated with any resource. I.e its currently not associated with any notebook in Jupyter extension. - * If `uri` is undefined, then the kernel is associated with the resource identified by the Uri. - */ - getActiveKernels(): { metadata: KernelConnectionMetadata; uri: Uri | undefined }[]; - /** - * Gets the Kernel connection & the metadata that's associated with a given resource. - * (only successfully started/active connections are returned). - */ - getKernel(uri: Uri): { metadata: KernelConnectionMetadata; connection: IKernelConnectionInfo } | undefined; - /** - * Starts a kernel for a given resource. - * The promise is resolved only after the kernel has successfully started. - * If one attempts to start another kernel for the same resource, the same promise is returned. - */ - startKernel( - metadata: KernelConnectionMetadata, - uri: Uri, - token?: CancellationToken - ): Promise; - /** - * Connects an existing kernel to a resource. - * The promise is resolved only after the kernel is successfully attached to a resource. - * If one attempts to start another kernel or connect another kernel for the same resource, the same promise is returned. - */ - connect(metadata: LiveRemoteKernelConnectionMetadata, uri: Uri): Promise; + export type IKernelConnectionInfo = { + /** + * Gives access to the jupyterlab Kernel.IKernelConnection object. + */ + connection: Kernel.IKernelConnection; + /** + * Underlying socket used by jupyterlab/services to communicate with kernel. + * See jupyterlab/services/kernel/default.ts + */ + kernelSocket: IKernelSocket; + }; + + export interface IExportedKernelService { + readonly status: 'discovering' | 'idle'; + /** + * Changes in kernel state (e.g. discovered kernels, not discovering kernel, etc). + */ + onDidChangeStatus: Event; + /** + * List of running kernels changed. + */ + onDidChangeKernels: Event; + /** + * List of kernel specs changed. + */ + onDidChangeKernelSpecifications: Event; + /** + * Gets a list of all kernel specifications that can be used to start a new kernel or to connect to an existing kernel. + * Local, remote kernels are returned, including Python interpreters that + * are treated as kernelspecs (as we can start Kernels for Python interpreters without Jupyter). + */ + getKernelSpecifications(): Promise; + /** + * Gets a list of all active kernel connections. + * If `uri` is undefined, then the kernel is not associated with any resource. I.e its currently not associated with any notebook in Jupyter extension. + * If `uri` is undefined, then the kernel is associated with the resource identified by the Uri. + */ + getActiveKernels(): { metadata: KernelConnectionMetadata; uri: Uri | undefined }[]; + /** + * Gets the Kernel connection & the metadata that's associated with a given resource. + * (only successfully started/active connections are returned). + */ + getKernel(uri: Uri): { metadata: KernelConnectionMetadata; connection: IKernelConnectionInfo } | undefined; + /** + * Starts a kernel for a given resource. + * The promise is resolved only after the kernel has successfully started. + * If one attempts to start another kernel for the same resource, the same promise is returned. + */ + startKernel( + metadata: KernelConnectionMetadata, + uri: Uri, + token?: CancellationToken + ): Promise; + /** + * Connects an existing kernel to a resource. + * The promise is resolved only after the kernel is successfully attached to a resource. + * If one attempts to start another kernel or connect another kernel for the same resource, the same promise is returned. + */ + connect(metadata: LiveRemoteKernelConnectionMetadata, uri: Uri): Promise; + } } -//#endregion diff --git a/src/kernels/jupyter/connection/jupyterConnection.ts b/src/kernels/jupyter/connection/jupyterConnection.ts index 1aa5facc290..1f0a454faee 100644 --- a/src/kernels/jupyter/connection/jupyterConnection.ts +++ b/src/kernels/jupyter/connection/jupyterConnection.ts @@ -14,7 +14,7 @@ import { IJupyterUriProviderRegistration, JupyterServerProviderHandle } from '../types'; -import { IJupyterServerUri } from '../../../api.unstable'; +import { IJupyterServerUri } from '../../../api'; import { JupyterSelfCertsError } from '../../../platform/errors/jupyterSelfCertsError'; import { Telemetry, sendTelemetryEvent } from '../../../telemetry'; import { JupyterSelfCertsExpiredError } from '../../../platform/errors/jupyterSelfCertsExpiredError'; diff --git a/src/kernels/jupyter/connection/jupyterConnection.unit.test.ts b/src/kernels/jupyter/connection/jupyterConnection.unit.test.ts index d7cd98c1a63..df8b730d9a1 100644 --- a/src/kernels/jupyter/connection/jupyterConnection.unit.test.ts +++ b/src/kernels/jupyter/connection/jupyterConnection.unit.test.ts @@ -17,7 +17,7 @@ import { import { disposeAllDisposables } from '../../../platform/common/helpers'; import { IConfigurationService, IDisposable } from '../../../platform/common/types'; import chaiAsPromised from 'chai-as-promised'; -import { IJupyterServerUri } from '../../../api.unstable'; +import { IJupyterServerUri } from '../../../api'; import { IApplicationShell } from '../../../platform/common/application/types'; import { IDataScienceErrorHandler } from '../../errors/types'; use(chaiAsPromised); diff --git a/src/kernels/jupyter/connection/jupyterUriProviderRegistration.ts b/src/kernels/jupyter/connection/jupyterUriProviderRegistration.ts index 168329be265..5b318c3016a 100644 --- a/src/kernels/jupyter/connection/jupyterUriProviderRegistration.ts +++ b/src/kernels/jupyter/connection/jupyterUriProviderRegistration.ts @@ -18,7 +18,7 @@ import { } from '../types'; import { sendTelemetryEvent } from '../../../telemetry'; import { traceError } from '../../../platform/logging'; -import { IJupyterServerUri, IJupyterUriProvider } from '../../../api.unstable'; +import { IJupyterServerUri, IJupyterUriProvider } from '../../../api'; import { Disposables } from '../../../platform/common/utils'; import { IServiceContainer } from '../../../platform/ioc/types'; import { IExtensionSyncActivationService } from '../../../platform/activation/types'; diff --git a/src/kernels/jupyter/connection/jupyterUriProviderRegistration.unit.test.ts b/src/kernels/jupyter/connection/jupyterUriProviderRegistration.unit.test.ts index 5de1545da99..8073d7e7009 100644 --- a/src/kernels/jupyter/connection/jupyterUriProviderRegistration.unit.test.ts +++ b/src/kernels/jupyter/connection/jupyterUriProviderRegistration.unit.test.ts @@ -12,7 +12,7 @@ import { import { IJupyterServerUriEntry, IJupyterServerUriStorage } from '../types'; import { IDisposable, IExtensions } from '../../../platform/common/types'; import { disposeAllDisposables } from '../../../platform/common/helpers'; -import { IJupyterServerUri, IJupyterUriProvider } from '../../../api.unstable'; +import { IJupyterServerUri, IJupyterUriProvider } from '../../../api'; import { IServiceContainer } from '../../../platform/ioc/types'; import { Disposable, EventEmitter, Memento, QuickPickItem } from 'vscode'; import { createEventHandler } from '../../../test/common'; diff --git a/src/kernels/jupyter/connection/serverSelector.ts b/src/kernels/jupyter/connection/serverSelector.ts index b3a86bd69f5..d865429be93 100644 --- a/src/kernels/jupyter/connection/serverSelector.ts +++ b/src/kernels/jupyter/connection/serverSelector.ts @@ -16,7 +16,7 @@ import { JupyterConnection } from './jupyterConnection'; import { JupyterSelfCertsError } from '../../../platform/errors/jupyterSelfCertsError'; import { JupyterSelfCertsExpiredError } from '../../../platform/errors/jupyterSelfCertsExpiredError'; import { JupyterInvalidPasswordError } from '../../errors/jupyterInvalidPassword'; -import { IJupyterServerUri } from '../../../api.unstable'; +import { IJupyterServerUri } from '../../../api'; export type SelectJupyterUriCommandSource = | 'nonUser' diff --git a/src/kernels/jupyter/connection/serverUriStorage.unit.test.ts b/src/kernels/jupyter/connection/serverUriStorage.unit.test.ts index 1a06e0c9182..f106f5effe1 100644 --- a/src/kernels/jupyter/connection/serverUriStorage.unit.test.ts +++ b/src/kernels/jupyter/connection/serverUriStorage.unit.test.ts @@ -16,7 +16,7 @@ import { IDisposable, IExtensionContext } from '../../../platform/common/types'; import { JupyterServerUriStorage, StorageMRUItem } from './serverUriStorage'; import { IEncryptedStorage } from '../../../platform/common/application/types'; import { IFileSystem } from '../../../platform/common/platform/types'; -import { IJupyterServerUri } from '../../../api.unstable'; +import { IJupyterServerUri } from '../../../api'; import { JVSC_EXTENSION_ID, Settings, UserJupyterServerPickerProviderId } from '../../../platform/common/constants'; import { TestEventHandler, createEventHandler } from '../../../test/common'; import { generateIdFromRemoteProvider } from '../jupyterUtils'; diff --git a/src/kernels/jupyter/jupyterUtils.ts b/src/kernels/jupyter/jupyterUtils.ts index f4ffee64313..fcbf0f7ee49 100644 --- a/src/kernels/jupyter/jupyterUtils.ts +++ b/src/kernels/jupyter/jupyterUtils.ts @@ -13,7 +13,7 @@ import { DataScience } from '../../platform/common/utils/localize'; import { sendTelemetryEvent } from '../../telemetry'; import { Identifiers, JVSC_EXTENSION_ID, Telemetry, isBuiltInJupyterProvider } from '../../platform/common/constants'; import { computeHash } from '../../platform/common/crypto'; -import { IJupyterServerUri } from '../../api.unstable'; +import { IJupyterServerUri } from '../../api'; import { traceWarning } from '../../platform/logging'; import { JupyterServerProviderHandle } from './types'; diff --git a/src/kernels/jupyter/types.ts b/src/kernels/jupyter/types.ts index e2d82c831da..275549131af 100644 --- a/src/kernels/jupyter/types.ts +++ b/src/kernels/jupyter/types.ts @@ -25,7 +25,7 @@ import { } from '../types'; import { ClassType } from '../../platform/ioc/types'; import { ContributedKernelFinderKind, IContributedKernelFinder } from '../internalTypes'; -import { IJupyterServerUri, IJupyterUriProvider } from '../../api.unstable'; +import { IJupyterServerUri, IJupyterUriProvider } from '../../api'; export type JupyterServerInfo = { base_url: string; diff --git a/src/standalone/api/api.ts b/src/standalone/api/api.ts index f84a36e8d1e..636b8c83e8e 100644 --- a/src/standalone/api/api.ts +++ b/src/standalone/api/api.ts @@ -5,7 +5,6 @@ import { ExtensionMode, NotebookDocument, Uri, commands, window, workspace } fro import { JupyterServerSelector } from '../../kernels/jupyter/connection/serverSelector'; import { IJupyterUriProviderRegistration } from '../../kernels/jupyter/types'; import { IDataViewerDataProvider, IDataViewerFactory } from '../../webviews/extension-side/dataviewer/types'; -import { IExportedKernelService, IJupyterUriProvider, JupyterAPI as UnStableJupyterAPI } from '../../api.unstable'; import { IPythonApiProvider, PythonApi } from '../../platform/api/types'; import { isTestExecution, JVSC_EXTENSION_ID, Telemetry } from '../../platform/common/constants'; import { IDisposable, IExtensionContext, IExtensions } from '../../platform/common/types'; @@ -15,9 +14,7 @@ import { IControllerRegistration } from '../../notebooks/controllers/types'; import { sendTelemetryEvent } from '../../telemetry'; import { noop } from '../../platform/common/utils/misc'; import { isRemoteConnection } from '../../kernels/types'; -import { JupyterAPI } from '../../api'; -import { JupyterAPI as ProposedJupyterAPI } from '../../api.proposed'; -import { JupyterAPI as PythonIntegrationAPI } from '../../api.pythonIntegration'; +import { JupyterAPI, IExportedKernelService, IJupyterUriProvider } from '../../api'; export const IExportedKernelServiceFactory = Symbol('IExportedKernelServiceFactory'); export interface IExportedKernelServiceFactory { @@ -29,7 +26,7 @@ export interface IExportedKernelServiceFactory { * This is the public API for other extensions to interact with this extension. */ -export interface IExtensionApi extends JupyterAPI, UnStableJupyterAPI, ProposedJupyterAPI, PythonIntegrationAPI {} +export interface IExtensionApi extends JupyterAPI {} function waitForNotebookControllersCreationForServer( serverId: { id: string; handle: string }, diff --git a/src/standalone/api/kernelApi.ts b/src/standalone/api/kernelApi.ts index 3a32d2458c3..45fc285d7b1 100644 --- a/src/standalone/api/kernelApi.ts +++ b/src/standalone/api/kernelApi.ts @@ -26,7 +26,7 @@ import { IKernelSocket, KernelConnectionMetadata, WebSocketData -} from '../../api.unstable'; +} from '../../api'; import { JupyterNotebookView, Telemetry } from '../../platform/common/constants'; import { KernelConnector } from '../../notebooks/controllers/kernelConnector'; import { DisplayOptions } from '../../kernels/displayOptions'; diff --git a/src/standalone/userJupyterServer/serverSelectorForTests.ts b/src/standalone/userJupyterServer/serverSelectorForTests.ts index 2976313b840..bfe31b906f3 100644 --- a/src/standalone/userJupyterServer/serverSelectorForTests.ts +++ b/src/standalone/userJupyterServer/serverSelectorForTests.ts @@ -10,7 +10,7 @@ import { IInternalJupyterUriProvider, IJupyterUriProviderRegistration } from '.. import { IExtensionSyncActivationService } from '../../platform/activation/types'; import { computeHash } from '../../platform/common/crypto'; import { Disposables } from '../../platform/common/utils'; -import { IJupyterServerUri } from '../../api.unstable'; +import { IJupyterServerUri } from '../../api'; /** * Registers commands to allow the user to set the remote server URI. diff --git a/src/standalone/userJupyterServer/userServerUrlProvider.ts b/src/standalone/userJupyterServer/userServerUrlProvider.ts index 9ede60dc0b3..ab17cdfe081 100644 --- a/src/standalone/userJupyterServer/userServerUrlProvider.ts +++ b/src/standalone/userJupyterServer/userServerUrlProvider.ts @@ -49,7 +49,7 @@ import { Common, DataScience } from '../../platform/common/utils/localize'; import { noop } from '../../platform/common/utils/misc'; import { traceError, traceWarning } from '../../platform/logging'; import { IJupyterPasswordConnectInfo, JupyterPasswordConnect } from './jupyterPasswordConnect'; -import { IJupyterServerUri } from '../../api.unstable'; +import { IJupyterServerUri } from '../../api'; import { IMultiStepInputFactory } from '../../platform/common/utils/multiStepInput'; import { JupyterSelfCertsError } from '../../platform/errors/jupyterSelfCertsError'; import { JupyterSelfCertsExpiredError } from '../../platform/errors/jupyterSelfCertsExpiredError'; diff --git a/src/telemetry.ts b/src/telemetry.ts index 1da3762e1da..0f2dc4e003b 100644 --- a/src/telemetry.ts +++ b/src/telemetry.ts @@ -20,7 +20,7 @@ import { PreferredKernelExactMatchReason } from './notebooks/controllers/types'; import { ExcludeType, PickType } from './platform/common/utils/misc'; import { SharedPropertyMapping } from './platform/telemetry/index'; import { IExtensionApi } from './standalone/api/api'; -import { IExportedKernelService, IJupyterServerUri } from './api.unstable'; +import { IExportedKernelService, IJupyterServerUri } from './api'; export * from './platform/telemetry/index'; export type DurationMeasurement = { diff --git a/src/test/client/api.vscode.test.ts b/src/test/client/api.vscode.test.ts index 6fbe680541d..3eb369bb6c3 100644 --- a/src/test/client/api.vscode.test.ts +++ b/src/test/client/api.vscode.test.ts @@ -20,7 +20,7 @@ import { createKernelController, TestNotebookDocument } from '../datascience/not import { IKernelProvider, IKernelFinder } from '../../kernels/types'; import { areInterpreterPathsSame } from '../../platform/pythonEnvironments/info/interpreter'; import { getDisplayPath } from '../../platform/common/platform/fs-paths'; -import { KernelConnectionMetadata } from '../../api.unstable'; +import { KernelConnectionMetadata } from '../../api'; suite('3rd Party Kernel Service API @kernelCore', function () { let api: IExtensionTestApi;