def test_group_date_prompt_upgrade_timestamp_to_date(): assert_result_equals( render( make_table(make_column("A", [datetime.datetime(2021, 5, 5)])), P( groups=dict( colnames=["A"], group_dates=True, date_granularities={"A": "Y"} ), aggregations=[dict(operation="size", colname="", outname="size")], ), ), ArrowRenderResult( make_table( make_column("A", [datetime.datetime(2021, 1, 1)]), make_column("size", [1], format="{:,d}"), ), [ RenderError( i18n_message("group_dates.granularity_deprecated.need_dates"), [ QuickFix( i18n_message( "group_dates.granularity_deprecated.quick_fix.convert_to_date" ), QuickFixAction.PrependStep( "converttimestamptodate", dict(colnames=["A"], unit="year"), ), ) ], ) ], ), )
def test_render_fetch_generated_error(): # fetch() generates errors when params are invalid _assert_render( twitter.FetchResult( Path("unused"), [twitter.RenderError(i18n_message("error.invalidUsername"))]), P(accumulate=False), None, [i18n_message("error.invalidUsername")], )
def test_warn_on_convert_to_str_including_column_header(self): table = pd.DataFrame({"A": [1, 2], "B": ["x", "y"], "C": [3, 4]}) result = render(table) assert_frame_equal( result[0], pd.DataFrame({ "A": ["B", "C"], "1": ["x", "3"], "2": ["y", "4"] }), ) self.assertEqual( result[1], [ { "message": i18n_message("warnings.headersConvertedToText.message", {"column_name": "A"}), "quickFixes": [{ "text": i18n_message( "warnings.headersConvertedToText.quickFix.text", {"column_name": '"A"'}, ), "action": "prependModule", "args": ["converttotext", { "colnames": ["A"] }], }], }, { "message": i18n_message( "warnings.differentColumnTypes.message", { "n_columns": 1, "first_colname": "C" }, ), "quickFixes": [{ "text": i18n_message( "warnings.differentColumnTypes.quickFix.text", {"n_columns": 1}, ), "action": "prependModule", "args": ["converttotext", { "colnames": ["C"] }], }], }, ], )
def test_integration_empty_params(): DefaultParams = { "title": "", "x_axis_label": "", "y_axis_label": "", "x_column": "", "y_columns": [], } table = pd.DataFrame({"A": [1, 2], "B": [2, 3]}) result = render( table, DefaultParams, input_columns={ "A": Column("A", "number", "{:,d}"), "B": Column("B", "number", "{:,.2f}"), }, ) assertResult( result, ( table, i18n_message("noXAxisError.message"), {"error": "Please correct the error in this step's data or parameters"}, ), )
def test_ignore_non_date_timestamps(): # Steps for the user to get here: # 1. Make a date column, 'A' # 2. Check "Group Dates". The column appears. # 3. Select column 'A', and select a date granularity for it # 4. Alter the input DataFrame such that 'A' is no longer datetime # # Expected results: you can't group it by date any more. assert_result_equals( render( make_table( make_column("A", [1]), # "used to be a datetime" make_column( "B", [datetime.datetime(2019, 1, 4)] ), # so we don't need quickfix ), P( groups=dict( colnames=["A"], group_dates=True, date_granularities={"A": "T"} ), aggregations=[dict(operation="size", colname="", outname="size")], ), ), ArrowRenderResult( make_table(make_column("A", [1]), make_column("size", [1], format="{:,d}")), [RenderError(i18n_message("group_dates.select_date_columns"))], ), )
def test_excel_error_out_of_range_columns(): _test( pd.DataFrame({"A": [1, 2]}), P(formula_excel="=SUM(A1:B1)", all_rows=True), expected_error=i18n_message("excel.all_rows.badColumnRef", {"ref": "A1:B1"}), )
def test_group_date_prompt_all_is_well_when_date_column_present(): assert_result_equals( render( make_table( make_column("A", [datetime.date(2021, 5, 10)], unit="week"), make_column("B", [1]), ), P( groups=dict( colnames=["A", "B"], group_dates=True, date_granularities={} ), aggregations=[dict(operation="size", colname="", outname="size")], ), ), ArrowRenderResult( make_table( make_column("A", [datetime.date(2021, 5, 10)], unit="week"), make_column("B", [1]), make_column("size", [1], format="{:,d}"), ), [ RenderError( i18n_message( "group_dates.date_selected", dict(columns=1, column0="A", unit0="week"), ) ) ], ), )
def test_render_v2_generic_api_error(): with _temp_tarfile([ lambda: _temp_json_lz4( "API-ERROR.lz4", { "title": "bad-request", "errors": [{ "message": "a message from Twitter" }], }, { "cjw:apiEndpoint": "2/tweets/search/recent", "cjw:apiParams": "expansions=author_id%2Cin_reply_to_user_id%2Creferenced_tweets.id.author_id&max_results=100&query=science&tweet.fields=id%2Ctext%2Cauthor_id%2Ccreated_at%2Cin_reply_to_user_id%2Cpublic_metrics%2Csource%2Clang%2Creferenced_tweets&user.fields=id%2Cdescription%2Cusername%2Cname", "cjw:httpStatus": "400", }, ) ]) as tar_path: _assert_render( twitter.FetchResult(tar_path, []), P(accumulate=False), None, [ i18n_message( "error.genericApiErrorV2", { "title": "bad-request", "message": "a message from Twitter" }, ) ], )
def test_render_v1_1_generic_api_error(): with _temp_tarfile([ lambda: _temp_json_lz4( "API-ERROR.lz4", {"error": "a message from Twitter"}, { "cjw:apiEndpoint": "1.1/statuses/user_timeline", "cjw:apiParams": "count=200&screen_name=adamhooper", "cjw:httpStatus": "500", }, ) ]) as tar_path: _assert_render( twitter.FetchResult(tar_path, []), P(accumulate=False), None, [ i18n_message( "error.genericApiErrorV1_1", { "httpStatus": "500", "error": "a message from Twitter" }, ) ], )
def test_excel_error_row_0(): _test( pd.DataFrame({"A": [1, 2]}), P(formula_excel="=A0*2", all_rows=False), expected_error=i18n_message("excel.one_row.invalidCellRange", {"token": "A0"}), )
def test_long_to_wide_error_not_enough_columns(self): in_table = pd.DataFrame({"x": [1, 2], "variable": ["y", "y"]}) result = render(in_table, P("longtowide", ["x"], ltw_varcolname="variable"), **DefaultKwargs) self.assertEqual(result, i18n_message("long_to_wide.error.noValueColumn"))
def test_not_text_is_error(self): result = render(pd.DataFrame({'A': [1, 2]}), { 'column': 'A', 'valueselect': ['1'], 'drop': True }, input_columns={'A': Column('A', 'number')}) self.assertEqual(result, i18n_message("badParam.column.notText"))
def test_group_date_prompt_convert_text_to_date(): assert_result_equals( render( make_table( make_column("A", ["2021-05-05"]), make_column("B", ["2021-05-05"]), ), P( groups=dict( colnames=["A", "B"], group_dates=True, date_granularities={} ), aggregations=[dict(operation="size", colname="", outname="size")], ), ), ArrowRenderResult( make_table( make_column("A", ["2021-05-05"]), make_column("B", ["2021-05-05"]), make_column("size", [1], format="{:,d}"), ), [ RenderError( i18n_message( "group_dates.text_selected", dict(columns=2, column0="A") ), [ QuickFix( i18n_message("group_dates.quick_fix.convert_text_to_date"), QuickFixAction.PrependStep( "converttexttodate", dict(colnames=["A", "B"]) ), ), QuickFix( i18n_message( "group_dates.quick_fix.convert_text_to_timestamp" ), QuickFixAction.PrependStep( "convert-date", dict(colnames=["A", "B"]) ), ), ], ) ], ), )
def test_long_to_wide_varcol_in_key(self): in_table = pd.DataFrame({ "x": ["1", "2"], "variable": ["A", "B"], "value": ["a", "b"] }) out = render(in_table, P("longtowide", ["x"], ltw_varcolname="x"), **DefaultKwargs) self.assertEqual(out, i18n_message("error.sameColumnAndRowVariables"))
def test_render_duplicate_column_name(): df = DataFrame({"A": [1, 2, 3]}) result = render(df, {"sql": "SELECT A, A FROM input"}) assert result == ( None, [ i18n_message("badValue.sql.duplicateColumnName", {"colname": "A"}), ], )
def test_excel_error_missing_row_number_in_range(): _test( pd.DataFrame({ "A": [1, 2], "B": [2, 3] }), P(formula_excel="=SUM(A:B)", all_rows=True), expected_error=i18n_message("excel.formulaFirstRowReference"), )
def test_render_range_clamp_range(self): table = pd.DataFrame({"A": [1, 2], "B": [2, 3], "C": [3, 4]}) result = render(table, P(select_range=True, column_numbers="-1,2,6")) self.assertEqual( result, i18n_message( "badParam.column_numbers.invalid", {"value": "-1"}, ))
def test_render_range_ignore_empty_range(self): table = pd.DataFrame({"A": [1, 2], "B": [2, 3], "C": [3, 4]}) result = render(table.copy(), P(select_range=True, column_numbers="")) self.assertEqual( result, i18n_message( "badParam.column_numbers.invalid", {"value": ""}, ), )
def test_long_to_wide_duplicate_key(self): in_table = pd.DataFrame({ "x": [1, 1], "variable": ["A", "A"], "value": ["x", "y"] }) out = render(in_table, P("longtowide", ["x"], ltw_varcolname="variable"), **DefaultKwargs) self.assertEqual(out, i18n_message("long_to_wide.error.repeatedVariables"))
def test_render_hint_invalid_table_name(): df = DataFrame({"foo": [1, 2, 3]}) result = render(df, {"sql": "SELECT * FROM input2"}) assert result == ( None, [ i18n_message("badValue.sql.invalidTableName", {"table_name": "input"}) ], )
def test_excel_error_syntax(): _test( pd.DataFrame({"A": [1, 2]}), P(formula_excel="=SUM B>", all_rows=False), expected_error=i18n_message( # The "%s" is built in to the formulas module. TODO file bugrep "excel.invalidFormula", {"error": "Not a valid formula:\n%s"}, ), )
def test_params_duplicate_columns(self): params = P( [ {"colname": "A", "is_ascending": False}, {"colname": "A", "is_ascending": False}, ] ) result = render(pd.DataFrame(), params) self.assertEqual(result, i18n_message("badParam.sort_columns.duplicate"))
def test_wide_to_long_mixed_value_types(self): in_table = pd.DataFrame({ "X": ["x", "y"], "A": [1, 2], "B": ["y", np.nan] }) result = render(in_table, P("widetolong", ["X"]), **DefaultKwargs) assert_frame_equal( result[0], pd.DataFrame({ "X": ["x", "x", "y", "y"], "variable": ["A", "B", "A", "B"], "value": ["1", "y", "2", np.nan], }), ) self.assertEqual( result[1], { "message": i18n_message( "wide_to_long.badColumns.mixedTypes.message", { "n_columns": 1, "first_colname": "A" }, ), "quickFixes": [{ "text": i18n_message( "wide_to_long.badColumns.mixedTypes.quick_fix.text", {"n_columns": 1}, ), "action": "prependModule", "args": ["converttotext", { "colnames": ["A"] }], }], }, ) self.assertIsInstance( result[1]["quickFixes"][0]["args"][1]["colnames"], list)
def test_render_range_non_numeric_ranges(self): table = pd.DataFrame({"A": [1, 2], "B": [2, 3], "C": [3, 4]}) result = render(table, P(select_range=True, column_numbers="2-3,giraffe")) self.assertEqual( result, i18n_message( "badParam.column_numbers.invalid", {"value": "giraffe"}, ), )
def test_excel_function_not_implemented(): _test( pd.DataFrame({"A": [1, 2, 3]}), { "formula_excel": "=DATEX(2019, 6, A1)", "all_rows": False, "out_column": "X", }, expected_error=i18n_message("excel.functionNotImplemented", {"name": "DATEX"}), )
def test_long_to_wide_error_too_many_columns(self): in_table = pd.DataFrame({ "x": [1, 2], "variable": ["y", "y"], "value": ["a", "b"], "other": ["", ""], }) result = render(in_table, P("longtowide", ["x"], ltw_varcolname="variable"), **DefaultKwargs) self.assertEqual( result, i18n_message("long_to_wide.error.tooManyValueColumns"))
def test_invalid_y_not_numeric(): form = build_form(y_columns=[YColumn("B", "#123456")]) table = pd.DataFrame({"A": [1, 2, 3], "B": ["a", "b", "c"]}) with pytest.raises(GentleValueError) as excinfo: form.make_chart( table, { "A": Column("A", "number", "{:}"), "B": Column("B", "text", None) }, ) assert excinfo.value.i18n_message == i18n_message( "axisNotNumericError.message", {"column_name": "B"})
def test_invalid_y_missing_values(): form = build_form( y_columns=[YColumn("B", "#123456"), YColumn("C", "#234567")]) table = pd.DataFrame({ "A": [1, 2, np.nan, np.nan, 5], "B": [4, np.nan, 6, 7, 8], "C": [np.nan, np.nan, 9, 10, np.nan], }) with pytest.raises(GentleValueError) as excinfo: form.make_chart(table, min_columns) assert excinfo.value.i18n_message == i18n_message("emptyAxisError.message", {"column_name": "C"})
def test_long_to_wide_convert_to_str(self): in_table = pd.DataFrame({ "x": [1, 1, 2, 2, 3, 3], "variable": [4, 5, 4, 5, 4, 5], "value": list("adbecf"), }) result = render(in_table, P("longtowide", ["x"], ltw_varcolname="variable"), **DefaultKwargs) assert_frame_equal( result[0], pd.DataFrame({ "x": [1, 2, 3], "4": ["a", "b", "c"], "5": ["d", "e", "f"] }), ) self.assertEqual( result[1], [{ "message": i18n_message( "long_to_wide.badColumn.notText.message", {"column_name": "variable"}, ), "quickFixes": [{ "text": i18n_message( "long_to_wide.badColumn.notText.quick_fix.text", {"column_name": "variable"}, ), "action": "prependModule", "args": ["converttotext", { "colnames": ["variable"] }], }], }], )
def test_wide_to_long_valcolname_conflict(self): out = render( pd.DataFrame({ "A": [1], "B": [2], "C": [3] }), P("widetolong", ["A"], wtl_varcolname="C", wtl_valcolname="A"), **DefaultKwargs) self.assertEqual( out, (None, [i18n_message("wide_to_long.badColumns.valcolname.conflict")]), )