def test_String(self): p = String() with pytest.raises(ValueError) as e: p.validate(10) assert matches(str(e.value), r"expected a value of type str, got 10 of type int")
def test_String(self): p = String() with pytest.raises(ValueError) as e: p.validate(10) assert not str(e).endswith("ValueError")
class Opts(Options): """ This is an Options class """ host = String(default="localhost", help="a host to connect to") port = Int(default=5890, help="a port to connect to")
class HP(HasProps): foo = Int(default=10) bar = String()
class Perspective(HTMLBox): aggregates = Either(Dict(String, Any), Null()) split_by = Either(List(String), Null()) columns = Either(List(Either(String, Null)), Null) expressions = Either(List(String), Null()) editable = Nullable(Bool()) filters = Either(List(Any), Null()) plugin = String() plugin_config = Either(Dict(String, Any), Null) group_by = Either(List(String), Null()) selectable = Nullable(Bool()) schema = Dict(String, String) sort = Either(List(List(String)), Null()) source = Instance(ColumnDataSource) toggle_config = Bool(True) theme = String() # pylint: disable=line-too-long __javascript__ = [ "https://unpkg.com/@finos/[email protected]/dist/umd/perspective.js", "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer.js", "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-datagrid.js", "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-d3fc.js", ] __js_skip__ = { "perspective": __javascript__, } __js_require__ = { "paths": { "perspective": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective", "perspective-viewer": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer", "perspective-viewer-datagrid": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-datagrid", "perspective-viewer-d3fc": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-d3fc", }, "exports": { "perspective": "perspective", "perspective-viewer": "PerspectiveViewer", "perspective-viewer-datagrid": "PerspectiveViewerDatagrid", "perspective-viewer-d3fc": "PerspectiveViewerD3fc", }, } __css__ = [ "https://unpkg.com/@finos/[email protected]/dist/css/themes.css" ]
class SomeModel(Model): a = Int(12) b = String("hello") c = List(Int, [1, 2, 3])
class DataTabulator(HTMLBox): """A Bokeh Model that enables easy use of Tabulator tables See http://tabulator.info/ """ aggregators = Dict(String, String) buttons = Dict(String, String) configuration = Dict(String, Any) columns = List(Instance(TableColumn), help=""" The list of child column widgets. """) download = Bool(default=False) children = Dict(Int, Instance(LayoutDOM)) editable = Bool(default=True) expanded = List(Int) filename = String(default="table.csv") filters = List(Any) follow = Bool(True) frozen_rows = List(Int) groupby = List(String) hidden_columns = List(String) indexes = List(String) layout = Enum('fit_data', 'fit_data_fill', 'fit_data_stretch', 'fit_data_table', 'fit_columns', default="fit_data") source = Instance(ColumnDataSource) styles = Dict( String, Either( String, Dict(Int, Dict(Int, List(Either(String, Tuple(String, String))))))) pagination = Nullable(String) page = Nullable(Int) page_size = Int() max_page = Int() sorters = List(Dict(String, String)) select_mode = Any() selectable_rows = Nullable(List(Int)) theme = Enum(*TABULATOR_THEMES, default="simple") theme_url = String(default=THEME_URL) __css_raw__ = CSS_URLS @classproperty def __css__(cls): cls.__css_raw__ = [ url for url in cls.__css_raw__ if 'simple' in url or len(cls.__css_raw__) == 1 ] return bundled_files(cls, 'css') __javascript_raw__ = [JS_SRC, MOMENT_SRC] @classproperty def __javascript__(cls): return bundled_files(cls) @classproperty def __js_skip__(cls): return { 'Tabulator': cls.__javascript__[:1], 'moment': cls.__javascript__[1:] } __js_require__ = { 'paths': { 'tabulator': JS_SRC[:-3], 'moment': MOMENT_SRC[:-3] }, 'exports': { 'tabulator': 'Tabulator', 'moment': 'moment' } }
class BoxGlyph(AggregateGlyph): """Summarizes the distribution with a collection of glyphs. A box glyph produces one "box" for a given array of vales. The box is made up of multiple other child composite glyphs (intervals, scatter) and directly produces glyph renderers for the whiskers, as well. """ q1 = Float(help="""Derived value for 25% of all values.""") q2 = Float(help="""Derived value for 50% of all values.""") q3 = Float(help="""Derived value for 75% of all values.""") iqr = Float() w0 = Float(help='Lower whisker') w1 = Float(help='Upper whisker') q2_glyph = Instance(QuartileGlyph) q3_glyph = Instance(QuartileGlyph) whisker_glyph = Instance(GlyphRenderer) outliers = Either(Bool, Instance(PointGlyph)) marker = String(default='circle') whisker_width = Float(default=0.3) whisker_line_width = Float(default=2) whisker_span_line_width = Float(default=2) whisker_color = String(default='black') outlier_fill_color = String(default='red') outlier_line_color = String(default='red') outlier_size = Float(default=5) bar_color = String(default='DimGrey') def __init__(self, label, values, outliers=True, **kwargs): width = kwargs.pop('width', None) bar_color = kwargs.pop('color', None) or kwargs.get( 'bar_color', None) or self.lookup('bar_color').class_default() kwargs['outliers'] = kwargs.pop('outliers', None) or outliers kwargs['label'] = label kwargs['values'] = values x_label = kwargs.get('x_label') kwargs['q2_glyph'] = QuartileGlyph(label=label, x_label=x_label, values=values, interval1=0.25, interval2=0.5, width=width, color=bar_color) kwargs['q3_glyph'] = QuartileGlyph(label=label, x_label=x_label, values=values, interval1=0.5, interval2=0.75, width=width, color=bar_color) super(BoxGlyph, self).__init__(**kwargs) self.setup() def build_renderers(self): """Yields all renderers that make up the BoxGlyph.""" self.calc_quartiles() outlier_values = self.values[((self.values < self.w0) | (self.values > self.w1))] self.whisker_glyph = GlyphRenderer( glyph=Segment(x0='x0s', y0='y0s', x1='x1s', y1='y1s', line_width=self.whisker_line_width, line_color=self.whisker_color)) if len(outlier_values) > 0 and self.outliers: self.outliers = PointGlyph(label=self.label, y=outlier_values, x=[self.get_dodge_label()] * len(outlier_values), line_color=self.outlier_line_color, fill_color=self.outlier_fill_color, size=self.outlier_size, marker=self.marker) for comp_glyph in self.composite_glyphs: for renderer in comp_glyph.renderers: yield renderer yield self.whisker_glyph def calc_quartiles(self): """Sets all derived stat properties of the BoxGlyph.""" self.q1 = self.q2_glyph.start self.q2 = self.q2_glyph.end self.q3 = self.q3_glyph.end self.iqr = self.q3 - self.q1 self.w0 = self.q1 - (1.5 * self.iqr) self.w1 = self.q3 + (1.5 * self.iqr) def build_source(self): """Calculate stats and builds and returns source for whiskers.""" self.calc_quartiles() x_label = self.get_dodge_label() x_w0_label = self.get_dodge_label(shift=(self.whisker_width / 2.0)) x_w1_label = self.get_dodge_label(shift=-(self.whisker_width / 2.0)) # span0, whisker bar0, span1, whisker bar1 x0s = [x_label, x_w0_label, x_label, x_w0_label] y0s = [self.w0, self.w0, self.q3, self.w1] x1s = [x_label, x_w1_label, x_label, x_w1_label] y1s = [self.q1, self.w0, self.w1, self.w1] return dict(x0s=x0s, y0s=y0s, x1s=x1s, y1s=y1s) def _set_sources(self): """Set the column data source on the whisker glyphs.""" self.whisker_glyph.data_source = self.source def get_extent(self, func, prop_name): return func([ getattr(renderer, prop_name) for renderer in self.composite_glyphs ]) @property def composite_glyphs(self): """Returns list of composite glyphs, excluding the regular glyph renderers.""" comp_glyphs = [self.q2_glyph, self.q3_glyph] if isinstance(self.outliers, PointGlyph): comp_glyphs.append(self.outliers) return comp_glyphs @property def x_max(self): return self.get_extent(max, 'x_max') + self.right_buffer @property def x_min(self): return self.get_extent(min, 'x_min') - self.left_buffer @property def y_max(self): return max(self.w1, self.get_extent(max, 'y_max')) + self.top_buffer @property def y_min(self): return min(self.w0, self.get_extent(min, 'y_min')) - self.bottom_buffer
class Perspective(HTMLBox): aggregates = Either(Dict(String, Any), Null()) column_pivots = Either(List(String), Null()) columns = Either(List(String), Null) computed_columns = Either(List(String), Null()) editable = Nullable(Bool()) filters = Either(List(Any), Null()) plugin = String() plugin_config = Either(Dict(String, Any), Null) row_pivots = Either(List(String), Null()) selectable = Nullable(Bool()) sort = Either(List(List(String)), Null()) source = Instance(ColumnDataSource) toggle_config = Bool(True) theme = String() # pylint: disable=line-too-long __javascript__ = [ "https://unpkg.com/@finos/[email protected]/dist/umd/perspective.js", "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer.js", "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-datagrid.js", "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-hypergrid.js", "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-d3fc.js", ] __js_skip__ = { "perspective": __javascript__, } __js_require__ = { "paths": { "perspective": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective", "perspective-viewer": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer", "perspective-viewer-datagrid": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-datagrid", "perspective-viewer-hypergrid": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-hypergrid", "perspective-viewer-d3fc": "https://unpkg.com/@finos/[email protected]/dist/umd/perspective-viewer-d3fc", }, "exports": { "perspective": "Perspective", "perspective-viewer": "PerspectiveViewer", "perspective-viewer-datagrid": "PerspectiveViewerDatagrid", "perspective-viewer-hypergrid": "PerspectiveViewerHypergrid", "perspective-viewer-d3fc": "PerspectiveViewerD3fc", }, } __css__ = [ "https://unpkg.com/@finos/[email protected]/dist/umd/all-themes.css" ]
class BinGlyph(XyGlyph): """Represents a group of data that was aggregated and is represented by a glyph. """ bins = Instance(Bins) column = String() stat = String() glyph_name = String() glyphs = {'rect': Rect} width = Float() height = Float() def __init__(self, x, y, values, column=None, stat='count', glyph='rect', width=1, height=1, **kwargs): df = pd.DataFrame(dict(x_vals=x, y_vals=y, values_vals=values)) df.drop_duplicates(inplace=True) kwargs['x'] = df.x_vals kwargs['y'] = df.y_vals kwargs['values'] = df.values_vals kwargs['column'] = column kwargs['stat'] = stat kwargs['glyph_name'] = glyph kwargs['height'] = height kwargs['width'] = width super(XyGlyph, self).__init__(**kwargs) self.setup() def build_source(self): return {'x': self.x, 'y': self.y, 'values': self.values} def build_renderers(self): glyph_class = self.glyphs[self.glyph_name] glyph = glyph_class(x='x', y='y', height=self.height, width=self.width, fill_color=self.fill_color, line_color=self.line_color, dilate=True) yield GlyphRenderer(glyph=glyph) @property def x_max(self): return self.get_data_range('x')[1] + self.width / 2.0 @property def x_min(self): return self.get_data_range('x')[0] - self.width / 2.0 @property def y_max(self): return self.get_data_range('y')[1] + self.height / 2.0 @property def y_min(self): return self.get_data_range('y')[0] - self.height / 2.0 def get_data_range(self, col): data = self.source.data[col] if ChartDataSource.is_number(data): return min(data), max(data) else: return 1, len(data.drop_duplicates())
class AggregateGlyph(NestedCompositeGlyph): """A base composite glyph for aggregating an array. Implements default stacking and dodging behavior that other composite glyphs can inherit. """ x_label = String() x_label_value = Any() stack_label = String() stack_shift = Float(default=0.0) dodge_label = String( help="""Where on the scale the glyph should be placed.""") dodge_shift = Float(default=None) agg = Instance(Stat, default=Sum()) span = Float(help="""The range of values represented by the aggregate.""") def __init__(self, x_label=None, **kwargs): if x_label is not None: kwargs['x_label_value'] = x_label if not isinstance(x_label, str): x_label = str(x_label) kwargs['x_label'] = x_label super(AggregateGlyph, self).__init__(**kwargs) def get_dodge_label(self, shift=0.0): """Generate the label defining an offset in relation to a position on a scale.""" if self.dodge_shift is None: shift_str = ':' + str(0.5 + shift) elif self.dodge_shift is not None: shift_str = ':' + str(self.dodge_shift + shift) else: shift_str = '' return str(label_from_index_dict(self.x_label)) + shift_str def filter_glyphs(self, glyphs): """Return only the glyphs that are of the same class.""" return [glyph for glyph in glyphs if isinstance(glyph, self.__class__)] @staticmethod def groupby(glyphs, prop): """Returns a dict of `CompositeGlyph`s, grouped by unique values of prop. For example, if all glyphs had a value of 'a' or 'b' for glyph.prop, the dict would contain two keys, 'a' and 'b', where each value is a list of the glyphs that had each of the values. """ grouped = defaultdict(list) labels = [getattr(glyph, prop) for glyph in glyphs] labels = [ tuple(label.values()) if isinstance(label, dict) else label for label in labels ] [grouped[label].append(glyph) for label, glyph in zip(labels, glyphs)] return grouped def __stack__(self, glyphs): """Apply relative shifts to the composite glyphs for stacking.""" if self.stack_label is not None: filtered_glyphs = self.filter_glyphs(glyphs) grouped = self.groupby(filtered_glyphs, 'x_label') for index, group in iteritems(grouped): # separate the negative and positive aggregates into separate groups neg_group = [glyph for glyph in group if glyph.span < 0] pos_group = [glyph for glyph in group if glyph.span >= 0] # apply stacking to each group separately for group in [neg_group, pos_group]: shift = [] for i, glyph in enumerate(group): # save off the top of each rect's height shift.append(glyph.span) if i > 0: glyph.stack_shift = sum(shift[0:i]) glyph.refresh() def __dodge__(self, glyphs): """Apply relative shifts to the composite glyphs for dodging.""" if self.dodge_label is not None: filtered_glyphs = self.filter_glyphs(glyphs) grouped = self.groupby(filtered_glyphs, 'dodge_label') # calculate transformations step = np.linspace(0, 1.0, len(grouped.keys()) + 1, endpoint=False) width = min(0.2, (1. / len(grouped.keys()))**1.1) # set bar attributes and re-aggregate for i, (index, group) in enumerate(iteritems(grouped)): for glyph in group: glyph.dodge_shift = step[i + 1] glyph.width = width glyph.refresh()
class DummyOpts(Options): foo = String(default="thing") bar = Nullable(Int())
class DupeProps(hp.HasProps): bar = AngleSpec() bar_units = String()
def test_String(self, detail): p = String() with pytest.raises(ValueError) as e: p.validate(10, detail) assert (str(e.value) == "") == (not detail)
class FooUnrelated(HasProps): x = Int(12) y = String("hello") z = List(Int, [1, 2, 3])
class IsDelegate(HasProps): x = Int(12) y = String("hello")
class Foo(HasProps): x = Int(12) y = String("hello") z = List(Int, [1, 2, 3]) zz = Dict(String, Int) s = Nullable(String(None))
class Base(HasProps): x = Int(12) y = String("hello")
class SomeModelToJson(Model): child = Instance(Model) foo = Int() bar = String()
class Foo(HasProps): x = Int(12) y = Enum("red", "blue", "green") z = String("blah")
class _TestModel2(HasProps): x = Int(12) y = String("hello") z = List(Int, [1, 2, 3]) zz = Dict(String, Int) s = String(None)
class NotSerialized(HasProps): x = Int(12, serialized=False) y = String("hello")
class EmbedTestUtilModel(Model): a = Int(12) b = String("hello") c = List(Int, [1, 2, 3])
class Readonly(HasProps): x = Int(12, readonly=True) # with default y = Nullable(Int(), readonly=True) # without default z = String("hello")
class ModelThatOverridesName(Model): name = String()
class IncludeDefaultsKwargsTest(HasProps): x = Int(12) y = String("hello")
def test_String(self, detail): p = String() with pytest.raises(ValueError) as e: p.validate(10, detail) assert str(e).endswith("ValueError") == (not detail)
class IncludeDefaultsSetToSameTest(HasProps): x = Int(12) y = String("hello")
class DownloadButton(Button): data = Instance(CustomJS) filename = String(default="data.bin") mime_type = String(default="application/octet-stream")
class SubOfThemedModel(ThemedModel): another_string = String("world")