Пример #1
0
class Card(Column):

    active_header_background = Nullable(
        String, help="Background color of active Card header.")

    button_css_classes = List(
        String, help="CSS classes to add to the Card collapse button.")

    collapsed = Bool(True, help="Whether the Card is collapsed.")

    collapsible = Bool(
        True, help="Whether the Card should have a button to collapse it.")

    header_background = Nullable(String,
                                 help="Background color of the Card header.")

    header_color = Nullable(String,
                            help="Color of the header text and button.")

    header_css_classes = List(String,
                              help="CSS classes to add to the Card header.")

    header_tag = String('div', help="HTML tag to use for the Card header.")

    hide_header = Bool(False, help="Whether to hide the Card header")

    tag = String('tag', help="CSS class to use for the Card as a whole.")
Пример #2
0
Файл: vtk.py Проект: xtaje/panel
class VTKPlot(HTMLBox):
    """
    A Bokeh model that wraps around a vtk-js library and renders it inside
    a Bokeh plot.
    """

    __javascript__ = [vtk_cdn]

    __js_require__ = {"paths": {"vtk": vtk_cdn[:-3]},
                      "shim": {"vtk": {"exports": "vtk"}}}

    __implementation__ = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'vtk.ts')

    append = Bool(default=False)

    data = String(help="""The serialized vtk.js data""")

    camera = Dict(String, Any)

    enable_keybindings = Bool(default=False)

    orientation_widget = Bool(default=False)

    renderer_el = Any(readonly=True)

    height = Override(default=300)

    width = Override(default=300)
Пример #3
0
class IonRangeSlider(InputWidget):
    # The special class attribute ``__implementation__`` should contain a string
    # of JavaScript, TypeScript or CoffeeScript code that implements the web broser
    # side of the custom extension model or a string name of a file with the implementation.

    __implementation__ = 'extensions_ion_range_slider.ts'
    __javascript__ = ["https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js",
                      "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/js/ion.rangeSlider.js"]
    __css__ = ["https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.css",
               "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.css",
               "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.skinFlat.min.css",
               "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/img/sprite-skin-flat.png"]

    # Below are all the "properties" for this model. Bokeh properties are
    # class attributes that define the fields (and their types) that can be
    # communicated automatically between Python and the browser. Properties
    # also support type validation. More information about properties in
    # can be found here:
    #
    #    https://bokeh.pydata.org/en/latest/docs/reference/core.html#bokeh-core-properties

    disable = Bool(default=True, help="""
    Enable or disable the slider.
    """)

    grid = Bool(default=True, help="""
    Show or hide the grid beneath the slider.
    """)

    start = Float(default=0, help="""
    The minimum allowable value.
    """)

    end = Float(default=1, help="""
    The maximum allowable value.
    """)

    range = Tuple(Float, Float, help="""
    The start and end values for the range.
    """)

    step = Float(default=0.1, help="""
    The step between consecutive values.
    """)

    callback = Instance(Callback, help="""
    A callback to run in the browser whenever the current Slider value changes.
    """)

    callback_throttle = Float(default=200, help="""
    Number of microseconds to pause between callback calls as the slider is moved.
    """)

    callback_policy = Enum(SliderCallbackPolicy, default="throttle", help="""
    When the callback is initiated. This parameter can take on only one of three options:
       "continuous": the callback will be executed immediately for each movement of the slider
       "throttle": the callback will be executed at most every ``callback_throttle`` milliseconds.
       "mouseup": the callback will be executed only once when the slider is released.
       The `mouseup` policy is intended for scenarios in which the callback is expensive in time.
    """)
Пример #4
0
 def test_Bool(self) -> None:
     p = Bool()
     with pytest.raises(ValueError) as e:
         p.validate("junk")
     assert matches(
         str(e.value),
         r"expected a value of type bool or bool_, got junk of type str")
Пример #5
0
class JSONEditor(HTMLBox):
    """
    A bokeh model that allows editing JSON.
    """

    data = Any()

    menu = Bool(True)

    mode = Enum("tree",
                "view",
                "form",
                "code",
                "text",
                "preview",
                default='tree')

    search = Bool(True)

    selection = List(Any)

    schema = Nullable(Dict(String, Any), default=None)

    templates = List(Any)

    __javascript_raw__ = [
        'https://cdn.jsdelivr.net/npm/[email protected]/dist/jsoneditor.min.js'
    ]

    __css_raw__ = [
        'https://cdn.jsdelivr.net/npm/[email protected]/dist/jsoneditor.min.css'
    ]

    @classproperty
    def __javascript__(cls):
        return bundled_files(cls)

    @classproperty
    def __css__(cls):
        return bundled_files(cls, 'css')

    @classproperty
    def __js_skip__(cls):
        return {'JSONEditor': cls.__javascript__}

    __js_require__ = {
        'paths': {
            'jsoneditor':
            "//cdn.jsdelivr.net/npm/[email protected]/dist/jsoneditor.min"
        },
        'exports': {
            'jsoneditor': 'JSONEditor'
        },
        'shim': {
            'jsoneditor': {
                'exports': "JSONEditor"
            }
        }
    }
Пример #6
0
class IonRangeSlider(InputWidget):
    # The special class attribute ``__implementation__`` should contain a string
    # of JavaScript or TypeScript code that implements the web browser
    # side of the custom extension model or a string name of a file with the implementation.

    __implementation__ = 'extensions_ion_range_slider.ts'
    __javascript__ = [
        "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/js/ion.rangeSlider.js"
    ]
    __css__ = [
        "https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.css",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.css",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/css/ion.rangeSlider.skinFlat.min.css",
        "https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/img/sprite-skin-flat.png"
    ]

    # Below are all the "properties" for this model. Bokeh properties are
    # class attributes that define the fields (and their types) that can be
    # communicated automatically between Python and the browser. Properties
    # also support type validation. More information about properties in
    # can be found here:
    #
    #    https://docs.bokeh.org/en/latest/docs/reference/core/properties.html#bokeh-core-properties

    disable = Bool(default=True,
                   help="""
    Enable or disable the slider.
    """)

    grid = Bool(default=True,
                help="""
    Show or hide the grid beneath the slider.
    """)

    start = Float(default=0, help="""
    The minimum allowable value.
    """)

    end = Float(default=1, help="""
    The maximum allowable value.
    """)

    range = Tuple(Float,
                  Float,
                  help="""
    The start and end values for the range.
    """)

    step = Float(default=0.1,
                 help="""
    The step between consecutive values.
    """)

    callback = Instance(Callback,
                        help="""
    A callback to run in the browser whenever the current Slider value changes.
    """)
Пример #7
0
class DataTabulator(HTMLBox):
    """A Bokeh Model that enables easy use of Tabulator tables
    See http://tabulator.info/
    """

    configuration = Dict(String, Any)

    columns = List(Instance(TableColumn), help="""
    The list of child column widgets.
    """)

    download = Bool(default=False)

    editable = Bool(default=True)

    filename = String(default="table.csv")

    follow = Bool(True)

    frozen_rows = List(Int)

    groupby = List(String)

    hidden_columns = 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(Int, Dict(Int, List(String)))

    pagination = Nullable(String)

    page = Nullable(Int)

    page_size = Int()

    max_page = Int()

    sorters = List(Dict(String, String))

    theme = Enum(*TABULATOR_THEMES, default="simple")

    theme_url = String(default=THEME_URL)

    __css__ = [THEME_URL+'tabulator_simple.min.css']

    __javascript__ = [
        JS_SRC,
        MOMENT_SRC
    ]

    __js_require__ = {
        'paths': {
            'tabulator': JS_SRC[:-3]
        },
        'exports': {'tabulator': 'Tabulator'}
    }
Пример #8
0
class Knob(HTMLBox):
    title = String(default="")
    value = Float(default=0)
    writable = Bool(default=False)
    scrollable = Bool(default=False)
    digits = Int(default=3)
    decimals = Int(default=3)
    max = Float()
    min = Float()
    wrap = Bool(default=False)
    unit = String()
    active = Bool(default=True)
Пример #9
0
class AcePlot(HTMLBox):
    """
    A Bokeh model that wraps around a Ace editor and renders it inside
    a Bokeh plot.
    """

    __javascript__ = [
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ace.js',
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-language_tools.js',
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-modelist.min.js'
    ]

    __js_skip__ = {'ace': __javascript__}

    __js_require__ = {
        'paths': {
            ('ace', ('ace/ace', 'ace/ext-language_tools')):
            '//cdnjs.cloudflare.com/ajax/libs/ace/1.4.7'
        },
        'exports': {
            'ace': 'ace'
        },
        'shim': {
            'ace/ext-language_tools': {
                'deps': ["ace/ace"]
            },
            'ace/ext-modelist': {
                'deps': ["ace/ace"]
            }
        }
    }

    code = String()

    theme = Enum(ace_themes, default='chrome')

    filename = String()

    language = String()

    annotations = List(Dict(String, Any), default=[])

    readonly = Bool(default=False)

    print_margin = Bool(default=False)

    height = Override(default=300)

    width = Override(default=300)
Пример #10
0
class Video(HTMLBox):

    loop = Bool(False, help="""Whether the video should loop""")

    paused = Bool(False, help="""Whether the video is paused""")

    time = Float(0, help="""
        The current time stamp of the video playback""")

    throttle = Int(250, help="""
        The frequency at which the time value is updated in milliseconds.""")

    value = Any(help="Encoded file data")

    volume = Int(0, help="""The volume of the video player.""")
Пример #11
0
class VTKSynchronizedPlot(AbstractVTKPlot):
    """
    Bokeh model for plotting a VTK render window
    """

    arrays = Dict(String, Any)

    arrays_processed = List(String)

    enable_keybindings = Bool(default=False)

    one_time_reset = Bool(default=False)

    rebuild = Bool(default=False, help="""If true when scene change all the render is rebuilt from scratch""")

    scene = Dict(String, Any, help="""The serialized vtk.js scene on json format""")
Пример #12
0
class JsonEditor(InputWidget):
    # The special class attribute ``__implementation__`` should contain a string
    # of JavaScript (or CoffeeScript) code that implements the JavaScript side
    # of the custom extension model or a string name of a JavaScript (or
    # CoffeeScript) file with the implementation.

    __implementation__ = 'json_editor.ts'
    __javascript__ = ["straxui/static/jsoneditor.min.js"]
    __css__ = ["straxui/static/jsoneditor.min.css"]

    # Below are all the "properties" for this model. Bokeh properties are
    # class attributes that define the fields (and their types) that can be
    # communicated automatically between Python and the browser. Properties
    # also support type validation. More information about properties in
    # can be found here:
    #
    #    https://bokeh.pydata.org/en/latest/docs/reference/core.html#bokeh-core-properties

    disable = Bool(default=True,
                   help="""
    Enable or disable the editor.
    """)

    json = Any(default={},
               help="""
    The actual json string to edit.
    """)
Пример #13
0
class AwesompleteInput(TextInput):
    """ Single-line input widget with auto-completion. """

    __implementation__ = "awesomplete_input.coffee"
    __css__ = [
        "https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.1/awesomplete.css"
    ]
    __javascript__ = [
        "https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.1/awesomplete.js"
    ]

    completions = List(String,
                       help="""
    A list of completion strings. This will be used to guide the
    user upon typing a substring of a desired value.
    """)

    min_chars = Int(default=1,
                    help="""
    Minimum characteres the user has to type before the autocomplete
    popup shows up.
    """)

    max_items = Int(default=10,
                    help="""
    Maximum number of suggestions to display.
    """)

    auto_first = Bool(default=False,
                      help="""
    Whether the first element should be automatically selected
    """)
Пример #14
0
class DotBuilder(BarBuilder):
    """Produces Dot Glyphs for groups of data.

    Handles dot plot options to produce one to many dots,
    which are used to describe the values of aggregated groups of data.

    """

    line_alpha = Float(default=1.0)

    # ToDo: Support easier adding of one attr without reimplementation
    default_attributes = {
        'label': CatAttr(),
        'color': ColorAttr(),
        'line_color': ColorAttr(),
        'stack': CatAttr(),
        'group': CatAttr(),
        'marker': MarkerAttr(),
    }

    stem = Bool(False,
                help="""
    Whether to draw a stem from each do to the axis.
    """)

    glyph = DotGlyph
Пример #15
0
class AbstractVTKPlot(HTMLBox):
    """
    Abstract Bokeh model for vtk plots that wraps around a vtk-js library and
    renders it inside a Bokeh plot.
    """

    __javascript__ = [vtk_cdn]

    __js_skip__ = {'vtk': [vtk_cdn]}

    __js_require__ = {
        "paths": {
            "vtk": vtk_cdn[:-3]
        },
        "exports": {
            "vtk": None
        },
        "shim": {
            "vtk": {
                "exports": "vtk"
            }
        }
    }

    renderer_el = Any(readonly=True)

    orientation_widget = Bool(default=False)

    camera = Dict(String, Any)

    height = Override(default=300)

    width = Override(default=300)
Пример #16
0
class VegaPlot(LayoutDOM):
    """
    A Bokeh model that wraps around a Vega plot and renders it inside
    a Bokeh plot.
    """

    __javascript_raw__ = [
        "https://cdn.jsdelivr.net/npm/vega@5",
        'https://cdn.jsdelivr.net/npm/vega-lite@4',
        'https://cdn.jsdelivr.net/npm/vega-embed@6'
    ]

    @classproperty
    def __javascript__(cls):
        return bundled_files(cls)

    @classproperty
    def __js_skip__(cls):
        return {
            'vega': cls.__javascript__[:1],
            'vegaLite': cls.__javascript__[1:2],
            'vegaEmbed': cls.__javascript__[2:]
        }

    __js_require__ = {
        'paths': {
            "vega-embed":
            "https://cdn.jsdelivr.net/npm/vega-embed@6/build/vega-embed.min",
            "vega-lite":
            "https://cdn.jsdelivr.net/npm/vega-lite@4/build/vega-lite.min",
            "vega": "https://cdn.jsdelivr.net/npm/vega@5/build/vega.min"
        },
        'exports': {
            'vega-embed': 'vegaEmbed',
            'vega': 'vega',
            'vega-lite': 'vl'
        }
    }

    data = Nullable(Dict(String, Any))

    data_sources = Dict(String, Instance(ColumnDataSource))

    events = List(String)

    show_actions = Bool(False)

    theme = Nullable(
        Enum('excel',
             'ggplot2',
             'quartz',
             'vox',
             'fivethirtyeight',
             'dark',
             'latimes',
             'urbaninstitute',
             'googlecharts',
             default=None))

    throttle = Dict(String, Int)
Пример #17
0
class AcePlot(HTMLBox):
    """
    A Bokeh model that wraps around a Ace editor and renders it inside
    a Bokeh plot.
    """

    __javascript__ = ['https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.3/ace.js',
                      'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.3/ext-language_tools.js']

    __js_require__ = {'paths': {'ace': 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.3/ace',
                                'ace_lang_tools': 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.3/ext-language_tools'},
                      'exports': {'ace': 'ace'}}

    code = String()

    theme = String(default='chrome')

    language = String(default='python')

    annotations = List(Dict(String, Any), default=[])

    readonly = Bool(default=False)

    height = Override(default=300)

    width = Override(default=300)
class HorizontalBoxZoomTool(Drag):

    __implementation__ = "horizontalBoxZoomTool.ts"

    dimensions = Enum(Dimensions, default="both")
    overlay = Instance(BoxAnnotation, default=DEFAULT_BOX_OVERLAY)
    match_aspect = Bool(default=False)
Пример #19
0
class Player(Widget):
    """
    The Player widget provides controls to play through a number of frames.
    """

    start = Int(help="Lower bound of the Player slider")

    end = Int(help="Upper bound of the Player slider")

    value = Int(0, help="Current value of the player app")

    step = Int(1, help="Number of steps to advance the player by.")

    interval = Int(500, help="Interval between updates")

    direction = Int(0,
                    help="""
        Current play direction of the Player (-1: playing in reverse,
        0: paused, 1: playing)""")

    loop_policy = Enum('once', 'reflect', 'loop', default='once')

    show_loop_controls = Bool(True,
                              help="""Whether the loop controls
        radio buttons are shown""")

    width = Override(default=400)

    height = Override(default=250)
Пример #20
0
class FileDownload(InputWidget):

    auto = Bool(False, help="""Whether to download on click""")

    button_type = Enum(ButtonType,
                       help="""
    A style for the button, signifying it's role.
    """)

    clicks = Int(0,
                 help="""
    A private property that used to trigger ``on_click`` event handler.
    """)

    data = String(help="""Encoded URI data.""")

    label = String("", help="""The text label for the button to display.""")

    filename = String(help="""Filename to use on download""")

    _transfers = Int(0,
                     help="""
    A private property to create and click the link.
    """)

    title = Override(default='')
class FontAwesomeIcon(AbstractIcon):
    """ A "stock" icon based on FontAwesome. """

    __implementation__ = "fontawesome_icon.ts"
    __dependencies__ = {"font-awesome": "^4.6.3"}

    icon_name = Enum(NamedIcon,
                     default="check",
                     help="""
    What icon to use. See http://fortawesome.github.io/Font-Awesome/icons/
    for the list of available icons.
    """)

    size = Float(1,
                 help="""
    The size multiplier (1x, 2x, ..., 5x).
    """)

    flip = Enum("horizontal",
                "vertical",
                default=None,
                help="""
    Optionally flip the icon horizontally or vertically.
    """)

    spin = Bool(False,
                help="""
    Indicates a spinning (animated) icon. This value is ignored for
    icons that do not support spinning.
    """)
Пример #22
0
def test_Property_wrap() -> None:
    types = [
        Bool(),
        Int(),
        Float(),
        Complex(),
        String(),
        Enum("Some", "a", "b"),
        Color(),
        Regex("^$"),
        Seq(Any),
        Tuple(Any, Any),
        Instance(_TestModel),
        Any(),
        Interval(Float, 0, 1),
        Either(Int, String),
        DashPattern(),
        Size(),
        Percent(),
        Angle(),
        MinMaxBounds(),
    ]

    for x in types:
        for y in (0, 1, 2.3, "foo", None, (), [], {}):
            r = x.wrap(y)
            assert r == y
            assert isinstance(r, type(y))
Пример #23
0
class VideoStream(HTMLBox):

    format = Enum('png', 'jpeg', default='png')

    paused = Bool(False, help="""Whether the video is paused""")

    snapshot = Bool(False, help="""On change generate a snapshot of the current video frame""")

    timeout = Float(None, help="""
        The timeout between snapshots (if None snapshot only generated
        when snapshot property is changed""")

    value = Any(help="""Snapshot Data""")

    height = Override(default=240)

    width = Override(default=320)
Пример #24
0
class VTKJSPlot(AbstractVTKPlot):
    """
    Bokeh model for plotting a 3D scene saved in the `.vtk-js` format
    """

    data = String(help="""The serialized vtk.js data""")

    enable_keybindings = Bool(default=False)
Пример #25
0
class VTKVolumePlot(AbstractVTKPlot):
    """
    Bokeh model dedicated to plot a volumetric object with the help of vtk-js
    """

    ambient = Float(default=0.2)

    colormap = String(help="Colormap Name")

    controller_expanded = Bool(default=True,
                               help="""
        If True the volume controller panel options is expanded in the view""")

    data = Nullable(Dict(String, Any))

    diffuse = Float(default=0.7)

    display_slices = Bool(default=False)

    display_volume = Bool(default=True)

    edge_gradient = Float(default=0.2)

    interpolation = Enum(enumeration('fast_linear', 'linear', 'nearest'))

    mapper = Dict(String, Any)

    nan_opacity = Float(default=1)

    render_background = String(default='#52576e')

    rescale = Bool(default=False)

    sampling = Float(default=0.4)

    shadow = Bool(default=True)

    slice_i = Int(default=0)

    slice_j = Int(default=0)

    slice_k = Int(default=0)

    specular = Float(default=0.3)

    specular_power = Float(default=8.)
Пример #26
0
class AbstractVTKPlot(HTMLBox):
    """
    Abstract Bokeh model for vtk plots that wraps around a vtk-js library and
    renders it inside a Bokeh plot.
    """

    __javascript_raw__ = [vtk_cdn]

    @classproperty
    def __javascript__(cls):
        return bundled_files(AbstractVTKPlot)

    @classproperty
    def __js_skip__(cls):
        return {'vtk': cls.__javascript__}

    __js_require__ = {
        "paths": {
            "vtk": vtk_cdn[:-3]
        },
        "exports": {
            "vtk": None
        },
        "shim": {
            "vtk": {
                "exports": "vtk"
            },
        }
    }

    axes = Instance(VTKAxes)

    camera = Dict(String, Any)

    color_mappers = List(Instance(ColorMapper))

    height = Override(default=300)

    orientation_widget = Bool(default=False)

    interactive_orientation_widget = Bool(default=False)

    width = Override(default=300)

    annotations = List(Dict(String, Any))
Пример #27
0
class LatexLabelSet(LabelSet):
    __javascript__ = [katex_js]
    __css__ = [katex_css]
    __implementation__ = "latex_label_set.ts"

    display_mode = Bool(default=False,
                        help="""
        Whether to use display mode for the LaTeX labels.
        """)
Пример #28
0
class State(Model):

    json = Bool(False, help="Whether the values point to json files")

    state = Dict(Any, Any, help="Contains the recorded state")

    widgets = Dict(Any, Any)

    values = List(Any)
Пример #29
0
class JSON(Markup):
    """
    A bokeh model that renders JSON as tree.
    """

    depth = Either(Int, Float, default=1, help="Depth to which the JSON tree is expanded.")

    hover_preview = Bool(default=False, help="Whether to show a hover preview for collapsed nodes.")

    theme = String(default='dark', help="Whether to expand all JSON nodes.")
Пример #30
0
class BootstrapSelect(InputWidget):
    __javascript__ = [
        "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap-select.min.js",
        "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/i18n/defaults-pl_PL.min.js"
    ]
    __css__ = [
        "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap-select.min.css"
    ]
    alt_title = String(default="")
    options = List(Tuple(String, Tuple(Either(Int, String), String)))
    value = List(Tuple(Either(Int, String), String))
    actions_box = Bool(default=False)
    live_search = Bool(default=False)
    # show_subtext = Bool(default=False)
    select_all_at_start = Bool(default=False)
    count_selected_text = String(default='')
    none_selected_text = String(default='')
    selected_text_format = String(default='')
    none_results_text = String(default='')
Пример #31
0
 def test_Bool(self):
     p = Bool()
     with pytest.raises(ValueError) as e:
         p.validate("junk")
     assert not str(e).endswith("ValueError")
Пример #32
0
 def test_Bool(self, detail):
     p = Bool()
     with pytest.raises(ValueError) as e:
         p.validate("junk", detail)
     assert str(e).endswith("ValueError") == (not detail)