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
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)