diff --git a/ibis/backends/clickhouse/tests/test_client.py b/ibis/backends/clickhouse/tests/test_client.py index 690d2a7fb15d..5cef7b9e3630 100644 --- a/ibis/backends/clickhouse/tests/test_client.py +++ b/ibis/backends/clickhouse/tests/test_client.py @@ -13,7 +13,7 @@ import ibis.common.exceptions as exc import ibis.expr.datatypes as dt import ibis.expr.types as ir -from ibis import config, udf +from ibis import udf from ibis.backends.clickhouse.tests.conftest import ( CLICKHOUSE_HOST, CLICKHOUSE_PASS, @@ -72,21 +72,19 @@ def test_limit_overrides_expr(con, alltypes): assert len(result) == 5 -def test_limit_equals_none_no_limit(alltypes): - with config.option_context("sql.default_limit", 10): - result = alltypes.execute(limit=None) - assert len(result) > 10 +def test_limit_equals_none_no_limit(alltypes, monkeypatch): + monkeypatch.setattr(ibis.options.sql, "default_limit", 10) + result = alltypes.execute(limit=None) + assert len(result) > 10 -def test_verbose_log_queries(con): +def test_verbose_log_queries(con, monkeypatch): queries = [] - def logger(x): - queries.append(x) + monkeypatch.setattr(ibis.options, "verbose", True) + monkeypatch.setattr(ibis.options, "verbose_log", queries.append) - with config.option_context("verbose", True): - with config.option_context("verbose_log", logger): - con.table("functional_alltypes") + con.table("functional_alltypes") expected = "DESCRIBE functional_alltypes" @@ -95,36 +93,43 @@ def logger(x): assert expected in queries -def test_sql_query_limits(alltypes): - table = alltypes - with config.option_context("sql.default_limit", 100000): - # table has 25 rows - assert len(table.execute()) == 7300 - # comply with limit arg for Table - assert len(table.execute(limit=10)) == 10 - # state hasn't changed - assert len(table.execute()) == 7300 - # non-Table ignores default_limit - assert table.count().execute() == 7300 - # non-Table doesn't observe limit arg - assert table.count().execute(limit=10) == 7300 - with config.option_context("sql.default_limit", 20): - # Table observes default limit setting - assert len(table.execute()) == 20 - # explicit limit= overrides default - assert len(table.execute(limit=15)) == 15 - assert len(table.execute(limit=23)) == 23 - # non-Table ignores default_limit - assert table.count().execute() == 7300 - # non-Table doesn't observe limit arg - assert table.count().execute(limit=10) == 7300 +def test_sql_query_limits_big(alltypes, monkeypatch): + monkeypatch.setattr(ibis.options.sql, "default_limit", 100_000) + + # alltypes has 7300 rows + assert len(alltypes.execute()) == 7300 # comply with limit arg for alltypes + assert len(alltypes.execute(limit=10)) == 10 + # state hasn't changed + assert len(alltypes.execute()) == 7300 + # non-alltypes ignores default_limit + assert alltypes.count().execute() == 7300 + # non-alltypes doesn't observe limit arg + assert alltypes.count().execute(limit=10) == 7300 + + +def test_sql_query_limits_small(alltypes, monkeypatch): + monkeypatch.setattr(ibis.options.sql, "default_limit", 20) + + # alltypes observes default limit setting + assert len(alltypes.execute()) == 20 + # explicit limit= overrides default + assert len(alltypes.execute(limit=15)) == 15 + assert len(alltypes.execute(limit=23)) == 23 + # non-alltypes ignores default_limit + assert alltypes.count().execute() == 7300 + # non-alltypes doesn't observe limit arg + assert alltypes.count().execute(limit=10) == 7300 + + +def test_sql_query_limits_none(alltypes, monkeypatch): + monkeypatch.setattr(ibis.options.sql, "default_limit", None) + # eliminating default_limit doesn't break anything - with config.option_context("sql.default_limit", None): - assert len(table.execute()) == 7300 - assert len(table.execute(limit=15)) == 15 - assert len(table.execute(limit=10000)) == 7300 - assert table.count().execute() == 7300 - assert table.count().execute(limit=10) == 7300 + assert len(alltypes.execute()) == 7300 + assert len(alltypes.execute(limit=15)) == 15 + assert len(alltypes.execute(limit=10000)) == 7300 + assert alltypes.count().execute() == 7300 + assert alltypes.count().execute(limit=10) == 7300 def test_embedded_identifier_quoting(alltypes): diff --git a/ibis/backends/impala/tests/test_client.py b/ibis/backends/impala/tests/test_client.py index 212aaf3b98a4..dfd9088125ba 100644 --- a/ibis/backends/impala/tests/test_client.py +++ b/ibis/backends/impala/tests/test_client.py @@ -10,7 +10,6 @@ import ibis import ibis.expr.datatypes as dt import ibis.expr.types as ir -from ibis import config from ibis.tests.util import assert_equal pytest.importorskip("impala") @@ -66,16 +65,17 @@ def test_result_as_dataframe(con, alltypes): assert len(result) == 10 -def test_adapt_scalar_array_results(con, alltypes): +def test_adapt_scalar_array_results(con, alltypes, monkeypatch): table = alltypes expr = table.double_col.sum() result = con.execute(expr) assert isinstance(result, float) - with config.option_context("interactive", True): - result2 = expr.execute() - assert isinstance(result2, float) + monkeypatch.setattr(ibis.options, "interactive", True) + + result2 = expr.execute() + assert isinstance(result2, float) expr = ( table.group_by("string_col").aggregate([table.count().name("count")]).string_col @@ -85,7 +85,7 @@ def test_adapt_scalar_array_results(con, alltypes): assert isinstance(result, pd.Series) -def test_interactive_repr_call_failure(con): +def test_interactive_repr_call_failure(con, monkeypatch): t = con.table("lineitem").limit(100000) t = t.select(t, t.l_receiptdate.cast("timestamp").name("date")) @@ -100,8 +100,9 @@ def test_interactive_repr_call_failure(con): metric = expr["avg_px"].mean().over(w2) enriched = expr.select(expr, metric) - with config.option_context("interactive", True): - repr(enriched) + + monkeypatch.setattr(ibis.options, "interactive", True) + repr(enriched) def test_array_default_limit(con, alltypes): @@ -118,20 +119,22 @@ def test_limit_overrides_expr(con, alltypes): assert len(result) == 5 -def test_limit_equals_none_no_limit(alltypes): +def test_limit_equals_none_no_limit(alltypes, monkeypatch): t = alltypes - with config.option_context("sql.default_limit", 10): - result = t.execute(limit=None) - assert len(result) > 10 + monkeypatch.setattr(ibis.options.sql, "default_limit", 10) + result = t.execute(limit=None) + assert len(result) > 10 -def test_verbose_log_queries(con, test_data_db): + +def test_verbose_log_queries(con, test_data_db, monkeypatch): queries = [] - with config.option_context("verbose", True): - with config.option_context("verbose_log", queries.append): - con.table("orders", database=test_data_db) + monkeypatch.setattr(ibis.options, "verbose", True) + monkeypatch.setattr(ibis.options, "verbose_log", queries.append) + + con.table("orders", database=test_data_db) # we can't make assertions about the length of queries, since the Python GC # could've collected a temporary pandas table any time between construction @@ -140,36 +143,47 @@ def test_verbose_log_queries(con, test_data_db): assert expected in queries -def test_sql_query_limits(con, test_data_db): +def test_sql_query_limits_big(con, test_data_db, monkeypatch): table = con.table("nation", database=test_data_db) - with config.option_context("sql.default_limit", 100000): - # table has 25 rows - assert len(table.execute()) == 25 - # comply with limit arg for Table - assert len(table.execute(limit=10)) == 10 - # state hasn't changed - assert len(table.execute()) == 25 - # non-Table ignores default_limit - assert table.count().execute() == 25 - # non-Table doesn't observe limit arg - assert table.count().execute(limit=10) == 25 - with config.option_context("sql.default_limit", 20): - # Table observes default limit setting - assert len(table.execute()) == 20 - # explicit limit= overrides default - assert len(table.execute(limit=15)) == 15 - assert len(table.execute(limit=23)) == 23 - # non-Table ignores default_limit - assert table.count().execute() == 25 - # non-Table doesn't observe limit arg - assert table.count().execute(limit=10) == 25 + monkeypatch.setattr(ibis.options.sql, "default_limit", 100_000) + + # table has 25 rows + assert len(table.execute()) == 25 + # comply with limit arg for Table + assert len(table.execute(limit=10)) == 10 + # state hasn't changed + assert len(table.execute()) == 25 + # non-Table ignores default_limit + assert table.count().execute() == 25 + # non-Table doesn't observe limit arg + assert table.count().execute(limit=10) == 25 + + +def test_sql_query_limits_small(con, test_data_db, monkeypatch): + table = con.table("nation", database=test_data_db) + monkeypatch.setattr(ibis.options.sql, "default_limit", 20) + + # Table observes default limit setting + assert len(table.execute()) == 20 + # explicit limit= overrides default + assert len(table.execute(limit=15)) == 15 + assert len(table.execute(limit=23)) == 23 + # non-Table ignores default_limit + assert table.count().execute() == 25 + # non-Table doesn't observe limit arg + assert table.count().execute(limit=10) == 25 + + +def test_sql_query_limits_none(con, test_data_db, monkeypatch): + table = con.table("nation", database=test_data_db) + monkeypatch.setattr(ibis.options.sql, "default_limit", None) + # eliminating default_limit doesn't break anything - with config.option_context("sql.default_limit", None): - assert len(table.execute()) == 25 - assert len(table.execute(limit=15)) == 15 - assert len(table.execute(limit=10000)) == 25 - assert table.count().execute() == 25 - assert table.count().execute(limit=10) == 25 + assert len(table.execute()) == 25 + assert len(table.execute(limit=15)) == 15 + assert len(table.execute(limit=10000)) == 25 + assert table.count().execute() == 25 + assert table.count().execute(limit=10) == 25 def test_set_compression_codec(con): diff --git a/ibis/backends/postgres/tests/test_functions.py b/ibis/backends/postgres/tests/test_functions.py index e8d0e1c20066..95423a59c4df 100644 --- a/ibis/backends/postgres/tests/test_functions.py +++ b/ibis/backends/postgres/tests/test_functions.py @@ -14,7 +14,6 @@ import ibis import ibis.expr.datatypes as dt import ibis.expr.types as ir -from ibis import config from ibis import literal as L pytest.importorskip("psycopg2") @@ -656,11 +655,12 @@ def test_not_exists(alltypes, df): tm.assert_frame_equal(result, expected, check_index_type=False, check_dtype=False) -def test_interactive_repr_shows_error(alltypes): +def test_interactive_repr_shows_error(alltypes, monkeypatch): expr = alltypes.int_col.convert_base(10, 2) - with config.option_context("interactive", True): - result = repr(expr) + monkeypatch.setattr(ibis.options, "interactive", True) + + result = repr(expr) assert "OperationNotDefinedError" in result assert "BaseConvert" in result diff --git a/ibis/backends/tests/test_interactive.py b/ibis/backends/tests/test_interactive.py index 74219cf0a5af..e4d91594afb1 100644 --- a/ibis/backends/tests/test_interactive.py +++ b/ibis/backends/tests/test_interactive.py @@ -13,11 +13,12 @@ # limitations under the License. from __future__ import annotations +import shutil + import pytest import ibis import ibis.common.exceptions as exc -from ibis import config @pytest.fixture @@ -40,19 +41,19 @@ def test_interactive_execute_on_repr(table, queries): assert len(queries) >= 1 -def test_repr_png_is_none_in_interactive(table): - with config.option_context("interactive", True): - assert table._repr_png_() is None +def test_repr_png_is_none_in_interactive(table, monkeypatch): + monkeypatch.setattr(ibis.options, "interactive", True) + assert table._repr_png_() is None -def test_repr_png_is_not_none_in_not_interactive(table): +def test_repr_png_is_not_none_in_not_interactive(table, monkeypatch): pytest.importorskip("ibis.expr.visualize") - with ( - config.option_context("interactive", False), - config.option_context("graphviz_repr", True), - ): - assert table._repr_png_() is not None + monkeypatch.setattr(ibis.options, "interactive", False) + monkeypatch.setattr(ibis.options, "graphviz_repr", True) + + assert shutil.which("dot") is not None + assert table._repr_png_() is not None @pytest.mark.notimpl(["polars"]) @@ -70,12 +71,14 @@ def test_respect_set_limit(table, queries): @pytest.mark.notimpl(["polars"]) -def test_disable_query_limit(table, queries): +def test_disable_query_limit(table, queries, monkeypatch): assert ibis.options.sql.default_limit is None - with config.option_context("sql.default_limit", 10): - assert ibis.options.sql.default_limit == 10 - repr(table.select("id", "bool_col")) + monkeypatch.setattr(ibis.options.sql, "default_limit", 10) + + assert ibis.options.sql.default_limit == 10 + + repr(table.select("id", "bool_col")) assert len(queries) >= 1 diff --git a/ibis/config.py b/ibis/config.py index ff1d1770160f..151cabbb2d85 100644 --- a/ibis/config.py +++ b/ibis/config.py @@ -1,6 +1,5 @@ from __future__ import annotations -import contextlib from collections.abc import Callable # noqa: TCH003 from typing import Annotated, Any, Optional @@ -27,21 +26,6 @@ def set(self, key: str, value: Any) -> None: conf = getattr(conf, field) setattr(conf, key, value) - @contextlib.contextmanager - def _with_temporary(self, options): - try: - old = {} - for key, value in options.items(): - old[key] = self.get(key) - self.set(key, value) - yield - finally: - for key, value in old.items(): - self.set(key, value) - - def __call__(self, options): - return self._with_temporary(options) - class SQL(Config): """SQL-related options. @@ -207,9 +191,4 @@ def _default_backend() -> Any: options = Options() -@public -def option_context(key, new_value): - return options({key: new_value}) - - public(options=options)