"""Module containing functions to ease and addapt the interface with external libraries"""importnumpyasnpfrompandasimportDataFramefromtypingimportLiteral# ---------------------------------- ## Numpy compatibility ## ---------------------------------- #
[docs]defis_empty_iterable(x):""" check if the object x is an empty iterable Parameters ---------- x : any object to check. Returns ------- bool """ifnotnp.iterable(x):returnFalseiflen(x)==0:returnTruereturnFalse
defset_idxs(_i:np.ndarray|int|tuple|None,_n:int|None)->np.ndarray:""" convert an object _i into an 1D array of index Parameters ---------- _i : np.ndarray | int | tuple | None Indexes considered, can be either: - None (default): all indexes from 0 to ``_n-1`` - int: single indexe corresponding to _i - tuple: all indexes between _i[0] and _i[1] _n : int | None _description_ Returns ------- np.ndarray """if_iisNoneand_nisnotNone:_i=np.arange(_n)elifnotnp.iterable(_i):_i=np.array([_i])elifisinstance(_i,tuple)andlen(_i)==2:_i=np.arange(*_i)elifisinstance(_i,list):_i=np.array(_i)ifisinstance(_i,np.ndarray)and_nisnotNone:_i=_i[_i<_n]return_i# ---------------------------------- ## Pandas compatibility ## ---------------------------------- #defget_query(*args,**kwgs):""" Combine a list of kwargs into a `str` compatible with pandas.DataFrame.query """queries=[]forexprinargs:ifisinstance(expr,str):queries+=[expr]fori_lab,i_valinkwgs.items():ifi_valisnotNone:ifisinstance(i_val,str):queries+=[i_val]elifisinstance(i_val,dict):queries+=[get_query(**i_val)]else:queries+=[f"{i_lab}.isin({set_idxs(i_val,None).tolist()})"]iflen(queries)==0:returnNonequeries=" and ".join(queries)returnqueriesdefdf_to(df:DataFrame,otype:None|Literal["numpy","list"],*args,**kwgs)->object:""" convert a :class:`pandas.DataFrame` to another type. Note ---- This function if a generalisation of all `pandas.DataFrame` methods `to_...`. In other words, if otype is not None, this function returns: `f"df.to_{otype}(*args, **kwgs)"` Parameters ---------- df : DataFrame :class:`pandas.DataFrame` to convert. otype : None | Literal["numpy", "list"] If None, return as a panda, convert into the corresponding class. Returns ------- _type_ _description_ """ifotypeisNone:returndfelse:to_any=eval(f"df.to_{otype}")returnto_any(*args,**kwgs)