示例#1
0
 def testDo(self):
   if IGNORE_TEST:
     return
   executor = Executor()
   executor.setDefinitions(DEFINITIONS)
   expander = Expander(executor, self.message)
   result = expander.do(SUBSTITUTION1)
   self.assertEqual(result[0], SUBSTITUTION1)
   result = expander.do(SUBSTITUTION2)
   expected = len(DEFINITIONS['a'])
   self.assertEqual(len(result), expected)
示例#2
0
 def testDoSubstitutionNoDefinition(self):
   if IGNORE_TEST:
     return
   executor = Executor()
   expander = Expander(executor, self.message)
   result = expander.do(SUBSTITUTION1)
   self.assertEqual(result[0], SUBSTITUTION1)
示例#3
0
 def testExpandTemplateExpressions(self):
   if IGNORE_TEST:
     return
   executor = Executor()
   var = 'n'
   definitions = {var: [1, 2, 3]}
   executor.setDefinitions(definitions)
   expander = Expander(executor, self.message)
   template = "T{%s} + A -> T{%s+1}" % (var, var)
   expansion = expander.do(template)
   self.assertEqual(len(expansion), len(definitions[var]))
   # Check that each substitution is found
   for value in definitions[var]:
     found = False
     for substitution in expansion:
       if "T%d" % value in substitution:
         found = True
         break
     self.assertTrue(found)
class TemplateProcessor(object):
    """
  This class processes an Antimony model written using template variable substitutions.
  See the project README for syntax details.
  """
    def __init__(self, template_string):
        """
    :param str template_string: string containing template variables
        and template escape statements to execute
    """
        self._extractor = LineExtractor(template_string)
        self._message = StatusMessage(self._extractor)
        self._executor = Executor()
        self._expander = Expander(self._executor, self._message)
        self._command = None  # Command being processed
        self._define_variable_statements = []

    @classmethod
    def processFile(cls, inpath, outpath):
        """
    Processes template strings in a file.
    :param str inpath: path to the file containing the templated model
    :param str outpath: path to the file where the flattened model is placed
    """
        template = ''
        with open(inpath, 'r') as infile:
            for line in infile:
                template += "\n" + line
        processor = cls(template)
        expansion = processor.do()
        with open(outpath, 'w') as outfile:
            outfile.write(expansion)

    @staticmethod
    def _makeComment(line):
        return "%s%s" % (COMMENT_STG, line)

    def _processCommand(self):
        """
    Handles command processing, either the current line
    is a command or in the midst of processing a paired command.
    :param list-of-str expansion:
    :return bool: True if processed line
    """
        line = self._extractor.getCurrentLine()
        line_type = self._extractor.getCurrentLineType()
        is_processed = False
        # Current line is a command
        if line_type == LINE_COMMAND:
            is_processed = True
            # Check for nested commands
            if self._command is not None:
                new_command = Command(line)
                # Is this a paired command?
                if new_command.getCommandVerb()  \
                    == self._command.getCommandVerb():
                    if new_command.isEnd():
                        pass
                    else:
                        self._message.error("Cannot nest commands")
            # Valid placement for a command.
            self._command = Command(line)
            # DefineVariables Command
            if self._command.isDefineVariables():
                if self._command.isBegin():
                    self._define_variables_statements = []
                elif self._command.isEnd():
                    try:
                        program = '\n'.join(self._define_variables_statements)
                        self._executor.doScript(program)
                    except Exception as err:
                        msg = "***Error %s executing in : \n%s"  \
                            % (str(err), program)
                        self._message.error(msg)
                    self._command = None
            # SetVersion command
            elif self._command.isSetVersion():
                version = self._command.getArguments()[0]
                if float(version) > float(VERSION):
                    self._message.error("Unsupported version %s" % version)
                self._command = None
            # Other commands
            else:
                self._message.error("Unknown command")
        # Process statements occurring within paired commands
        elif self._command is not None:
            is_processed = True
            if self._command.isDefineVariables() and self._command.isBegin():
                self._define_variables_statements.append(line)
            else:
                self._message.error("Invalid paired command.")
        return is_processed

    def do(self):
        """
    Processes the template string and returns the expanded lines for input
    to road runner.
    Phases
      1. Construct content lines (non-blank, not comments)
      2. Extract the template variable definitions
      3. Construct the substitution instances
      4. Process the lines with template variables
    State used:
      reads: _definitions
    :return str expanded_string:
    :raises ValueError: errors encountered in the template string
    """
        cls = TemplateProcessor
        expansion = []
        line, line_type = self._extractor.do()
        statements = []
        while line is not None:
            if self._processCommand():
                expansion.append(cls._makeComment(line))
            # No command being processed
            else:
                # Transparent line (comment)
                if line_type == LINE_TRAN:
                    expansion.append(line)
                elif line_type == LINE_NONE:
                    pass
                # Line to be substituted
                elif line_type == LINE_SUBS:
                    # Do the variable substitutions
                    try:
                        substitutions = self._expander.do(line)
                    except Exception as err:
                        msg = "Runtime error in expression"
                        self._message.error(msg)
                    if len(substitutions) > 1:
                        expansion.append(cls._makeComment(line))
                    expansion.extend(substitutions)
                else:
                    import pdb
                    pdb.set_trace()
                    raise RuntimeError("Unexepcted state")
            line, line_type = self._extractor.do()
        if self._command is not None:
            msg = "Still processing command %s at EOF" % str(self._command)
            self._message.error(msg)
        return "\n".join(expansion)