Repository: modin-project/modin

Issue:
REFACTOR: Use `contextlib.nullcontext` instead of custom one



Discussion:

Resolving patch:
diff --git a/modin/core/storage_formats/pandas/parsers.py b/modin/core/storage_formats/pandas/parsers.py
--- a/modin/core/storage_formats/pandas/parsers.py
+++ b/modin/core/storage_formats/pandas/parsers.py
@@ -39,6 +39,7 @@
   parameters are passed into `pandas.read_sql` function without modification.
 """
 
+import contextlib
 import json
 import os
 import warnings
@@ -55,10 +56,7 @@
 from pandas.util._decorators import doc
 
 from modin.core.io.file_dispatcher import OpenFile
-from modin.core.storage_formats.pandas.utils import (
-    _nullcontext,
-    split_result_of_axis_func_pandas,
-)
+from modin.core.storage_formats.pandas.utils import split_result_of_axis_func_pandas
 from modin.db_conn import ModinDatabaseConnection
 from modin.error_message import ErrorMessage
 from modin.logging import ClassLogger
@@ -888,7 +886,7 @@ def parse(files_for_parser, engine, **kwargs):
 
         for file_for_parser in files_for_parser:
             if isinstance(file_for_parser.path, IOBase):
-                context = _nullcontext(file_for_parser.path)
+                context = contextlib.nullcontext(file_for_parser.path)
             else:
                 context = fsspec.open(file_for_parser.path, **storage_options)
             with context as f:
diff --git a/modin/core/storage_formats/pandas/utils.py b/modin/core/storage_formats/pandas/utils.py
--- a/modin/core/storage_formats/pandas/utils.py
+++ b/modin/core/storage_formats/pandas/utils.py
@@ -13,7 +13,6 @@
 
 """Contains utility functions for frame partitioning."""
 
-import contextlib
 import re
 from math import ceil
 from typing import Hashable, List
@@ -24,18 +23,6 @@
 from modin.config import MinPartitionSize, NPartitions
 
 
-@contextlib.contextmanager
-def _nullcontext(dummy_value=None):  # noqa: PR01
-    """
-    Act as a replacement for contextlib.nullcontext missing in older Python.
-
-    Notes
-    -----
-    contextlib.nullcontext is only available from Python 3.7.
-    """
-    yield dummy_value
-
-
 def compute_chunksize(axis_len, num_splits, min_block_size=None):
     """
     Compute the number of elements (rows/columns) to include in each partition.


Test patch:
diff --git a/modin/experimental/pandas/test/test_io_exp.py b/modin/experimental/pandas/test/test_io_exp.py
--- a/modin/experimental/pandas/test/test_io_exp.py
+++ b/modin/experimental/pandas/test/test_io_exp.py
@@ -11,9 +11,9 @@
 # ANY KIND, either express or implied. See the License for the specific language
 # governing permissions and limitations under the License.
 
+import contextlib
 import glob
 import json
-from contextlib import nullcontext
 
 import numpy as np
 import pandas
@@ -140,7 +140,7 @@ def test_read_csv_glob_4373(self):
         with (
             warns_that_defaulting_to_pandas()
             if Engine.get() == "Dask"
-            else nullcontext()
+            else contextlib.nullcontext()
         ):
             df.to_csv(filename)
 
@@ -258,7 +258,7 @@ def test_distributed_pickling(filename, compression):
     with (
         warns_that_defaulting_to_pandas()
         if filename_param == test_default_to_pickle_filename
-        else nullcontext()
+        else contextlib.nullcontext()
     ):
         df.to_pickle_distributed(filename, compression=compression)
         pickled_df = pd.read_pickle_distributed(filename, compression=compression)
diff --git a/modin/pandas/test/test_general.py b/modin/pandas/test/test_general.py
--- a/modin/pandas/test/test_general.py
+++ b/modin/pandas/test/test_general.py
@@ -40,12 +40,6 @@
     pytestmark = pytest.mark.filterwarnings(default_to_pandas_ignore_string)
 
 
-@contextlib.contextmanager
-def _nullcontext():
-    """Replacement for contextlib.nullcontext missing in older Python."""
-    yield
-
-
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
 @pytest.mark.parametrize("append_na", [True, False])
 @pytest.mark.parametrize("op", ["isna", "isnull", "notna", "notnull"])
@@ -86,7 +80,7 @@ def test_merge():
 
     join_types = ["outer", "inner"]
     for how in join_types:
-        with warns_that_defaulting_to_pandas() if how == "outer" else _nullcontext():
+        with warns_that_defaulting_to_pandas() if how == "outer" else contextlib.nullcontext():
             modin_result = pd.merge(modin_df, modin_df2, how=how)
         pandas_result = pandas.merge(pandas_df, pandas_df2, how=how)
         df_equals(modin_result, pandas_result)
@@ -115,7 +109,7 @@ def test_merge():
         if how == "outer":
             warning_catcher = warns_that_defaulting_to_pandas()
         else:
-            warning_catcher = _nullcontext()
+            warning_catcher = contextlib.nullcontext()
         with warning_catcher:
             modin_result = pd.merge(
                 modin_df, modin_df2, how=how, left_on="col1", right_on="col1"
@@ -129,7 +123,7 @@ def test_merge():
         if how == "outer":
             warning_catcher = warns_that_defaulting_to_pandas()
         else:
-            warning_catcher = _nullcontext()
+            warning_catcher = contextlib.nullcontext()
         with warning_catcher:
             modin_result = pd.merge(
                 modin_df, modin_df2, how=how, left_on="col2", right_on="col2"
@@ -896,7 +890,7 @@ def test_default_to_pandas_warning_message(func, regex):
 
 def test_empty_dataframe():
     df = pd.DataFrame(columns=["a", "b"])
-    with warns_that_defaulting_to_pandas() if StorageFormat.get() != "Hdk" else _nullcontext():
+    with warns_that_defaulting_to_pandas() if StorageFormat.get() != "Hdk" else contextlib.nullcontext():
         df[(df.a == 1) & (df.b == 2)]
 
 
diff --git a/modin/pandas/test/test_io.py b/modin/pandas/test/test_io.py
--- a/modin/pandas/test/test_io.py
+++ b/modin/pandas/test/test_io.py
@@ -115,12 +115,6 @@
 }
 
 
-@contextlib.contextmanager
-def _nullcontext():
-    """Replacement for contextlib.nullcontext missing in older Python."""
-    yield
-
-
 def assert_files_eq(path1, path2):
     with open(path1, "rb") as file1, open(path2, "rb") as file2:
         file1_content = file1.read()
@@ -1317,7 +1311,7 @@ def _check_relative_io(fn_name, unique_filename, path_arg, storage_default=()):
     pinned_home = {envvar: dirname for envvar in ("HOME", "USERPROFILE", "HOMEPATH")}
     should_default = Engine.get() == "Python" or StorageFormat.get() in storage_default
     with mock.patch.dict(os.environ, pinned_home):
-        with warns_that_defaulting_to_pandas() if should_default else _nullcontext():
+        with warns_that_defaulting_to_pandas() if should_default else contextlib.nullcontext():
             eval_io(
                 fn_name=fn_name,
                 **{path_arg: f"~/{basename}"},