Repository: modin-project/modin

Issue:
FEAT: Support sqlalchemy connections in read_sql by converting them to strings
We can use the trick that we use [here](https://github.com/modin-project/modin/blob/01c529cf06cfaf412b5725f41c81a5f914b44b95/modin/core/io/sql/sql_dispatcher.py#L152) for `to_sql` to support reading from sqlalchemy connections in `read_sql`. Currently, for the distributed read, we [require](https://github.com/modin-project/modin/blob/01c529cf06cfaf412b5725f41c81a5f914b44b95/modin/core/io/sql/sql_dispatcher.py#L64) the user to supply a connection string or a `ModinDatabaseConnection` object that usually contains their credentials. Otherwise we default to pandas.


Discussion:

Resolving patch:
diff --git a/modin/core/io/sql/sql_dispatcher.py b/modin/core/io/sql/sql_dispatcher.py
--- a/modin/core/io/sql/sql_dispatcher.py
+++ b/modin/core/io/sql/sql_dispatcher.py
@@ -32,6 +32,17 @@
 class SQLDispatcher(FileDispatcher):
     """Class handles utils for reading SQL queries or database tables."""
 
+    @classmethod
+    def _is_supported_sqlalchemy_object(cls, obj):  # noqa: GL08
+        supported = None
+        try:
+            import sqlalchemy as sa
+
+            supported = isinstance(obj, (sa.engine.Engine, sa.engine.Connection))
+        except ImportError:
+            supported = False
+        return supported
+
     @classmethod
     def _read(cls, sql, con, index_col=None, **kwargs):
         """
@@ -55,6 +66,12 @@ def _read(cls, sql, con, index_col=None, **kwargs):
         """
         if isinstance(con, str):
             con = ModinDatabaseConnection("sqlalchemy", con)
+
+        if cls._is_supported_sqlalchemy_object(con):
+            con = ModinDatabaseConnection(
+                "sqlalchemy", con.engine.url.render_as_string(hide_password=False)
+            )
+
         if not isinstance(con, ModinDatabaseConnection):
             return cls.single_worker_read(
                 sql,
@@ -62,7 +79,7 @@ def _read(cls, sql, con, index_col=None, **kwargs):
                 index_col=index_col,
                 read_sql_engine=ReadSqlEngine.get(),
                 reason="To use the parallel implementation of `read_sql`, pass either "
-                + "the SQL connection string or a ModinDatabaseConnection "
+                + "a SQLAlchemy connectable, the SQL connection string, or a ModinDatabaseConnection "
                 + "with the arguments required to make a connection, instead "
                 + f"of {type(con)}. For documentation on the ModinDatabaseConnection, see "
                 + "https://modin.readthedocs.io/en/latest/supported_apis/io_supported.html#connecting-to-a-database-for-read-sql",
@@ -111,17 +128,6 @@ def _read(cls, sql, con, index_col=None, **kwargs):
         new_frame.synchronize_labels(axis=0)
         return cls.query_compiler_cls(new_frame)
 
-    @classmethod
-    def _is_supported_sqlalchemy_object(cls, obj):  # noqa: GL08
-        supported = None
-        try:
-            import sqlalchemy as sa
-
-            supported = isinstance(obj, (sa.engine.Engine, sa.engine.Connection))
-        except ImportError:
-            supported = False
-        return supported
-
     @classmethod
     def write(cls, qc, **kwargs):
         """


Test patch: