Пример #1
0
    def test_clean_tab_wf_module_changed_raises_unneededexecution(self):
        """
        If a user changes tabs' output during render, raise UnneededExecution.

        It doesn't really matter _what_ the return value is, since the render()
        result will never be saved if this WfModule's delta has changed.
        UnneededExecution seems like the simplest contract to enforce.
        """
        # tab_output is what 'render' _thinks_ the output should be
        tab_output = ProcessResult(pd.DataFrame({'A': [1, 2]}))

        workflow = Workflow.create_and_init()
        tab = workflow.tabs.first()
        wfm = tab.wf_modules.create(
            order=0, last_relevant_delta_id=workflow.last_delta_id)
        wfm.cache_render_result(workflow.last_delta_id, tab_output)
        # Simulate reality: wfm.last_relevant_delta_id will change
        wfm.last_relevant_delta_id += 1
        wfm.save(update_fields=['last_relevant_delta_id'])

        context = RenderContext(
            workflow.id, None, None, {
                tab.slug: StepResultShape('ok', tab_output.table_shape),
            }, None)
        with self.assertRaises(UnneededExecution):
            clean_value(ParamDType.Tab(), tab.slug, context)
Пример #2
0
    def test_clean_multicolumn_from_other_tab(self):
        tab_output = ProcessResult(pd.DataFrame({'A-from-tab-2': [1, 2]}))
        workflow = Workflow.create_and_init()
        tab = workflow.tabs.first()
        wfm = tab.wf_modules.create(
            order=0, last_relevant_delta_id=workflow.last_delta_id)
        wfm.cache_render_result(workflow.last_delta_id, tab_output)

        schema = ParamDType.Dict({
            'tab':
            ParamDType.Tab(),
            'columns':
            ParamDType.Multicolumn(tab_parameter='tab'),
        })
        params = {'tab': tab.slug, 'columns': ['A-from-tab-1', 'A-from-tab-2']}
        context = RenderContext(
            workflow.id, None,
            TableShape(3, [
                Column('A-from-tab-1', ColumnType.NUMBER()),
            ]), {
                tab.slug: StepResultShape('ok', tab_output.table_shape),
            }, params)
        result = clean_value(schema, params, context)
        # result['tab'] is not what we're testing here
        self.assertEqual(result['columns'], ['A-from-tab-2'])
Пример #3
0
    def test_clean_tab_tab_delete_race_raises_unneededexecution(self):
        """
        If a user deletes the tab during render, raise UnneededExecution.

        It doesn't really matter _what_ the return value is, since the render()
        result will never be saved if this WfModule's delta has changed.
        UnneededExecution just seems like the quickest way out of this mess:
        it's an error the caller is meant to raise anyway, unlike
        `Tab.DoesNotExist`.
        """
        # tab_output is what 'render' _thinks_ the output should be
        tab_output = ProcessResult(pd.DataFrame({'A': [1, 2]}))

        workflow = Workflow.create_and_init()
        tab = workflow.tabs.first()
        wfm = tab.wf_modules.create(
            order=0, last_relevant_delta_id=workflow.last_delta_id)
        wfm.cache_render_result(workflow.last_delta_id, tab_output)
        tab.is_deleted = True
        tab.save(update_fields=['is_deleted'])
        # Simulate reality: wfm.last_relevant_delta_id will change
        wfm.last_relevant_delta_id += 1
        wfm.save(update_fields=['last_relevant_delta_id'])

        context = RenderContext(
            workflow.id, None, None, {
                tab.slug: StepResultShape('ok', tab_output.table_shape),
            }, None)
        with self.assertRaises(UnneededExecution):
            clean_value(ParamDType.Tab(), tab.slug, context)
Пример #4
0
    def test_clean_multicolumn_from_other_tab(self):
        tab_output = ProcessResult(pd.DataFrame({"A-from-tab-2": [1, 2]}))
        workflow = Workflow.create_and_init()
        tab = workflow.tabs.first()
        wfm = tab.wf_modules.create(
            order=0,
            slug="step-1",
            last_relevant_delta_id=workflow.last_delta_id)
        wfm.cache_render_result(workflow.last_delta_id, tab_output)

        schema = ParamDType.Dict({
            "tab":
            ParamDType.Tab(),
            "columns":
            ParamDType.Multicolumn(tab_parameter="tab"),
        })
        params = {"tab": tab.slug, "columns": ["A-from-tab-1", "A-from-tab-2"]}
        context = RenderContext(
            workflow.id,
            None,
            TableShape(3, [Column("A-from-tab-1", ColumnType.NUMBER())]),
            {tab.slug: StepResultShape("ok", tab_output.table_shape)},
            params,
        )
        result = clean_value(schema, params, context)
        # result['tab'] is not what we're testing here
        self.assertEqual(result["columns"], ["A-from-tab-2"])
Пример #5
0
    def test_clean_tab_missing_tab_selected_gives_none(self):
        """
        If the user has selected a nonexistent tab, pretend tab is blank.

        The JS side of things will see the nonexistent tab, but not render().
        """
        context = RenderContext(None, None, None, {}, None)
        result = clean_value(ParamDType.Tab(), 'tab-XXX', context)
        self.assertEqual(result, None)
Пример #6
0
    def test_clean_multicolumn_from_other_tab_that_does_not_exist(self):
        # The other tab would not exist if the user selected and then deleted
        # it.
        workflow = Workflow.create_and_init()
        workflow.tabs.first()

        schema = ParamDType.Dict({
            'tab': ParamDType.Tab(),
            'columns': ParamDType.Multicolumn(tab_parameter='tab'),
        })
        param_values = {'tab': 'tab-missing', 'columns': ['A-from-tab']}
        params = Params(schema, param_values, {})
        context = RenderContext(workflow.id, None, TableShape(3, [
            Column('A-from-tab-1', ColumnType.NUMBER()),
        ]), {}, params)
        result = clean_value(schema, param_values, context)
        # result['tab'] is not what we're testing here
        self.assertEqual(result['columns'], [])
Пример #7
0
    def test_clean_tab_happy_path(self):
        tab_output = ProcessResult(pd.DataFrame({'A': [1, 2]}))
        workflow = Workflow.create_and_init()
        tab = workflow.tabs.first()
        wfm = tab.wf_modules.create(
            order=0, last_relevant_delta_id=workflow.last_delta_id)
        wfm.cache_render_result(workflow.last_delta_id, tab_output)

        context = RenderContext(
            workflow.id, None, None, {
                tab.slug: StepResultShape('ok', tab_output.table_shape),
            }, None)
        result = clean_value(ParamDType.Tab(), tab.slug, context)
        self.assertEqual(result.slug, tab.slug)
        self.assertEqual(result.name, tab.name)
        self.assertEqual(result.columns, {
            'A': RenderColumn('A', 'number', '{:,}'),
        })
        assert_frame_equal(result.dataframe, pd.DataFrame({'A': [1, 2]}))
Пример #8
0
    def test_clean_multicolumn_from_other_tab_that_does_not_exist(self):
        # The other tab would not exist if the user selected and then deleted
        # it.
        workflow = Workflow.create_and_init()
        workflow.tabs.first()

        schema = ParamDType.Dict({
            "tab":
            ParamDType.Tab(),
            "columns":
            ParamDType.Multicolumn(tab_parameter="tab"),
        })
        params = {"tab": "tab-missing", "columns": ["A-from-tab"]}
        context = RenderContext(
            workflow.id,
            None,
            TableShape(3, [Column("A-from-tab-1", ColumnType.NUMBER())]),
            {},
            params,
        )
        result = clean_value(schema, params, context)
        # result['tab'] is not what we're testing here
        self.assertEqual(result["columns"], [])
Пример #9
0
 def test_clean_tab_tab_error_raises_cycle(self):
     shape = StepResultShape('error', TableShape(0, []))
     context = RenderContext(None, None, None, {'tab-1': shape}, None)
     with self.assertRaises(TabOutputUnreachableError):
         clean_value(ParamDType.Tab(), 'tab-1', context)
Пример #10
0
 def test_clean_tab_no_tab_output_raises_cycle(self):
     context = RenderContext(None, None, None, {'tab-1': None}, None)
     with self.assertRaises(TabCycleError):
         clean_value(ParamDType.Tab(), 'tab-1', context)
Пример #11
0
 def test_clean_tab_no_tab_selected_gives_none(self):
     context = RenderContext(None, None, None, {}, None)
     result = clean_value(ParamDType.Tab(), '', context)
     self.assertEqual(result, None)
Пример #12
0
 def test_clean_tab_unsupported(self):
     with self.assertRaisesRegex(RuntimeError, "Unsupported: fetch tab"):
         clean_value(ParamDType.Tab(), "", None)