66
77import pandas as pd
88import requests
9+ import requests .exceptions
910from loguru import logger
1011from sqlalchemy import UniqueConstraint , and_ , create_engine , inspect , text
1112from sqlalchemy .orm import Session , sessionmaker
@@ -32,7 +33,7 @@ def route_or_direct(route_endpoint: str, method: request_methods = "POST", send_
3233
3334 def decorator (func : Callable ) -> Callable :
3435 @wraps (func )
35- def wrapper (* args : list , ** kwargs : dict ) -> Callable :
36+ def wrapper (* args : list , ** kwargs : dict ) -> Optional [ Callable ] :
3637 session = kwargs .pop ("session" , None )
3738 backend_url = ENV_VARS .BACKEND_URL .get_value ()
3839 route_to_backend = ENV_VARS .ROUTE_TO_BACKEND .get_value ()
@@ -80,7 +81,7 @@ def wrapper(*args: list, **kwargs: dict) -> Callable:
8081 "Provide Session or Set DATABASE_URL env var to use direct database operations or set "
8182 "ROUTE_TO_BACKEND to true and configure BACKEND_URL to use backend routing"
8283 )
83- session = sessionmaker (create_engine (database_url ))()
84+ session = sessionmaker (create_engine (database_url ))() # ty: ignore[no-matching-overload]
8485
8586 return func (* args , ** kwargs , session = session )
8687
@@ -116,6 +117,8 @@ def write_to_table(
116117 SQLAlchemyError: For database errors
117118
118119 """
120+ if not isinstance (session , Session ):
121+ raise TypeError ("Session must be a SQLAlchemy session" )
119122 if if_exists not in ["error" , "replace" , "update" , "ignore" ]:
120123 raise ValueError ("on_conflict must be one of: 'error', 'replace', 'update', 'ignore'" )
121124
@@ -202,7 +205,7 @@ def build_pk_conditions(
202205 return pk_conditions
203206
204207
205- def extract_unique_constraints (inspector : inspect , data : dict [str , Any ]):
208+ def extract_unique_constraints (inspector : Any , data : dict [str , Any ]):
206209 """
207210 Identify unique constraints that can be used to match existing entries.
208211
@@ -248,17 +251,19 @@ def find_existing_entry(
248251
249252 """
250253 if pk_conditions :
251- existing = session .query (TableModel ).filter (and_ (* pk_conditions )).first ()
254+ existing = session .query (TableModel ).filter (and_ (* pk_conditions )).first () # ty: ignore[missing-argument]
252255 if existing :
253256 return existing
254257
255258 all_constraints = []
256259 for constraint_columns in unique_constraints :
257- constraint_condition = and_ (* (getattr (TableModel , col ) == val for col , val in constraint_columns ))
260+ constraint_condition = and_ ( # ty: ignore[missing-argument]
261+ * (getattr (TableModel , col ) == val for col , val in constraint_columns )
262+ )
258263 all_constraints .append (constraint_condition )
259264
260265 if all_constraints :
261- return session .query (TableModel ).filter (and_ (* all_constraints )).first ()
266+ return session .query (TableModel ).filter (and_ (* all_constraints )).first () # ty: ignore[missing-argument]
262267
263268 return None
264269
@@ -268,7 +273,7 @@ def handle_existing_entry( # noqa: PLR0913
268273 TableModel , # noqa: N803, ANN001
269274 data : dict [str , Any ],
270275 pk_columns : list [str ],
271- inspector : inspect ,
276+ inspector : Any ,
272277 if_exists : conflict_actions ,
273278 session : Optional [Session ],
274279):
@@ -322,6 +327,8 @@ def handle_existing_entry( # noqa: PLR0913
322327@route_or_direct ("load_time_data" , send_file = True )
323328def load_time_data (probe_key : ProbeKey , data : pd .DataFrame , session : Optional [Session ] = None ):
324329 """Load time series data"""
330+ if not isinstance (session , Session ):
331+ raise TypeError ("Session must be a SQLAlchemy session" )
325332 route_to_backend = ENV_VARS .ROUTE_TO_BACKEND .get_value ()
326333 if route_to_backend :
327334 csv_data = data .to_csv (index = False ).encode ("utf-8" )
@@ -352,7 +359,7 @@ def load_time_data(probe_key: ProbeKey, data: pd.DataFrame, session: Optional[Se
352359 # Ensure correct dtypes
353360 df = df .astype ({"time" : "datetime64[ns]" , "value" : "float64" , "probe_uuid" : str })
354361
355- dtype = {column .name : column .type for column in ProbeData .__table__ .columns }
362+ dtype = {column .name : column .type_ for column in ProbeData .__table__ .columns }
356363
357364 # Write directly to database using pandas
358365 df .to_sql (
@@ -380,6 +387,8 @@ def load_probe_metadata(
380387 session : Optional [Session ] = None ,
381388):
382389 """Write object to table"""
390+ if not isinstance (session , Session ):
391+ raise TypeError ("Session must be a SQLAlchemy session" )
383392 route_to_backend = ENV_VARS .ROUTE_TO_BACKEND .get_value ()
384393 if route_to_backend :
385394 return {
@@ -419,6 +428,8 @@ def load_probe_metadata(
419428@route_or_direct ("create_new_tables" , method = "GET" )
420429def create_new_tables (create_schema : bool = True , session : Optional [Session ] = None ):
421430 """Use the ORM definition to create all tables, optionally creating the schema as well"""
431+ if not isinstance (session , Session ):
432+ raise TypeError ("Session must be a SQLAlchemy session" )
422433 route_to_backend = ENV_VARS .ROUTE_TO_BACKEND .get_value ()
423434 if route_to_backend :
424435 return {"create_schema" : create_schema }
0 commit comments