def makeFunctionProgram(self, function_name, inputs, outputs): """ Creates a function for the table :param function_name: string name of the function to be created :param inputs: list of column names that are input to the function :param outputs: list of columns that are output from the function :return str program: Program as a string """ # Initializations sa = StatementAccumulator() # Program Prologue # TODO: This won't work with nested columns statement = """# Export of the table %s """ % self._table.getName( is_global_name=False ) sa.add(statement) sa.add("") # Make the function definition. This must enclose the prologue # and epilogue sa.add(_makeFunctionStatement(function_name, inputs)) sa.indent(1) sa.add(self._makeAPIPluginInitializationStatements(function_name)) excludes = list(inputs) excludes.extend(outputs) sa.add(self._makePrologue(excludes=excludes)) # Assign the column values to function variables. # Note that inputs and outputs are not assigned. # sa.add(self._makeFormulaEvaluationStatements(excludes=excludes)) sa.add(self._makeClosingException()) sa.add(self._makeEpilogue()) sa.add(_makeReturnStatement(outputs)) return sa.get()
def _makeFormulaEvaluationStatements(self, **kwargs): """ Constructs a script to evaluate table formulas. :return str: statements Notes: (1) Iterate N (#formulas) times to handle dependencies between formulas """ # Initializations sa = StatementAccumulator() formula_columns = self._formulaColumns() num_formulas = len(formula_columns) if num_formulas == 0: return [] # Statements that evaluate the formulas # Iteratively evaluate the formulas. The iteration # terminates under three conditions: # 1. No exception and no change in table data since the # last iteration. # 2. No exception and the iteration count is equal to the # number of columns. # 3. The iteration count exceeds a maximum value. statement = """ # Formula evaluation loop %s.controller.initializeLoop() while not %s.controller.isTerminateLoop(): """ % ( API_OBJECT, API_OBJECT, ) sa.add(statement) sa.indent(1) sa.add("%s.controller.startAnIteration()" % API_OBJECT) # Formula Evaluation block header sa.add("# Formula Execution Blocks") # Formula Evaluation block formulas for column in formula_columns: sa.add("try:") sa.indent(1) colnm = column.getName(is_global_name=False) sa.add("# Column %s" % colnm) statement = "%s.controller.startBlock('%s')" % (API_OBJECT, colnm) sa.add(statement) statement = column.getFormulaStatement() sa.add(statement) sa.add("%s.controller.endBlock()" % API_OBJECT) if column.isExpression(): sa.add("%s = %s.coerceValues('%s', %s)" % (colnm, API_OBJECT, colnm, colnm)) sa.indent(-1) sa.add("except Exception as exc:") sa.indent(1) sa.add("%s.controller.exceptionForBlock(exc)" % API_OBJECT) sa.indent(-1) sa.add(" ") # Formula Evaluation block footer # End of loop statement = self._makeClosingOfFormulaEvaluationLoop(**kwargs) sa.add(statement) return sa.get()
def _wrapProgram(self): """ Puts a wrapper around the program so that an exception can be caught and its location determined within the program. :returns str: program wrapped in try/catch blocks :sideeffects: puts CONTROLLER object in the namespace """ self._namespace[CONTROLLER] = self._controller sa = StatementAccumulator() sa.add("try:") sa.indent(1) statement = "%s.startBlock('%s')" % (CONTROLLER, self._program_name) sa.add(statement) sa.add(self._program) statement = "%s.endBlock()" % CONTROLLER sa.add(statement) sa.indent(-1) statement = """ except Exception as exc: %s.exceptionForBlock(exc)""" % CONTROLLER sa.add(statement) return sa.get()
class TestStatementAccumulator(unittest.TestCase): def setUp(self): self.sa = StatementAccumulator() def testAdd(self): statement = "This is a test." self.sa.add(statement) self.assertEqual(self.sa._statements[0], statement) statement = "This is another test." self.sa.add(statement) self.assertEqual(self.sa._statements[1], statement) def testAddWithIndent(self): statement = "This is a test." self.sa.add(statement) self.sa.indent(1) statement = "This is another test." self.sa.add(statement) self.assertEqual(self.sa._statements[1], " %s" % statement) self.sa.indent(1) statement = "This is another test." self.sa.add(statement) self.assertEqual(self.sa._statements[2], " %s" % statement) self.sa.indent(-1) statement = "This is another test." self.sa.add(statement) self.assertEqual(self.sa._statements[3], " %s" % statement) def testGet(self): first_statement = "This is a test." self.sa.add(first_statement) self.assertEqual(self.sa.get(), first_statement) self.sa.indent(1) second_statement = "This is a test." self.sa.add(second_statement) expected_result ="%s\n %s" % (first_statement, second_statement) self.assertEqual(self.sa.get(), expected_result) def testExtra(self): statement = '''# Evaluation of the table %s. ''' % "aName" self.sa.add(statement)
def makeEvaluationScriptProgram(self, create_API_object=False): """ Creates a python script that evaluates the table formulas when there is a change to the scisheet :param bool create_API_object: True means that code will be generated that creates the API object. :return str program: Program as a string """ sa = StatementAccumulator() # TODO: This won't work with nested columns statement = """# Evaluation of the table %s. """ % self._table.getName( is_global_name=False ) sa.add(statement) sa.add(self._makeAPIInitializationStatements(create_API_object=create_API_object)) sa.add("try:") sa.indent(1) sa.add(self._makePrologue()) sa.add(self._makeFormulaEvaluationStatements()) statement = "if %s.controller.getException() is None:" % API_OBJECT sa.add(statement) sa.indent(1) sa.add(self._makeEpilogue()) sa.indent(-2) # Handle exceptions in the Prologue and Epilogue statement = ( """ except Exception as exc: %s.controller.exceptionForBlock(exc)""" % API_OBJECT ) sa.add(statement) sa.add(self._makeClosingException(is_absolute_linenumber=False)) return sa.get()
def makeTestProgram(self, function_name=None, inputs=None, outputs=None): """ Creates a program that tests the function exported for the table :param function_name: string name of the function to be created :param inputs: list of column names that are input to the function :param outputs: list of columns that are output from the function :return (str error, str program): """ sa = StatementAccumulator() prefix = "self." output_str = _makeOutputStr(outputs) statement = '''""" Tests for %s """ from scisheets.core import api as api from %s import %s import unittest ############################# # Tests ############################# # pylint: disable=W0212,C0111,R0904 class Test%s(unittest.TestCase): ''' % ( function_name, function_name, function_name, function_name, ) sa.add(statement) # Construct setup method sa.indent(1) sa.add("def setUp(self):") sa.indent(1) statement = self._makeAPIPluginInitializationStatements(function_name, prefix=prefix) sa.add(statement) sa.indent(-1) # Construct the test function header sa.add("def testBasics(self):") sa.indent(1) # Assign values to the columns sa.add(self._makeVariableAssignmentStatements(prefix=prefix, only_includes=inputs)) # Construct the call to the function being tested statement = _makeOutputStr(outputs) statement += " = %s(" % function_name statement += ",".join(inputs) statement += ")" sa.add(statement) # Construct the tests for column_name in outputs: statement = "self.assertTrue(self.%s.compareToColumnValues('%s', %s))" % ( API_OBJECT, column_name, column_name, ) sa.add(statement) sa.indent(-2) # Construct the program epilogue statement = """ if __name__ == '__main__': unittest.main()""" sa.add(statement) return sa.get()