Search code examples
pythonsqlalchemytype-hintingdatabase-cursor

What is the right type hint for the returned sqlalchemy objects "cursor" and "cursor.fetchall()" records?


In search for the right type hint for a sqlalchemy cursor of a sqlalchemy query, here is an example function:

import sqlalchemy
from typing import Tuple, tuple

def get_cursor_and_records(
    connection, query) -> Tuple[sqlalchemy.engine.cursor?, tuple]:
    """Make a database cursor for the query and fetch the query output
    :param connection: mysqldb connection to db
    :param query: mysql query string
    returns:
     cursor: row-wise data fetch from the db connection's query
     records: List(Tuple([column types...])) output from cursor.fetchall()
    """
    cursor = connection.cursor()
    cursor.execute(query)
    records = cursor.fetchall()
    return cursor, records

The cursor is built with sqlalchemy (in many steps, not just in one step like here):

sqlalchemy.create_engine(
    sqlalchemy.engine.URL.create(**settings), 
    encoding="utf8"
    ).raw_connection().cursor()

The records are then:

cursor.fetchall()`

From Type hinting sqlalchemy query result, it seems to be right to use tuple (as one of three objects to choose from). This shows that -> List[Tuple[int, str, str]] would be right for example. Yet, I use this function for many queries with changing column number and types. Therefore I use tuple, not fully sure about it, though.

What is the right type hint for a sqlalchemy cursor? And if wrong, what is the right type hint for the sqlalchemy records?


Solution

  • Solved by printing out the type:

    logger.log_text(str(type(cursor)))
    logger.log_text(str(type(records)))
    

    Out:

    <class 'MySQLdb.cursors.Cursor'>
    <class 'tuple'>
    

    Thus, not the sqlalchemy cursor, but the MySQLdb cursor type is used here. And: the built-in tuple is needed, I had mistakenly thought it would be a tuple type from sqlalchemy.

    import sqlalchemy
    from MySQLdb.cursors import Cursor
    from typing import Tuple
    
    def get_cursor_and_records(
        connection, query) -> Tuple[Cursor, tuple]:
        """Make a database cursor for the query and fetch the query output
        :param connection: mysqldb connection to db
        :param query: mysql query string
        returns:
         cursor: row-wise data fetch from the db connection's query
         records: List(Tuple([column types...])) output from cursor.fetchall()
        """
        cursor = connection.cursor()
        cursor.execute(query)
        records = cursor.fetchall()
        return cursor, records
    

    UPDATE: This "trick" of getting the right type for typing is also at Type hints for SQLAlchemy engine and session objects.