def test_make_grouping_by_position_mixed(mixed_grouping_size): grouping, size = mixed_grouping_size flat_values = make_flat_values(size) result = make_grouping_by_index(grouping, flat_values) # Check for size mutation on flat_values assert len(flat_values) == size # Check with stack-based algorithm as independent implementation groupings = [grouping] results = [result] while groupings: next_grouping = groupings.pop(0) next_result = results.pop(0) print("check {} with {}".format(next_result, next_grouping)) if isinstance(next_grouping, tuple): assert isinstance(next_result, tuple) assert len(next_grouping) == len(next_result) groupings.extend(next_grouping) results.extend(next_result) elif isinstance(next_grouping, dict): assert isinstance(next_result, dict) assert list(next_result) == list(next_grouping) groupings.extend(next_grouping.values()) results.extend(next_result.values()) else: assert isinstance(next_grouping, int) assert flat_values[next_grouping] == next_result
def make_grouping_attr_source(int_grouping): size = grouping_len(int_grouping) props = make_flat_values(size) vals = list(range(100, 100 + size)) letter_grouping = make_grouping_by_index(int_grouping, props) Source = namedtuple("Source", props) return letter_grouping, Source(*vals)
def wrapper(*args): # args are the flat list of positional arguments passed to function by # app.callback expected_num_args = max( [slc.stop for _, slc in input_groupings.values()]) if len(args) != expected_num_args: # Not an error condition a user should reach since we control args and # input groupings raise ValueError("Expected {} input value(s), received {}".format( expected_num_args, len(args))) fn_kwargs = {} for name, (grouping, slc) in input_groupings.items(): fn_kwargs[name] = make_grouping_by_index(grouping, list(args[slc])) if input_form == "list": # keys of fn_kwargs are integers and we need to build list of position # arguments for fn fn_args = [None for _ in fn_kwargs] for i, val in fn_kwargs.items(): fn_args[i] = val return fn(*fn_args) elif input_form == "scalar": return fn(fn_kwargs[0]) else: # "dict" return fn(**fn_kwargs)
def build_component_with_grouping(component_cls, int_grouping, size): component = component_cls() props = all_component_props(component)[5:5 + size] # set component property values for i, prop in enumerate(props): setattr(component, prop, i) # Build prop grouping prop_grouping = make_grouping_by_index(int_grouping, props) return component, prop_grouping, int_grouping
def test_map_grouping_mixed(mixed_grouping_size): grouping, size = mixed_grouping_size def fn(x): return x * 2 + 5 result = map_grouping(fn, grouping) expected = make_grouping_by_index( grouping, list(map(fn, flatten_grouping(grouping)))) assert expected == result
def test_make_grouping_by_position_dict(dict_grouping_size): grouping, size = dict_grouping_size flat_values = make_flat_values(size) result = make_grouping_by_index(grouping, flat_values) expected = {k: flat_values[i] for i, k in enumerate(grouping)} assert expected == result
def test_make_grouping_by_position_tuple(tuple_grouping_size): grouping, size = tuple_grouping_size flat_values = make_flat_values(size) result = make_grouping_by_index(grouping, flat_values) expected = tuple(flat_values) assert expected == result
def test_make_grouping_by_position_scalar(scalar_grouping_size): grouping, size = scalar_grouping_size flat_values = make_flat_values(size) result = make_grouping_by_index(grouping, flat_values) expected = flat_values[0] assert expected == result
def test_make_schema_mixed(mixed_grouping_size): grouping, size = mixed_grouping_size result = make_schema_with_nones(grouping) expected = make_grouping_by_index( grouping, [None for _ in range(grouping_len(grouping))]) assert expected == result
def _make_dependency_grouping(self, dependency): return make_grouping_by_index(self.component_property, self._make_flat_dependencies(dependency))
def make_numbers_grouping(grouping, offset=0): return make_grouping_by_index( grouping, list(range(offset, offset + grouping_len(grouping))))
def make_letters_grouping(grouping, upper=False): return make_grouping_by_index( grouping, make_letters(grouping_len(grouping), upper=upper))
def button_component_prop_for_grouping(grouping): props_grouping = make_grouping_by_index( grouping, button_props[:grouping_len(grouping)]) return html.Button(), props_grouping
def check_dependencies_as_groupings( app, input_grouping, state_grouping, output_grouping, template, input_form="list", output_form="list", ): # Compute grouping sizes input_size = grouping_len(input_grouping) state_size = grouping_len(state_grouping) output_size = grouping_len(output_grouping) # Build flat dependency lists # Note we add a scalar positional argument to input and output flat_input_deps = make_deps(Input, input_size + 1) flat_state_deps = make_deps(State, state_size) flat_output_deps = make_deps(Output, output_size + 1) # Build grouped dependency lists grouped_input_deps = [ make_grouping_by_index(input_grouping, flat_input_deps[:-1]), flat_input_deps[-1], ] grouped_state_deps = [ make_grouping_by_index(state_grouping, flat_state_deps), ] grouped_output_deps = [ flat_output_deps[0], make_grouping_by_index(output_grouping, flat_output_deps[1:]), ] # Build flat input/output values (state is part of input now) flat_input_values = (make_letters(input_size) + ["-"] + make_letters(state_size, upper=True)) flat_output_values = [-1] + list(range(5, output_size + 5)) # Build grouped input/output values (state is part of input) grouped_input_values = [ make_letters_grouping(input_grouping), "-", make_letters_grouping(state_grouping, upper=True), ] grouped_output_values = [ -1, make_numbers_grouping(output_grouping, offset=5) ] if input_form == "dict": only_input_keys = make_letters(len(grouped_input_deps), upper=True) grouped_input_deps = { k: v for k, v in zip(only_input_keys, grouped_input_deps) } state_keys = make_letters(len(grouped_state_deps), upper=False) grouped_state_deps = { k: v for k, v in zip(state_keys, grouped_state_deps) } input_value_keys = only_input_keys + state_keys grouped_input_values = { k: v for k, v in zip(input_value_keys, grouped_input_values) } if output_form == "scalar": # Remove first extra scalar value, leave only grouped value as scalar grouped_output_deps = grouped_output_deps[1] grouped_output_values = grouped_output_values[1] flat_output_values = flat_output_values[1:] flat_output_deps = flat_output_deps[1:] elif output_form == "dict": grouped_output_deps = { k: v for k, v in zip(make_letters(len(grouped_output_deps), upper=True), grouped_output_deps) } grouped_output_values = { k: v for k, v in zip( make_letters(len(grouped_output_deps), upper=True), grouped_output_values, ) } # Build mock function with grouped output as return values fn = mock_fn_with_return(grouped_output_values) # Wrap callback with grouped dependency specifications fn_wrapper = dl.callback( app, output=grouped_output_deps, inputs=grouped_input_deps, state=grouped_state_deps, template=template, )(fn) # call flat version (like dash.Dash.callback would) assert fn_wrapper._flat_fn(*flat_input_values) == flat_output_values # Check that mock function was called with expected grouped values args, kwargs = fn.call_args if input_form == "list": assert args == tuple(grouped_input_values) assert not kwargs elif input_form == "dict": assert kwargs == grouped_input_values assert not args # Check order of dependencies assert_deps_eq(fn_wrapper._flat_input_deps, flat_input_deps) assert_deps_eq(fn_wrapper._flat_state_deps, flat_state_deps) assert_deps_eq(fn_wrapper._flat_output_deps, flat_output_deps)