def _execute_logical_form_on_table(logical_form: str, table: str):
        """
        The parameters are written out to files which the jar file reads and then executes the
        logical form.
        """
        logical_form_filename = os.path.join(SEMPRE_DIR, 'logical_forms.txt')
        with open(logical_form_filename, 'w') as temp_file:
            temp_file.write(logical_form + '\n')

        table_dir = os.path.join(SEMPRE_DIR, 'tsv/')
        os.makedirs(table_dir, exist_ok=True)
        # The .tsv file extension is important here since the table string parameter is in tsv format.
        # If this file was named with suffix .csv then Sempre would interpret it as comma separated
        # and return the wrong denotation.
        table_filename = 'context.tsv'
        with open(os.path.join(table_dir, table_filename),
                  'w',
                  encoding='utf-8') as temp_file:
            temp_file.write(table)

        # The id, target, and utterance are ignored, we just need to get the
        # table filename into sempre's lisp format.
        test_record = (
            '(example (id nt-0) (utterance none) (context (graph tables.TableKnowledgeGraph %s))'
            '(targetValue (list (description "6"))))' % (table_filename))
        test_data_filename = os.path.join(SEMPRE_DIR, 'data.examples')
        with open(test_data_filename, 'w') as temp_file:
            temp_file.write(test_record)

        # TODO(matt): The jar that we have isn't optimal for this use case - we're using a
        # script designed for computing accuracy, and just pulling out a piece of it. Writing
        # a new entry point to the jar that's tailored for this use would be cleaner.
        if not check_for_java():
            raise RuntimeError('Java is not installed properly.')
        command = ' '.join([
            'java', '-jar',
            cached_path(DEFAULT_EXECUTOR_JAR), test_data_filename,
            logical_form_filename, table_dir
        ])
        run(command, shell=True)

        denotations_file = os.path.join(SEMPRE_DIR,
                                        'logical_forms_denotations.tsv')
        with open(denotations_file) as temp_file:
            line = temp_file.readline().split('\t')

        # Clean up all the temp files generated from this function.
        # Take care to not remove the auxiliary sempre files
        os.remove(logical_form_filename)
        shutil.rmtree(table_dir)
        os.remove(denotations_file)
        os.remove(test_data_filename)
        return line[1] if len(line) > 1 else line[0]
Example #2
0
    def _create_sempre_executor(self) -> None:
        """
        Creates a server running SEMPRE that we can send logical forms to for evaluation.  This
        uses inter-process communication, because SEMPRE is java code.  We also need to be careful
        to clean up the process when our program exits.
        """
        if self._executor_process:
            return

        # It'd be much nicer to just use `cached_path` for these files.  However, the SEMPRE jar
        # that we're using expects to find these files in a particular location, so we need to make
        # sure we put the files in that location.
        os.makedirs(SEMPRE_DIR, exist_ok=True)
        abbreviations_path = os.path.join(SEMPRE_DIR, 'abbreviations.tsv')
        grammar_path = os.path.join(SEMPRE_DIR, 'grow.grammar')

        with session_with_backoff() as session:
            if not os.path.exists(abbreviations_path):
                result = session.get(ABBREVIATIONS_FILE)
                with open(abbreviations_path, 'wb') as downloaded_file:
                    downloaded_file.write(result.content)

            if not os.path.exists(grammar_path):
                result = session.get(GROW_FILE)
                with open(grammar_path, 'wb') as downloaded_file:
                    downloaded_file.write(result.content)

        if not check_for_java():
            raise RuntimeError('Java is not installed properly.')
        args = [
            'java', '-jar',
            cached_path(SEMPRE_EXECUTOR_JAR), 'serve', self._table_directory
        ]
        self._executor_process = subprocess.Popen(args,
                                                  stdin=subprocess.PIPE,
                                                  stdout=subprocess.PIPE,
                                                  bufsize=1)

        lines = []
        for _ in range(6):
            # SEMPRE outputs six lines of stuff when it loads that I can't disable.  So, we clear
            # that here.
            lines.append(str(self._executor_process.stdout.readline()))
        assert 'Parser' in lines[
            -1], "SEMPRE server output unexpected; the server may have changed"
        logger.info("Started SEMPRE server for evaluating logical forms")

        # This is supposed to ensure that the subprocess gets killed when python exits.
        atexit.register(self._stop_sempre_executor)
    def _create_sempre_executor(self) -> None:
        """
        Creates a server running SEMPRE that we can send logical forms to for evaluation.  This
        uses inter-process communication, because SEMPRE is java code.  We also need to be careful
        to clean up the process when our program exits.
        """
        if self._executor_process:
            return

        # It'd be much nicer to just use `cached_path` for these files.  However, the SEMPRE jar
        # that we're using expects to find these files in a particular location, so we need to make
        # sure we put the files in that location.
        os.makedirs(SEMPRE_DIR, exist_ok=True)
        abbreviations_path = os.path.join(SEMPRE_DIR, 'abbreviations.tsv')
        if not os.path.exists(abbreviations_path):
            result = requests.get(ABBREVIATIONS_FILE)
            with open(abbreviations_path, 'wb') as downloaded_file:
                downloaded_file.write(result.content)

        grammar_path = os.path.join(SEMPRE_DIR, 'grow.grammar')
        if not os.path.exists(grammar_path):
            result = requests.get(GROW_FILE)
            with open(grammar_path, 'wb') as downloaded_file:
                downloaded_file.write(result.content)

        if not check_for_java():
            raise RuntimeError('Java is not installed properly.')
        args = ['java', '-jar', cached_path(SEMPRE_EXECUTOR_JAR), 'serve', self._table_directory]
        self._executor_process = subprocess.Popen(args,
                                                  stdin=subprocess.PIPE,
                                                  stdout=subprocess.PIPE,
                                                  bufsize=1)

        lines = []
        for _ in range(6):
            # SEMPRE outputs six lines of stuff when it loads that I can't disable.  So, we clear
            # that here.
            lines.append(str(self._executor_process.stdout.readline()))
        assert 'Parser' in lines[-1], "SEMPRE server output unexpected; the server may have changed"
        logger.info("Started SEMPRE server for evaluating logical forms")

        # This is supposed to ensure that the subprocess gets killed when python exits.
        atexit.register(self._stop_sempre_executor)