Ejemplo n.º 1
0
def _maybe_compose_deltas(old_delta: Delta,
                          new_delta: Delta) -> Optional[Delta]:
    """Combines new_delta onto old_delta if possible.

    If the combination takes place, the function returns a new Delta that
    should replace old_delta in the queue.

    If the new_delta is incompatible with old_delta, the function returns None.
    In this case, the new_delta should just be appended to the queue as normal.
    """
    old_delta_type = old_delta.WhichOneof("type")
    if old_delta_type == "add_block":
        # We never replace add_block deltas, because blocks can have
        # other dependent deltas later in the queue. For example:
        #
        #   placeholder = st.empty()
        #   placeholder.columns(1)
        #   placeholder.empty()
        #
        # The call to "placeholder.columns(1)" creates two blocks, a parent
        # container with delta_path (0, 0), and a column child with
        # delta_path (0, 0, 0). If the final "placeholder.empty()" Delta
        # is composed with the parent container Delta, the frontend will
        # throw an error when it tries to add that column child to what is
        # now just an element, and not a block.
        return None

    new_delta_type = new_delta.WhichOneof("type")
    if new_delta_type == "new_element":
        return new_delta

    if new_delta_type == "add_block":
        return new_delta

    return None
def _maybe_compose_deltas(old_delta: Delta,
                          new_delta: Delta) -> Optional[Delta]:
    """Combines new_delta onto old_delta if possible.

    If the combination takes place, the function returns a new Delta that
    should replace old_delta in the queue.

    If the new_delta is incompatible with old_delta, the function returns None.
    In this case, the new_delta should just be appended to the queue as normal.
    """
    old_delta_type = old_delta.WhichOneof("type")
    if old_delta_type == "add_block":
        # We never replace add_block deltas, because blocks can have
        # other dependent deltas later in the queue. For example:
        #
        #   placeholder = st.empty()
        #   placeholder.columns(1)
        #   placeholder.empty()
        #
        # The call to "placeholder.columns(1)" creates two blocks, a parent
        # container with delta_path (0, 0), and a column child with
        # delta_path (0, 0, 0). If the final "placeholder.empty()" Delta
        # is composed with the parent container Delta, the frontend will
        # throw an error when it tries to add that column child to what is
        # now just an element, and not a block.
        return None

    new_delta_type = new_delta.WhichOneof("type")
    if new_delta_type == "new_element":
        return new_delta

    if new_delta_type == "add_block":
        return new_delta

    if new_delta_type == "add_rows":
        import streamlit.elements.legacy_data_frame as data_frame

        # We should make data_frame.add_rows *not* mutate any of the
        # inputs. In the meantime, we have to deepcopy the input that will be
        # mutated.
        composed_delta = copy.deepcopy(old_delta)
        data_frame.add_rows(composed_delta,
                            new_delta,
                            name=new_delta.add_rows.name)
        return composed_delta

    # We deliberately don't handle the "arrow_add_rows" delta type. With Arrow,
    # `add_rows` is a frontend-only operation.

    return None
Ejemplo n.º 3
0
    def _enqueue_new_element_delta(self, marshall_element):
        """Fake enqueue new element delta.

        The real DeltaGenerator method actually enqueues the deltas but
        to test _with_element we just need this method to exist.  The
        real enqueue_new_element_delta will be tested later on.
        """
        delta = Delta()
        marshall_element(delta.new_element)
        return delta
Ejemplo n.º 4
0
def _get_data_frame(delta: Delta, name: Optional[str] = None) -> DataFrame:
    """Extract the dataframe protobuf from a delta protobuf."""
    delta_type = delta.WhichOneof("type")

    if delta_type == "new_element":
        element_type = delta.new_element.WhichOneof("type")

        # Some element types don't support named datasets.
        if name and element_type in ("data_frame", "table", "chart"):
            raise ValueError("Dataset names not supported for st.%s" %
                             element_type)

        if element_type in "data_frame":
            return delta.new_element.data_frame
        elif element_type in "table":
            return delta.new_element.table
        elif element_type == "chart":
            return delta.new_element.chart.data
        elif element_type == "vega_lite_chart":
            chart_proto = delta.new_element.vega_lite_chart
            if name:
                return _get_or_create_dataset(chart_proto.datasets, name)
            elif len(chart_proto.datasets) == 1:
                # Support the case where the dataset name was randomly given by
                # the charting library (e.g. Altair) and the user has no
                # knowledge of it.
                return chart_proto.datasets[0].data
            else:
                return chart_proto.data
        # TODO: Support DeckGL. Need to figure out how to handle layer indices
        # first.

    elif delta_type == "add_rows":
        if delta.add_rows.has_name and name != delta.add_rows.name:
            raise ValueError('No dataset found with name "%s".' % name)
        return delta.add_rows.data
    else:
        raise ValueError("Cannot extract DataFrame from %s." % delta_type)
Ejemplo n.º 5
0
 def _enqueue(self, delta_type, element_proto):
     delta = Delta()
     el_proto = getattr(delta.new_element, delta_type)
     el_proto.CopyFrom(element_proto)
     return delta
Ejemplo n.º 6
0
    def test_get_data_frame(self):
        """Test streamlit.data_frame_proto._get_data_frame."""
        # Test delta not new_element or add_rows
        with pytest.raises(ValueError) as e:
            delta = Delta()
            data_frame_proto._get_data_frame(delta)

        err_msg = "Cannot extract DataFrame from None."
        self.assertEqual(err_msg, str(e.value))

        # Generic Data
        aa = AnyArray()
        aa.int64s.data.extend([1, 2, 3])

        # Delta DataFrame
        delta_df = Delta()
        delta_df.new_element.data_frame.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_df)
        self.assertEqual(df, delta_df.new_element.data_frame)

        # Delta Table
        delta_table = Delta()
        delta_table.new_element.table.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_table)
        self.assertEqual(df, delta_table.new_element.table)

        # Vega-Lite Chart
        delta_vega = Delta()
        delta_vega.new_element.vega_lite_chart.data.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_vega)
        self.assertEqual(df, delta_vega.new_element.vega_lite_chart.data)

        # Vega-Lite Chart w/ named dataset
        delta_vega_dataset = Delta()

        ds1 = NamedDataSet()
        ds1.name = "dataset 1"
        ds1.has_name = True
        ds1.data.data.cols.extend([aa])

        delta_vega_dataset.new_element.vega_lite_chart.datasets.extend([ds1])

        df = data_frame_proto._get_data_frame(delta_vega_dataset, "dataset 1")
        self.assertEqual(
            df, delta_vega_dataset.new_element.vega_lite_chart.datasets[0].data
        )

        # Vega-Lite Chart w/ unnamed dataset
        delta_vega_unnamed_dataset = Delta()

        ds2 = NamedDataSet()
        ds2.has_name = False
        ds2.data.data.cols.extend([aa])

        delta_vega_unnamed_dataset.new_element.vega_lite_chart.datasets.extend([ds2])

        df = data_frame_proto._get_data_frame(delta_vega_unnamed_dataset)
        self.assertEqual(
            df, delta_vega_unnamed_dataset.new_element.vega_lite_chart.datasets[0].data
        )

        # add_rows w/ name
        delta_add_rows = Delta()
        delta_add_rows.add_rows.name = "named dataset"
        delta_add_rows.add_rows.has_name = True
        delta_add_rows.add_rows.data.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_add_rows, "named dataset")
        self.assertEqual(df, delta_add_rows.add_rows.data)

        # add_rows w/out name
        with pytest.raises(ValueError) as e:
            delta_add_rows_noname = Delta()
            delta_add_rows_noname.add_rows.name = "named dataset"
            delta_add_rows_noname.add_rows.has_name = True
            delta_add_rows_noname.add_rows.data.data.cols.extend([aa])
            df = data_frame_proto._get_data_frame(delta_add_rows_noname)

        err_msg = 'No dataset found with name "None".'
        self.assertEqual(err_msg, str(e.value))
Ejemplo n.º 7
0
    def test_add_rows(self):
        """Test streamlit.data_frame_proto._add_rows."""
        # Generic Data
        aa = AnyArray()
        aa.int64s.data.extend([1, 2])

        cell_style = CellStyle()
        cell_style.css.extend([_css_style("color", "black")])

        style = CellStyleArray()
        style.styles.extend([cell_style])

        # Delta DataFrame
        dt1 = Delta()
        dt1.new_element.data_frame.data.cols.extend([aa])
        dt1.new_element.data_frame.index.plain_index.data.int64s.data.extend([3, 4])
        dt1.new_element.data_frame.columns.plain_index.data.int64s.data.extend([5, 6])
        dt1.new_element.data_frame.style.cols.extend([style])

        dt2 = Delta()
        dt2.new_element.data_frame.data.cols.extend([aa])
        dt2.new_element.data_frame.index.plain_index.data.int64s.data.extend([3, 4])
        dt2.new_element.data_frame.columns.plain_index.data.int64s.data.extend([5, 6])
        dt2.new_element.data_frame.style.cols.extend([style])

        combined = Delta()
        aa_combined = AnyArray()
        aa_combined.int64s.data.extend([1, 2, 1, 2])

        style_combined = CellStyleArray()
        style_combined.styles.extend([cell_style, cell_style])

        combined.new_element.data_frame.data.cols.extend([aa_combined])
        row_index = combined.new_element.data_frame.index.plain_index
        row_index.data.int64s.data.extend([3, 4, 3, 4])
        col_index = combined.new_element.data_frame.columns.plain_index
        col_index.data.int64s.data.extend([5, 6])
        combined.new_element.data_frame.style.cols.extend([style_combined])

        # Test both not empty
        data_frame_proto.add_rows(dt1, dt2)
        self.assertEqual(dt1, combined)

        # Test one empty
        dt0 = Delta()
        dt0.new_element.data_frame.data.cols.extend([])

        data_frame_proto.add_rows(dt0, dt1)
        self.assertEqual(str(dt0), str(dt1))

        # Test both empty
        empty0 = Delta()
        empty0.new_element.data_frame.data.cols.extend([])

        empty1 = Delta()
        empty1.new_element.data_frame.data.cols.extend([])

        data_frame_proto.add_rows(empty0, empty1)
        self.assertEqual(str(empty0), str(empty1))

        # Test different data shapes
        diff0 = Delta()
        diff0.new_element.data_frame.data.cols.extend([aa, aa])

        diff1 = Delta()
        diff1.new_element.data_frame.data.cols.extend([aa])

        with pytest.raises(ValueError) as e:
            data_frame_proto.add_rows(diff0, diff1)

        err_msg = "Dataframes have incompatible shapes"
        self.assertEqual(err_msg, str(e.value))
Ejemplo n.º 8
0
    def test_get_data_frame(self):
        """Test streamlit.data_frame_proto._get_data_frame."""
        # Test delta not new_element or add_rows
        with pytest.raises(ValueError) as e:
            delta = Delta()
            data_frame_proto._get_data_frame(delta)

        err_msg = 'Cannot extract DataFrame from None.'
        self.assertEqual(err_msg, str(e.value))

        # Test delta = new_element, a name is used and type is chart, df, table
        with pytest.raises(ValueError) as e:
            delta = Delta()
            # TODO(armando): test df and table
            delta.new_element.chart.type = 'some chart'
            data_frame_proto._get_data_frame(delta, name='some name')

        err_msg = 'Dataset names not supported for st.chart'
        self.assertEqual(err_msg, str(e.value))

        # Generic Data
        aa = AnyArray()
        aa.int64s.data.extend([1, 2, 3])

        # Delta DataFrame
        delta_df = Delta()
        delta_df.new_element.data_frame.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_df)
        self.assertEqual(df, delta_df.new_element.data_frame)

        # Delta Table
        delta_table = Delta()
        delta_table.new_element.table.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_table)
        self.assertEqual(df, delta_table.new_element.table)

        # Delta Chart
        delta_chart = Delta()
        delta_chart.new_element.chart.data.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_chart)
        self.assertEqual(df, delta_chart.new_element.chart.data)

        # Vega-Lite Chart
        delta_vega = Delta()
        delta_vega.new_element.vega_lite_chart.data.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_vega)
        self.assertEqual(df, delta_vega.new_element.vega_lite_chart.data)

        # Vega-Lite Chart w/ named dataset
        delta_vega_dataset = Delta()

        ds1 = NamedDataSet()
        ds1.name = 'dataset 1'
        ds1.has_name = True
        ds1.data.data.cols.extend([aa])

        delta_vega_dataset.new_element.vega_lite_chart.datasets.extend([ds1])

        df = data_frame_proto._get_data_frame(delta_vega_dataset, 'dataset 1')
        self.assertEqual(
            df,
            delta_vega_dataset.new_element.vega_lite_chart.datasets[0].data)

        # Vega-Lite Chart w/ unnamed dataset
        delta_vega_unnamed_dataset = Delta()

        ds2 = NamedDataSet()
        ds2.has_name = False
        ds2.data.data.cols.extend([aa])

        delta_vega_unnamed_dataset.new_element.vega_lite_chart.datasets.extend(
            [ds2])

        df = data_frame_proto._get_data_frame(delta_vega_unnamed_dataset)
        self.assertEqual(
            df, delta_vega_unnamed_dataset.new_element.vega_lite_chart.
            datasets[0].data)

        # add_rows w/ name
        delta_add_rows = Delta()
        delta_add_rows.add_rows.name = 'named dataset'
        delta_add_rows.add_rows.has_name = True
        delta_add_rows.add_rows.data.data.cols.extend([aa])
        df = data_frame_proto._get_data_frame(delta_add_rows, 'named dataset')
        self.assertEqual(df, delta_add_rows.add_rows.data)

        # add_rows w/out name
        with pytest.raises(ValueError) as e:
            delta_add_rows_noname = Delta()
            delta_add_rows_noname.add_rows.name = 'named dataset'
            delta_add_rows_noname.add_rows.has_name = True
            delta_add_rows_noname.add_rows.data.data.cols.extend([aa])
            df = data_frame_proto._get_data_frame(delta_add_rows_noname)

        err_msg = 'No dataset found with name "None".'
        self.assertEqual(err_msg, str(e.value))