Exemplo n.º 1
0
    def test_add_pattern_to_graph_basic_zero_or_more_with_patterns(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')

        element = ET.fromstring('<pattern># HELLO</pattern>')
        template_graph_root = TemplateWordNode("RESPONSE1")
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)

        element = ET.fromstring('<pattern>WELL HI THERE</pattern>')
        template_graph_root = TemplateWordNode("RESPONSE2")
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)

        matcher = PatternMatcher(graph)

        self.assertIsNone(matcher.match(self.bot, self.clientid, Sentence(""), [], Sentence("*"), [], Sentence("*"), []))

        template = matcher.match(self.bot, self.clientid, Sentence("HELLO"), [], Sentence("*"), [], Sentence("*"), [])
        self.assertIsNotNone(template)
        self.assertIsInstance(template, PatternTemplateNode)
        self.assertEqual(template.template.resolve(None, None), "RESPONSE1")

        template = matcher.match(self.bot, self.clientid, Sentence("WELL HI THERE"), [], Sentence("*"), [], Sentence("*"), [])
        self.assertIsNotNone(template)
        self.assertIsInstance(template, PatternTemplateNode)
        self.assertEqual(template.template.resolve(None, None), "RESPONSE2")
Exemplo n.º 2
0
    def test_add_pattern_to_graph_basic_one_or_more(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        element = ET.fromstring('<pattern>*</pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element,
                                   template_graph_root)

        self.assertIsNotNone(graph.root)
        self.assertIsNotNone(graph.root._1ormore_star)
        self.assertIsInstance(graph.root._1ormore_star,
                              PatternOneOrMoreWildCardNode)
        self.assertEqual(graph.root._1ormore_star.wildcard, "*")

        self.assertEqual(len(graph.root._priority_words), 0)
        self.assertIsNone(graph.root._0ormore_arrow)
        self.assertIsNone(graph.root._0ormore_hash)
        self.assertIsNone(graph.root._1ormore_underline)

        matcher = PatternMatcher(graph)
        self.assertIsNone(
            matcher.match(self.bot, self.clientid, Sentence(""), [],
                          Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(
            matcher.match(self.bot, self.clientid, Sentence("test1"), [],
                          Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(
            matcher.match(self.bot, self.clientid, Sentence("test1 test2"), [],
                          Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(
            matcher.match(self.bot, self.clientid,
                          Sentence("test1 test2 test3"), [], Sentence("*"), [],
                          Sentence("*"), []))
Exemplo n.º 3
0
    def test_add_pattern_to_graph_basic(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        element = ET.fromstring("<pattern>test1</pattern>")
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)

        self.assertIsNotNone(graph.root)
        self.assertIsNotNone(graph.root.children)
        self.assertEqual(len(graph.root.children), 1)
        self.assertIsInstance(graph.root.children[0], PatternWordNode)
        self.assertEqual(graph.root.children[0].word, "test1")

        element = ET.fromstring("<pattern>test2</pattern>")
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)

        self.assertIsNotNone(graph.root)
        self.assertIsNotNone(graph.root.children)
        self.assertEqual(len(graph.root.children), 2)
        self.assertIsInstance(graph.root.children[0], PatternWordNode)
        self.assertEqual(graph.root.children[0].word, "test1")
        self.assertIsInstance(graph.root.children[0], PatternWordNode)
        self.assertEqual(graph.root.children[1].word, "test2")

        matcher = PatternMatcher(graph)
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("test1"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("test2"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNone(matcher.match(self.bot, self.clientid, Sentence("test1 test2"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNone(matcher.match(self.bot, self.clientid, Sentence("test2 test1"), [], Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 4
0
    def test_add_pattern_to_graph_basic_set_name_attrib(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        self.bot.brain.sets._sets["SET1"] = ["val1", "val2", "val3", "val5"]

        element = ET.fromstring('<pattern><set name="set1" /></pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element,
                                   template_graph_root)

        self.assertIsNotNone(graph.root)
        self.assertIsNotNone(graph.root.children)
        self.assertEqual(len(graph.root.children), 1)
        self.assertIsInstance(graph.root.children[0], PatternSetNode)
        self.assertEqual(graph.root.children[0].word, "SET1")

        matcher = PatternMatcher(graph)
        self.assertIsNotNone(
            matcher.match(self.bot, self.clientid, Sentence("val1"), [],
                          Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(
            matcher.match(self.bot, self.clientid, Sentence("val2"), [],
                          Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(
            matcher.match(self.bot, self.clientid, Sentence("val3"), [],
                          Sentence("*"), [], Sentence("*"), []))
        self.assertIsNone(
            matcher.match(self.bot, self.clientid, Sentence("val4"), [],
                          Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 5
0
    def test_mixed_priorty_and_star(self):
        graph = PatternGraph()

        pattern_element1 = ET.fromstring("<pattern>A $B C</pattern>")
        pattern_element2 = ET.fromstring("<pattern>A * C</pattern>")
        pattern_element3 = ET.fromstring("<pattern>A D C</pattern>")
        topic_element = ET.fromstring("<topic>*</topic>")
        that_element = ET.fromstring("<that>*</that>")
        template_node1 = TemplateNode()
        template_node2 = TemplateNode()
        template_node3 = TemplateNode()

        graph.add_pattern_to_graph(pattern_element1, topic_element, that_element, template_node1)
        graph.add_pattern_to_graph(pattern_element2, topic_element, that_element, template_node2)
        graph.add_pattern_to_graph(pattern_element3, topic_element, that_element, template_node3)

        matcher = PatternMatcher(graph)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A B C"), pattern_stars,
                               Sentence("*"), topic_stars,
                               Sentence("*"), that_stars)
        self.assertIsNotNone(result)
        self.assertIsInstance(result, PatternTemplateNode)
        self.assertEqual(result.template, template_node1)
        self.assertEqual(len(pattern_stars), 0)
        self.assertEqual(len(topic_stars), 0)
        self.assertEqual(len(that_stars), 0)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A F C"), pattern_stars,
                               Sentence("*"), topic_stars,
                               Sentence("*"), that_stars)
        self.assertIsNotNone(result)
        self.assertIsInstance(result, PatternTemplateNode)
        self.assertEqual(result.template, template_node2)
        self.assertEqual(len(pattern_stars), 1)
        self.assertEqual("F", pattern_stars[0])
        self.assertEqual(len(topic_stars), 0)
        self.assertEqual(len(that_stars), 0)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A D C"), pattern_stars,
                               Sentence("*"), topic_stars,
                               Sentence("*"), that_stars)
        self.assertIsNotNone(result)
        self.assertIsInstance(result, PatternTemplateNode)
        self.assertEqual(result.template, template_node3)
        self.assertEqual(len(pattern_stars), 0)
        self.assertEqual(len(topic_stars), 0)
        self.assertEqual(len(that_stars), 0)
Exemplo n.º 6
0
    def test_add_pattern_to_graph_basic_bot_name_attrib(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        self.bot.brain.properties._properties['bot1'] = 'val1'

        element = ET.fromstring('<pattern><bot name="bot1" /></pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element,
                                   template_graph_root)

        self.assertIsNotNone(graph.root)
        self.assertIsNotNone(graph.root.children)
        self.assertEqual(len(graph.root.children), 1)
        self.assertIsInstance(graph.root.children[0], PatternBotNode)
        self.assertEqual(graph.root.children[0].word, "bot1")

        matcher = PatternMatcher(graph)
        self.assertIsNotNone(
            matcher.match(self.bot, self.clientid, Sentence("val1"), [],
                          Sentence("*"), [], Sentence("*"), []))
        self.assertIsNone(
            matcher.match(self.bot, self.clientid, Sentence("val2"), [],
                          Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 7
0
    def test_add_pattern_to_graph_one_or_more_last(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        element = ET.fromstring('<pattern>XXX *</pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)

        matcher = PatternMatcher(graph)
        self.assertIsNone(matcher.match(self.bot, self.clientid, Sentence(""), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("XXX HELLO THERE YYY"), [], Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 8
0
    def test_add_pattern_to_graph_zero_or_more_multiple(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        element = ET.fromstring('<pattern>XXX # YYY # ZZZ</pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)

        matcher = PatternMatcher(graph)
        self.assertIsNone(matcher.match(self.bot, self.clientid, Sentence(""), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("XXX Hello YYY There ZZZ"), [], Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 9
0
    def test_add_pattern_to_graph_basic_zero_or_more(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        element = ET.fromstring('<pattern>#</pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)

        matcher = PatternMatcher(graph)
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence(""), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("test1"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("test1 test2"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("test1 test2 test3"), [], Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 10
0
    def test_multiple_hashes_with_star_and_that(self):
        graph = PatternGraph()

        pattern_element = ET.fromstring("<pattern>A # # D</pattern>")
        topic_element = ET.fromstring("<topic>*</topic>")
        that_element = ET.fromstring("<that>THAT</that>")
        template_node = TemplateNode()

        graph.add_pattern_to_graph(pattern_element, topic_element, that_element, template_node)

        matcher = PatternMatcher(graph)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A B C C2 D"), pattern_stars,
                               Sentence("THIS"), topic_stars,
                               Sentence("THAT"), that_stars)
        self.assertIsNotNone(result)
        self.assertIsInstance(result, PatternTemplateNode)
        self.assertEqual(len(pattern_stars), 2)
        self.assertEqual('B', pattern_stars[0])
        self.assertEqual('C C2', pattern_stars[1])
        self.assertEqual(len(topic_stars), 1)
        self.assertEqual("THIS", topic_stars[0])
        self.assertEqual(len(that_stars), 0)
Exemplo n.º 11
0
    def test_simple_arrow_and_hash_at_end(self):
        graph = PatternGraph()

        pattern_element1 = ET.fromstring("<pattern>A ^</pattern>")
        pattern_element2 = ET.fromstring("<pattern>A #</pattern>")
        topic_element = ET.fromstring("<topic>*</topic>")
        that_element = ET.fromstring("<that>*</that>")
        template_node1 = TemplateNode()
        template_node2 = TemplateNode()

        graph.add_pattern_to_graph(pattern_element1, topic_element, that_element, template_node1)
        graph.add_pattern_to_graph(pattern_element2, topic_element, that_element, template_node2)

        matcher = PatternMatcher(graph)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A C"), pattern_stars,
                               Sentence("*"), topic_stars,
                               Sentence("*"), that_stars)
        self.assertIsNotNone(result)
        self.assertIsInstance(result, PatternTemplateNode)
        self.assertEqual(result.template, template_node2)
        self.assertEqual(1, len(pattern_stars))
        self.assertEqual('C', pattern_stars[0])
        self.assertEqual(len(topic_stars), 0)
        self.assertEqual(len(that_stars), 0)
Exemplo n.º 12
0
    def test_multi_star_multi_branch_star(self):
        graph = PatternGraph()

        pattern_element1 = ET.fromstring("<pattern>A * B * C</pattern>")
        pattern_element2 = ET.fromstring("<pattern>A * C * D</pattern>")
        topic_element = ET.fromstring("<topic>*</topic>")
        that_element = ET.fromstring("<that>*</that>")
        template_node = TemplateNode()

        graph.add_pattern_to_graph(pattern_element1, topic_element, that_element, template_node)
        graph.add_pattern_to_graph(pattern_element2, topic_element, that_element, template_node)

        matcher = PatternMatcher(graph)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A X B Y C"), pattern_stars,
                               Sentence("*"), topic_stars,
                               Sentence("*"), that_stars)
        self.assertIsNotNone(result)
        self.assertIsInstance(result, PatternTemplateNode)
        self.assertEqual(2, len(pattern_stars))
        self.assertEqual('X', pattern_stars[0])
        self.assertEqual('Y', pattern_stars[1])
        self.assertEqual(len(topic_stars), 0)
        self.assertEqual(len(that_stars), 0)
Exemplo n.º 13
0
    def test_simple_topic_and_star(self):
        graph = PatternGraph()

        pattern_element = ET.fromstring("<pattern>A * D</pattern>")
        topic_element = ET.fromstring("<topic>TOPIC1</topic>")
        that_element = ET.fromstring("<that>*</that>")
        template_node = TemplateNode()

        graph.add_pattern_to_graph(pattern_element, topic_element, that_element, template_node)

        matcher = PatternMatcher(graph)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A B C D"), pattern_stars,
                               Sentence("TOPIC1"), topic_stars,
                               Sentence("THAT1"), that_stars)
        self.assertIsNotNone(result)
        self.assertEqual(len(pattern_stars), 1)
        self.assertEqual('B C', pattern_stars[0])
        self.assertEqual(len(topic_stars), 0)
        self.assertEqual(len(that_stars), 1)
        self.assertEqual('THAT1', that_stars[0])
Exemplo n.º 14
0
    def test_simple_star_at_end(self):
        graph = PatternGraph()

        pattern_element = ET.fromstring("<pattern>A B *</pattern>")
        topic_element = ET.fromstring("<topic>*</topic>")
        that_element = ET.fromstring("<that>*</that>")
        template_node = TemplateNode()

        graph.add_pattern_to_graph(pattern_element, topic_element, that_element, template_node)

        matcher = PatternMatcher(graph)

        pattern_stars = []
        topic_stars = []
        that_stars = []
        result = matcher.match(PatternMatcherTests.bot, PatternMatcherTests.clientid,
                               Sentence("A B C"), pattern_stars,
                               Sentence("*"), topic_stars,
                               Sentence("*"), that_stars)
        self.assertIsNotNone(result)
        self.assertIsInstance(result, PatternTemplateNode)
        self.assertEqual(len(pattern_stars), 1)
        self.assertEqual('C', pattern_stars[0])
        self.assertEqual(len(topic_stars), 0)
        self.assertEqual(len(that_stars), 0)
Exemplo n.º 15
0
    def test_add_pattern_to_graph_basic_set_text(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        self.bot.brain.sets._sets["SET1"] = ["VAL1", "VAL2", "VAL3", "VAL5"]

        element = ET.fromstring('<pattern><set>set1</set> IS A VALUE</pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)
        
        self.assertIsNotNone(graph.root)
        self.assertIsNotNone(graph.root.children)
        self.assertEqual(len(graph.root.children), 1)
        self.assertIsInstance(graph.root.children[0], PatternSetNode)
        self.assertEqual(graph.root.children[0].word, "SET1")

        matcher = PatternMatcher(graph)
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("VAL1 IS A VALUE"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("VAL2 IS A VALUE"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("VAL3 IS A VALUE"), [], Sentence("*"), [], Sentence("*"), []))
        self.assertIsNone(matcher.match(self.bot, self.clientid, Sentence("VAL4 IS A VALUE"), [], Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 16
0
    def test_add_pattern_to_graph_word_set_bot(self):
        graph = PatternGraph()
        topic_element = ET.fromstring('<topic>*</topic>')
        that_element = ET.fromstring('<that>*</that>')
        template_graph_root = None

        self.bot.brain.sets._sets["SET1"] = ["val1", "val2", "val3", "val5"]
        self.bot.brain.properties._properties['bot1'] = 'val1'

        element = ET.fromstring('<pattern>test1 test2 <set name="SET1" /> test4 <bot name="bot1" /> test6</pattern>')
        graph.add_pattern_to_graph(element, topic_element, that_element, template_graph_root)
        
        self.assertIsNotNone(graph.root)

        self.assertIsNotNone(graph.root.children)
        self.assertEqual(len(graph.root.children), 1)
        self.assertIsInstance(graph.root.children[0], PatternWordNode)
        self.assertEqual(graph.root.children[0].word, "test1")

        self.assertIsNotNone(graph.root.children[0].children)
        self.assertEqual(len(graph.root.children[0].children), 1)
        self.assertIsInstance(graph.root.children[0].children[0], PatternWordNode)
        self.assertEqual(graph.root.children[0].children[0].word, "test2")

        self.assertIsNotNone(graph.root.children[0].children[0].children)
        self.assertEqual(len(graph.root.children[0].children[0].children), 1)
        self.assertIsInstance(graph.root.children[0].children[0].children[0], PatternSetNode)
        self.assertEqual(graph.root.children[0].children[0].children[0].word, "SET1")

        self.assertIsNotNone(graph.root.children[0].children[0].children[0].children)
        self.assertEqual(len(graph.root.children[0].children[0].children[0].children), 1)
        self.assertIsInstance(graph.root.children[0].children[0].children[0].children[0], PatternWordNode)
        self.assertEqual(graph.root.children[0].children[0].children[0].children[0].word, "test4")

        self.assertIsNotNone(graph.root.children[0].children[0].children[0].children[0].children)
        self.assertEqual(len(graph.root.children[0].children[0].children[0].children[0].children), 1)
        self.assertIsInstance(graph.root.children[0].children[0].children[0].children[0].children[0], PatternBotNode)
        self.assertEqual(graph.root.children[0].children[0].children[0].children[0].children[0].word, "bot1")

        self.assertIsNotNone(graph.root.children[0].children[0].children[0].children[0].children[0].children)
        self.assertEqual(len(graph.root.children[0].children[0].children[0].children[0].children[0].children), 1)
        self.assertIsInstance(graph.root.children[0].children[0].children[0].children[0].children[0].children[0],
                              PatternWordNode)
        self.assertEqual(graph.root.children[0].children[0].children[0].children[0].children[0].children[0].word,
                         "test6")

        matcher = PatternMatcher(graph)
        self.assertIsNotNone(matcher.match(self.bot, self.clientid, Sentence("test1 test2 val1 test4 val1 test6"), [],
                                         Sentence("*"), [], Sentence("*"), []))
Exemplo n.º 17
0
class AIMLParser(object):
    def __init__(self, supress_warnings=False, stop_on_invalid=False):
        self._supress_warnings = supress_warnings
        self.stop_on_invalid = stop_on_invalid
        self.pattern_parser = PatternGraph()
        self.pattern_matcher = PatternMatcher(self.pattern_parser)
        self.template_parser = TemplateGraph(self)
        self.template_evaluator = TemplateEvaluator()
        self._filename = "Unknown"
        self._version = "Unknown"
        self._aiml_loader = AIMLLoader(self)
        self._num_categories = 0

    @property
    def supress_warnings(self):
        return self._supress_warnings

    @property
    def num_categories(self):
        return self._num_categories

    def load_aiml(self, brain_configuration: BrainConfiguration):
        self._supress_warnings = brain_configuration.supress_warnings
        if brain_configuration.aiml_files is not None:
            aimls_loaded = self._aiml_loader.load_dir_contents(brain_configuration.aiml_files.files,
                                                               brain_configuration.aiml_files.directories,
                                                               brain_configuration.aiml_files.extension)
            logging.info("Loaded a total of %d aiml files", len(aimls_loaded))
        else:
            logging.info("No AIML files defined in configuration to load")

    def parse_from_file(self, filename):
        """
        Parse an AIML file and return all the cateogeries found in the file
        :param filename: Name of file to parse
        :return list of categories parsed from file:
        """
        self._filename = filename

        logging.info("Loading aiml file file: " + self._filename)

        tree = ET.parse(filename, parser=LineNumberingParser())
        aiml = tree.getroot()

        if aiml is None or aiml.tag != 'aiml':
            raise ParserException("Error, root tag is not <aiml>", filename=filename)
        else:
            try:
                self.parse_aiml(aiml, filename)
            except ParserException as parser_excep:
                parser_excep.filename = filename
                raise parser_excep
            except ET.ParseError as xmlpe:
                xmlpe.filename = filename
                xmlpe.xml_exception = xmlpe

    def parse_from_text(self, text):
        """
         Parse an AIML text version of an aiml file and return all the cateogeries found in the file
         :param text: Fully validated AIML snippet
         :return list of categories parsed from file:
         """

        aiml = ET.fromstring(text)

        if aiml is None or aiml.tag != 'aiml':
            ParserException("Error, root tag is not <aiml>", filename="text")
        else:
            self.parse_aiml(aiml, "text")

    #########################################################################################
    #
    #   <?xml version = "1.0" encoding = "UTF-8"?>
    #   <aiml>
    #       <category>
    #           :
    #       </category>
    #       <topic>
    #           <category>
    #           :
    #           </category>
    #       </topic>
    #   </aiml>
    #

    def parse_aiml(self, aiml_xml, filename):
        self.parse_version(aiml_xml)

        categories_found = False
        for expression in aiml_xml:
            if expression.tag == 'topic':
                try:
                    self.parse_topic(expression)
                    categories_found = True
                except ParserException as parser_excep:
                    parser_excep.filename = filename
                    logging.error(parser_excep.format_message())
                    if self.stop_on_invalid is True:
                        raise parser_excep

            elif expression.tag == 'category':
                try:
                    self.parse_category(expression)
                    categories_found = True
                except ParserException as parser_excep:
                    parser_excep.filename = filename
                    logging.error(parser_excep.format_message())
                    if self.stop_on_invalid is True:
                        raise parser_excep

            else:
                raise ParserException("Error, unknown top level tag, %s" % expression.tag, xml_element=expression)

        if categories_found is False:
            logging.warning("no categories in aiml file")
            if self.stop_on_invalid is True:
                raise ParserException("Error, no categories in aiml file", filename=filename)

    #########################################################################################
    #
    # AIML_VERSION ::== 0.9 | 1.0 | 1.1 | 2.0
    #

    def parse_version(self, aiml):
        if 'version' in aiml.attrib:
            self._version = aiml.attrib['version']
            if self._version not in ['0.9', '1.0', '1.1', '2.0']:
                if self._supress_warnings is False:
                    logging.warning("Version number not a supported version: %s", self._version)
        else:
            if self._supress_warnings is False:
                logging.warning("No version info, defaulting to 2.0")
            self._version = "2.0"

    #########################################################################################
    #
    # TOPIC_EXPRESSION:: == <topic name = "PATTERN_EXPRESSION" > (CATEGORY_EXPRESSION) + < / topic >
    #
    # PATTERN_EXPRESSION:: == WORD | PRIORITY_WORD | WILDCARD | SET_STATEMENT | PATTERN_SIDE_BOT_PROPERTY_EXPRESSION
    # PATTERN_EXPRESSION:: == PATTERN_EXPRESSION PATTERN_EXPRESSION
    #
    # This means both topic and that can also be a set of words, stars, hash, sets and bots
    #
    # CATEGORY_EXPRESSION:: == <category>
    #                               <pattern> PATTERN_EXPRESSION </pattern>
    #                              (<that> PATTERN_EXPRESSION </that>)
    #                              (<topic> PATTERN_EXPRESSION </topic>)
    #                              < template > TEMPLATE_EXPRESSION < / template >
    #                          </category>

    def parse_topic(self, topic_element):

        if 'name' in topic_element.attrib:
            name = topic_element.attrib['name']
            if name is None or len(name) == 0:
                raise ParserException("Topic name empty or null", xml_element=topic_element)
            xml = "<topic>%s</topic>" % name
            logging.info("Topic attrib converted to %s", xml)
            topic_pattern = ET.fromstring(xml)
        else:
            raise ParserException("Error, missing name attribute for topic", xml_element=topic_element)

        category_found = False
        for child in topic_element:
            logging.debug(child.tag)
            if child.tag == 'category':
                self.parse_category(child, topic_pattern)
                category_found = True
            else:
                raise ParserException("Error unknown child node of topic, %s" % child.tag, xml_element=topic_element)

        if category_found is False:
            raise ParserException("Error, no categories in topic", xml_element=topic_element)

    def parse_category(self, category_xml, topic_element=None, add_to_graph=True):

        topics = category_xml.findall('topic')
        if topic_element is not None:
            if len(topics) > 0:
                raise ParserException("Error, topic exists in category AND as parent node", xml_element=category_xml)

        else:
            if len(topics) > 1:
                raise ParserException("Error, multiple <topic> nodes found in category", xml_element=category_xml)
            elif len(topics) == 1:
                topic_element = topics[0]
            else:
                topic_element = ET.fromstring("<topic>*</topic>")

        thats = category_xml.findall('that')
        if len(thats) > 1:
            raise ParserException("Error, multiple <that> nodes found in category", xml_element=category_xml)
        elif len(thats) == 1:
            that_element = thats[0]
        else:
            that_element = ET.fromstring("<that>*</that>")

        templates = category_xml.findall('template')
        if len(templates) == 0:
            raise ParserException("Error, no template node found in category", xml_element=category_xml)
        elif len(templates) > 1:
            raise ParserException("Error, multiple <template> nodes found in category", xml_element=category_xml)
        else:
            template_graph_root = self.template_parser.parse_template_expression(templates[0])

        patterns = category_xml.findall('pattern')
        if len(patterns) == 0:
            raise ParserException("Error, no pattern node found in category", xml_element=category_xml)
        elif len(patterns) > 1:
            raise ParserException("Error, multiple <pattern> nodes found in category", xml_element=category_xml)
        else:
            if add_to_graph is True:
                self.pattern_parser.add_pattern_to_graph(patterns[0], topic_element, that_element, template_graph_root)
                self._num_categories += 1

        return (patterns[0], topic_element, that_element, template_graph_root)

    def match_sentence(self, bot, clientid, sentence, parent_question, topic_pattern, that_pattern):
        logging.debug("Matching sentence [%s], topic=[%s], that=[%s] ", sentence.text(), topic_pattern, that_pattern)

        if parent_question is not None:
            pattern_stars = parent_question.current_sentence()._stars
            topic_stars = parent_question.current_sentence()._topicstars
            that_stars = parent_question.current_sentence()._thatstars
        else:
            pattern_stars = sentence._stars
            topic_stars = sentence._topicstars
            that_stars = sentence._thatstars

        matched = self.pattern_matcher.match(bot, clientid,
                                             sentence, pattern_stars,
                                             Sentence(topic_pattern),topic_stars,
                                             Sentence(that_pattern), that_stars)
        if matched is not None:
            return self.template_evaluator.evaluate(bot, clientid, matched.template)

        # pattern_stars = []
        # topic_stars = []
        # that_stars = []
        # matched = self.pattern_matcher.match(bot, clientid, sentence, pattern_stars, Sentence(topic_pattern),
        #                                      topic_stars, Sentence(that_pattern), that_stars)
        # if matched is not None:
        #     if parent_question is not None:
        #         parent_question.current_sentence().stars = pattern_stars
        #         parent_question.current_sentence().topicstars = topic_stars
        #         parent_question.current_sentence().thatstars = that_stars
        #     else:
        #         sentence.stars = pattern_stars
        #         sentence.topicstars = topic_stars
        #         sentence.thatstars = that_stars
        #
        #     return self.template_evaluator.evaluate(bot, clientid, matched.template)

        return None