def get_reply(self, user, message, groups=None):
<EOL>if not self.sorted:<EOL><INDENT>self.sort()<EOL><DEDENT>user = self.get_user(user)<EOL>groups = groups or {None}<EOL>message = Message(self, message)<EOL>request_log_entry = self.request_log.add(user, message, groups)<EOL>triggers = [trigger for trigger in self._sorted_triggers if user.topic == trigger.topic]<EOL>if not triggers and user.topic is not None:<EOL><INDENT>self._log.warn('<STR_LIT>'.format(user=user.id, topic=user.topic))<EOL>user.topic = None<EOL>triggers = [trigger for trigger in self._sorted_triggers if user.topic == trigger.topic]<EOL><DEDENT>if not triggers:<EOL><INDENT>raise AgentMLError('<STR_LIT>')<EOL><DEDENT>if groups is not AnyGroup:<EOL><INDENT>triggers = [trigger for trigger in triggers if groups.issuperset(trigger.groups or {None})]<EOL><DEDENT>if not triggers:<EOL><INDENT>if not user.topic:<EOL><INDENT>self._log.info('<STR_LIT>')<EOL>return<EOL><DEDENT>self._log.info('<STR_LIT>'<EOL>'<STR_LIT>'.format(topic=user.topic, groups=str(groups)))<EOL>user.topic = None<EOL>triggers = [trigger for trigger in self._sorted_triggers if user.topic == trigger.topic]<EOL><DEDENT>for trigger in triggers:<EOL><INDENT>try:<EOL><INDENT>match = trigger.match(user, message)<EOL><DEDENT>except ParserBlockingError:<EOL><INDENT>return<EOL><DEDENT>if match:<EOL><INDENT>message = str(match)<EOL>request_log_entry.response = self.response_log.add(message, request_log_entry)<EOL>return message<EOL><DEDENT><DEDENT>if user.topic:<EOL><INDENT>self._log.info('<STR_LIT>'<EOL>.format(topic=user.topic))<EOL>user.topic = None<EOL>return self.get_reply(user.id, message.raw)<EOL><DEDENT>
Attempt to retrieve a reply to the provided message
:param user: The user / client. This can be a hostmask, IP address, database ID or any other unique identifier
:type  user: str

:param message: The message to retrieve a reply to
:type  message: string_types

:param groups: The trigger groups to search, defaults to only matching non-grouped triggers
:type  groups: set or AnyGroup

:rtype: str or None