Skip to content

Commit

Permalink
basic contentsmanager strawman
Browse files Browse the repository at this point in the history
  • Loading branch information
bollwyvl committed Oct 31, 2023
1 parent dfa4ba7 commit de4a0ad
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 0 deletions.
93 changes: 93 additions & 0 deletions examples/contents.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "b0fe59fc-2f42-4ee5-b1cf-d3a73ccd80b2",
"metadata": {},
"source": [
"# Contents"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6451c811-83be-45fc-be07-73eb363b4239",
"metadata": {},
"outputs": [],
"source": [
"from ipylab import JupyterFrontEnd"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "db015374-352c-442b-af4e-81bc8d5e6db8",
"metadata": {},
"outputs": [],
"source": [
"app = JupyterFrontEnd()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aff5288d-2cf6-4304-ba94-966480174534",
"metadata": {},
"outputs": [],
"source": [
"app.contents"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d3dfcf18-c84d-4d5c-b4c9-1d1d37ad15ca",
"metadata": {},
"outputs": [],
"source": [
"readme = app.contents.get(\"README.md\", content=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e7838972-dde8-40c8-b08a-61ea05e70143",
"metadata": {},
"outputs": [],
"source": [
"readme.size"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21ca52e3-2f07-4c2a-8fbc-d812702e7b98",
"metadata": {},
"outputs": [],
"source": [
"readme.content = \"bar\""
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
97 changes: 97 additions & 0 deletions ipylab/contents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env python
# coding: utf-8

# Copyright (c) ipylab contributors.
# Distributed under the terms of the Modified BSD License.

import typing as t
from uuid import uuid4
from ipywidgets import Widget, register
from traitlets import HasTraits, Unicode, Any, Instance, observe, Int, Bool
from ._frontend import module_name, module_version


@register
class ContentsManager(Widget):
_model_name = Unicode("ContentsManagerModel").tag(sync=True)
_model_module = Unicode(module_name).tag(sync=True)
_model_module_version = Unicode(module_version).tag(sync=True)

_requests: t.Dict[str, t.Callable]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._requests = {}
self.on_msg(self._on_frontend_msg)

def _on_frontend_msg(self, _, content, buffers):
if content.get("event", "") == "got":
_id = content.get("_id")
callback = self._requests.pop(_id, None)
if callback:
callback(content)

def get(self, path: str, content: t.Optional[bool] = None) -> "ContentsModel":
_id = str(uuid4())
self.send(
{
"_id": _id,
"func": "get",
"payload": {"path": path, "options": {"content": content}},
}
)

model = ContentsModel(path=path, _contents_manager=self)

self._requests[_id] = model._on_get

return model

def save(self, model: "ContentsModel"):
_id = str(uuid4())
self.send(
{
"_id": _id,
"func": "save",
"payload": {
"path": model.path,
"options": {
"content": model.content,
"type": model.type,
"format": model.format,
},
},
}
)

self._requests[_id] = model._on_get

return model


@register
class ContentsModel(Widget):
_model_name = Unicode("ContentsModelModel").tag(sync=True)
_model_module = Unicode(module_name).tag(sync=True)
_model_module_version = Unicode(module_version).tag(sync=True)
_contents_manager = Instance(ContentsManager)

name = Unicode()
path = Unicode()
last_modified = Unicode()
created = Unicode()
format = Unicode()
mimetype = Unicode()
size = Int()
writeable = Bool()
type = Unicode()
content = Any()

def _on_get(self, content):
with self.hold_trait_notifications():
for key, value in content.get("model", {}).items():
setattr(self, key, value)

@observe("content")
def _on_content(self, change) -> None:
self._contents_manager.save(self)
3 changes: 3 additions & 0 deletions ipylab/jupyterfrontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .commands import CommandRegistry
from .shell import Shell
from .sessions import SessionManager
from .contents import ContentsManager


@register
Expand All @@ -25,13 +26,15 @@ class JupyterFrontEnd(Widget):
shell = Instance(Shell).tag(sync=True, **widget_serialization)
commands = Instance(CommandRegistry).tag(sync=True, **widget_serialization)
sessions = Instance(SessionManager).tag(sync=True, **widget_serialization)
contents = Instance(ContentsManager).tag(sync=True, **widget_serialization)

def __init__(self, *args, **kwargs):
super().__init__(
*args,
shell=Shell(),
commands=CommandRegistry(),
sessions=SessionManager(),
contents=ContentsManager(),
**kwargs,
)
self._ready_event = asyncio.Event()
Expand Down
2 changes: 2 additions & 0 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const extension: JupyterFrontEndPlugin<void> = {

// add globals
widgetExports.JupyterFrontEndModel.app = app;
widgetExports.ContentsManagerModel.contentsManager =
app.serviceManager.contents;
widgetExports.ShellModel.shell = app.shell;
widgetExports.ShellModel.labShell = labShell;
widgetExports.CommandRegistryModel.commands = app.commands;
Expand Down
3 changes: 3 additions & 0 deletions src/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CommandRegistryModel } from './widgets/commands';
import { CommandPaletteModel } from './widgets/palette';
import { SessionManagerModel } from './widgets/sessions';
import { JupyterFrontEndModel } from './widgets/frontend';
import { ContentsManagerModel, ContentsModelModel } from './widgets/contents';
import { PanelModel } from './widgets/panel';
import { ShellModel } from './widgets/shell';
import { SplitPanelModel, SplitPanelView } from './widgets/split_panel';
Expand All @@ -14,6 +15,8 @@ import { IconView, IconModel } from './widgets/icon';
export {
CommandRegistryModel,
CommandPaletteModel,
ContentsManagerModel,
ContentsModelModel,
JupyterFrontEndModel,
PanelModel,
ShellModel,
Expand Down
103 changes: 103 additions & 0 deletions src/widgets/contents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) ipylab contributors
// Distributed under the terms of the Modified BSD License.

import { WidgetModel } from '@jupyter-widgets/base';
import { Contents } from '@jupyterlab/services';

import { MODULE_NAME, MODULE_VERSION } from '../version';

export class ContentsManagerModel extends WidgetModel {
/**
* The default attributes.
*/
defaults(): any {
return {
...super.defaults(),
_model_name: ContentsManagerModel.model_name,
_model_module: ContentsManagerModel.model_module,
_model_module_version: ContentsManagerModel.model_module_version
};
}

/**
* Initialize a ContentsManagerModel instance.
*
* @param attributes The base attributes.
* @param options The initialization options.
*/
initialize(attributes: any, options: any): void {
super.initialize(attributes, options);
this.on('msg:custom', this._onMessage.bind(this));
}

/**
* Handle a custom message from the backend.
*
* @param msg The message to handle.
*/
private async _onMessage(msg: any): Promise<void> {
switch (msg.func) {
case 'get':
void this._get(msg._id, msg.payload);
break;
case 'save':
void this._save(msg._id, msg.payload);
break;
default:
break;
}
}

private async _get(
_id: string,
payload: { path: string; options: Record<string, any> }
) {
const model = await ContentsManagerModel.contentsManager.get(
payload.path,
payload.options
);
this.send({ event: 'got', _id, model: model as any });
}

private async _save(
_id: string,
payload: { path: string; options: Record<string, any> }
) {
const model = await ContentsManagerModel.contentsManager.save(
payload.path,
payload.options
);
this.send({ event: 'saved', _id, model: model as any });
}

static model_name = 'ContentsManagerModel';
static model_module = MODULE_NAME;
static model_module_version = MODULE_VERSION;
static view_name: string = null;
static view_module: string = null;
static view_module_version = MODULE_VERSION;

static contentsManager: Contents.IManager;
}

export class ContentsModelModel extends WidgetModel {
/**
* The default attributes.
*/
defaults(): any {
return {
...super.defaults(),
contents: null,
_model_name: ContentsModelModel.model_name,
_model_module: ContentsModelModel.model_module,
_model_module_version: ContentsModelModel.model_module_version
};
}

static model_name = 'ContentsModelModel';
static model_module = MODULE_NAME;
static model_module_version = MODULE_VERSION;
static view_name: string = null;
static view_module: string = null;
static view_module_version = MODULE_VERSION;
}

0 comments on commit de4a0ad

Please sign in to comment.