From 3b730d977581905bff2c825dc6cc51473326b0c9 Mon Sep 17 00:00:00 2001 From: Gil Forsyth Date: Tue, 28 Nov 2023 13:35:13 -0500 Subject: [PATCH] refactor(tests): remove test rounding mixins --- ibis/backends/bigquery/tests/conftest.py | 4 +- ibis/backends/clickhouse/tests/conftest.py | 5 ++- ibis/backends/datafusion/tests/conftest.py | 4 +- ibis/backends/druid/tests/conftest.py | 5 ++- ibis/backends/duckdb/tests/conftest.py | 4 +- ibis/backends/flink/tests/conftest.py | 4 +- ibis/backends/impala/tests/conftest.py | 4 +- ibis/backends/mssql/tests/conftest.py | 5 ++- ibis/backends/mysql/tests/conftest.py | 5 ++- ibis/backends/oracle/tests/conftest.py | 5 ++- ibis/backends/pandas/tests/conftest.py | 5 ++- ibis/backends/polars/tests/conftest.py | 4 +- ibis/backends/postgres/tests/conftest.py | 5 ++- ibis/backends/pyspark/tests/conftest.py | 4 +- ibis/backends/snowflake/tests/conftest.py | 4 +- ibis/backends/sqlite/tests/conftest.py | 4 +- ibis/backends/tests/base.py | 45 +++++++++------------- ibis/backends/trino/tests/conftest.py | 4 +- 18 files changed, 59 insertions(+), 61 deletions(-) diff --git a/ibis/backends/bigquery/tests/conftest.py b/ibis/backends/bigquery/tests/conftest.py index d55785bb6def..e842a4f47024 100644 --- a/ibis/backends/bigquery/tests/conftest.py +++ b/ibis/backends/bigquery/tests/conftest.py @@ -15,7 +15,7 @@ from ibis.backends.bigquery import EXTERNAL_DATA_SCOPES, Backend from ibis.backends.bigquery.datatypes import BigQuerySchema from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest from ibis.backends.tests.data import json_types, non_null_array_types, struct_types, win DATASET_ID = "ibis_gbq_testing" @@ -25,7 +25,7 @@ PROJECT_ID_ENV_VAR = "GOOGLE_BIGQUERY_PROJECT_ID" -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): """Backend-specific class with information for testing.""" supports_divide_by_zero = True diff --git a/ibis/backends/clickhouse/tests/conftest.py b/ibis/backends/clickhouse/tests/conftest.py index 7b1d5e65307f..618f97a3b633 100644 --- a/ibis/backends/clickhouse/tests/conftest.py +++ b/ibis/backends/clickhouse/tests/conftest.py @@ -9,7 +9,7 @@ import ibis import ibis.expr.types as ir from ibis import util -from ibis.backends.tests.base import RoundHalfToEven, ServiceBackendTest +from ibis.backends.tests.base import ServiceBackendTest if TYPE_CHECKING: from collections.abc import Iterable @@ -22,7 +22,7 @@ IBIS_TEST_CLICKHOUSE_DB = os.environ.get("IBIS_TEST_DATA_DB", "ibis_testing") -class TestConf(ServiceBackendTest, RoundHalfToEven): +class TestConf(ServiceBackendTest): check_dtype = False supports_window_operations = False returned_timestamp_unit = "s" @@ -30,6 +30,7 @@ class TestConf(ServiceBackendTest, RoundHalfToEven): supports_floating_modulus = False supports_json = False force_sort_before_comparison = True + rounding_method = "half_to_even" data_volume = "/var/lib/clickhouse/user_files/ibis" service_name = "clickhouse" deps = ("clickhouse_connect",) diff --git a/ibis/backends/datafusion/tests/conftest.py b/ibis/backends/datafusion/tests/conftest.py index 1e20f4238471..49adf83e6fb8 100644 --- a/ibis/backends/datafusion/tests/conftest.py +++ b/ibis/backends/datafusion/tests/conftest.py @@ -6,11 +6,11 @@ import ibis from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest from ibis.backends.tests.data import array_types, win -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): # check_names = False # supports_divide_by_zero = True # returned_timestamp_unit = 'ns' diff --git a/ibis/backends/druid/tests/conftest.py b/ibis/backends/druid/tests/conftest.py index 88704efd5141..b95227a9aa61 100644 --- a/ibis/backends/druid/tests/conftest.py +++ b/ibis/backends/druid/tests/conftest.py @@ -12,7 +12,7 @@ from requests import Session import ibis -from ibis.backends.tests.base import RoundHalfToEven, ServiceBackendTest +from ibis.backends.tests.base import ServiceBackendTest if TYPE_CHECKING: from collections.abc import Iterable @@ -89,7 +89,7 @@ def run_query(session: Session, query: str) -> None: time.sleep(REQUEST_INTERVAL) -class TestConf(ServiceBackendTest, RoundHalfToEven): +class TestConf(ServiceBackendTest): # druid has the same rounding behavior as postgres check_dtype = False supports_window_operations = False @@ -99,6 +99,7 @@ class TestConf(ServiceBackendTest, RoundHalfToEven): native_bool = True supports_structs = False supports_json = False # it does, but we haven't implemented it + rounding_method = "half_to_even" service_name = "druid-middlemanager" deps = ("pydruid.db.sqlalchemy",) diff --git a/ibis/backends/duckdb/tests/conftest.py b/ibis/backends/duckdb/tests/conftest.py index 8ef6c9f6132c..bc62b94fe034 100644 --- a/ibis/backends/duckdb/tests/conftest.py +++ b/ibis/backends/duckdb/tests/conftest.py @@ -6,7 +6,7 @@ import ibis from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest from ibis.conftest import SANDBOXED if TYPE_CHECKING: @@ -15,7 +15,7 @@ from ibis.backends.base import BaseBackend -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): supports_map = True deps = "duckdb", "duckdb_engine" stateful = False diff --git a/ibis/backends/flink/tests/conftest.py b/ibis/backends/flink/tests/conftest.py index 46497fd5096f..92b412ebbeb0 100644 --- a/ibis/backends/flink/tests/conftest.py +++ b/ibis/backends/flink/tests/conftest.py @@ -6,10 +6,10 @@ import ibis from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): supports_structs = False force_sort_before_comparison = True deps = "pandas", "pyflink" diff --git a/ibis/backends/impala/tests/conftest.py b/ibis/backends/impala/tests/conftest.py index 0d37399e1451..4e46b646c6e1 100644 --- a/ibis/backends/impala/tests/conftest.py +++ b/ibis/backends/impala/tests/conftest.py @@ -18,12 +18,12 @@ from ibis import options, util from ibis.backends.conftest import TEST_TABLES from ibis.backends.impala.compiler import ImpalaCompiler, ImpalaExprTranslator -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest from ibis.backends.tests.data import win from ibis.tests.expr.mocks import MockBackend -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): supports_arrays = True supports_arrays_outside_of_select = False check_dtype = False diff --git a/ibis/backends/mssql/tests/conftest.py b/ibis/backends/mssql/tests/conftest.py index 6f8ef88d58c6..87161387bb72 100644 --- a/ibis/backends/mssql/tests/conftest.py +++ b/ibis/backends/mssql/tests/conftest.py @@ -8,7 +8,7 @@ import ibis from ibis.backends.conftest import init_database -from ibis.backends.tests.base import RoundHalfToEven, ServiceBackendTest +from ibis.backends.tests.base import ServiceBackendTest if TYPE_CHECKING: from collections.abc import Iterable @@ -21,7 +21,7 @@ IBIS_TEST_MSSQL_DB = os.environ.get("IBIS_TEST_MSSQL_DATABASE", "ibis_testing") -class TestConf(ServiceBackendTest, RoundHalfToEven): +class TestConf(ServiceBackendTest): # MSSQL has the same rounding behavior as postgres check_dtype = False supports_window_operations = False @@ -30,6 +30,7 @@ class TestConf(ServiceBackendTest, RoundHalfToEven): supports_arrays_outside_of_select = supports_arrays supports_structs = False supports_json = False + rounding_method = "half_to_even" service_name = "mssql" deps = "pymssql", "sqlalchemy" diff --git a/ibis/backends/mysql/tests/conftest.py b/ibis/backends/mysql/tests/conftest.py index d2e77d47704a..8c0ad8007051 100644 --- a/ibis/backends/mysql/tests/conftest.py +++ b/ibis/backends/mysql/tests/conftest.py @@ -9,7 +9,7 @@ import ibis from ibis.backends.conftest import TEST_TABLES, init_database -from ibis.backends.tests.base import RoundHalfToEven, ServiceBackendTest +from ibis.backends.tests.base import ServiceBackendTest if TYPE_CHECKING: from collections.abc import Iterable @@ -22,7 +22,7 @@ IBIS_TEST_MYSQL_DB = os.environ.get("IBIS_TEST_MYSQL_DATABASE", "ibis_testing") -class TestConf(ServiceBackendTest, RoundHalfToEven): +class TestConf(ServiceBackendTest): # mysql has the same rounding behavior as postgres check_dtype = False returned_timestamp_unit = "s" @@ -30,6 +30,7 @@ class TestConf(ServiceBackendTest, RoundHalfToEven): supports_arrays_outside_of_select = supports_arrays native_bool = False supports_structs = False + rounding_method = "half_to_even" service_name = "mysql" deps = "pymysql", "sqlalchemy" diff --git a/ibis/backends/oracle/tests/conftest.py b/ibis/backends/oracle/tests/conftest.py index be4688b46f14..79d1de373bfd 100644 --- a/ibis/backends/oracle/tests/conftest.py +++ b/ibis/backends/oracle/tests/conftest.py @@ -11,7 +11,7 @@ import sqlalchemy as sa import ibis -from ibis.backends.tests.base import RoundHalfToEven, ServiceBackendTest +from ibis.backends.tests.base import ServiceBackendTest if TYPE_CHECKING: from collections.abc import Iterable @@ -29,7 +29,7 @@ # where ORACLE_DB is the same name you used in the docker-compose file. -class TestConf(ServiceBackendTest, RoundHalfToEven): +class TestConf(ServiceBackendTest): check_dtype = False supports_window_operations = False returned_timestamp_unit = "s" @@ -40,6 +40,7 @@ class TestConf(ServiceBackendTest, RoundHalfToEven): native_bool = False supports_structs = False supports_json = False + rounding_method = "half_to_even" data_volume = "/opt/oracle/data" service_name = "oracle" deps = "oracledb", "sqlalchemy" diff --git a/ibis/backends/pandas/tests/conftest.py b/ibis/backends/pandas/tests/conftest.py index 4c6bdd567d87..8aa998871d2a 100644 --- a/ibis/backends/pandas/tests/conftest.py +++ b/ibis/backends/pandas/tests/conftest.py @@ -4,16 +4,17 @@ import ibis from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundHalfToEven +from ibis.backends.tests.base import BackendTest from ibis.backends.tests.data import array_types, json_types, struct_types, win -class TestConf(BackendTest, RoundHalfToEven): +class TestConf(BackendTest): check_names = False supported_to_timestamp_units = BackendTest.supported_to_timestamp_units | {"ns"} supports_divide_by_zero = True returned_timestamp_unit = "ns" stateful = False + rounding_method = "half_to_even" deps = ("pandas",) def _load_data(self, **_: Any) -> None: diff --git a/ibis/backends/polars/tests/conftest.py b/ibis/backends/polars/tests/conftest.py index 9eb1d62cbe9f..a337ea16fbac 100644 --- a/ibis/backends/polars/tests/conftest.py +++ b/ibis/backends/polars/tests/conftest.py @@ -7,11 +7,11 @@ import ibis from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest from ibis.backends.tests.data import array_types, struct_types, win -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): supports_structs = True supports_json = False reduction_tolerance = 1e-3 diff --git a/ibis/backends/postgres/tests/conftest.py b/ibis/backends/postgres/tests/conftest.py index bb8237e4379e..23d3c8f2d27d 100644 --- a/ibis/backends/postgres/tests/conftest.py +++ b/ibis/backends/postgres/tests/conftest.py @@ -21,7 +21,7 @@ import ibis from ibis.backends.conftest import init_database -from ibis.backends.tests.base import RoundHalfToEven, ServiceBackendTest +from ibis.backends.tests.base import ServiceBackendTest if TYPE_CHECKING: from collections.abc import Iterable @@ -42,12 +42,13 @@ ) -class TestConf(ServiceBackendTest, RoundHalfToEven): +class TestConf(ServiceBackendTest): # postgres rounds half to even for double precision and half away from zero # for numeric and decimal returned_timestamp_unit = "s" supports_structs = False + rounding_method = "half_to_even" service_name = "postgres" deps = "psycopg2", "sqlalchemy" diff --git a/ibis/backends/pyspark/tests/conftest.py b/ibis/backends/pyspark/tests/conftest.py index db49960382e2..03ec6aa1a715 100644 --- a/ibis/backends/pyspark/tests/conftest.py +++ b/ibis/backends/pyspark/tests/conftest.py @@ -11,7 +11,7 @@ import ibis from ibis import util from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest from ibis.backends.tests.data import json_types, win @@ -19,7 +19,7 @@ def set_pyspark_database(con, database): con._session.catalog.setCurrentDatabase(database) -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): supported_to_timestamp_units = {"s"} deps = ("pyspark",) diff --git a/ibis/backends/snowflake/tests/conftest.py b/ibis/backends/snowflake/tests/conftest.py index 4faac50223a0..0ff7ce7cf586 100644 --- a/ibis/backends/snowflake/tests/conftest.py +++ b/ibis/backends/snowflake/tests/conftest.py @@ -13,7 +13,7 @@ import ibis from ibis.backends.conftest import TEST_TABLES from ibis.backends.snowflake.datatypes import SnowflakeType -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest from ibis.formats.pyarrow import PyArrowSchema if TYPE_CHECKING: @@ -63,7 +63,7 @@ def copy_into(con, data_dir: Path, table: str) -> None: ) -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): supports_map = True default_identifier_case_fn = staticmethod(str.upper) deps = ("snowflake.connector", "snowflake.sqlalchemy") diff --git a/ibis/backends/sqlite/tests/conftest.py b/ibis/backends/sqlite/tests/conftest.py index a1a52db6f384..3577061e9ab3 100644 --- a/ibis/backends/sqlite/tests/conftest.py +++ b/ibis/backends/sqlite/tests/conftest.py @@ -11,10 +11,10 @@ import ibis import ibis.expr.types as ir from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): supports_arrays = False supports_arrays_outside_of_select = supports_arrays supports_window_operations = True diff --git a/ibis/backends/tests/base.py b/ibis/backends/tests/base.py index 2890b485087f..4c1c52749889 100644 --- a/ibis/backends/tests/base.py +++ b/ibis/backends/tests/base.py @@ -20,33 +20,6 @@ import ibis.expr.types as ir -# TODO: Merge into BackendTest, #2564 -class RoundingConvention: - @staticmethod - @abc.abstractmethod - def round(series: pd.Series, decimals: int = 0) -> pd.Series: - """Round a series to `decimals` number of decimal values.""" - - -# TODO: Merge into BackendTest, #2564 -class RoundAwayFromZero(RoundingConvention): - @staticmethod - def round(series: pd.Series, decimals: int = 0) -> pd.Series: - if not decimals: - return (-(np.sign(series)) * np.ceil(-(series.abs()) - 0.5)).astype( - np.int64 - ) - return series.round(decimals=decimals) - - -# TODO: Merge into BackendTest, #2564 -class RoundHalfToEven(RoundingConvention): - @staticmethod - def round(series: pd.Series, decimals: int = 0) -> pd.Series: - result = series.round(decimals=decimals) - return result if decimals else result.astype(np.int64) - - class BackendTest(abc.ABC): check_dtype = True check_names = True @@ -67,6 +40,7 @@ class BackendTest(abc.ABC): service_name = None supports_tpch = False force_sort_before_comparison = False + rounding_method = "away_from_zero" @property @abc.abstractmethod @@ -186,6 +160,23 @@ def assert_frame_equal( kwargs.setdefault("check_dtype", cls.check_dtype) tm.assert_frame_equal(left, right, *args, **kwargs) + @classmethod + def round(cls, series: pd.Series, decimals: int = 0) -> pd.Series: + return getattr(cls, cls.rounding_method)(series, decimals) + + @staticmethod + def away_from_zero(series: pd.Series, decimals: int = 0) -> pd.Series: + if not decimals: + return (-(np.sign(series)) * np.ceil(-(series.abs()) - 0.5)).astype( + np.int64 + ) + return series.round(decimals=decimals) + + @staticmethod + def half_to_even(series: pd.Series, decimals: int = 0) -> pd.Series: + result = series.round(decimals=decimals) + return result if decimals else result.astype(np.int64) + @staticmethod def default_series_rename(series: pd.Series, name: str = "tmp") -> pd.Series: return series.rename(name) diff --git a/ibis/backends/trino/tests/conftest.py b/ibis/backends/trino/tests/conftest.py index ac9e7185a599..6410ab0cb64e 100644 --- a/ibis/backends/trino/tests/conftest.py +++ b/ibis/backends/trino/tests/conftest.py @@ -11,7 +11,7 @@ import ibis.expr.datatypes as dt import ibis.selectors as s from ibis.backends.conftest import TEST_TABLES -from ibis.backends.tests.base import BackendTest, RoundAwayFromZero +from ibis.backends.tests.base import BackendTest if TYPE_CHECKING: from collections.abc import Iterable @@ -32,7 +32,7 @@ ) -class TestConf(BackendTest, RoundAwayFromZero): +class TestConf(BackendTest): # trino rounds half to even for double precision and half away from zero # for numeric and decimal