holoviz / panel
1 6
from functools import partial
2

3 6
import bokeh.core.properties as bp
4 6
import param
5

6 6
from bokeh.models import Div
7 6
from panel.layout import Tabs, WidgetBox
8 6
from panel.reactive import Reactive, ReactiveHTML
9 6
from panel.viewable import Viewable
10 6
from panel.widgets import Checkbox, StaticText, TextInput, IntInput
11

12

13 6
def test_link():
14
    "Link two Reactive objects"
15

16 6
    class ReactiveLink(Reactive):
17

18 6
        a = param.Parameter()
19

20 6
    obj = ReactiveLink()
21 6
    obj2 = ReactiveLink()
22 6
    obj.link(obj2, a='a')
23 6
    obj.a = 1
24

25 6
    assert obj.a == 1
26 6
    assert obj2.a == 1
27

28

29 6
def test_param_rename():
30
    "Test that Reactive renames params and properties"
31

32 6
    class ReactiveRename(Reactive):
33

34 6
        a = param.Parameter()
35

36 6
        _rename = {'a': 'b'}
37

38 6
    obj = ReactiveRename()
39

40 6
    params = obj._process_property_change({'b': 1})
41 6
    assert params == {'a': 1}
42

43 6
    properties = obj._process_param_change({'a': 1})
44 6
    assert properties == {'b': 1}
45

46

47 6
def test_link_properties_nb(document, comm):
48

49 6
    class ReactiveLink(Reactive):
50

51 6
        text = param.String(default='A')
52

53 6
    obj = ReactiveLink()
54 6
    div = Div()
55

56
    # Link property and check bokeh js property callback is defined
57 6
    obj._link_props(div, ['text'], document, div, comm)
58 6
    assert 'text' in div._callbacks
59

60
    # Assert callback is set up correctly
61 6
    cb = div._callbacks['text'][0]
62 6
    assert isinstance(cb, partial)
63 6
    assert cb.args == (document, div.ref['id'], comm)
64 6
    assert cb.func == obj._comm_change
65

66

67 6
def test_link_properties_server(document):
68

69 6
    class ReactiveLink(Reactive):
70

71 6
        text = param.String(default='A')
72

73 6
    obj = ReactiveLink()
74 6
    div = Div()
75

76
    # Link property and check bokeh callback is defined
77 6
    obj._link_props(div, ['text'], document, div)
78 6
    assert 'text' in div._callbacks
79

80
    # Assert callback is set up correctly
81 6
    cb = div._callbacks['text'][0]
82 6
    assert isinstance(cb, partial)
83 6
    assert cb.args == (document, div.ref['id'])
84 6
    assert cb.func == obj._server_change
85

86

87 6
def test_text_input_controls():
88 6
    text_input = TextInput()
89

90 6
    controls = text_input.controls()
91

92 6
    assert isinstance(controls, Tabs)
93 6
    assert len(controls) == 2
94 6
    wb1, wb2 = controls
95 6
    assert isinstance(wb1, WidgetBox)
96 6
    assert len(wb1) == 7
97 6
    name, disabled, visible, *(ws) = wb1
98

99 6
    assert isinstance(name, StaticText)
100 6
    assert isinstance(disabled, Checkbox)
101 6
    assert isinstance(visible, Checkbox)
102

103 6
    not_checked = []
104 6
    for w in ws:
105 6
        print(w.name)
106 6
        if w.name == 'Value':
107 6
            assert isinstance(w, TextInput)
108 6
            text_input.value = "New value"
109 6
            assert w.value == "New value"
110 6
        elif w.name == 'Value input':
111 6
            assert isinstance(w, TextInput)
112 6
        elif w.name == 'Placeholder':
113 6
            assert isinstance(w, TextInput)
114 6
            text_input.placeholder = "Test placeholder..."
115 6
            assert w.value == "Test placeholder..."
116 6
        elif w.name == 'Max length':
117 6
            assert isinstance(w, IntInput)
118
        else:
119 0
            not_checked.append(w)
120

121 6
    assert not not_checked
122

123 6
    assert isinstance(wb2, WidgetBox)
124 6
    assert len(wb2) == len(list(Viewable.param)) + 1
125

126

127

128 6
def test_text_input_controls_explicit():
129 6
    text_input = TextInput()
130

131 6
    controls = text_input.controls(['placeholder', 'disabled'])
132

133 6
    assert isinstance(controls, WidgetBox)
134 6
    assert len(controls) == 3
135 6
    name, disabled, placeholder = controls
136

137 6
    assert isinstance(name, StaticText)
138 6
    assert isinstance(disabled, Checkbox)
139 6
    assert isinstance(placeholder, TextInput)
140

141 6
    text_input.disabled = True
142 6
    assert disabled.value
143

144 6
    text_input.placeholder = "Test placeholder..."
145 6
    assert placeholder.value == "Test placeholder..."
146

147

148 6
def test_reactive_html_basic():
149

150 6
    class Test(ReactiveHTML):
151

152 6
        int = param.Integer(default=3, doc='An integer')
153

154 6
        float = param.Number(default=3.14, doc='A float')
155

156 6
        _template = '<div id="div" width=${int}></div>'
157

158 6
    data_model = Test._data_model
159 6
    assert data_model.__name__ == 'Test1'
160

161 6
    properties = data_model.properties()
162 6
    assert 'int' in properties
163 6
    assert 'float' in properties
164

165 6
    int_prop = data_model.lookup('int')
166 6
    assert isinstance(int_prop.property, bp.Int)
167 6
    assert int_prop.class_default(data_model) == 3
168

169 6
    float_prop = data_model.lookup('float')
170 6
    assert isinstance(float_prop.property, bp.Float)
171 6
    assert float_prop.class_default(data_model) == 3.14
172

173 6
    assert Test._attrs == {'div': [('width', ['int'], '{int}')]}
174 6
    assert Test._node_callbacks == {}
175

176

177 6
    test = Test()
178 6
    root = test.get_root()
179 6
    assert root.callbacks == {}
180 6
    assert root.events == {}
181

182

183 6
def test_reactive_html_dom_events():
184

185 6
    class TestDOMEvents(ReactiveHTML):
186

187 6
        int = param.Integer(default=3, doc='An integer')
188

189 6
        float = param.Number(default=3.14, doc='A float')
190

191 6
        _template = '<div id="div" width=${int}></div>'
192

193 6
        _dom_events = {'div': ['change']}
194

195 6
    data_model = TestDOMEvents._data_model
196 6
    assert data_model.__name__ == 'TestDOMEvents1'
197

198 6
    properties = data_model.properties()
199 6
    assert 'int' in properties
200 6
    assert 'float' in properties
201

202 6
    int_prop = data_model.lookup('int')
203 6
    assert isinstance(int_prop.property, bp.Int)
204 6
    assert int_prop.class_default(data_model) == 3
205

206 6
    float_prop = data_model.lookup('float')
207 6
    assert isinstance(float_prop.property, bp.Float)
208 6
    assert float_prop.class_default(data_model) == 3.14
209

210 6
    assert TestDOMEvents._attrs == {'div': [('width', ['int'], '{int}')]}
211 6
    assert TestDOMEvents._node_callbacks == {}
212

213 6
    test = TestDOMEvents()
214 6
    root = test.get_root()
215 6
    assert root.callbacks == {}
216 6
    assert root.events == {'div': {'change': True}}
217

218

219 6
def test_reactive_html_inline():
220 6
    class TestInline(ReactiveHTML):
221

222 6
        int = param.Integer(default=3, doc='An integer')
223

224 6
        _template = '<div id="div" onchange=${_div_change} width=${int}></div>'
225

226 6
        def _div_change(self, event):
227 0
            pass
228

229 6
    data_model = TestInline._data_model
230 6
    assert data_model.__name__ == 'TestInline1'
231

232 6
    properties = data_model.properties()
233 6
    assert 'int' in properties
234

235 6
    int_prop = data_model.lookup('int')
236 6
    assert isinstance(int_prop.property, bp.Int)
237 6
    assert int_prop.class_default(data_model) == 3
238

239 6
    assert TestInline._attrs == {
240
        'div': [
241
            ('onchange', [], '{_div_change}'),
242
            ('width', ['int'], '{int}')
243
        ]
244
    }
245 6
    assert TestInline._node_callbacks == {'div': [('onchange', '_div_change')]}
246 6
    assert TestInline._inline_callbacks == [('div', 'onchange', '_div_change')]
247

248 6
    test = TestInline()
249 6
    root = test.get_root()
250 6
    assert root.callbacks == {'div': [('onchange', '_div_change')]}
251 6
    assert root.events == {}
252

253 6
    test.on_event('div', 'click', print)
254 6
    assert root.events == {'div': {'click': False}}
255

256

257 6
def test_reactive_html_children():
258

259 6
    class TestChildren(ReactiveHTML):
260

261 6
        children = param.List(default=[])
262

263 6
        _template = '<div id="div">${children}</div>'
264

265 6
    assert TestChildren._attrs == {}
266 6
    assert TestChildren._node_callbacks == {}
267 6
    assert TestChildren._inline_callbacks == []
268 6
    assert TestChildren._parser.children == {'div': 'children'}
269

270 6
    widget = TextInput()
271 6
    test = TestChildren(children=[widget])
272 6
    root = test.get_root()
273 6
    assert root.children == {'div': [widget._models[root.ref['id']][0]]}
274

275 6
    widget_new = TextInput()
276 6
    test.children = [widget_new]
277 6
    assert len(widget._models) == 0
278 6
    assert root.children == {'div': [widget_new._models[root.ref['id']][0]]}
279

280

281

282 6
def test_reactive_html_templated_children():
283

284 6
    class TestTemplatedChildren(ReactiveHTML):
285

286 6
        children = param.List(default=[])
287

288 6
        _template = """
289
        <select id="select">
290
        {% for option in children %}
291
        <option id="option-{{ loop.index0 }}">${children[{{ loop.index0 }}]}</option>
292
        {% endfor %}
293
        </div>
294
        """
295

296 6
    assert TestTemplatedChildren._attrs == {}
297 6
    assert TestTemplatedChildren._node_callbacks == {}
298 6
    assert TestTemplatedChildren._inline_callbacks == []
299 6
    assert TestTemplatedChildren._parser.children == {'option': 'children'}
300

301 6
    widget = TextInput()
302 6
    test = TestTemplatedChildren(children=[widget])
303 6
    root = test.get_root()
304 6
    assert root.looped == ['option']
305 6
    assert root.children == {'option': [widget._models[root.ref['id']][0]]}
306

307 6
    widget_new = TextInput()
308 6
    test.children = [widget_new]
309 6
    assert len(widget._models) == 0
310 6
    assert root.children == {'option': [widget_new._models[root.ref['id']][0]]}
311

312

313

314 6
def test_reactive_html_templated_children_add_loop_id():
315

316 6
    class TestTemplatedChildren(ReactiveHTML):
317

318 6
        children = param.List(default=[])
319

320 6
        _template = """
321
        <select id="select">
322
        {% for option in children %}
323
          <option id="option">${children[{{ loop.index0 }}]}</option>
324
        {% endfor %}
325
        </select>
326
        """
327

328 6
    assert TestTemplatedChildren._attrs == {}
329 6
    assert TestTemplatedChildren._node_callbacks == {}
330 6
    assert TestTemplatedChildren._inline_callbacks == []
331 6
    assert TestTemplatedChildren._parser.children == {'option': 'children'}
332

333 6
    test = TestTemplatedChildren(children=['A', 'B', 'C'])
334

335 6
    assert test._get_template() == """
336
        <select id="select-${id}">
337
        
338
          <option id="option-0-${id}"></option>
339
        
340
          <option id="option-1-${id}"></option>
341
        
342
          <option id="option-2-${id}"></option>
343
        
344
        </select>
345
        """
346

347 6
    model = test.get_root()
348 6
    assert model.looped == ['option']
349

350

351

352 6
def test_reactive_html_templated_children_add_loop_id_and_for_loop_var():
353

354 6
    class TestTemplatedChildren(ReactiveHTML):
355

356 6
        children = param.List(default=[])
357

358 6
        _template = """
359
        <select id="select">
360
        {% for option in children %}
361
          <option id="option">${option}</option>
362
        {% endfor %}
363
        </select>
364
        """
365

366 6
    assert TestTemplatedChildren._attrs == {}
367 6
    assert TestTemplatedChildren._node_callbacks == {}
368 6
    assert TestTemplatedChildren._inline_callbacks == []
369 6
    assert TestTemplatedChildren._parser.children == {'option': 'children'}
370

371 6
    test = TestTemplatedChildren(children=['A', 'B', 'C'])
372

373 6
    assert test._get_template() == """
374
        <select id="select-${id}">
375
        
376
          <option id="option-0-${id}"></option>
377
        
378
          <option id="option-1-${id}"></option>
379
        
380
          <option id="option-2-${id}"></option>
381
        
382
        </select>
383
        """
384 6
    model = test.get_root()
385 6
    assert model.looped == ['option']

Read our documentation on viewing source code .

Loading