0

Our class project has hit a dead end, we have three files, two are our transition and state machine programs, the other is our statement text file. Everything seems to work except when we attempt to input our text file, it always classifies it as an error_state. However, if we read the input into the transition program it works properly.

This is our result:

Greg is beautiful

('reached the end state that is a ', 'error_state')
Greg is ugly

('reached the end state that is a ', 'error_state')
Greg is O.K.

('reached the end state that is a ', 'error_state')

We have also tried reading it in as one list and splitting it.

Here is our code:

Statemachine.py

class StateMachine:
    def __init__(self):
        self.handlers = {}
        self.startState = None
        self.endStates = []

    def add_state(self, name, handler, end_state=0):
        name = name.upper()
        self.handlers[name] = handler
        if end_state:
            self.endStates.append(name)

    def set_start(self, name):
        self.startState = name.upper()

    def run(self, cargo):
        try:
            handler = self.handlers[self.startState]
        except:
            raise InitializationError("must call .set_start() before .run()")
        if not self.endStates:
            raise  InitializationError("at least one state must be an end_state")

        while True:
            (newState, cargo) = handler(cargo)
            if newState.upper() in self.endStates:
                print("reached the end state that is a ", newState)
                break 
            else:
                handler = self.handlers[newState.upper()]   

Transitions.py

from Statemachine import StateMachine

positive_adjectives = ["great","fun", "handsome", "beautiful"]
negative_adjectives = ["boring", "difficult", "ugly", "goofy"]

def start_transitions(txt):
    splitted_txt = txt.split(None,1)
    word, txt = splitted_txt if len(splitted_txt) > 1 else (txt,"")
    if word == "Greg":
        newState = "Greg_state"
    else:
        newState = "error_state"
    return (newState, txt)

def is_state_transitions(txt):
    splitted_txt = txt.split(None,1)
    word, txt = splitted_txt if len(splitted_txt) > 1 else (txt,"")
    if word == "is":
        newState = "is_state"
    else:
        newState = "error_state"
    return (newState, txt)

def not_state_transitions(txt):
    splitted_txt = txt.split(None,1)
    word, txt = splitted_txt if len(splitted_txt) > 1 else (txt,"")
    if word == "not":
        newState = "not_state"
    elif word in positive_adjectives:
        newState = "positive_state"
    elif word in negative_adjectives:
        newState = "negative_state"
    else:
        newState = "error_state"
    return (newState, txt)

def adjective_state_transitions(txt):
    splitted_txt = txt.split(None,1)
    word, txt = splitted_txt if len(splitted_txt) > 1 else (txt,"")
    if word in positive_adjectives:
        newState = "negative_state"
    elif word in negative_adjectives:
        newState = "positive_state"
    else:
        newState = "error_state"
    return (newState, txt)

def neg_state(txt):
    print("Not nice :(")
    return ("negative_state", "")

if __name__== "__main__":
    m = StateMachine()
    m.add_state("Start", start_transitions)
    m.add_state("Greg_state", is_state_transitions)
    m.add_state("is_state", is_state_transitions)
    m.add_state("not_state", not_state_transitions)
    m.add_state("negative_state", None, end_state=1)
    m.add_state("positive_state", None, end_state=1)
    m.add_state("error_state", None, end_state=1)
    m.set_start("Start")

    with open('states.txt', 'r') as f_input:
        statement1 = f_input.readline()
        statement2 = f_input.readline()
        statement3 = f_input.readline()
        print (statement1)
        m.run (statement1)
        print (statement2)
        m.run (statement2)
        print (statement3)
        m.run (statement3) 
        f_input.close()

states.txt

Greg is beautiful

Greg is ugly

Greg is O.K.

-Thank you!

Akshat Mahajan
  • 9,543
  • 4
  • 35
  • 44
Mary Kate
  • 67
  • 1
  • 6

1 Answers1

1

The reason your code doesn't work is because you aren't removing newline characters from each line in states.txt.

In other words, your input text actually looks like this (with newline characters revealed):

Greg is beautiful\n
\n
Greg is ugly\n
\n
Greg is O.K.\n

(You can verify this is how Python sees it by opening the file as f_input and calling f_input.read() in the interpreter).

When reading from states.txt, doing f_input.readline() gives (for just the first line) Greg is beautiful\n. Your functions split this up into ['Greg', 'is', 'beautiful\n'].

Obviously, the extra newline character throws everything off. beautiful\n is recognised as an error and everything is classed as an error state. This happens in all of your functions.

Solution

Use .strip() to remove trailing newline characters. In all of your functions, replace txt with txt.strip() before calling any split() functions on it.

e.g.

def start_transitions(txt):
    splitted_txt = txt.strip().split(None,1)
    ...

Additionally, I would strongly recommend removing the extra blank line between all of your input lines. This will make your life much easier, especially because you may inadvertently assign read in that blank line as your statements.

Other Tips

This code is not production quality. You have a lot of duplicated code in all of your functions (especially for splitting your input text), and you can use Python's ternary expressions to make it more concise.

I would strongly recommend asking how to improve this on CodeReview once you are convinced the code works correctly - it'll benefit you and the program enormously.

Community
  • 1
  • 1
Akshat Mahajan
  • 9,543
  • 4
  • 35
  • 44
  • I had tried, however I was getting a callback error. Traceback (most recent call last): File "C:\Users\Mary\Desktop\Python Programs\Statemachine.py", line 26, in run (newState, cargo) = handler(cargo) File "C:\Users\Mary\Desktop\Python Programs\Transistions.py", line 7, in start_transitions splitted_txt = txt.strip().txt.split(None,1) AttributeError: 'str' object has no attribute 'txt' Should I just raise the AttributeError? – Mary Kate Apr 20 '16 at 22:22
  • @MaryKate Not surprised. You defined `splitted_txt` as `splitted_txt = txt.strip().txt.split(None,1)`. Why would you do `.txt` again? I presume it's a typo - the code I provided explains clearly what changes you have to make. – Akshat Mahajan Apr 20 '16 at 22:24
  • @Askat Mahajan Sorry, I also did that, and I still have them all transitioned to the error state. – Mary Kate Apr 21 '16 at 00:21