diff --git a/package.json b/package.json index 2b11b8d..d4de286 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "yjs": "^13.5.40" }, "jupyterlab": { + "schemaDir": "schema", "extension": true, "outputDir": "lckr_jupyterlab_variableinspector/labextension", "sharedPackages": { diff --git a/schema/jupyterlab-variableInspector-settings.json b/schema/jupyterlab-variableInspector-settings.json new file mode 100644 index 0000000..90ad7ca --- /dev/null +++ b/schema/jupyterlab-variableInspector-settings.json @@ -0,0 +1,13 @@ +{ + "title": "jupyterlab-variableInspector settings", + "description": "Settings for the jupyterlab-variableInspector extension.", + "type": "object", + "properties": { + "maxItems": { + "type": "number", + "title": "Maximum number of items", + "description": "The maximum number of items to show in lists/dicts etc", + "default": 10 + } + } +} diff --git a/src/handler.ts b/src/handler.ts index 0da7ec4..4c059a3 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -1,5 +1,7 @@ import { ISessionContext } from '@jupyterlab/apputils'; +import { ISettingRegistry } from '@jupyterlab/settingregistry'; + import { IExecuteResult } from '@jupyterlab/nbformat'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; @@ -100,8 +102,12 @@ export class VariableInspectionHandler extends AbstractHandler { private _matrixQueryCommand: string; private _widgetQueryCommand: string; private _deleteCommand: string; + private _changeSettingsCommand: + | ((settings: IVariableInspector.ISettings) => string) + | undefined; private _ready: Promise; private _id: string; + private _setting: ISettingRegistry.ISettings; constructor(options: VariableInspectionHandler.IOptions) { super(options.connector); @@ -110,11 +116,14 @@ export class VariableInspectionHandler extends AbstractHandler { this._queryCommand = options.queryCommand; this._matrixQueryCommand = options.matrixQueryCommand; this._widgetQueryCommand = options.widgetQueryCommand; + this._changeSettingsCommand = options.changeSettingsCommand; this._deleteCommand = options.deleteCommand; this._initScript = options.initScript; + this._setting = options.setting; this._ready = this._connector.ready.then(() => { this._initOnKernel().then((msg: KernelMessage.IExecuteReplyMsg) => { + this.performSettingsChange(); this._connector.iopubMessage.connect(this._queryCall); return; }); @@ -131,12 +140,20 @@ export class VariableInspectionHandler extends AbstractHandler { this._ready = kernelReady.then(() => { this._initOnKernel().then((msg: KernelMessage.IExecuteReplyMsg) => { + this.performSettingsChange(); this._connector.iopubMessage.connect(this._queryCall); this.performInspection(); }); }); }; + this._setting.changed.connect(async () => { + await this._ready; + + this.performSettingsChange(); + this.performInspection(); + }); + this._connector.kernelRestarted.connect(onKernelReset); this._connector.kernelChanged.connect(onKernelReset); } @@ -232,6 +249,27 @@ export class VariableInspectionHandler extends AbstractHandler { this._connector.fetch(content, this._handleQueryResponse); } + /** + * Send a kernel request to change settings + */ + performSettingsChange(): void { + if (!this._changeSettingsCommand) { + return; + } + + const settings: IVariableInspector.ISettings = { + maxItems: this._setting.get('maxItems').composite as number + }; + + const content: KernelMessage.IExecuteRequestMsg['content'] = { + code: this._changeSettingsCommand(settings), + stop_on_error: false, + store_history: false + }; + + this._connector.fetch(content, this._handleQueryResponse); + } + /** * Initializes the kernel by running the set up script located at _initScriptPath. */ @@ -344,9 +382,11 @@ export namespace VariableInspectionHandler { queryCommand: string; matrixQueryCommand: string; widgetQueryCommand: string; + changeSettingsCommand?(settings: IVariableInspector.ISettings): string; deleteCommand: string; initScript: string; id: string; + setting: ISettingRegistry.ISettings; } } diff --git a/src/index.ts b/src/index.ts index 0883ff2..dd42f55 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,8 @@ import { IConsoleTracker } from '@jupyterlab/console'; import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook'; +import { ISettingRegistry } from '@jupyterlab/settingregistry'; + import { listIcon } from '@jupyterlab/ui-components'; import { DummyHandler, VariableInspectionHandler } from './handler'; @@ -30,6 +32,9 @@ namespace CommandIDs { export const open = 'variableinspector:open'; } +const SETTINGS_ID = + '@lckr/jupyterlab_variableinspector:jupyterlab-variableInspector-settings'; + /** * A service providing variable introspection. */ @@ -110,17 +115,24 @@ const variableinspector: JupyterFrontEndPlugin = { */ const consoles: JupyterFrontEndPlugin = { id: '@lckr/jupyterlab-variableinspector:consoles', - requires: [IVariableInspectorManager, IConsoleTracker, ILabShell], + requires: [ + IVariableInspectorManager, + IConsoleTracker, + ILabShell, + ISettingRegistry + ], autoStart: true, - activate: ( + activate: async ( app: JupyterFrontEnd, manager: IVariableInspectorManager, consoles: IConsoleTracker, - labShell: ILabShell - ): void => { + labShell: ILabShell, + settings: ISettingRegistry + ): Promise => { const handlers: { [id: string]: Promise; } = {}; + const setting = await settings.load(SETTINGS_ID); /** * Subscribes to the creation of new consoles. If a new notebook is created, build a new handler for the consoles. @@ -150,15 +162,18 @@ const consoles: JupyterFrontEndPlugin = { const matrixQueryCommand = result.matrixQueryCommand; const widgetQueryCommand = result.widgetQueryCommand; const deleteCommand = result.deleteCommand; + const changeSettingsCommand = result.changeSettingsCommand; const options: VariableInspectionHandler.IOptions = { - queryCommand: queryCommand, - matrixQueryCommand: matrixQueryCommand, + queryCommand, + matrixQueryCommand, widgetQueryCommand, - deleteCommand: deleteCommand, - connector: connector, - initScript: initScript, - id: session.path //Using the sessions path as an identifier for now. + deleteCommand, + connector, + initScript, + changeSettingsCommand, + id: session.path, //Using the sessions path as an identifier for now. + setting }; const handler = new VariableInspectionHandler(options); manager.addHandler(handler); @@ -222,15 +237,22 @@ const consoles: JupyterFrontEndPlugin = { */ const notebooks: JupyterFrontEndPlugin = { id: '@lckr/jupyterlab-variableinspector:notebooks', - requires: [IVariableInspectorManager, INotebookTracker, ILabShell], + requires: [ + IVariableInspectorManager, + INotebookTracker, + ILabShell, + ISettingRegistry + ], autoStart: true, - activate: ( + activate: async ( app: JupyterFrontEnd, manager: IVariableInspectorManager, notebooks: INotebookTracker, - labShell: ILabShell - ): void => { + labShell: ILabShell, + settings: ISettingRegistry + ): Promise => { const handlers: { [id: string]: Promise } = {}; + const setting = await settings.load(SETTINGS_ID); /** * Subscribes to the creation of new notebooks. If a new notebook is created, build a new handler for the notebook. @@ -256,16 +278,19 @@ const notebooks: JupyterFrontEndPlugin = { const matrixQueryCommand = result.matrixQueryCommand; const widgetQueryCommand = result.widgetQueryCommand; const deleteCommand = result.deleteCommand; + const changeSettingsCommand = result.changeSettingsCommand; const options: VariableInspectionHandler.IOptions = { - queryCommand: queryCommand, - matrixQueryCommand: matrixQueryCommand, + queryCommand, + matrixQueryCommand, widgetQueryCommand, - deleteCommand: deleteCommand, - connector: connector, + deleteCommand, + connector, rendermime, - initScript: initScript, - id: session.path //Using the sessions path as an identifier for now. + initScript, + changeSettingsCommand, + id: session.path, //Using the sessions path as an identifier for now. + setting }; const handler = new VariableInspectionHandler(options); manager.addHandler(handler); diff --git a/src/inspectorscripts.ts b/src/inspectorscripts.ts index 27dcbb4..30e770c 100644 --- a/src/inspectorscripts.ts +++ b/src/inspectorscripts.ts @@ -1,3 +1,5 @@ +import { IVariableInspector } from './tokens'; + export namespace Languages { export type LanguageModel = { initScript: string; @@ -5,6 +7,7 @@ export namespace Languages { matrixQueryCommand: string; widgetQueryCommand: string; deleteCommand: string; + changeSettingsCommand?: (settings: IVariableInspector.ISettings) => string; }; } @@ -26,6 +29,8 @@ _jupyterlab_variableinspector_nms = NamespaceMagics() _jupyterlab_variableinspector_Jupyter = get_ipython() _jupyterlab_variableinspector_nms.shell = _jupyterlab_variableinspector_Jupyter.kernel.shell +_jupyterlab_variableinspector_maxitems = 10 + __np = None __pd = None __pyspark = None @@ -56,6 +61,12 @@ def _check_imported(): __xr = _attempt_import('xarray') +def _jupyterlab_variableinspector_changesettings(maxitems, **kwargs): + global _jupyterlab_variableinspector_maxitems + + _jupyterlab_variableinspector_maxitems = maxitems + + def _jupyterlab_variableinspector_getsizeof(x): if type(x).__name__ in ['ndarray', 'Series']: return x.nbytes @@ -106,15 +117,18 @@ def _jupyterlab_variableinspector_getcontentof(x): if isinstance(x, (bool, str, int, float, type(None))): content = str(x) elif isinstance(x, (list, tuple)): - if len(x) < 10: + if len(x) <= _jupyterlab_variableinspector_maxitems: content = str(x) else: - content = f"[{x[0]}, {x[1]}, {x[2]}, ..., {x[-1]}]" + content = "[" + for i in range(_jupyterlab_variableinspector_maxitems): + content += f"{x[i]}, " + content += "...]" elif isinstance(x, collections.abc.Mapping): - if len(x.keys()) < 10: + if len(x.keys()) <= _jupyterlab_variableinspector_maxitems: content = str(x) else: - first_ten_keys = list(islice(x.keys(), 10)) + first_ten_keys = list(islice(x.keys(), _jupyterlab_variableinspector_maxitems)) content = "{" for idx, key in enumerate(first_ten_keys): if idx > 0: @@ -331,21 +345,27 @@ def _jupyterlab_variableinspector_deletevariable(x): queryCommand: '_jupyterlab_variableinspector_dict_list()', matrixQueryCommand: '_jupyterlab_variableinspector_getmatrixcontent', widgetQueryCommand: '_jupyterlab_variableinspector_displaywidget', - deleteCommand: '_jupyterlab_variableinspector_deletevariable' + deleteCommand: '_jupyterlab_variableinspector_deletevariable', + changeSettingsCommand: (settings: IVariableInspector.ISettings) => + `_jupyterlab_variableinspector_changesettings(maxitems=${settings.maxItems})` }, python2: { initScript: Languages.py_script, queryCommand: '_jupyterlab_variableinspector_dict_list()', matrixQueryCommand: '_jupyterlab_variableinspector_getmatrixcontent', widgetQueryCommand: '_jupyterlab_variableinspector_displaywidget', - deleteCommand: '_jupyterlab_variableinspector_deletevariable' + deleteCommand: '_jupyterlab_variableinspector_deletevariable', + changeSettingsCommand: (settings: IVariableInspector.ISettings) => + `_jupyterlab_variableinspector_changesettings(maxitems=${settings.maxItems})` }, python: { initScript: Languages.py_script, queryCommand: '_jupyterlab_variableinspector_dict_list()', matrixQueryCommand: '_jupyterlab_variableinspector_getmatrixcontent', widgetQueryCommand: '_jupyterlab_variableinspector_displaywidget', - deleteCommand: '_jupyterlab_variableinspector_deletevariable' + deleteCommand: '_jupyterlab_variableinspector_deletevariable', + changeSettingsCommand: (settings: IVariableInspector.ISettings) => + `_jupyterlab_variableinspector_changesettings(maxitems=${settings.maxItems})` }, R: { initScript: Languages.r_script, diff --git a/src/tokens.ts b/src/tokens.ts index 118fa16..cbed401 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -53,6 +53,10 @@ export namespace IVariableInspector { performDelete(varName: string): void; } + export interface ISettings { + maxItems: number; + } + export interface IVariableInspectorUpdate { title: IVariableTitle; payload: Array; @@ -67,6 +71,7 @@ export namespace IVariableInspector { isMatrix: boolean; isWidget: boolean; } + export interface IVariableTitle { kernelName?: string; contextName?: string; //Context currently reserved for special information.