Repository: modin-project/modin

Issue:
Provide the ability to use experimental functionality when experimental mode is not enabled globally via an environment variable.
Example where it can be useful:

```python
import modin.pandas as pd

df = pd.DataFrame([1,2,3,4])
# [some code]

with modin.utils.enable_exp_mode():
    # this import has side effects that will need to be removed when leaving the context
    # for example:
    # 1. `IsExperimental.put(True)` 
    # 2. `setattr(DataFrame, "to_pickle_distributed", to_pickle_distributed)`
    # 3. Modification of internal factory and IO classes
    from modin.experimental.pandas import read_pickle_distributed, to_pickle_distributed
    to_pickle_distributed(df, "test_file*.pkl")
    # [some code]
    new_df = read_pickle_distributed("test_file*.pkl")
```


Discussion:

Patch:
diff --git a/modin/core/execution/dask/implementations/pandas_on_dask/io/io.py b/modin/core/execution/dask/implementations/pandas_on_dask/io/io.py
--- a/modin/core/execution/dask/implementations/pandas_on_dask/io/io.py
+++ b/modin/core/execution/dask/implementations/pandas_on_dask/io/io.py
@@ -31,6 +31,9 @@
     SQLDispatcher,
 )
 from modin.core.storage_formats.pandas.parsers import (
+    ExperimentalCustomTextParser,
+    ExperimentalPandasPickleParser,
+    PandasCSVGlobParser,
     PandasCSVParser,
     PandasExcelParser,
     PandasFeatherParser,
@@ -40,6 +43,12 @@
     PandasSQLParser,
 )
 from modin.core.storage_formats.pandas.query_compiler import PandasQueryCompiler
+from modin.experimental.core.io import (
+    ExperimentalCSVGlobDispatcher,
+    ExperimentalCustomTextDispatcher,
+    ExperimentalPickleDispatcher,
+    ExperimentalSQLDispatcher,
+)
 
 
 class PandasOnDaskIO(BaseIO):
@@ -74,5 +83,18 @@ def __make_write(*classes, build_args=build_args):
     to_sql = __make_write(SQLDispatcher)
     read_excel = __make_read(PandasExcelParser, ExcelDispatcher)
 
+    # experimental methods that don't exist in pandas
+    read_csv_glob = __make_read(PandasCSVGlobParser, ExperimentalCSVGlobDispatcher)
+    read_pickle_distributed = __make_read(
+        ExperimentalPandasPickleParser, ExperimentalPickleDispatcher
+    )
+    to_pickle_distributed = __make_write(ExperimentalPickleDispatcher)
+    read_custom_text = __make_read(
+        ExperimentalCustomTextParser, ExperimentalCustomTextDispatcher
+    )
+    read_sql_distributed = __make_read(
+        ExperimentalSQLDispatcher, build_args={**build_args, "base_read": read_sql}
+    )
+
     del __make_read  # to not pollute class namespace
     del __make_write  # to not pollute class namespace
diff --git a/modin/core/execution/dispatching/factories/dispatcher.py b/modin/core/execution/dispatching/factories/dispatcher.py
--- a/modin/core/execution/dispatching/factories/dispatcher.py
+++ b/modin/core/execution/dispatching/factories/dispatcher.py
@@ -118,41 +118,33 @@ def get_factory(cls) -> factories.BaseFactory:
         return cls.__factory
 
     @classmethod
-    # FIXME: replace `_` parameter with `*args`
-    def _update_factory(cls, _):
+    def _update_factory(cls, *args):
         """
         Update and prepare factory with a new one specified via Modin config.
 
         Parameters
         ----------
-        _ : object
+        *args : iterable
             This parameters serves the compatibility purpose.
             Does not affect the result.
         """
         factory_name = get_current_execution() + "Factory"
+        experimental_factory_name = "Experimental" + factory_name
         try:
-            cls.__factory = getattr(factories, factory_name)
+            cls.__factory = getattr(factories, factory_name, None) or getattr(
+                factories, experimental_factory_name
+            )
         except AttributeError:
-            if factory_name == "ExperimentalOmnisciOnRayFactory":
+            if not IsExperimental.get():
+                # allow missing factories in experimental mode only
                 msg = (
-                    "OmniSci storage format no longer needs Ray engine; "
-                    + "please specify MODIN_ENGINE='native'"
+                    "Cannot find neither factory {} nor experimental factory {}. "
+                    + "Potential reason might be incorrect environment variable value for "
+                    + f"{StorageFormat.varname} or {Engine.varname}"
+                )
+                raise FactoryNotFoundError(
+                    msg.format(factory_name, experimental_factory_name)
                 )
-                raise FactoryNotFoundError(msg)
-            if not IsExperimental.get():
-                # allow missing factories in experimenal mode only
-                if hasattr(factories, "Experimental" + factory_name):
-                    msg = (
-                        "{0} is only accessible through the experimental API.\nRun "
-                        + "`import modin.experimental.pandas as pd` to use {0}."
-                    )
-                else:
-                    msg = (
-                        "Cannot find factory {}. "
-                        + "Potential reason might be incorrect environment variable value for "
-                        + f"{StorageFormat.varname} or {Engine.varname}"
-                    )
-                raise FactoryNotFoundError(msg.format(factory_name))
             cls.__factory = StubFactory.set_failing_name(factory_name)
         else:
             try:
@@ -200,14 +192,12 @@ def read_csv(cls, **kwargs):
         return cls.get_factory()._read_csv(**kwargs)
 
     @classmethod
-    @_inherit_docstrings(factories.ExperimentalPandasOnRayFactory._read_csv_glob)
+    @_inherit_docstrings(factories.PandasOnRayFactory._read_csv_glob)
     def read_csv_glob(cls, **kwargs):
         return cls.get_factory()._read_csv_glob(**kwargs)
 
     @classmethod
-    @_inherit_docstrings(
-        factories.ExperimentalPandasOnRayFactory._read_pickle_distributed
-    )
+    @_inherit_docstrings(factories.PandasOnRayFactory._read_pickle_distributed)
     def read_pickle_distributed(cls, **kwargs):
         return cls.get_factory()._read_pickle_distributed(**kwargs)
 
@@ -266,6 +256,11 @@ def read_pickle(cls, **kwargs):
     def read_sql(cls, **kwargs):
         return cls.get_factory()._read_sql(**kwargs)
 
+    @classmethod
+    @_inherit_docstrings(factories.PandasOnRayFactory._read_sql_distributed)
+    def read_sql_distributed(cls, **kwargs):
+        return cls.get_factory()._read_sql_distributed(**kwargs)
+
     @classmethod
     @_inherit_docstrings(factories.BaseFactory._read_fwf)
     def read_fwf(cls, **kwargs):
@@ -297,14 +292,12 @@ def to_pickle(cls, *args, **kwargs):
         return cls.get_factory()._to_pickle(*args, **kwargs)
 
     @classmethod
-    @_inherit_docstrings(
-        factories.ExperimentalPandasOnRayFactory._to_pickle_distributed
-    )
+    @_inherit_docstrings(factories.PandasOnRayFactory._to_pickle_distributed)
     def to_pickle_distributed(cls, *args, **kwargs):
         return cls.get_factory()._to_pickle_distributed(*args, **kwargs)
 
     @classmethod
-    @_inherit_docstrings(factories.ExperimentalPandasOnRayFactory._read_custom_text)
+    @_inherit_docstrings(factories.PandasOnRayFactory._read_custom_text)
     def read_custom_text(cls, **kwargs):
         return cls.get_factory()._read_custom_text(**kwargs)
 
diff --git a/modin/core/execution/dispatching/factories/factories.py b/modin/core/execution/dispatching/factories/factories.py
--- a/modin/core/execution/dispatching/factories/factories.py
+++ b/modin/core/execution/dispatching/factories/factories.py
@@ -26,9 +26,9 @@
 import pandas
 from pandas.util._decorators import doc
 
-from modin.config import Engine
+from modin.config import IsExperimental
 from modin.core.io import BaseIO
-from modin.utils import _inherit_docstrings, get_current_execution
+from modin.utils import get_current_execution
 
 _doc_abstract_factory_class = """
 Abstract {role} factory which allows to override the IO module easily.
@@ -93,10 +93,10 @@
 
 types_dictionary = {"pandas": {"category": pandas.CategoricalDtype}}
 
-supported_execution = (
-    "ExperimentalPandasOnRay",
-    "ExperimentalPandasOnUnidist",
-    "ExperimentalPandasOnDask",
+supported_executions = (
+    "PandasOnRay",
+    "PandasOnUnidist",
+    "PandasOnDask",
 )
 
 
@@ -427,86 +427,7 @@ def _to_parquet(cls, *args, **kwargs):
         """
         return cls.io_cls.to_parquet(*args, **kwargs)
 
-
-@doc(_doc_factory_class, execution_name="cuDFOnRay")
-class CudfOnRayFactory(BaseFactory):
-    @classmethod
-    @doc(_doc_factory_prepare_method, io_module_name="``cuDFOnRayIO``")
-    def prepare(cls):
-        from modin.core.execution.ray.implementations.cudf_on_ray.io import cuDFOnRayIO
-
-        cls.io_cls = cuDFOnRayIO
-
-
-@doc(_doc_factory_class, execution_name="PandasOnRay")
-class PandasOnRayFactory(BaseFactory):
-    @classmethod
-    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnRayIO``")
-    def prepare(cls):
-        from modin.core.execution.ray.implementations.pandas_on_ray.io import (
-            PandasOnRayIO,
-        )
-
-        cls.io_cls = PandasOnRayIO
-
-
-@doc(_doc_factory_class, execution_name="PandasOnPython")
-class PandasOnPythonFactory(BaseFactory):
-    @classmethod
-    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnPythonIO``")
-    def prepare(cls):
-        from modin.core.execution.python.implementations.pandas_on_python.io import (
-            PandasOnPythonIO,
-        )
-
-        cls.io_cls = PandasOnPythonIO
-
-
-@doc(_doc_factory_class, execution_name="PandasOnDask")
-class PandasOnDaskFactory(BaseFactory):
-    @classmethod
-    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnDaskIO``")
-    def prepare(cls):
-        from modin.core.execution.dask.implementations.pandas_on_dask.io import (
-            PandasOnDaskIO,
-        )
-
-        cls.io_cls = PandasOnDaskIO
-
-
-@doc(_doc_abstract_factory_class, role="experimental")
-class ExperimentalBaseFactory(BaseFactory):
-    @classmethod
-    @_inherit_docstrings(BaseFactory._read_sql)
-    def _read_sql(cls, **kwargs):
-        supported_engines = ("Ray", "Unidist", "Dask")
-        if Engine.get() not in supported_engines:
-            if "partition_column" in kwargs:
-                if kwargs["partition_column"] is not None:
-                    warnings.warn(
-                        f"Distributed read_sql() was only implemented for {', '.join(supported_engines)} engines."
-                    )
-                del kwargs["partition_column"]
-            if "lower_bound" in kwargs:
-                if kwargs["lower_bound"] is not None:
-                    warnings.warn(
-                        f"Distributed read_sql() was only implemented for {', '.join(supported_engines)} engines."
-                    )
-                del kwargs["lower_bound"]
-            if "upper_bound" in kwargs:
-                if kwargs["upper_bound"] is not None:
-                    warnings.warn(
-                        f"Distributed read_sql() was only implemented for {', '.join(supported_engines)} engines."
-                    )
-                del kwargs["upper_bound"]
-            if "max_sessions" in kwargs:
-                if kwargs["max_sessions"] is not None:
-                    warnings.warn(
-                        f"Distributed read_sql() was only implemented for {', '.join(supported_engines)} engines."
-                    )
-                del kwargs["max_sessions"]
-        return cls.io_cls.read_sql(**kwargs)
-
+    # experimental methods that don't exist in pandas
     @classmethod
     @doc(
         _doc_io_method_raw_template,
@@ -515,7 +436,7 @@ def _read_sql(cls, **kwargs):
     )
     def _read_csv_glob(cls, **kwargs):
         current_execution = get_current_execution()
-        if current_execution not in supported_execution:
+        if current_execution not in supported_executions:
             raise NotImplementedError(
                 f"`_read_csv_glob()` is not implemented for {current_execution} execution."
             )
@@ -529,12 +450,39 @@ def _read_csv_glob(cls, **kwargs):
     )
     def _read_pickle_distributed(cls, **kwargs):
         current_execution = get_current_execution()
-        if current_execution not in supported_execution:
+        if current_execution not in supported_executions:
             raise NotImplementedError(
                 f"`_read_pickle_distributed()` is not implemented for {current_execution} execution."
             )
         return cls.io_cls.read_pickle_distributed(**kwargs)
 
+    @classmethod
+    @doc(
+        _doc_io_method_raw_template,
+        source="SQL files",
+        params=_doc_io_method_kwargs_params,
+    )
+    def _read_sql_distributed(cls, **kwargs):
+        current_execution = get_current_execution()
+        if current_execution not in supported_executions:
+            extra_parameters = (
+                "partition_column",
+                "lower_bound",
+                "upper_bound",
+                "max_sessions",
+            )
+            if any(
+                param in kwargs and kwargs[param] is not None
+                for param in extra_parameters
+            ):
+                warnings.warn(
+                    f"Distributed read_sql() was only implemented for {', '.join(supported_executions)} executions."
+                )
+            for param in extra_parameters:
+                del kwargs[param]
+            return cls.io_cls.read_sql(**kwargs)
+        return cls.io_cls.read_sql_distributed(**kwargs)
+
     @classmethod
     @doc(
         _doc_io_method_raw_template,
@@ -543,7 +491,7 @@ def _read_pickle_distributed(cls, **kwargs):
     )
     def _read_custom_text(cls, **kwargs):
         current_execution = get_current_execution()
-        if current_execution not in supported_execution:
+        if current_execution not in supported_executions:
             raise NotImplementedError(
                 f"`_read_custom_text()` is not implemented for {current_execution} execution."
             )
@@ -562,40 +510,64 @@ def _to_pickle_distributed(cls, *args, **kwargs):
             Arguments to the writer method.
         """
         current_execution = get_current_execution()
-        if current_execution not in supported_execution:
+        if current_execution not in supported_executions:
             raise NotImplementedError(
                 f"`_to_pickle_distributed()` is not implemented for {current_execution} execution."
             )
         return cls.io_cls.to_pickle_distributed(*args, **kwargs)
 
 
-@doc(_doc_factory_class, execution_name="experimental PandasOnRay")
-class ExperimentalPandasOnRayFactory(ExperimentalBaseFactory, PandasOnRayFactory):
+@doc(_doc_factory_class, execution_name="PandasOnRay")
+class PandasOnRayFactory(BaseFactory):
     @classmethod
-    @doc(_doc_factory_prepare_method, io_module_name="``ExperimentalPandasOnRayIO``")
+    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnRayIO``")
     def prepare(cls):
-        from modin.experimental.core.execution.ray.implementations.pandas_on_ray.io import (
-            ExperimentalPandasOnRayIO,
+        from modin.core.execution.ray.implementations.pandas_on_ray.io import (
+            PandasOnRayIO,
         )
 
-        cls.io_cls = ExperimentalPandasOnRayIO
+        cls.io_cls = PandasOnRayIO
 
 
-@doc(_doc_factory_class, execution_name="experimental PandasOnDask")
-class ExperimentalPandasOnDaskFactory(ExperimentalBaseFactory, PandasOnDaskFactory):
+@doc(_doc_factory_class, execution_name="PandasOnPython")
+class PandasOnPythonFactory(BaseFactory):
     @classmethod
-    @doc(_doc_factory_prepare_method, io_module_name="``ExperimentalPandasOnDaskIO``")
+    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnPythonIO``")
     def prepare(cls):
-        from modin.experimental.core.execution.dask.implementations.pandas_on_dask.io import (
-            ExperimentalPandasOnDaskIO,
+        from modin.core.execution.python.implementations.pandas_on_python.io import (
+            PandasOnPythonIO,
         )
 
-        cls.io_cls = ExperimentalPandasOnDaskIO
+        cls.io_cls = PandasOnPythonIO
 
 
-@doc(_doc_factory_class, execution_name="experimental PandasOnPython")
-class ExperimentalPandasOnPythonFactory(ExperimentalBaseFactory, PandasOnPythonFactory):
-    pass
+@doc(_doc_factory_class, execution_name="PandasOnDask")
+class PandasOnDaskFactory(BaseFactory):
+    @classmethod
+    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnDaskIO``")
+    def prepare(cls):
+        from modin.core.execution.dask.implementations.pandas_on_dask.io import (
+            PandasOnDaskIO,
+        )
+
+        cls.io_cls = PandasOnDaskIO
+
+
+@doc(_doc_factory_class, execution_name="PandasOnUnidist")
+class PandasOnUnidistFactory(BaseFactory):
+    @classmethod
+    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnUnidistIO``")
+    def prepare(cls):
+        from modin.core.execution.unidist.implementations.pandas_on_unidist.io import (
+            PandasOnUnidistIO,
+        )
+
+        cls.io_cls = PandasOnUnidistIO
+
+
+# EXPERIMENTAL FACTORIES
+# Factories that operate only in experimental mode. They provide access to executions
+# that have little coverage of implemented functionality or are not stable enough.
 
 
 @doc(_doc_factory_class, execution_name="experimental PyarrowOnRay")
@@ -607,6 +579,9 @@ def prepare(cls):
             PyarrowOnRayIO,
         )
 
+        if not IsExperimental.get():
+            raise ValueError("'PyarrowOnRay' only works in experimental mode.")
+
         cls.io_cls = PyarrowOnRayIO
 
 
@@ -619,32 +594,20 @@ def prepare(cls):
             HdkOnNativeIO,
         )
 
+        if not IsExperimental.get():
+            raise ValueError("'HdkOnNative' only works in experimental mode.")
+
         cls.io_cls = HdkOnNativeIO
 
 
-@doc(_doc_factory_class, execution_name="PandasOnUnidist")
-class PandasOnUnidistFactory(BaseFactory):
+@doc(_doc_factory_class, execution_name="cuDFOnRay")
+class ExperimentalCudfOnRayFactory(BaseFactory):
     @classmethod
-    @doc(_doc_factory_prepare_method, io_module_name="``PandasOnUnidistIO``")
+    @doc(_doc_factory_prepare_method, io_module_name="``cuDFOnRayIO``")
     def prepare(cls):
-        from modin.core.execution.unidist.implementations.pandas_on_unidist.io import (
-            PandasOnUnidistIO,
-        )
-
-        cls.io_cls = PandasOnUnidistIO
-
+        from modin.core.execution.ray.implementations.cudf_on_ray.io import cuDFOnRayIO
 
-@doc(_doc_factory_class, execution_name="experimental PandasOnUnidist")
-class ExperimentalPandasOnUnidistFactory(
-    ExperimentalBaseFactory, PandasOnUnidistFactory
-):
-    @classmethod
-    @doc(
-        _doc_factory_prepare_method, io_module_name="``ExperimentalPandasOnUnidistIO``"
-    )
-    def prepare(cls):
-        from modin.experimental.core.execution.unidist.implementations.pandas_on_unidist.io import (
-            ExperimentalPandasOnUnidistIO,
-        )
+        if not IsExperimental.get():
+            raise ValueError("'CudfOnRay' only works in experimental mode.")
 
-        cls.io_cls = ExperimentalPandasOnUnidistIO
+        cls.io_cls = cuDFOnRayIO
diff --git a/modin/core/execution/ray/implementations/pandas_on_ray/io/io.py b/modin/core/execution/ray/implementations/pandas_on_ray/io/io.py
--- a/modin/core/execution/ray/implementations/pandas_on_ray/io/io.py
+++ b/modin/core/execution/ray/implementations/pandas_on_ray/io/io.py
@@ -30,6 +30,9 @@
     SQLDispatcher,
 )
 from modin.core.storage_formats.pandas.parsers import (
+    ExperimentalCustomTextParser,
+    ExperimentalPandasPickleParser,
+    PandasCSVGlobParser,
     PandasCSVParser,
     PandasExcelParser,
     PandasFeatherParser,
@@ -39,6 +42,12 @@
     PandasSQLParser,
 )
 from modin.core.storage_formats.pandas.query_compiler import PandasQueryCompiler
+from modin.experimental.core.io import (
+    ExperimentalCSVGlobDispatcher,
+    ExperimentalCustomTextDispatcher,
+    ExperimentalPickleDispatcher,
+    ExperimentalSQLDispatcher,
+)
 
 from ..dataframe import PandasOnRayDataframe
 from ..partitioning import PandasOnRayDataframePartition
@@ -76,6 +85,19 @@ def __make_write(*classes, build_args=build_args):
     to_sql = __make_write(SQLDispatcher)
     read_excel = __make_read(PandasExcelParser, ExcelDispatcher)
 
+    # experimental methods that don't exist in pandas
+    read_csv_glob = __make_read(PandasCSVGlobParser, ExperimentalCSVGlobDispatcher)
+    read_pickle_distributed = __make_read(
+        ExperimentalPandasPickleParser, ExperimentalPickleDispatcher
+    )
+    to_pickle_distributed = __make_write(ExperimentalPickleDispatcher)
+    read_custom_text = __make_read(
+        ExperimentalCustomTextParser, ExperimentalCustomTextDispatcher
+    )
+    read_sql_distributed = __make_read(
+        ExperimentalSQLDispatcher, build_args={**build_args, "base_read": read_sql}
+    )
+
     del __make_read  # to not pollute class namespace
     del __make_write  # to not pollute class namespace
 
diff --git a/modin/core/execution/unidist/implementations/pandas_on_unidist/io/io.py b/modin/core/execution/unidist/implementations/pandas_on_unidist/io/io.py
--- a/modin/core/execution/unidist/implementations/pandas_on_unidist/io/io.py
+++ b/modin/core/execution/unidist/implementations/pandas_on_unidist/io/io.py
@@ -29,6 +29,9 @@
     SQLDispatcher,
 )
 from modin.core.storage_formats.pandas.parsers import (
+    ExperimentalCustomTextParser,
+    ExperimentalPandasPickleParser,
+    PandasCSVGlobParser,
     PandasCSVParser,
     PandasExcelParser,
     PandasFeatherParser,
@@ -38,6 +41,12 @@
     PandasSQLParser,
 )
 from modin.core.storage_formats.pandas.query_compiler import PandasQueryCompiler
+from modin.experimental.core.io import (
+    ExperimentalCSVGlobDispatcher,
+    ExperimentalCustomTextDispatcher,
+    ExperimentalPickleDispatcher,
+    ExperimentalSQLDispatcher,
+)
 
 from ..dataframe import PandasOnUnidistDataframe
 from ..partitioning import PandasOnUnidistDataframePartition
@@ -75,6 +84,19 @@ def __make_write(*classes, build_args=build_args):
     to_sql = __make_write(SQLDispatcher)
     read_excel = __make_read(PandasExcelParser, ExcelDispatcher)
 
+    # experimental methods that don't exist in pandas
+    read_csv_glob = __make_read(PandasCSVGlobParser, ExperimentalCSVGlobDispatcher)
+    read_pickle_distributed = __make_read(
+        ExperimentalPandasPickleParser, ExperimentalPickleDispatcher
+    )
+    to_pickle_distributed = __make_write(ExperimentalPickleDispatcher)
+    read_custom_text = __make_read(
+        ExperimentalCustomTextParser, ExperimentalCustomTextDispatcher
+    )
+    read_sql_distributed = __make_read(
+        ExperimentalSQLDispatcher, build_args={**build_args, "base_read": read_sql}
+    )
+
     del __make_read  # to not pollute class namespace
     del __make_write  # to not pollute class namespace
 
diff --git a/modin/experimental/core/execution/dask/implementations/pandas_on_dask/io/__init__.py b/modin/experimental/core/execution/dask/implementations/pandas_on_dask/io/__init__.py
deleted file mode 100644
--- a/modin/experimental/core/execution/dask/implementations/pandas_on_dask/io/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Licensed to Modin Development Team under one or more contributor license agreements.
-# See the NOTICE file distributed with this work for additional information regarding
-# copyright ownership.  The Modin Development Team licenses this file to you under the
-# Apache License, Version 2.0 (the "License"); you may not use this file except in
-# compliance with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software distributed under
-# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
-# ANY KIND, either express or implied. See the License for the specific language
-# governing permissions and limitations under the License.
-
-"""Experimental Base IO classes optimized for pandas on Dask execution."""
-
-from .io import ExperimentalPandasOnDaskIO
-
-__all__ = ["ExperimentalPandasOnDaskIO"]
diff --git a/modin/experimental/core/execution/dask/implementations/pandas_on_dask/io/io.py b/modin/experimental/core/execution/dask/implementations/pandas_on_dask/io/io.py
deleted file mode 100644
--- a/modin/experimental/core/execution/dask/implementations/pandas_on_dask/io/io.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Licensed to Modin Development Team under one or more contributor license agreements.
-# See the NOTICE file distributed with this work for additional information regarding
-# copyright ownership.  The Modin Development Team licenses this file to you under the
-# Apache License, Version 2.0 (the "License"); you may not use this file except in
-# compliance with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software distributed under
-# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
-# ANY KIND, either express or implied. See the License for the specific language
-# governing permissions and limitations under the License.
-
-"""
-Module houses experimental IO classes and parser functions needed for these classes.
-
-Any function or class can be considered experimental API if it is not strictly replicating existent
-Query Compiler API, even if it is only extending the API.
-"""
-
-from modin.core.execution.dask.common import DaskWrapper
-from modin.core.execution.dask.implementations.pandas_on_dask.dataframe import (
-    PandasOnDaskDataframe,
-)
-from modin.core.execution.dask.implementations.pandas_on_dask.io import PandasOnDaskIO
-from modin.core.execution.dask.implementations.pandas_on_dask.partitioning import (
-    PandasOnDaskDataframePartition,
-)
-from modin.core.storage_formats.pandas.parsers import (
-    ExperimentalCustomTextParser,
-    ExperimentalPandasPickleParser,
-    PandasCSVGlobParser,
-)
-from modin.core.storage_formats.pandas.query_compiler import PandasQueryCompiler
-from modin.experimental.core.io import (
-    ExperimentalCSVGlobDispatcher,
-    ExperimentalCustomTextDispatcher,
-    ExperimentalPickleDispatcher,
-    ExperimentalSQLDispatcher,
-)
-
-
-class ExperimentalPandasOnDaskIO(PandasOnDaskIO):
-    """
-    Class for handling experimental IO functionality with pandas storage format and Dask engine.
-
-    ``ExperimentalPandasOnDaskIO`` inherits some util functions and unmodified IO functions
-    from ``PandasOnDaskIO`` class.
-    """
-
-    build_args = dict(
-        frame_partition_cls=PandasOnDaskDataframePartition,
-        query_compiler_cls=PandasQueryCompiler,
-        frame_cls=PandasOnDaskDataframe,
-        base_io=PandasOnDaskIO,
-    )
-
-    def __make_read(*classes, build_args=build_args):
-        # used to reduce code duplication
-        return type("", (DaskWrapper, *classes), build_args).read
-
-    def __make_write(*classes, build_args=build_args):
-        # used to reduce code duplication
-        return type("", (DaskWrapper, *classes), build_args).write
-
-    read_csv_glob = __make_read(PandasCSVGlobParser, ExperimentalCSVGlobDispatcher)
-    read_pickle_distributed = __make_read(
-        ExperimentalPandasPickleParser, ExperimentalPickleDispatcher
-    )
-    to_pickle_distributed = __make_write(ExperimentalPickleDispatcher)
-    read_custom_text = __make_read(
-        ExperimentalCustomTextParser, ExperimentalCustomTextDispatcher
-    )
-    read_sql = __make_read(ExperimentalSQLDispatcher)
-
-    del __make_read  # to not pollute class namespace
-    del __make_write  # to not pollute class namespace
diff --git a/modin/experimental/core/execution/ray/implementations/pandas_on_ray/__init__.py b/modin/experimental/core/execution/ray/implementations/pandas_on_ray/__init__.py
deleted file mode 100644
--- a/modin/experimental/core/execution/ray/implementations/pandas_on_ray/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# Licensed to Modin Development Team under one or more contributor license agreements.
-# See the NOTICE file distributed with this work for additional information regarding
-# copyright ownership.  The Modin Development Team licenses this file to you under the
-# Apache License, Version 2.0 (the "License"); you may not use this file except in
-# compliance with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software distributed under
-# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
-# ANY KIND, either express or implied. See the License for the specific language
-# governing permissions and limitations under the License.
-
-"""Experimental functionality related to Ray execution engine and optimized for pandas storage format."""
diff --git a/modin/experimental/core/execution/ray/implementations/pandas_on_ray/io/__init__.py b/modin/experimental/core/execution/ray/implementations/pandas_on_ray/io/__init__.py
deleted file mode 100644
--- a/modin/experimental/core/execution/ray/implementations/pandas_on_ray/io/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Licensed to Modin Development Team under one or more contributor license agreements.
-# See the NOTICE file distributed with this work for additional information regarding
-# copyright ownership.  The Modin Development Team licenses this file to you under the
-# Apache License, Version 2.0 (the "License"); you may not use this file except in
-# compliance with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software distributed under
-# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
-# ANY KIND, either express or implied. See the License for the specific language
-# governing permissions and limitations under the License.
-
-"""Experimental Base IO classes optimized for pandas on Ray execution."""
-
-from .io import ExperimentalPandasOnRayIO
-
-__all__ = ["ExperimentalPandasOnRayIO"]
diff --git a/modin/experimental/core/execution/ray/implementations/pandas_on_ray/io/io.py b/modin/experimental/core/execution/ray/implementations/pandas_on_ray/io/io.py
deleted file mode 100644
--- a/modin/experimental/core/execution/ray/implementations/pandas_on_ray/io/io.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Licensed to Modin Development Team under one or more contributor license agreements.
-# See the NOTICE file distributed with this work for additional information regarding
-# copyright ownership.  The Modin Development Team licenses this file to you under the
-# Apache License, Version 2.0 (the "License"); you may not use this file except in
-# compliance with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software distributed under
-# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
-# ANY KIND, either express or implied. See the License for the specific language
-# governing permissions and limitations under the License.
-
-"""
-Module houses experimental IO classes and parser functions needed for these classes.
-
-Any function or class can be considered experimental API if it is not strictly replicating existent
-Query Compiler API, even if it is only extending the API.
-"""
-
-from modin.core.execution.ray.common import RayWrapper
-from modin.core.execution.ray.implementations.pandas_on_ray.dataframe import (
-    PandasOnRayDataframe,
-)
-from modin.core.execution.ray.implementations.pandas_on_ray.io import PandasOnRayIO
-from modin.core.execution.ray.implementations.pandas_on_ray.partitioning import (
-    PandasOnRayDataframePartition,
-)
-from modin.core.storage_formats.pandas.parsers import (
-    ExperimentalCustomTextParser,
-    ExperimentalPandasPickleParser,
-    PandasCSVGlobParser,
-)
-from modin.core.storage_formats.pandas.query_compiler import PandasQueryCompiler
-from modin.experimental.core.io import (
-    ExperimentalCSVGlobDispatcher,
-    ExperimentalCustomTextDispatcher,
-    ExperimentalPickleDispatcher,
-    ExperimentalSQLDispatcher,
-)
-
-
-class ExperimentalPandasOnRayIO(PandasOnRayIO):
-    """
-    Class for handling experimental IO functionality with pandas storage format and Ray engine.
-
-    ``ExperimentalPandasOnRayIO`` inherits some util functions and unmodified IO functions
-    from ``PandasOnRayIO`` class.
-    """
-
-    build_args = dict(
-        frame_partition_cls=PandasOnRayDataframePartition,
-        query_compiler_cls=PandasQueryCompiler,
-        frame_cls=PandasOnRayDataframe,
-        base_io=PandasOnRayIO,
-    )
-
-    def __make_read(*classes, build_args=build_args):
-        # used to reduce code duplication
-        return type("", (RayWrapper, *classes), build_args).read
-
-    def __make_write(*classes, build_args=build_args):
-        # used to reduce code duplication
-        return type("", (RayWrapper, *classes), build_args).write
-
-    read_csv_glob = __make_read(PandasCSVGlobParser, ExperimentalCSVGlobDispatcher)
-    read_pickle_distributed = __make_read(
-        ExperimentalPandasPickleParser, ExperimentalPickleDispatcher
-    )
-    to_pickle_distributed = __make_write(ExperimentalPickleDispatcher)
-    read_custom_text = __make_read(
-        ExperimentalCustomTextParser, ExperimentalCustomTextDispatcher
-    )
-    read_sql = __make_read(ExperimentalSQLDispatcher)
-
-    del __make_read  # to not pollute class namespace
-    del __make_write  # to not pollute class namespace
diff --git a/modin/experimental/core/execution/unidist/implementations/pandas_on_unidist/io/__init__.py b/modin/experimental/core/execution/unidist/implementations/pandas_on_unidist/io/__init__.py
deleted file mode 100644
--- a/modin/experimental/core/execution/unidist/implementations/pandas_on_unidist/io/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Licensed to Modin Development Team under one or more contributor license agreements.
-# See the NOTICE file distributed with this work for additional information regarding
-# copyright ownership.  The Modin Development Team licenses this file to you under the
-# Apache License, Version 2.0 (the "License"); you may not use this file except in
-# compliance with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software distributed under
-# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
-# ANY KIND, either express or implied. See the License for the specific language
-# governing permissions and limitations under the License.
-
-"""Experimental Base IO classes optimized for pandas on unidist execution."""
-
-from .io import ExperimentalPandasOnUnidistIO
-
-__all__ = ["ExperimentalPandasOnUnidistIO"]
diff --git a/modin/experimental/core/execution/unidist/implementations/pandas_on_unidist/io/io.py b/modin/experimental/core/execution/unidist/implementations/pandas_on_unidist/io/io.py
deleted file mode 100644
--- a/modin/experimental/core/execution/unidist/implementations/pandas_on_unidist/io/io.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# Licensed to Modin Development Team under one or more contributor license agreements.
-# See the NOTICE file distributed with this work for additional information regarding
-# copyright ownership.  The Modin Development Team licenses this file to you under the
-# Apache License, Version 2.0 (the "License"); you may not use this file except in
-# compliance with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software distributed under
-# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
-# ANY KIND, either express or implied. See the License for the specific language
-# governing permissions and limitations under the License.
-
-"""
-Module houses experimental IO classes and parser functions needed for these classes.
-
-Any function or class can be considered experimental API if it is not strictly replicating existent
-Query Compiler API, even if it is only extending the API.
-"""
-
-from modin.core.execution.unidist.common import UnidistWrapper
-from modin.core.execution.unidist.implementations.pandas_on_unidist.dataframe import (
-    PandasOnUnidistDataframe,
-)
-from modin.core.execution.unidist.implementations.pandas_on_unidist.io import (
-    PandasOnUnidistIO,
-)
-from modin.core.execution.unidist.implementations.pandas_on_unidist.partitioning import (
-    PandasOnUnidistDataframePartition,
-)
-from modin.core.storage_formats.pandas.parsers import (
-    ExperimentalCustomTextParser,
-    ExperimentalPandasPickleParser,
-    PandasCSVGlobParser,
-)
-from modin.core.storage_formats.pandas.query_compiler import PandasQueryCompiler
-from modin.experimental.core.io import (
-    ExperimentalCSVGlobDispatcher,
-    ExperimentalCustomTextDispatcher,
-    ExperimentalPickleDispatcher,
-    ExperimentalSQLDispatcher,
-)
-
-
-class ExperimentalPandasOnUnidistIO(PandasOnUnidistIO):
-    """
-    Class for handling experimental IO functionality with pandas storage format and unidist engine.
-
-    ``ExperimentalPandasOnUnidistIO`` inherits some util functions and unmodified IO functions
-    from ``PandasOnUnidistIO`` class.
-    """
-
-    build_args = dict(
-        frame_partition_cls=PandasOnUnidistDataframePartition,
-        query_compiler_cls=PandasQueryCompiler,
-        frame_cls=PandasOnUnidistDataframe,
-        base_io=PandasOnUnidistIO,
-    )
-
-    def __make_read(*classes, build_args=build_args):
-        # used to reduce code duplication
-        return type("", (UnidistWrapper, *classes), build_args).read
-
-    def __make_write(*classes, build_args=build_args):
-        # used to reduce code duplication
-        return type("", (UnidistWrapper, *classes), build_args).write
-
-    read_csv_glob = __make_read(PandasCSVGlobParser, ExperimentalCSVGlobDispatcher)
-    read_pickle_distributed = __make_read(
-        ExperimentalPandasPickleParser, ExperimentalPickleDispatcher
-    )
-    to_pickle_distributed = __make_write(ExperimentalPickleDispatcher)
-    read_custom_text = __make_read(
-        ExperimentalCustomTextParser, ExperimentalCustomTextDispatcher
-    )
-    read_sql = __make_read(ExperimentalSQLDispatcher)
-
-    del __make_read  # to not pollute class namespace
-    del __make_write  # to not pollute class namespace
diff --git a/modin/experimental/core/io/sql/sql_dispatcher.py b/modin/experimental/core/io/sql/sql_dispatcher.py
--- a/modin/experimental/core/io/sql/sql_dispatcher.py
+++ b/modin/experimental/core/io/sql/sql_dispatcher.py
@@ -72,7 +72,7 @@ def _read(
             message = "Defaulting to Modin core implementation; \
                 'partition_column', 'lower_bound', 'upper_bound' must be different from None"
             warnings.warn(message)
-            return cls.base_io.read_sql(
+            return cls.base_read(
                 sql,
                 con,
                 index_col,
diff --git a/modin/experimental/pandas/__init__.py b/modin/experimental/pandas/__init__.py
--- a/modin/experimental/pandas/__init__.py
+++ b/modin/experimental/pandas/__init__.py
@@ -32,6 +32,8 @@
 >>> df = pd.read_csv_glob("data*.csv")
 """
 
+import functools
+
 from modin.config import IsExperimental
 
 IsExperimental.put(True)
@@ -48,10 +50,17 @@
     to_pickle_distributed,
 )
 
-setattr(DataFrame, "to_pickle_distributed", to_pickle_distributed)  # noqa: F405
+old_to_pickle_distributed = to_pickle_distributed
 
-warnings.warn(
-    "Thank you for using the Modin Experimental pandas API."
-    + "\nPlease note that some of these APIs deviate from pandas in order to "
-    + "provide improved performance."
-)
+
+@functools.wraps(to_pickle_distributed)
+def to_pickle_distributed(*args, **kwargs):
+    warnings.warn(
+        "`DataFrame.to_pickle_distributed` is deprecated and will be removed in a future version. "
+        + "Please use `DataFrame.modin.to_pickle_distributed` instead.",
+        category=FutureWarning,
+    )
+    return old_to_pickle_distributed(*args, **kwargs)
+
+
+setattr(DataFrame, "to_pickle_distributed", to_pickle_distributed)  # noqa: F405
diff --git a/modin/experimental/pandas/io.py b/modin/experimental/pandas/io.py
--- a/modin/experimental/pandas/io.py
+++ b/modin/experimental/pandas/io.py
@@ -115,7 +115,7 @@ def read_sql(
 
     assert IsExperimental.get(), "This only works in experimental mode"
 
-    result = FactoryDispatcher.read_sql(**kwargs)
+    result = FactoryDispatcher.read_sql_distributed(**kwargs)
     if isinstance(result, BaseQueryCompiler):
         return DataFrame(query_compiler=result)
     return (DataFrame(query_compiler=qc) for qc in result)
@@ -316,7 +316,7 @@ def read_pickle_distributed(
 
     This experimental feature provides parallel reading from multiple pickle files which are
     defined by glob pattern. The files must contain parts of one dataframe, which can be
-    obtained, for example, by `to_pickle_distributed` function.
+    obtained, for example, by `DataFrame.modin.to_pickle_distributed` function.
 
     Parameters
     ----------
diff --git a/modin/pandas/accessor.py b/modin/pandas/accessor.py
--- a/modin/pandas/accessor.py
+++ b/modin/pandas/accessor.py
@@ -21,7 +21,10 @@
 CachedAccessor implements API of pandas.core.accessor.CachedAccessor
 """
 
+import pickle
+
 import pandas
+from pandas._typing import CompressionOptions, StorageOptions
 from pandas.core.dtypes.dtypes import SparseDtype
 
 from modin import pandas as pd
@@ -191,3 +194,66 @@ def __get__(self, obj, cls):
         accessor_obj = self._accessor(obj)
         object.__setattr__(obj, self._name, accessor_obj)
         return accessor_obj
+
+
+class ExperimentalFunctions:
+    """
+    Namespace class for accessing experimental Modin functions.
+
+    Parameters
+    ----------
+    data : DataFrame or Series
+        Object to operate on.
+    """
+
+    def __init__(self, data):
+        self._data = data
+
+    def to_pickle_distributed(
+        self,
+        filepath_or_buffer,
+        compression: CompressionOptions = "infer",
+        protocol: int = pickle.HIGHEST_PROTOCOL,
+        storage_options: StorageOptions = None,
+    ):
+        """
+        Pickle (serialize) object to file.
+
+        This experimental feature provides parallel writing into multiple pickle files which are
+        defined by glob pattern, otherwise (without glob pattern) default pandas implementation is used.
+
+        Parameters
+        ----------
+        filepath_or_buffer : str, path object or file-like object
+            File path where the pickled object will be stored.
+        compression : {{'infer', 'gzip', 'bz2', 'zip', 'xz', None}}, default: 'infer'
+            A string representing the compression to use in the output file. By
+            default, infers from the file extension in specified path.
+            Compression mode may be any of the following possible
+            values: {{'infer', 'gzip', 'bz2', 'zip', 'xz', None}}. If compression
+            mode is 'infer' and path_or_buf is path-like, then detect
+            compression mode from the following extensions:
+            '.gz', '.bz2', '.zip' or '.xz'. (otherwise no compression).
+            If dict given and mode is 'zip' or inferred as 'zip', other entries
+            passed as additional compression options.
+        protocol : int, default: pickle.HIGHEST_PROTOCOL
+            Int which indicates which protocol should be used by the pickler,
+            default HIGHEST_PROTOCOL (see `pickle docs <https://docs.python.org/3/library/pickle.html>`_
+            paragraph 12.1.2 for details). The possible  values are 0, 1, 2, 3, 4, 5. A negative value
+            for the protocol parameter is equivalent to setting its value to HIGHEST_PROTOCOL.
+        storage_options : dict, optional
+            Extra options that make sense for a particular storage connection, e.g.
+            host, port, username, password, etc., if using a URL that will be parsed by
+            fsspec, e.g., starting "s3://", "gcs://". An error will be raised if providing
+            this argument with a non-fsspec URL. See the fsspec and backend storage
+            implementation docs for the set of allowed keys and values.
+        """
+        from modin.experimental.pandas.io import to_pickle_distributed
+
+        to_pickle_distributed(
+            self._data,
+            filepath_or_buffer=filepath_or_buffer,
+            compression=compression,
+            protocol=protocol,
+            storage_options=storage_options,
+        )
diff --git a/modin/pandas/dataframe.py b/modin/pandas/dataframe.py
--- a/modin/pandas/dataframe.py
+++ b/modin/pandas/dataframe.py
@@ -53,7 +53,7 @@
     try_cast_to_pandas,
 )
 
-from .accessor import CachedAccessor, SparseFrameAccessor
+from .accessor import CachedAccessor, ExperimentalFunctions, SparseFrameAccessor
 from .base import _ATTRS_NO_LOOKUP, BasePandasDataset
 from .groupby import DataFrameGroupBy
 from .iterator import PartitionIterator
@@ -3187,3 +3187,6 @@ def __reduce__(self):
         return self._inflate_light, (self._query_compiler, pid)
 
     # Persistance support methods - END
+
+    # Namespace for experimental functions
+    modin = CachedAccessor("modin", ExperimentalFunctions)
diff --git a/modin/utils.py b/modin/utils.py
--- a/modin/utils.py
+++ b/modin/utils.py
@@ -695,7 +695,7 @@ def get_current_execution() -> str:
     str
         Returns <StorageFormat>On<Engine>-like string.
     """
-    return f"{'Experimental' if IsExperimental.get() else ''}{StorageFormat.get()}On{Engine.get()}"
+    return f"{StorageFormat.get()}On{Engine.get()}"
 
 
 def instancer(_class: Callable[[], T]) -> T:


Test patch:
diff --git a/modin/core/execution/dispatching/factories/test/test_dispatcher.py b/modin/core/execution/dispatching/factories/test/test_dispatcher.py
--- a/modin/core/execution/dispatching/factories/test/test_dispatcher.py
+++ b/modin/core/execution/dispatching/factories/test/test_dispatcher.py
@@ -113,8 +113,8 @@ def test_factory_switch():
 
 def test_engine_wrong_factory():
     with pytest.raises(FactoryNotFoundError):
-        with _switch_value(StorageFormat, "Pyarrow"):
-            with _switch_value(Engine, "Dask"):
+        with _switch_value(Engine, "Dask"):
+            with _switch_value(StorageFormat, "Pyarrow"):
                 pass
 
 
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
@@ -260,7 +260,7 @@ def test_distributed_pickling(filename, compression):
         if filename_param == test_default_to_pickle_filename
         else contextlib.nullcontext()
     ):
-        df.to_pickle_distributed(filename, compression=compression)
+        df.modin.to_pickle_distributed(filename, compression=compression)
         pickled_df = pd.read_pickle_distributed(filename, compression=compression)
     df_equals(pickled_df, df)
 
diff --git a/modin/pandas/test/test_api.py b/modin/pandas/test/test_api.py
--- a/modin/pandas/test/test_api.py
+++ b/modin/pandas/test/test_api.py
@@ -153,17 +153,21 @@ def test_dataframe_api_equality():
     modin_dir = [obj for obj in dir(pd.DataFrame) if obj[0] != "_"]
     pandas_dir = [obj for obj in dir(pandas.DataFrame) if obj[0] != "_"]
 
-    ignore = ["timetuple"]
+    ignore_in_pandas = ["timetuple"]
+    # modin - namespace for using experimental functionality
+    ignore_in_modin = ["modin"]
     missing_from_modin = set(pandas_dir) - set(modin_dir)
     assert not len(
-        missing_from_modin - set(ignore)
-    ), "Differences found in API: {}".format(len(missing_from_modin - set(ignore)))
+        missing_from_modin - set(ignore_in_pandas)
+    ), "Differences found in API: {}".format(
+        len(missing_from_modin - set(ignore_in_pandas))
+    )
     assert not len(
-        set(modin_dir) - set(pandas_dir)
+        set(modin_dir) - set(ignore_in_modin) - set(pandas_dir)
     ), "Differences found in API: {}".format(set(modin_dir) - set(pandas_dir))
 
     # These have to be checked manually
-    allowed_different = ["to_hdf", "hist"]
+    allowed_different = ["to_hdf", "hist", "modin"]
 
     assert_parameters_eq((pandas.DataFrame, pd.DataFrame), modin_dir, allowed_different)