1#----------------------------------------------------------------------------- 2# Copyright (c) 2012 - 2021, Anaconda, Inc., and Bokeh Contributors. 3# All rights reserved. 4# 5# The full license is in the file LICENSE.txt, distributed with this software. 6#----------------------------------------------------------------------------- 7 8#----------------------------------------------------------------------------- 9# Boilerplate 10#----------------------------------------------------------------------------- 11import pytest ; pytest 12 13#----------------------------------------------------------------------------- 14# Imports 15#----------------------------------------------------------------------------- 16 17# External imports 18import numpy as np 19from mock import patch 20 21# Bokeh imports 22from bokeh._testing.util.api import verify_all 23from bokeh.core.has_props import HasProps 24 25# Module under test 26import bokeh.core.property.bases as bcpb # isort:skip 27 28#----------------------------------------------------------------------------- 29# Setup 30#----------------------------------------------------------------------------- 31 32ALL = ( 33 'ContainerProperty', 34 'DeserializationError', 35 'PrimitiveProperty', 36 'Property', 37 'validation_on', 38) 39 40#----------------------------------------------------------------------------- 41# General API 42#----------------------------------------------------------------------------- 43 44class TestProperty: 45 @patch('bokeh.core.property.bases.Property.validate') 46 def test_is_valid_supresses_validation_detail(self, mock_validate) -> None: 47 p = bcpb.Property() 48 p.is_valid(None) 49 assert mock_validate.called 50 assert mock_validate.call_args[0] == (None, False) 51 52 def test_serialized_default(self) -> None: 53 p = bcpb.Property() 54 assert p.serialized == True 55 assert p.readonly == False 56 57 # readonly=True sets serialized=False if unspecified 58 p = bcpb.Property(readonly=True) 59 assert p.serialized == False 60 assert p.readonly == True 61 62 # explicit serialized value always respected 63 p = bcpb.Property(readonly=True, serialized=True) 64 assert p.serialized == True 65 assert p.readonly == True 66 67 68 def test_assert_bools(self) -> None: 69 hp = HasProps() 70 p = bcpb.Property() 71 72 p.asserts(True, "true") 73 assert p.prepare_value(hp, "foo", 10) == 10 74 75 p.asserts(False, "false") 76 with pytest.raises(ValueError) as e: 77 p.prepare_value(hp, "foo", 10) 78 assert str(e) == "false" 79 80 def test_assert_functions(self) -> None: 81 hp = HasProps() 82 p = bcpb.Property() 83 84 p.asserts(lambda obj, value: True, "true") 85 p.asserts(lambda obj, value: obj is hp, "true") 86 p.asserts(lambda obj, value: value==10, "true") 87 assert p.prepare_value(hp, "foo", 10) == 10 88 89 p.asserts(lambda obj, value: False, "false") 90 with pytest.raises(ValueError) as e: 91 p.prepare_value(hp, "foo", 10) 92 assert str(e) == "false" 93 94 def test_assert_msg_funcs(self) -> None: 95 hp = HasProps() 96 p = bcpb.Property() 97 98 def raise_(ex): 99 raise ex 100 101 p.asserts(False, lambda obj, name, value: raise_(ValueError("bad %s %s %s" % (hp==obj, name, value)))) 102 103 with pytest.raises(ValueError) as e: 104 p.prepare_value(hp, "foo", 10) 105 assert str(e) == "bad True name, 10" 106 107 def test_matches_basic_types(self, capsys) -> None: 108 p = bcpb.Property() 109 for x in [1, 1.2, "a", np.arange(4), None, False, True, {}, []]: 110 assert p.matches(x, x) is True 111 assert p.matches(x, "junk") is False 112 out, err = capsys.readouterr() 113 assert err == "" 114 115 def test_matches_compatible_arrays(self, capsys) -> None: 116 p = bcpb.Property() 117 a = np.arange(5) 118 b = np.arange(5) 119 assert p.matches(a, b) is True 120 assert p.matches(a, b+1) is False 121 for x in [1, 1.2, "a", np.arange(4), None, False]: 122 assert p.matches(a, x) is False 123 assert p.matches(x, b) is False 124 out, err = capsys.readouterr() 125 assert err == "" 126 127 def test_matches_incompatible_arrays(self, capsys) -> None: 128 p = bcpb.Property() 129 a = np.arange(5) 130 b = np.arange(5).astype(str) 131 assert p.matches(a, b) is False 132 out, err = capsys.readouterr() 133 # no way to suppress FutureWarning in this case 134 # assert err == "" 135 136 def test_matches_dicts_with_array_values(self, capsys) -> None: 137 p = bcpb.Property() 138 d1 = dict(foo=np.arange(10)) 139 d2 = dict(foo=np.arange(10)) 140 141 assert p.matches(d1, d1) is True 142 assert p.matches(d1, d2) is True 143 144 # XXX not sure if this is preferable to have match, or not 145 assert p.matches(d1, dict(foo=list(range(10)))) is True 146 147 assert p.matches(d1, dict(foo=np.arange(11))) is False 148 assert p.matches(d1, dict(bar=np.arange(10))) is False 149 assert p.matches(d1, dict(bar=10)) is False 150 out, err = capsys.readouterr() 151 assert err == "" 152 153 def test_matches_non_dict_containers_with_array_false(self, capsys) -> None: 154 p = bcpb.Property() 155 d1 = [np.arange(10)] 156 d2 = [np.arange(10)] 157 assert p.matches(d1, d1) is True # because object identity 158 assert p.matches(d1, d2) is False 159 160 t1 = (np.arange(10),) 161 t2 = (np.arange(10),) 162 assert p.matches(t1, t1) is True # because object identity 163 assert p.matches(t1, t2) is False 164 165 out, err = capsys.readouterr() 166 assert err == "" 167 168 def test_matches_dicts_with_series_values(self, capsys, pd) -> None: 169 p = bcpb.Property() 170 d1 = pd.DataFrame(dict(foo=np.arange(10))) 171 d2 = pd.DataFrame(dict(foo=np.arange(10))) 172 173 assert p.matches(d1.foo, d1.foo) is True 174 assert p.matches(d1.foo, d2.foo) is True 175 176 # XXX not sure if this is preferable to have match, or not 177 assert p.matches(d1.foo, (range(10))) is True 178 179 assert p.matches(d1.foo, np.arange(11)) is False 180 assert p.matches(d1.foo, np.arange(10)+1) is False 181 assert p.matches(d1.foo, 10) is False 182 out, err = capsys.readouterr() 183 assert err == "" 184 185 def test_matches_dicts_with_index_values(self, capsys, pd) -> None: 186 p = bcpb.Property() 187 d1 = pd.DataFrame(dict(foo=np.arange(10))) 188 d2 = pd.DataFrame(dict(foo=np.arange(10))) 189 190 assert p.matches(d1.index, d1.index) is True 191 assert p.matches(d1.index, d2.index) is True 192 193 # XXX not sure if this is preferable to have match, or not 194 assert p.matches(d1.index, list(range(10))) is True 195 196 assert p.matches(d1.index, np.arange(11)) is False 197 assert p.matches(d1.index, np.arange(10)+1) is False 198 assert p.matches(d1.index, 10) is False 199 out, err = capsys.readouterr() 200 assert err == "" 201 202 def test_validation_on(self) -> None: 203 assert bcpb.Property._should_validate == True 204 assert bcpb.validation_on() 205 206 bcpb.Property._should_validate = False 207 assert not bcpb.validation_on() 208 209 bcpb.Property._should_validate = True 210 assert bcpb.validation_on() 211 212#----------------------------------------------------------------------------- 213# Dev API 214#----------------------------------------------------------------------------- 215 216#----------------------------------------------------------------------------- 217# Private API 218#----------------------------------------------------------------------------- 219 220#----------------------------------------------------------------------------- 221# Code 222#----------------------------------------------------------------------------- 223 224Test___all__ = verify_all(bcpb, ALL) 225