or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-widget.mdexperimental.mdfile-management.mdindex.mdipython-integration.md

experimental.mddocs/

0

# Experimental Features

1

2

Advanced decorator-based patterns and cutting-edge features for creating widgets using modern Python idioms. These experimental features provide alternative approaches to widget creation using dataclasses, event systems, and function-based patterns.

3

4

## Capabilities

5

6

### Widget Decorator

7

8

Decorator for converting regular classes into widgets with ES module and CSS support, providing a more functional approach to widget creation.

9

10

```python { .api }

11

def widget(

12

*,

13

esm: str | Path,

14

css: str | Path | None = None,

15

**kwargs

16

):

17

"""

18

Decorator to register a widget class as a mimebundle.

19

20

Parameters:

21

esm (str | Path): The path or contents of an ES Module for the widget

22

css (str | Path | None): The path or contents of a CSS file for the widget

23

**kwargs: Additional keyword arguments passed to the widget

24

25

Returns:

26

Callable: A decorator that registers the widget class as a mimebundle

27

28

Usage:

29

@widget(esm="./widget.js", css="./widget.css")

30

class MyWidget:

31

pass

32

"""

33

```

34

35

### Dataclass Widget Decorator

36

37

Combines dataclass, psygnal events, and widget functionality into a single decorator for reactive widget creation.

38

39

```python { .api }

40

def dataclass(

41

cls=None,

42

*,

43

esm: str | Path,

44

css: str | Path | None = None,

45

**dataclass_kwargs

46

):

47

"""

48

Turns class into a dataclass, makes it evented, and registers it as a widget.

49

50

Parameters:

51

cls (type | None): The class to decorate (when used without parentheses)

52

esm (str | Path): The path or contents of an ES Module for the widget

53

css (str | Path | None): The path or contents of a CSS file for the widget

54

**dataclass_kwargs: Additional keyword arguments passed to dataclass decorator

55

56

Returns:

57

type: The evented dataclass with widget capabilities

58

59

Usage:

60

@dataclass(esm="./counter.js")

61

class Counter:

62

value: int = 0

63

"""

64

```

65

66

67

### MimeBundleDescriptor

68

69

Advanced descriptor for managing widget representations and communication channels with fine-grained control over synchronization and display behavior.

70

71

```python { .api }

72

class MimeBundleDescriptor:

73

"""

74

Descriptor that builds a ReprMimeBundle when accessed on an instance.

75

76

Manages communication channels between Python models and JavaScript views

77

with support for bidirectional state synchronization and event handling.

78

"""

79

80

def __init__(

81

self,

82

*,

83

follow_changes: bool = True,

84

autodetect_observer: bool = True,

85

no_view: bool = False,

86

**extra_state

87

):

88

"""

89

Initialize the descriptor with synchronization options.

90

91

Parameters:

92

follow_changes (bool): Enable bidirectional state synchronization

93

autodetect_observer (bool): Automatically detect observer patterns (psygnal, traitlets)

94

no_view (bool): Create DOM-less widget (comm only, no display)

95

**extra_state: Additional state to send to JavaScript view

96

"""

97

```

98

99

100

## Usage Examples

101

102

### Widget Decorator Pattern

103

104

```python

105

from anywidget.experimental import widget

106

import psygnal

107

108

@widget(esm="./my-widget.js", css="./my-widget.css")

109

@psygnal.evented

110

class ReactiveWidget:

111

def __init__(self):

112

self.value = 0

113

self.label = "Counter"

114

115

def increment(self):

116

self.value += 1

117

118

# Usage

119

widget_instance = ReactiveWidget()

120

widget_instance # Displays in Jupyter

121

```

122

123

### Dataclass Widget Pattern

124

125

```python

126

from anywidget.experimental import dataclass

127

128

@dataclass(esm="""

129

function render({ model, el }) {

130

let updateDisplay = () => {

131

el.innerHTML = `

132

<div>

133

<h3>${model.get("title")}</h3>

134

<p>Value: ${model.get("value")}</p>

135

<p>Status: ${model.get("status")}</p>

136

</div>

137

`;

138

};

139

140

model.on("change", updateDisplay);

141

updateDisplay();

142

}

143

export default { render };

144

""")

145

class StatusWidget:

146

title: str = "Status Dashboard"

147

value: int = 0

148

status: str = "Ready"

149

150

# Create reactive widget

151

dashboard = StatusWidget(title="My Dashboard", value=42)

152

dashboard.value = 100 # Automatically updates display

153

```

154

155

156

### Custom MimeBundleDescriptor

157

158

```python

159

from anywidget.experimental import MimeBundleDescriptor

160

import dataclasses

161

162

@dataclasses.dataclass

163

class CustomModel:

164

name: str = "Default"

165

value: float = 0.0

166

active: bool = True

167

168

# Custom descriptor with specific behavior

169

_repr_mimebundle_ = MimeBundleDescriptor(

170

follow_changes=True,

171

autodetect_observer=False, # Manual control

172

no_view=False,

173

_esm="""

174

function render({ model, el }) {

175

let update = () => {

176

el.innerHTML = `

177

<div class="custom-model">

178

<h4>${model.get("name")}</h4>

179

<div>Value: ${model.get("value")}</div>

180

<div>Active: ${model.get("active")}</div>

181

</div>

182

`;

183

};

184

model.on("change", update);

185

update();

186

}

187

export default { render };

188

""",

189

_css="""

190

.custom-model {

191

border: 2px solid #333;

192

padding: 10px;

193

border-radius: 5px;

194

font-family: monospace;

195

}

196

"""

197

)

198

199

model = CustomModel(name="Test Model", value=3.14159)

200

model # Displays with custom representation

201

```

202

203

### DOM-less Widget (Communication Only)

204

205

```python

206

from anywidget.experimental import MimeBundleDescriptor

207

import threading

208

import time

209

210

class BackgroundProcessor:

211

def __init__(self):

212

self.status = "idle"

213

self.progress = 0

214

self.results = []

215

216

# No visual display, just communication

217

_repr_mimebundle_ = MimeBundleDescriptor(

218

no_view=True, # DOM-less widget

219

_esm="""

220

// Background communication handler

221

function render({ model, el }) {

222

// No DOM elements, just event handling

223

model.on("change:status", () => {

224

console.log("Status:", model.get("status"));

225

});

226

}

227

export default { render };

228

"""

229

)

230

231

def start_processing(self):

232

"""Start background processing"""

233

def process():

234

self.status = "running"

235

for i in range(101):

236

self.progress = i

237

time.sleep(0.1)

238

self.status = "completed"

239

240

threading.Thread(target=process, daemon=True).start()

241

242

processor = BackgroundProcessor()

243

processor # Creates comm channel but no display

244

processor.start_processing()

245

```