Skip to content

Commit d7e9c10

Browse files
SNOW-2338542: Add session parameter pandas_hybrid_execution_enabled (#3789)
1 parent d99fdfa commit d7e9c10

3 files changed

Lines changed: 75 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
#### New Features
1919

2020
#### Improvements
21+
2122
- Hybrid execution mode is now enabled by default. Certain operations on smaller data will now automatically execute in native pandas in-memory. Use `from modin.config import AutoSwitchBackend; AutoSwitchBackend.disable()` to turn this off and force all execution to occur in Snowflake.
23+
- Added a session parameter `pandas_hybrid_execution_enabled` to enable/disable hybrid execution as an alternative to using `AutoSwitchBackend`.
2224
- Removed an unnecessary `SHOW OBJECTS` query issued from `read_snowflake` under certain conditions.
2325

2426
## 1.39.0 (2025-09-17)

src/snowflake/snowpark/session.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@
304304
_SNOWPARK_PANDAS_DUMMY_ROW_POS_OPTIMIZATION_ENABLED = (
305305
"SNOWPARK_PANDAS_DUMMY_ROW_POS_OPTIMIZATION_ENABLED"
306306
)
307+
_SNOWPARK_PANDAS_HYBRID_EXECUTION_ENABLED = "SNOWPARK_PANDAS_HYBRID_EXECUTION_ENABLED"
307308

308309
# AST encoding.
309310
_PYTHON_SNOWPARK_USE_AST = "PYTHON_SNOWPARK_USE_AST"
@@ -754,6 +755,21 @@ def __init__(
754755
)
755756
)
756757

758+
if importlib.util.find_spec("modin"):
759+
try:
760+
from modin.config import AutoSwitchBackend
761+
762+
pandas_hybrid_execution_enabled: bool = (
763+
self._conn._get_client_side_session_parameter(
764+
_SNOWPARK_PANDAS_HYBRID_EXECUTION_ENABLED,
765+
AutoSwitchBackend().get(),
766+
)
767+
)
768+
AutoSwitchBackend.put(pandas_hybrid_execution_enabled)
769+
except Exception:
770+
# Continue session initialization even if Modin configuration fails
771+
pass
772+
757773
self._thread_store = create_thread_local(
758774
self._conn._thread_safe_session_enabled
759775
)
@@ -1025,6 +1041,21 @@ def dummy_row_pos_optimization_enabled(self) -> bool:
10251041
"""
10261042
return self._dummy_row_pos_optimization_enabled
10271043

1044+
@property
1045+
def pandas_hybrid_execution_enabled(self) -> bool:
1046+
"""Set to ``True`` to enable hybrid execution mode (has the same default as AutoSwitchBackend).
1047+
When enabled, certain operations on smaller data will automatically execute in native pandas in-memory.
1048+
This can significantly improve performance for operations that are more efficient in pandas than in Snowflake.
1049+
"""
1050+
if not importlib.util.find_spec("modin"):
1051+
raise ImportError(
1052+
"The 'modin' package is required to enable this feature. Please install it first."
1053+
)
1054+
1055+
from modin.config import AutoSwitchBackend
1056+
1057+
return AutoSwitchBackend().get()
1058+
10281059
@property
10291060
def custom_package_usage_config(self) -> Dict:
10301061
"""Get or set configuration parameters related to usage of custom Python packages in Snowflake.
@@ -1200,6 +1231,23 @@ def dummy_row_pos_optimization_enabled(self, value: bool) -> None:
12001231
"value for dummy_row_pos_optimization_enabled must be True or False!"
12011232
)
12021233

1234+
@pandas_hybrid_execution_enabled.setter
1235+
def pandas_hybrid_execution_enabled(self, value: bool) -> None:
1236+
"""Set the value for pandas_hybrid_execution_enabled"""
1237+
if not importlib.util.find_spec("modin"):
1238+
raise ImportError(
1239+
"The 'modin' package is required to enable this feature. Please install it first."
1240+
)
1241+
1242+
from modin.config import AutoSwitchBackend
1243+
1244+
if value in [True, False]:
1245+
AutoSwitchBackend.put(value)
1246+
else:
1247+
raise ValueError(
1248+
"value for pandas_hybrid_execution_enabled must be True or False!"
1249+
)
1250+
12031251
@custom_package_usage_config.setter
12041252
@experimental_parameter(version="1.6.0")
12051253
def custom_package_usage_config(self, config: Dict) -> None:

tests/integ/modin/hybrid/test_switch_operations.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,9 @@ def test_tqdm_usage_during_snowflake_to_pandas_switch():
395395
("Series", "transform", (lambda x: x * 2,)), # declared in series_overrides
396396
],
397397
)
398+
@pytest.mark.parametrize("use_session_param", [True, False])
398399
@sql_count_checker(query_count=1)
399-
def test_unimplemented_autoswitches(class_name, method_name, f_args):
400+
def test_unimplemented_autoswitches(class_name, method_name, f_args, use_session_param):
400401
# Unimplemented methods declared via register_*_not_implemented should automatically
401402
# default to local pandas execution.
402403
# This test needs to be modified if any of the APIs in question are ever natively implemented
@@ -405,6 +406,13 @@ def test_unimplemented_autoswitches(class_name, method_name, f_args):
405406
method = getattr(getattr(pd, class_name)(data).move_to("Snowflake"), method_name)
406407
# Attempting to call the method without switching should raise.
407408
with config_context(AutoSwitchBackend=False):
409+
if use_session_param:
410+
from modin.config import AutoSwitchBackend
411+
412+
AutoSwitchBackend.enable()
413+
pd.session.pandas_hybrid_execution_enabled = False
414+
assert pd.session.pandas_hybrid_execution_enabled is False
415+
assert AutoSwitchBackend.get() is False
408416
with pytest.raises(
409417
NotImplementedError, match="Snowpark pandas does not yet support the method"
410418
):
@@ -433,14 +441,15 @@ def test_to_datetime():
433441
assert isinstance(result, DatetimeIndex)
434442

435443

444+
@pytest.mark.parametrize("use_session_param", [True, False])
436445
@sql_count_checker(
437446
query_count=11,
438447
join_count=6,
439448
udtf_count=2,
440449
high_count_expected=True,
441450
high_count_reason="tests queries across different execution modes",
442451
)
443-
def test_query_count_no_switch(init_transaction_tables):
452+
def test_query_count_no_switch(init_transaction_tables, use_session_param):
444453
"""
445454
Tests that when there is no switching behavior the query count is the
446455
same under hybrid mode and non-hybrid mode.
@@ -458,11 +467,25 @@ def inner_test(df_in):
458467
hybrid_len = None
459468
with pd.session.query_history() as query_history_orig:
460469
with config_context(AutoSwitchBackend=False, NativePandasMaxRows=10):
470+
if use_session_param:
471+
from modin.config import AutoSwitchBackend
472+
473+
AutoSwitchBackend.enable()
474+
pd.session.pandas_hybrid_execution_enabled = False
475+
assert pd.session.pandas_hybrid_execution_enabled is False
476+
assert AutoSwitchBackend.get() is False
461477
df_result = inner_test(df_transactions)
462478
orig_len = len(df_result)
463479

464480
with pd.session.query_history() as query_history_hybrid:
465481
with config_context(AutoSwitchBackend=True, NativePandasMaxRows=10):
482+
if use_session_param:
483+
from modin.config import AutoSwitchBackend
484+
485+
AutoSwitchBackend.disable()
486+
pd.session.pandas_hybrid_execution_enabled = True
487+
assert pd.session.pandas_hybrid_execution_enabled is True
488+
assert AutoSwitchBackend.get() is True
466489
df_result = inner_test(df_transactions)
467490
hybrid_len = len(df_result)
468491

0 commit comments

Comments
 (0)