Skip to content

Commit

Permalink
refactor(config): remove option_context
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `option_context` is removed. Use `contextlib.contextmanager` to create your own version of this functionality if necessary.
  • Loading branch information
cpcloud committed Nov 6, 2024
1 parent 9f57999 commit 4f15905
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 123 deletions.
85 changes: 45 additions & 40 deletions ibis/backends/clickhouse/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"

Expand All @@ -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):
Expand Down
102 changes: 58 additions & 44 deletions ibis/backends/impala/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand All @@ -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"))
Expand All @@ -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):
Expand All @@ -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
Expand All @@ -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):
Expand Down
8 changes: 4 additions & 4 deletions ibis/backends/postgres/tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down
31 changes: 17 additions & 14 deletions ibis/backends/tests/test_interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"])
Expand All @@ -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

Expand Down
21 changes: 0 additions & 21 deletions ibis/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import contextlib
from collections.abc import Callable # noqa: TCH003
from typing import Annotated, Any, Optional

Expand All @@ -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.
Expand Down Expand Up @@ -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)

0 comments on commit 4f15905

Please sign in to comment.