示例#1
0
def test_get_svl_data_number_multi_row(test_conn):
    """ Tests that get_svl_data raises an SvlNumberValueError when the query
    returns multiple values.
    """
    svl_plot = {
        "type": "number",
        "data": "bigfoot",
        "value": {
            "field": "number"
        },
    }

    with pytest.raises(SvlNumberValueError):
        get_svl_data(svl_plot, test_conn)
示例#2
0
def test_get_svl_data_empty_result_set(test_conn):
    """ Tests that the get_svl_data function raises a sqlite3.DatabaseError
        when there's an empty result set returned.
    """
    svl_plot = {
        "type": "pie",
        "data": "bigfoot",
        "axis": {
            "field": "classification"
        },
        "filter": "classification = 'D'",
    }

    with pytest.raises(sqlite3.DatabaseError):
        get_svl_data(svl_plot, test_conn)
示例#3
0
def test_get_svl_data_xy_color_by(test_conn):
    """ Tests that the get_svl_data function returns the correct data for xy
        plots that have a color_by axis.
    """
    svl_plot = {
        "data": "bigfoot",
        "type": "bar",
        "x": {
            "field": "date",
            "temporal": "YEAR"
        },
        "y": {
            "agg": "COUNT"
        },
        "color_by": {
            "field": "temperature_mid",
            "agg": "AVG"
        },
    }
    answer = get_svl_data(svl_plot, test_conn)

    assert "x" in answer
    assert "y" in answer
    assert "color_by" in answer
    assert len(answer["x"]) == len(answer["y"])
    assert len(answer["x"]) == len(answer["color_by"])
示例#4
0
def test_get_svl_data_xy_split_by(test_conn):
    """ Tests that the get_svl_data function returns the correct value when
        there's a split by field for an xy plot.
    """
    svl_plot = {
        "data": "bigfoot",
        "type": "bar",
        "x": {
            "field": "date",
            "temporal": "YEAR"
        },
        "y": {
            "agg": "COUNT"
        },
        "split_by": {
            "field": "classification"
        },
    }

    answer = get_svl_data(svl_plot, test_conn)
    for split_by in ["Class A", "Class B"]:
        assert split_by in answer
        assert "x" in answer[split_by]
        assert "y" in answer[split_by]
        assert len(answer[split_by]["x"]) == len(answer[split_by]["y"])
示例#5
0
def test_get_svl_data_number(test_conn):
    """ Tests that the get_svl_data returns the correct data for number plots.
    """
    svl_plot = {
        "type": "number",
        "data": "bigfoot",
        "value": {
            "field": "number",
            "agg": "COUNT"
        },
        "filter": "Classification = 'A'",
    }

    answer = get_svl_data(svl_plot, test_conn)
    assert "value" in answer
示例#6
0
def test_get_svl_data_histogram(test_conn):
    """ Tests that the get_svl_data function returns the correct data for
        histogram plots.
    """
    svl_plot = {
        "type": "histogram",
        "data": "bigfoot",
        "x": {
            "field": "temperature_mid"
        },
        "bins": 25,
    }

    answer = get_svl_data(svl_plot, test_conn)
    assert "x" in answer
示例#7
0
def test_get_svl_data_pie(test_conn):
    """ Tests that the get_svl_data function returns the correct data for pie
        plots.
    """
    svl_plot = {
        "type": "pie",
        "data": "bigfoot",
        "axis": {
            "field": "classification"
        },
    }

    answer = get_svl_data(svl_plot, test_conn)
    assert "labels" in answer
    assert "values" in answer
    assert len(answer["labels"]) == len(answer["values"])
示例#8
0
def test_get_svl_data_histogram_split_by(test_conn):
    """ Tests that the get_svl_data function returns the correct data for
        histogram plots with a split-by axis.
    """
    svl_plot = {
        "type": "histogram",
        "data": "bigfoot",
        "y": {
            "field": "temperature_mid"
        },
        "split_by": {
            "field": "classification"
        },
    }

    answer = get_svl_data(svl_plot, test_conn)
    for split_by in ["Class A", "Class B"]:
        assert split_by in answer
        assert "y" in answer[split_by]
示例#9
0
def test_get_svl_data_xy(test_conn):
    """ Tests that the get_svl_data function returns the correct value for
        an xy plot.
    """
    svl_plot = {
        "data": "bigfoot",
        "type": "line",
        "x": {
            "field": "date",
            "temporal": "YEAR"
        },
        "y": {
            "agg": "COUNT"
        },
    }

    answer = get_svl_data(svl_plot, test_conn)

    assert "x" in answer
    assert "y" in answer
    assert len(answer["x"]) == len(answer["y"])
示例#10
0
def svl(svl_source,
        backend="plotly",
        datasets=[],
        offline_js=False,
        debug=False):
    """ Compiles the SVL source into a rendered plot template.

    Parameters
    -----------
    svl_source : str
        The SVL source code.
    backend : str
        Which plotting backend to render the plots with. Default: "plotly".
    datasets : list[str]
        A list of additional datasets to inject into the ast, for datasets not
        present in the SVL source code. Each dataset specifier must be of the
        form "dataset_name=dataset_location".
    offline_js : bool
        Whether to embed the javascript into the final HTML directly.
        Default: False.
    debug : bool
        If this flag is true, return the pretty-printed parse tree instead of
        the compiled program.

    Returns
    -------
    str
        The rendered HTML template for the plots.

    Raises
    ------
    ValueError
        If there is a malformed additional dataset specifier.
    SvlSyntaxError
        If there is a syntax error in the SVL source.
    SvlMissingFileError
        If there is a missing file in the SVL source or additional datasets.
    SvlMissingDatasetError
        If there is a dataset specified in a plot that isn't in the dataset
        specifiers for the SVL program.
    SvlPlotError
        If there is an error in any of the SVL plots.
    SvlDataLoadError
        If there is an error loading the data into sqlite.
    SvlDataProcessingError
        If there is an error processing the plot data.
    NotImplementedError
        If a backend is selected that hasn't been implemented.
    """
    if debug:
        return parse_svl(svl_source, debug=True).pretty()

    for dataset in datasets:
        if len(dataset.split("=")) != 2:
            raise ValueError(
                "dataset {} needs to be name=path".format(dataset))

    additional_datasets = _extract_additional_datasets(datasets)

    try:
        svl_ast = parse_svl(svl_source, **additional_datasets)
    except SvlSyntaxError as e:
        raise e

    # Validate that all of the files exist that need to exist.
    for _, dataset in svl_ast["datasets"].items():
        if ("file" in dataset) and (not os.path.exists(dataset["file"])):
            raise SvlMissingFileError("File {} does not exist.".format(
                dataset["file"]))

    # Flatten the AST plot representation into a list with grid coordinates.
    svl_plots = tree_to_grid(svl_ast)

    # Validate the plots.
    for plot in svl_plots:
        # Each plot must point to a dataset that exists.
        if plot["data"] not in svl_ast["datasets"]:
            existing_dataset = ", ".join(list(svl_ast["datasets"].keys()))
            raise SvlMissingDatasetError(
                "Dataset {} is not in provided datasets {}.".format(
                    plot["data"], existing_dataset))
        # Each plot must be a valid specification.
        ok, msg = validate_plot(plot)
        if not ok:
            raise SvlPlotError("Plot error: {}".format(msg))

    # Set up the connection to sqlite. Eventually this will be abstracted since
    # in principle we could have other data sources but for now sqlite is what
    # we've got.
    try:
        sqlite_conn = create_datasets(svl_ast["datasets"])
    except sqlite3.DatabaseError as e:
        raise SvlDataLoadError("Error loading data: {}.".format(e))

    # Get the data for the plots.
    try:
        svl_plot_data = [get_svl_data(plot, sqlite_conn) for plot in svl_plots]
    except sqlite3.DatabaseError as e:
        raise SvlDataProcessingError(
            "Error processing plot data: {}".format(e))

    # Select and render the template.
    if backend == "plotly":
        template_vars = plotly_template_vars(svl_plots, svl_plot_data)
        template = plotly_template()

        # If offline is selected, use the offline plotly in the template.
        template_vars["plotly_offline"] = offline_js
    else:
        raise NotImplementedError(
            "Unable to use {} as a backend.".format(backend))

    return template.render(**template_vars)