interview.py 6.42 KB
Newer Older
Theresa Pollinger's avatar
Theresa Pollinger committed
1
2
#!/usr/bin/env python3

3
# http://cmd2.readthedocs.io
Theresa Pollinger's avatar
Theresa Pollinger committed
4
import cmd2 as cmd
5
# http://mattoc.com/python-yes-no-prompt-cli.html
Theresa Pollinger's avatar
Theresa Pollinger committed
6
from distutils.util import strtobool
7
# https://github.com/phfaist/pylatexenc for directly converting Latex commands to unicode
Theresa Pollinger's avatar
Theresa Pollinger committed
8
9
10
from pylatexenc.latex2text import LatexNodes2Text
import pyparsing as pp

11
from pde_state_machine import *
12
13
14
15

# This "main class" is two things: a REPL loop, by subclassing the cmd2 Cmd class
# and a state machine as given by the pytransitions package
class Interview(cmd.Cmd):
Theresa Pollinger's avatar
Theresa Pollinger committed
16
    def __init__(self, *args, **kwargs):
17
18
19

        self.state_machine = PDE_States(self.poutput, self.update_prompt, self.please_prompt)

Theresa Pollinger's avatar
Theresa Pollinger committed
20
21
22
        # initialize legal characters for cmd
        self.legalChars = u'!#$%.:;?@_-<>' + pp.printables + pp.alphas8bit + pp.punc8bit
        # TODO why does "<" not show?
23
24
        # allow all useful unicode characters to be used, and some more
        for i in range(0x20, 0x2E7F):
Theresa Pollinger's avatar
Theresa Pollinger committed
25
26
27
28
29
30
            self.legalChars += chr(i)

        # call cmd constructor
        super(Interview, self).__init__(*args, **kwargs)

        # Initialize cmd member variables
31
        self.myname = 'TheInterview'
Theresa Pollinger's avatar
Theresa Pollinger committed
32
        self.username = 'user'
33
34
35
36
        self.intro = "Hello, " + self.username + "! I am " + self.myname + \
                     ", your partial differential equations and simulations expert. " \
                     "Let's set up a simulation together.\n" \
                     "Please enter anything to start the interview."
37
        # self.greeting()
Theresa Pollinger's avatar
Theresa Pollinger committed
38
39
        self.update_prompt()

40

41
    #### functions for user interaction
Theresa Pollinger's avatar
Theresa Pollinger committed
42
43

    def obviously_stupid_input(self):
44
        self.poutput("Trying to be funny, huh?")
Theresa Pollinger's avatar
Theresa Pollinger committed
45

46
    ############# input processing if not explain or undo
Theresa Pollinger's avatar
Theresa Pollinger committed
47
48
49
    def default(self, line):
        raw = line.parsed['raw']
        arg = LatexNodes2Text().latex_to_text(raw)
50
        # pythonic switch-case, cf. https://bytebaker.com/2008/11/03/switch-case-statement-in-python/
51
52
53
54
55
56
57

        if not self.prompt_input_handling(arg):
            self.state_input_handling(arg)

    def state_input_handling(self, arg):
        """The standard input handling, depending on which state we are in"""
        # pythonic switch-case, cf. https://bytebaker.com/2008/11/03/switch-case-statement-in-python/
Theresa Pollinger's avatar
Theresa Pollinger committed
58
        try:
59
            self.state_machine.stateDependentInputHandling[self.state_machine.state](arg)
60
        except Exception as error:
61
            #self.state_machine.exaout.create_output(self.state_machine.simdata)
Theresa Pollinger's avatar
Theresa Pollinger committed
62
63
            raise

64
    def please_prompt(self, query, if_yes, if_no=None, pass_other=False):
Theresa Pollinger's avatar
Theresa Pollinger committed
65
        self.poutput(str(query) + " [y/n]? ")
66
67
68
        self.state_machine.prompted = True
        self.state_machine.if_yes = if_yes
        self.state_machine.if_no = if_no
69
        self.state_machine.pass_other = pass_other
70
71
72
73

    def prompt_input_handling(self, arg):
        """ If we asked for a yes-no answer, execute what was specified in please_prompt.
        return true if the input was handled here, and false if not."""
74
        if self.state_machine.prompted:
75
76
77
78
79
80
            if arg == "":
                ret = True
            else:
                try:
                    ret = strtobool(str(arg).strip().lower())
                except ValueError:
81
82
                    if self.state_machine.pass_other:
                        return False
83
                    # or use as input to callback an input processing fcn..?
84
                    self.poutput("Please answer with y/n")
85
                    return True
86
            self.state_machine.prompted = False
87
            if ret:
88
89
                if self.state_machine.if_yes is not None:
                    self.state_machine.if_yes()
90
91
            elif self.state_machine.if_no is not None:
                self.state_machine.if_no()
92
93
94
            return True
        return False

Theresa Pollinger's avatar
Theresa Pollinger committed
95
96
97
98
    # called when user types 'explain [expression]'
    def do_explain(self, expression):
        "Explain an expression or the theoretical background to what we are currently looking for"
        if expression:
99
            explanation = "hello, " + expression  # TODO query flexiformal content through mmt
Theresa Pollinger's avatar
Theresa Pollinger committed
100
101
102
103
104
        else:
            explanation = 'hello'
        self.poutput(explanation)

    def help_explain(self):
105
106
107
        self.poutput('\n'.join(['explain [expression]',
                                'explain the expression given or the theory currently used',
                                ]))
Theresa Pollinger's avatar
Theresa Pollinger committed
108
109
110
111
112
113
114

    # called when user types 'undo'
    def do_undo(self, expression):
        "Go back to the last question"
        self.trigger('last_state')

    def help_undo(self):
115
116
117
        self.poutput('\n'.join(['undo',
                                'Go back to the last question',
                                ]))
Theresa Pollinger's avatar
Theresa Pollinger committed
118
119

    def update_prompt(self):
120
        self.prompt = "(" + self.state_machine.state + ")"
Theresa Pollinger's avatar
Theresa Pollinger committed
121

122
    # tab completion for empty lines
Theresa Pollinger's avatar
Theresa Pollinger committed
123
124
125
126
127
128
    def completenames(self, text, line, begidx, endidx):
        """Override of cmd2 method which completes command names both for command completion and help."""
        command = text
        if self.case_insensitive:
            command = text.lower()
        if not command:
129
            # define the "default" input for the different states we can be in
Theresa Pollinger's avatar
Theresa Pollinger committed
130
131
132
            self.stateDependentDefaultInput = {
                'dimensions': '1',
                'domain': ['Ω = [ 0 ; 1 ]'],
133
                'unknowns': ['u : Ω → ℝ'],
134
                'parameters': ['f :  ℝ → ℝ = [x: ℝ] x '],  # ['f : Ω → ℝ = [x:Ω] x ⋅ x'],
135
136
137
                'pdes': ['∆u = f(x_1)'],
                'bcs': ['u (0) = 0'],  # ,'u (1) = x_1**2'],
                'sim': ['FD'],
Theresa Pollinger's avatar
Theresa Pollinger committed
138
            }
139
            return self.stateDependentDefaultInput[self.state_machine.state]
Theresa Pollinger's avatar
Theresa Pollinger committed
140
141
142
143
144
145
146
147
148
        else:
            # Call super class method.  Need to do it this way for Python 2 and 3 compatibility
            cmd_completion = cmd.Cmd.completenames(self, command)

            # If we are completing the initial command name and get exactly 1 result and are at end of line, add a space
            if begidx == 0 and len(cmd_completion) == 1 and endidx == len(line):
                cmd_completion[0] += ' '
            return cmd_completion

149
150
151
152
    def greeting(self):  # TODO make work in proper order
        self.poutput(
            "Hello, " + self.username + "! I am " + self.myname + ", your partial differential equations and simulations expert. " \
                                                                  "Let's set up a simulation together.\n")
Theresa Pollinger's avatar
Theresa Pollinger committed
153
154
        self.trigger("greeting_over")

155

Theresa Pollinger's avatar
Theresa Pollinger committed
156
157
if __name__ == '__main__':
    Interview().cmdloop()