def test_missing_renderers(self): p = figure() p.renderers = [] with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.warning.call_count == 1 assert mock_logger.warning.call_args[0][0].startswith("W-1000 (MISSING_RENDERERS): Plot has no renderers")
def test_no_warning_with_long_palette(self, mock_warn, mock_error) -> None: m = bmm.CategoricalColorMapper( factors=["a", "b", "c"], palette=["red", "green", "orange", "blue"]) check_integrity([m]) assert not mock_error.called assert not mock_warn.called
def test(layout: LayoutDOM) -> None: with mock.patch("bokeh.core.validation.check.log") as mock_logger: check_integrity([layout]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith( "E-1027 (REPEATED_LAYOUT_CHILD): The same model can't be used multiple times in a layout" )
def test_can_add_multiple_glyph_renderers_to_legend_item(): legend_item = LegendItem() gr_1 = GlyphRenderer() gr_2 = GlyphRenderer() legend_item.renderers = [gr_1, gr_2] with mock.patch('bokeh.core.validation.check.logger') as mock_logger: check_integrity([legend_item]) assert mock_logger.error.call_count == 0
def test_legend_item_with_field_label_raises_error_if_field_not_in_cds(): legend_item = LegendItem() gr_1 = GlyphRenderer(data_source=ColumnDataSource()) legend_item.label = field('label') legend_item.renderers = [gr_1] with mock.patch('bokeh.core.validation.check.logger') as mock_logger: check_integrity([legend_item]) assert mock_logger.error.call_count == 1
def test_legend_item_with_value_label_and_different_data_sources_does_not_raise_a_validation_error(): legend_item = LegendItem() gr_1 = GlyphRenderer(data_source=ColumnDataSource()) gr_2 = GlyphRenderer(data_source=ColumnDataSource()) legend_item.label = value('label') legend_item.renderers = [gr_1, gr_2] with mock.patch('bokeh.core.validation.check.logger') as mock_logger: check_integrity([legend_item]) assert mock_logger.error.call_count == 0
def test_toolbar_box_with_no_children_does_not_raise_a_bokeh_warning(mock__show_with_state: MagicMock) -> None: # This is the normal way a ToolbarBox would be instantiated for example in # a gridplot. So we don't want to worry people with warnings. The children # for the ToolbarBox are created on the JS side. tb_box = ToolbarBox() with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([tb_box]) assert mock_logger.warning.call_count == 0
def test_legend_item_with_field_label_and_different_data_sources_raises_a_validation_error() -> None: legend_item = LegendItem() gr_1 = GlyphRenderer(data_source=ColumnDataSource(data={'label': [1]})) gr_2 = GlyphRenderer(data_source=ColumnDataSource(data={'label': [1]})) legend_item.label = field('label') legend_item.renderers = [gr_1, gr_2] with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([legend_item]) assert mock_logger.error.call_count == 1
def test_silence_with_bad_input_and_check_warn(mock_warn, mock_error): m = Mod(foo=-10) with pytest.raises(ValueError, match=('Input to silence should be a ' 'warning object')): v.silence('EXT:W') v.check_integrity([m]) assert not mock_error.called assert mock_warn.called
def test_toolbar_box_with_no_children_does_not_raise_a_bokeh_warning(mock__show_with_state): # This is the normal way a ToolbarBox would be instantiated for example in # a gridplot. So we don't want to worry people with warnings. The children # for the ToolbarBox are created on the JS side. tb_box = ToolbarBox() with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([tb_box]) assert mock_logger.warning.call_count == 0
def test_bad_extra_range_only_immediate_refs(self) -> None: # test whether adding a figure (*and* it's extra ranges) # to another's references doesn't create a false positive p, dep = figure(), figure() dep.extra_x_ranges['foo'] = Range1d() dep.grid.x_range_name="foo" p.grid[0].js_on_change("dimension", CustomJS(code = "", args = {"toto": dep.grid[0]})) with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 0
def test_missing_range(self): p = figure() p.x_range = None with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith("E-1004 (REQUIRED_RANGE): A required Range object is missing: x_range") p.y_range = None with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith("E-1004 (REQUIRED_RANGE): A required Range object is missing: x_range, y_range")
def test_silence_and_check_warn(mock_warn, mock_error): from bokeh.core.validation.warnings import EXT m = Mod(foo=-10) try: v.silence(EXT) # turn the warning off v.check_integrity([m]) assert not mock_error.called assert not mock_warn.called finally: v.silence(EXT, False) # turn the warning back on v.check_integrity([m]) assert not mock_error.called assert mock_warn.called
def test_missing_scale(self): p = figure() p.x_scale = None with mock.patch('bokeh.core.validation.check.logger') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith("E-1008 (REQUIRED_SCALE): A required Scale object is missing: x_scale") p.y_scale = None with mock.patch('bokeh.core.validation.check.logger') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith("E-1008 (REQUIRED_SCALE): A required Scale object is missing: x_scale, y_scale")
def test_silence_and_check_warn(mock_warn, mock_error) -> None: from bokeh.core.validation.warnings import EXT m = Mod(foo=-10) try: v.silence(EXT) # turn the warning off issues = v.check_integrity([m]) v.process_validation_issues(issues) assert not mock_error.called assert not mock_warn.called finally: v.silence(EXT, False) # turn the warning back on issues = v.check_integrity([m]) v.process_validation_issues(issues) assert not mock_error.called assert mock_warn.called
def test_check_integrity_warning() -> None: m = Mod(foo = -10) issues = ValidationIssues( error=[], warning=[ValidationIssue(9999, "EXT:W", "Custom extension reports warning", "wrn")], ) assert v.check_integrity([m]) == issues
def test_check_integrity_error() -> None: m = Mod(foo=10) issues = { 'error': [(9999, 'EXT:E', 'Custom extension reports error', 'err')], 'warning': [] } assert v.check_integrity([m]) == issues
def test_check_integrity_warning() -> None: m = Mod(foo=-10) issues = { 'error': [], 'warning': [(9999, 'EXT:W', 'Custom extension reports warning', 'wrn')] } assert v.check_integrity([m]) == issues
def test_check_integrity_error() -> None: m = Mod(foo = 10) issues = ValidationIssues( error=[ValidationIssue(9999, "EXT:E", "Custom extension reports error", "err")], warning=[], ) assert v.check_integrity([m]) == issues
def test_check_pass(mock_warn: MagicMock, mock_error: MagicMock) -> None: m = Mod() issues = v.check_integrity([m]) v.process_validation_issues(issues) assert not mock_error.called assert not mock_warn.called
def test_warning_with_short_palette(self, mock_warn, mock_error) -> None: m = bmm.CategoricalColorMapper(factors=["a", "b", "c"], palette=["red", "green"]) issues = check_integrity([m]) process_validation_issues(issues) assert not mock_error.called assert mock_warn.called
def test_silence_remove_warning_that_is_not_in_silencers_is_ok( mock_warn, mock_error): from bokeh.core.validation.warnings import EXT m = Mod(foo=-10) silencers0 = v.silence(EXT) # turn the warning off assert len(silencers0) == 1 silencers1 = v.silence(EXT, False) # turn the warning back on silencers2 = v.silence(EXT, False) # do it a second time - no-op assert len(silencers1) == 0 assert silencers1 == silencers2 v.check_integrity([m]) assert not mock_error.called assert mock_warn.called
def test_silence_with_bad_input_and_check_warn(mock_warn: MagicMock, mock_error: MagicMock) -> None: m = Mod(foo=-10) with pytest.raises(ValueError, match="Input to silence should be a warning object"): v.silence(cast(Any, "EXT:W")) issues = v.check_integrity([m]) v.process_validation_issues(issues) assert not mock_error.called assert mock_warn.called
def test_silence_warning_already_in_silencers_is_ok(mock_warn, mock_error): from bokeh.core.validation.warnings import EXT m = Mod(foo=-10) try: silencers0 = v.silence(EXT) # turn the warning off silencers1 = v.silence(EXT) # do it a second time - no-op assert len(silencers0) == 1 assert silencers0 == silencers1 # silencers is same as before v.check_integrity([m]) assert not mock_error.called assert not mock_warn.called finally: v.silence(EXT, False) # turn the warning back on v.check_integrity([m]) assert not mock_error.called assert mock_warn.called
def test_missing_scale(self): p = figure() p.x_scale = None with mock.patch('bokeh.core.validation.check.logger') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith( "E-1008 (REQUIRED_SCALE): A required Scale object is missing: x_scale" ) p.y_scale = None with mock.patch('bokeh.core.validation.check.logger') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith( "E-1008 (REQUIRED_SCALE): A required Scale object is missing: x_scale, y_scale" )
def test_can_add_multiple_glyph_renderers_to_legend_item() -> None: legend_item = LegendItem() gr_1 = GlyphRenderer(data_source=ColumnDataSource()) gr_2 = GlyphRenderer(data_source=ColumnDataSource()) legend_item.renderers = [gr_1, gr_2] with mock.patch('bokeh.core.validation.check.log') as mock_logger: issues = check_integrity([legend_item]) process_validation_issues(issues) assert mock_logger.error.call_count == 0
def test_duplicate_factors_raises_validation_error(self) -> None: r = FactorRange("foo", "bar", "foo") with mock.patch('bokeh.core.validation.check.log') as mock_logger: issues = check_integrity([r]) process_validation_issues(issues) assert mock_logger.error.call_count == 1 r = FactorRange(factors=[("foo", "a"), ("foo", "b"), ("foo", "a")]) with mock.patch('bokeh.core.validation.check.log') as mock_logger: issues = check_integrity([r]) process_validation_issues(issues) assert mock_logger.error.call_count == 1 r = FactorRange(factors=[("foo", "a", "1"), ("foo", "a", "2"), ("foo", "a", "1")]) with mock.patch('bokeh.core.validation.check.log') as mock_logger: issues = check_integrity([r]) process_validation_issues(issues) assert mock_logger.error.call_count == 1
def test_no_warning_with_long_palette(self, mock_warn: MagicMock, mock_error: MagicMock) -> None: m = bmm.CategoricalColorMapper( factors=["a", "b", "c"], palette=["red", "green", "orange", "blue"]) issues = check_integrity([m]) process_validation_issues(issues) assert not mock_error.called assert not mock_warn.called
def test_bad_extra_range_name(self): p = figure() p.xaxis.x_range_name="junk" with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith( "E-1020 (BAD_EXTRA_RANGE_NAME): An extra range name is configued with a name that does not correspond to any range: x_range_name='junk' [LinearAxis" ) p = figure() p.extra_x_ranges['foo'] = Range1d() p.grid.x_range_name="junk" with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith( "E-1020 (BAD_EXTRA_RANGE_NAME): An extra range name is configued with a name that does not correspond to any range: x_range_name='junk' [Grid" ) assert mock_logger.error.call_args[0][0].count("Grid") == 2
def test_bad_extra_range_name(self): p = figure() p.xaxis.x_range_name = "junk" with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith( "E-1020 (BAD_EXTRA_RANGE_NAME): An extra range name is configued with a name that does not correspond to any range: x_range_name='junk' [LinearAxis" ) p = figure() p.extra_x_ranges['foo'] = Range1d() p.grid.x_range_name = "junk" with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 1 assert mock_logger.error.call_args[0][0].startswith( "E-1020 (BAD_EXTRA_RANGE_NAME): An extra range name is configued with a name that does not correspond to any range: x_range_name='junk' [Grid" ) assert mock_logger.error.call_args[0][0].count("Grid") == 2 # test whether adding a figure (*and* it's extra ranges) # to another's references doesn't create a false positive p, dep = figure(), figure() dep.extra_x_ranges['foo'] = Range1d() dep.grid.x_range_name = "foo" p.x_range.callback = CustomJS(code="", args={"dep": dep}) assert dep in p.references() with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([p]) assert mock_logger.error.call_count == 0
def test_duplicate_factors_raises_validation_error(self): r = FactorRange("foo", "bar", "foo") with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([r]) assert mock_logger.error.call_count == 1 r = FactorRange(factors=[("foo", "a"), ("foo", "b"), ("foo", "a")]) with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([r]) assert mock_logger.error.call_count == 1 r = FactorRange(factors=[("foo", "a", "1"), ("foo", "a", "2"), ("foo", "a", "1")]) with mock.patch('bokeh.core.validation.check.log') as mock_logger: check_integrity([r]) assert mock_logger.error.call_count == 1
def test_check_pass(mock_warn, mock_error): m = Mod() v.check_integrity([m]) assert not mock_error.called assert not mock_warn.called
def test_check_warn(mock_warn, mock_error): m = Mod(foo=-10) v.check_integrity([m]) assert not mock_error.called assert mock_warn.called