1

I'm diving into type hints and type hinting some of my code as I think it is a good practice. I have a function that takes both sqlalchemy and cx_Oracle connection/session objects. I was able to figure out the hinting for sqlalchemy here. Poked around some docs trying to figure it out with cx_Oracle to no avail.

My code

import pandas as pd

from sqlalchemy import create_engine
from sqlalchemy.engine.base import Engine

import cx_Oracle

# code that creates engine would go here 
...

def pullData(oracleEngine: __what_here__?, sqlEngine: Engine) -> pd.DataFrame:
     # do stuff
     return df

In general, are there any tips or tricks for type hinting with types that aren't built-in core python data types? Ie I found this source for how to type hint text files. Also, is it a bad practice to give imported type hints an alias like so?

from sqlalchemy.engine.base import Engine as sql_Engine

def foo(sqlEngine: sql_Engine) ...
bismo
  • 1,257
  • 1
  • 16
  • 36
  • The highlight a comment from the current answer: use the newest version of cx_Oracle (now called python-oracledb), see the [release announcement](https://cjones-oracle.medium.com/open-source-python-thin-driver-for-oracle-database-e82aac7ecf5a). This has a top layer written in Python so type hinting, auto completion etc are better. To use it in SQLAlchemy, see https://levelup.gitconnected.com/using-python-oracledb-1-0-with-sqlalchemy-pandas-django-and-flask-5d84e910cb19 – Christopher Jones Oct 09 '22 at 22:37

1 Answers1

1

Yes, IMHO type annotations should be mandatory for everything that isn't a quickly thrown together draft script. If you are interested in more details about typing options and best practices in Python, I recommend starting with PEP 484 and the typing module.


Regarding cx_Oracle, it seems it is written entirely in C, so there are no real Python signatures available for all their functions. I could not find any stub files either.

You also did not explain, where that oracleEngine argument is supposed to come from, so the best I can do is guess that you are referring to the object returned by the context manager cx_Oracle.connect, which in turn should be an instance of the cx_Oracle.Connection class. So this is what I would use to annotate that function parameter.


In general, are there any tips or tricks for type hinting with types that aren't built-in core python data types?

Types are generally annotated with concrete classes or with generic types/type variables. Keep in mind that what you refer to as "built-in core python data types" are also nothing but classes. Everything in Python is an object.

So if you want to pass the return value of sqlalchemy.create_engine to a function, that function parameter should be annotated with the Engine class, as you already did.


... is it a bad practice to give imported type hints an alias [...]?

Not at all. If aliasing objects on import improves readability or better conveys contextual meaning, I would say it is encouraged.

The only thing is that I would suggest sticking to PEP 8, unless you have very good reasons not to. (See my code example below.)

As a matter of fact, it can sometimes be helpful to explicitly use TypeAlias, if you have long (maybe even qualified) class names that you repeat multiple times in type annotations, such as pd.DataFrame.


All together, I would suggest to modify your example code like this:

from typing import TypeAlias

import pandas as pd
from cx_Oracle import Connection as OracleConn
from sqlalchemy.engine.base import Engine as SQLAEngine


DF: TypeAlias = pd.DataFrame


def pull_data(oracle_conn: OracleConn, sqla_engine: SQLAEngine) -> DF:
    # do stuff
    ...

Keep in mind that I made a few assumptions and guesses regarding the Oracle types. I also noticed that they mention very explicitly in their documentation that cx_Oracle is being replaced by python-oracledb. The latter also seems to support typing much better at first glance. So that may be worth upgrading to.

Hope this helps.

Daniil Fajnberg
  • 12,753
  • 2
  • 10
  • 41
  • Incredible, precise answer. Thank you! I understand your response regarding the typing... but now I have another question (that is likely an entirely separate conversation) ... what is the difference between a type and a class in python? The more I read about them, the more they seem to be the same thing. And as you mentioned *"Keep in mind that what you refer to as 'built-in core python data types' are also nothing but classes. Everything in Python is an object."* Example: `type(pd.DataFrame)` returns `type` while `type(pd.DataFrame())` returns `pandas.core.frame.DataFrame` – bismo Oct 09 '22 at 14:08
  • @bismo Glad I could help. You're right, that is a whole other topic. But very briefly: The terms _"class"_ and _"type"_ are often used interchangeably because they mostly refer to the same "entities". But at least in Python, the former is typically used in the context of the actual algorithm (runtime), while the other is mostly used in conjunction with static type analysis. I hope this makes sense. In Python, even a class is an object - an object of the class `type`. See here: https://stackoverflow.com/questions/100003 – Daniil Fajnberg Oct 10 '22 at 09:25