# Copyright (c) 2022, IRIS-HEP# All rights reserved.## Redistribution and use in source and binary forms, with or without# modification, are permitted provided that the following conditions are met:## * Redistributions of source code must retain the above copyright notice, this# list of conditions and the following disclaimer.## * Redistributions in binary form must reproduce the above copyright notice,# this list of conditions and the following disclaimer in the documentation# and/or other materials provided with the distribution.## * Neither the name of the copyright holder nor the names of its# contributors may be used to endorse or promote products derived from# this software without specific prior written permission.## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.importastfromtypingimportOptional,cast
[docs]classFuncADLServerException(Exception):'Thrown when an exception happens contacting the server'def__init__(self,msg):Exception.__init__(self,msg)
[docs]defhas_tuple(a:ast.AST)->bool:"""Determine if this query used tuples in its final result NOTE: This can't do depth searches in a really complex query - then you need to follow best practices. Args: a (ast.AST): The query Returns: bool: True if the final Select statement has tuples or not. """deffind_Select(a:ast.AST)->Optional[ast.Call]:# Descent the call chain until we find a Select.whileisinstance(a,ast.Call):ifisinstance(a.func,ast.Name):ifcast(ast.Name,a.func).id=="Select":returnaa=a.args[0]returnNoneselect_statement=find_Select(a)ifselect_statementisNone:returnFalse# Ok - we have a select statement. Now we need to see if it is returning a tuple.func_called=select_statement.args[1]assertisinstance(func_called,ast.Lambda)body=func_called.bodyreturnisinstance(body,ast.Tuple)
[docs]defhas_col_names(a:ast.AST)->bool:"""Determine if any column names were specified in this request. Args: a (ast.AST): The complete AST of the request. Returns: bool: True if no column names were specified, False otherwise. """assertisinstance(a,ast.Call)func_ast=atop_function=cast(ast.Name,a.func).idiftop_function=="ResultAwkwardArray":iflen(a.args)>=2:cols=a.args[1]ifisinstance(cols,ast.List):iflen(cols.elts)>0:returnTrueelifisinstance(ast.literal_eval(cols),str):returnTruefunc_ast=a.args[0]assertisinstance(func_ast,ast.Call)top_function=cast(ast.Name,func_ast.func).idiftop_functionnotin["Select","SelectMany"]:returnFalse# Grab the lambda and see if it is returning a dictfunc_called=func_ast.args[1]assertisinstance(func_called,ast.Lambda)body=func_called.bodyifisinstance(body,ast.Dict):returnTrue# Ok - we didn't find evidence of column names being# specified. It could still happen, but not as far# as we can tell.returnFalse