rivescript package¶
Submodules¶
rivescript.rivescript module¶
-
class
rivescript.rivescript.
RiveScript
(debug=False, strict=True, depth=50, log='', utf8=False)[source]¶ Bases:
object
A RiveScript interpreter for Python 2 and 3.
Parameters: - debug (bool) – Set to True to enable verbose logging.
- strict (bool) – Enable strict mode.
Strict mode causes RiveScript syntax errors to be fatal.
This option is
True
by default. - log (str) – Specify a log file to write debug output to.
This can redirect debug lines to a file instead of
STDOUT
. - depth (int) – Specify the recursion depth limit.
This is how many times RiveScript will recursively follow redirects
before giving up with a
DeepRecursionError
exception. The default is50
. - utf8 (bool) – Enable UTF-8 mode.
The default is
False
.
-
classmethod
VERSION
()[source]¶ Return the version number of the RiveScript library.
This may be called as either a class method or a method of a RiveScript object instance.
-
clear_uservars
(user=None)[source]¶ Delete all variables about a user (or all users).
Parameters: user (str) – The user ID to clear variables for, or else clear all variables for all users if not provided.
-
current_user
()[source]¶ Retrieve the user ID of the current user talking to your bot.
This is mostly useful inside of a Python object macro to get the user ID of the person who caused the object macro to be invoked (i.e. to set a variable for that user from within the object).
This will return
None
if used outside of the context of getting a reply (the value is unset at the end of thereply()
method).
-
deparse
()[source]¶ Dump the in-memory RiveScript brain as a Python data structure.
This would be useful, for example, to develop a user interface for editing RiveScript replies without having to edit the RiveScript source code directly.
Return dict: JSON-serializable Python data structure containing the contents of all RiveScript replies currently loaded in memory.
-
freeze_uservars
(user)[source]¶ Freeze the variable state for a user.
This will clone and preserve a user’s entire variable state, so that it can be restored later with
thaw_uservars()
.Parameters: user (str) – The user ID to freeze variables for.
-
get_global
(name)[source]¶ Retrieve the current value of a global variable.
Parameters: name (str) – The name of the variable to get. Return str: The value of the variable or "undefined"
.
-
get_uservar
(user, name)[source]¶ Get a variable about a user.
Parameters: - user (str) – The user ID to look up a variable for.
- name (str) – The name of the variable to get.
Returns: The user variable, or
None
or"undefined"
:- If the user has no data at all, this returns
None
. - If the user doesn’t have this variable set, this returns the
string
"undefined"
. - Otherwise this returns the string value of the variable.
-
get_uservars
(user=None)[source]¶ Get all variables about a user (or all users).
Parameters: str user (optional) – The user ID to retrieve all variables for. If not passed, this function will return all data for all users.
Return dict: All the user variables.
- If a
user
was passed, this is adict
of key/value pairs of that user’s variables. If the user doesn’t exist in memory, this returnsNone
. - Otherwise, this returns a
dict
of key/value pairs that map user IDs to their variables (adict
ofdict
).
- If a
-
get_variable
(name)[source]¶ Retrieve the current value of a bot variable.
Parameters: name (str) – The name of the variable to get. Return str: The value of the variable or "undefined"
.
-
last_match
(user)[source]¶ Get the last trigger matched for the user.
Parameters: user (str) – The user ID to get the last matched trigger for. Return str: The raw trigger text (tags and all) of the trigger that the user most recently matched. If there was no match to their last message, this returns None
instead.
-
load_directory
(directory, ext=None)[source]¶ Load RiveScript documents from a directory.
Parameters: - directory (str) – The directory of RiveScript documents to load replies from.
- ext ([]str) – List of file extensions to consider as RiveScript
documents. The default is
[".rive", ".rs"]
.
-
load_file
(filename)[source]¶ Load and parse a RiveScript document.
Parameters: filename (str) – The path to a RiveScript file.
-
reply
(user, msg, errors_as_replies=True)[source]¶ Fetch a reply from the RiveScript brain.
Parameters: - user (str) – A unique user ID for the person requesting a reply. This could be e.g. a screen name or nickname. It’s used internally to store user variables (including topic and history), so if your bot has multiple users each one should have a unique ID.
- msg (str) – The user’s message. This is allowed to contain punctuation and such, but any extraneous data such as HTML tags should be removed in advance.
- errors_as_replies (bool) – When errors are encountered (such as a
deep recursion error, no reply matched, etc.) this will make the
reply be a text representation of the error message. If you set
this to
False
, errors will instead raise an exception, such as aDeepRecursionError
orNoReplyError
. By default, no exceptions are raised and errors are set in the reply instead.
Returns: The reply output.
Return type: str
-
set_global
(name, value)[source]¶ Set a global variable.
Equivalent to
! global
in RiveScript code.Parameters: - name (str) – The name of the variable to set.
- value (str) – The value of the variable.
Set this to
None
to delete the variable.
-
set_handler
(language, obj)[source]¶ Define a custom language handler for RiveScript objects.
Pass in a
None
value for the object to delete an existing handler (for example, to prevent Python code from being able to be run by default).Look in the
eg
folder of the rivescript-python distribution for an example script that sets up a JavaScript language handler.Parameters: - language (str) – The lowercased name of the programming language. Examples: python, javascript, perl
- obj (class) –
An instance of an implementation class object. It should provide the following interface:
class MyObjectHandler: def __init__(self): pass def load(self, name, code): # name = the name of the object from the RiveScript code # code = the source code of the object def call(self, rs, name, fields): # rs = the current RiveScript interpreter object # name = the name of the object being called # fields = array of arguments passed to the object return reply
-
set_person
(what, rep)[source]¶ Set a person substitution.
Equivalent to
! person
in RiveScript code.Parameters: - what (str) – The original text to replace.
- rep (str) – The text to replace it with.
Set this to
None
to delete the substitution.
-
set_subroutine
(name, code)[source]¶ Define a Python object from your program.
This is equivalent to having an object defined in the RiveScript code, except your Python code is defining it instead.
Parameters: - name (str) – The name of the object macro.
- code (def) – A Python function with a method signature of
(rs, args)
This method is only available if there is a Python handler set up (which there is by default, unless you’ve called
set_handler("python", None)
).
-
set_substitution
(what, rep)[source]¶ Set a substitution.
Equivalent to
! sub
in RiveScript code.Parameters: - what (str) – The original text to replace.
- rep (str) – The text to replace it with.
Set this to
None
to delete the substitution.
-
set_uservar
(user, name, value)[source]¶ Set a variable for a user.
This is like the
<set>
tag in RiveScript code.Parameters: - user (str) – The user ID to set a variable for.
- name (str) – The name of the variable to set.
- value (str) – The value to set there.
-
set_uservars
(user, data=None)[source]¶ Set many variables for a user, or set many variables for many users.
This function can be called in two ways:
# Set a dict of variables for a single user. rs.set_uservars(username, vars) # Set a nested dict of variables for many users. rs.set_uservars(many_vars)
In the first syntax,
vars
is a simple dict of key/value string pairs. In the second syntax,many_vars
is a structure like this:{ "username1": { "key": "value", }, "username2": { "key": "value", }, }
This way you can export all user variables via
get_uservars()
and then re-import them all at once, instead of setting them once per user.Parameters: - str user (optional) – The user ID to set many variables for. Skip this parameter to set many variables for many users instead.
- data (dict) – The dictionary of key/value pairs for user variables, or else a dict of dicts mapping usernames to key/value pairs.
This may raise a
TypeError
exception if you pass it invalid data types. Note that only the standarddict
type is accepted, but not variants likeOrderedDict
, so if you have a dict-like type you should cast it todict
first.
-
set_variable
(name, value)[source]¶ Set a bot variable.
Equivalent to
! var
in RiveScript code.Parameters: - name (str) – The name of the variable to set.
- value (str) – The value of the variable.
Set this to
None
to delete the variable.
-
sort_replies
(thats=False)[source]¶ Sort the loaded triggers in memory.
After you have finished loading your RiveScript code, call this method to populate the various internal sort buffers. This is absolutely necessary for reply matching to work efficiently!
-
stream
(code)[source]¶ Stream in RiveScript source code dynamically.
Parameters: code – Either a string containing RiveScript code or an array of lines of RiveScript code.
-
thaw_uservars
(user, action='thaw')[source]¶ Thaw a user’s frozen variables.
Parameters: action (str) – The action to perform when thawing the variables:
discard
: Don’t restore the user’s variables, just delete the frozen copy.keep
: Keep the frozen copy after restoring the variables.thaw
: Restore the variables, then delete the frozen copy (this is the default).
-
trigger_info
(trigger=None, dump=False)[source]¶ Get information about a trigger.
Pass in a raw trigger to find out what file name and line number it appeared at. This is useful for e.g. tracking down the location of the trigger last matched by the user via
last_match()
. Returns a list of matching triggers, containing their topics, filenames and line numbers. ReturnsNone
if there weren’t any matches found.The keys in the trigger info is as follows:
category
: Either ‘topic’ (for normal) or ‘thats’ (for %Previous triggers)topic
: The topic nametrigger
: The raw trigger textfilename
: The filename the trigger was found in.lineno
: The line number the trigger was found on.
Pass in a true value for
dump
, and the entire syntax tracking tree is returned.Parameters: - trigger (str) – The raw trigger text to look up.
- dump (bool) – Whether to dump the entire syntax tracking tree.
Returns: A list of matching triggers or
None
if no matches.
-
write
(fh, deparsed=None)[source]¶ Write the currently parsed RiveScript data into a file.
Pass either a file name (string) or a file handle object.
This uses
deparse()
to dump a representation of the loaded data and writes it to the destination file. If you provide your own data as thedeparsed
argument, it will use that data instead of callingdeparse()
itself. This way you can usedeparse()
, edit the data, and use that to write the RiveScript document (for example, to be used by a user interface for editing RiveScript without writing the code directly).Parameters: - fh – Either a file name
str
or a file handle object of a file opened in write mode. - dict deparsed (optional) – A data structure in the same format as
what
deparse()
returns. If not passed, this value will come from the current in-memory data fromdeparse()
.
- fh – Either a file name
rivescript.brain module¶
-
class
rivescript.brain.
Brain
(master, strict=True, utf8=False)[source]¶ Bases:
object
The Brain class controls the actual reply fetching phase for RiveScript.
Parameters: - master (RiveScript) – A reference to the parent RiveScript instance.
- strict (bool) – Whether strict mode is enabled.
- utf8 (bool) – Whether UTF-8 mode is enabled.
-
do_expand_array
(array_name, depth=0)[source]¶ Do recurrent array expansion, returning a set of keywords.
Exception is thrown when there are cyclical dependencies between arrays or if the
@array
name references an undefined array.Parameters: - array_name (str) – The name of the array to expand.
- depth (int) – The recursion depth counter.
Return set: The final set of array entries.
-
expand_array
(array_name)[source]¶ Expand variables and return a set of keywords.
Parameters: array_name (str) – The name of the array to expand. Return list: The final array contents. Warning is issued when exceptions occur.
-
format_message
(msg, botreply=False)[source]¶ Format a user’s message for safe processing.
This runs substitutions on the message and strips out any remaining symbols (depending on UTF-8 mode).
Parameters: - msg (str) – The user’s message.
- botreply (bool) – Whether this formatting is being done for the
bot’s last reply (e.g. in a
%Previous
command).
Return str: The formatted message.
Post process tags in a message.
Parameters: - user (str) – The user ID.
- msg (str) – The user’s formatted message.
- reply (str) – The raw RiveScript reply for the message.
- st ([]str) – The array of
<star>
matches from the trigger. - bst ([]str) – The array of
<botstar>
matches from a%Previous
command. - depth (int) – The recursion depth counter.
- ignore_object_errors (bool) – Whether to ignore errors in Python
object macros instead of raising an
ObjectError
exception.
Return str: The final reply after tags have been processed.
-
reply_regexp
(user, regexp)[source]¶ Prepares a trigger for the regular expression engine.
Parameters: - user (str) – The user ID invoking a reply.
- regexp (str) – The original trigger text to be turned into a regexp.
Return regexp: The final regexp object.
rivescript.exceptions module¶
-
exception
rivescript.exceptions.
DeepRecursionError
[source]¶ Bases:
rivescript.exceptions.RiveScriptError
A deep recursion condition was detected and a reply can’t be given.
This error can occur when you have triggers that redirect to each other in a circle, for example:
+ one @ two + two @ one
By default, RiveScript will only recursively look for a trigger up to 50 levels deep before giving up. This should be a large enough window for most use cases, but if you need to increase this limit you can do so by setting a higher value for the
depth
parameter to the constructor or changing it in your RiveScript source code, for example:! global depth = 75
The text version is
[ERR: Deep recursion detected]
-
exception
rivescript.exceptions.
NoDefaultRandomTopicError
[source]¶ Bases:
Exception
No default topic could be found.
This is a critical error and usually means no replies were loaded into the bot. Very unlikely is it the case that all replies belong to other topics than the default (
random
).
-
exception
rivescript.exceptions.
NoMatchError
[source]¶ Bases:
rivescript.exceptions.RiveScriptError
No reply could be matched.
This means that no trigger was a match for the user’s message. To avoid this error, add a trigger that only consists of a wildcard:
+ * - I do not know how to reply to that.
The lone-wildcard trigger acts as a catch-all fallback trigger and will ensure that every message the user could send will match at least one trigger.
The text version is
[ERR: No reply matched]
-
exception
rivescript.exceptions.
NoReplyError
[source]¶ Bases:
rivescript.exceptions.RiveScriptError
No reply could be found.
This means that the user’s message matched a trigger, but the trigger didn’t yield any response for the user. For example, if a trigger was followed only by
*Conditions
and none of them were true and there were no normal replies to fall back on, this error can come up.To avoid this error, always make sure you have at least one
-Reply
for every trigger.The text version is
[ERR: No reply found]
.
-
exception
rivescript.exceptions.
ObjectError
(error_message='[ERR: Error when executing Python object]')[source]¶ Bases:
rivescript.exceptions.RiveScriptError
An error occurred when executing a Python object macro.
This will usually be some kind of run-time error, like a
ZeroDivisionError
orIndexError
for example.The text version is
[ERR: Error when executing Python object]
rivescript.inheritance module¶
-
rivescript.inheritance.
get_topic_tree
(rs, topic, depth=0)[source]¶ Given one topic, get the list of all included/inherited topics.
Parameters: - topic (str) – The topic to start the search at.
- depth (int) – The recursion depth counter.
Return []str: Array of topics.
-
rivescript.inheritance.
get_topic_triggers
(rs, topic, thats, depth=0, inheritance=0, inherited=False)[source]¶ Recursively scan a topic and return a list of all triggers.
Parameters: - rs (RiveScript) – A reference to the parent RiveScript instance.
- topic (str) – The original topic name.
- thats (bool) – Are we getting triggers for ‘previous’ replies?
- depth (int) – Recursion step counter.
- inheritance (int) – The inheritance level counter, for topics that inherit other topics.
- inherited (bool) – Whether the current topic is inherited by others.
Returns: List of all triggers found.
Return type: []str
rivescript.interactive module¶
rivescript.parser module¶
-
class
rivescript.parser.
Parser
(master, strict=True, utf8=False)[source]¶ Bases:
object
The RiveScript language parser.
Parameters: - master (RiveScript) – A reference to the parent RiveScript bot instance,
mostly useful for its debug methods like
warn()
. - strict (bool) – Strict syntax checking (true by default).
- utf8 (bool) – Enable UTF-8 mode (false by default).
-
check_syntax
(cmd, line)[source]¶ Syntax check a line of RiveScript code.
Parameters: - cmd (str) – The command symbol for the line of code, such as one
of
+
,-
,*
,>
, etc. - line (str) – The remainder of the line of code, such as the text of a trigger or reply.
Returns: A string syntax error message or
None
if no errors.Return type: str
- cmd (str) – The command symbol for the line of code, such as one
of
-
concat_modes
= {'newline': '\n', 'space': ' ', 'none': ''}¶
-
parse
(filename, code)[source]¶ Read and parse a RiveScript document.
Returns a data structure that represents all of the useful contents of the document, in this format:
{ "begin": { # "begin" data "global": {}, # map of !global vars "var": {}, # bot !var's "sub": {}, # !sub substitutions "person": {}, # !person substitutions "array": {}, # !array lists }, "topics": { # main reply data "random": { # (topic name) "includes": {}, # map of included topics (values=1) "inherits": {}, # map of inherited topics "triggers": [ # array of triggers { "trigger": "hello bot", "reply": [], # array of replies "condition": [], # array of conditions "redirect": None, # redirect command "previous": None, # 'previous' reply }, # ... ] } } "objects": [ # parsed object macros { "name": "", # object name "language": "", # programming language "code": [], # array of lines of code } ] }
Parameters: - filename (str) – The name of the file that the code came from, for syntax error reporting purposes.
- code (str[]) – The source code to parse.
Returns: The aforementioned data structure.
Return type: dict
- master (RiveScript) – A reference to the parent RiveScript bot instance,
mostly useful for its debug methods like
rivescript.python module¶
-
class
rivescript.python.
PyRiveObjects
[source]¶ Bases:
object
A RiveScript object handler for Python code.
This class provides built-in support for your RiveScript documents to include and execute object macros written in Python. For example:
> object base64 python import base64 as b64 return b64.b64encode(" ".join(args)) < object + encode * in base64 - OK: <call>base64 <star></call>
Python object macros receive these two parameters:
rs
(RiveScript): The reference to the parent RiveScript instance.args
([]str): A list of argument words passed to your object.
Python support is on by default. To turn it off, just unset the Python language handler on your RiveScript object:
rs.set_handler("python", None)
-
call
(rs, name, user, fields)[source]¶ Invoke a previously loaded object.
Parameters: - rs (RiveScript) – the parent RiveScript instance.
- name (str) – The name of the object macro to be called.
- user (str) – The user ID invoking the object macro.
- fields ([]str) – Array of words sent as the object’s arguments.
Return str: The output of the object macro.
rivescript.regexp module¶
-
class
rivescript.regexp.
RE
[source]¶ Bases:
object
-
array
= re.compile('\\@(.+?)\\b')¶
-
bot_tag
= re.compile('<bot (.+?)>')¶
-
botstars
= re.compile('<botstar(\\d+)>')¶
-
cond_parse
= re.compile('^(.+?)\\s+(==|eq|!=|ne|<>|<|<=|>|>=)\\s+(.+?)$')¶
-
cond_split
= re.compile('\\s*=>\\s*')¶
-
cond_syntax
= re.compile('^.+?\\s*(?:==|eq|!=|ne|<>|<|<=|>|>=)\\s*.+?=>.+?$')¶
-
crlf
= re.compile('<crlf>')¶
-
def_syntax
= re.compile('^.+(?:\\s+.+|)\\s*=\\s*.+?$')¶
-
equals
= re.compile('\\s*=\\s*')¶
-
get_tag
= re.compile('<get (.+?)>')¶
-
inherit
= re.compile('\\{inherits=(\\d+)\\}')¶
-
literal_w
= re.compile('\\\\w')¶
-
name_syntax
= re.compile('[^a-z0-9_\\-\\s]')¶
-
nasties
= re.compile('[^A-Za-z0-9 ]')¶
-
objend
= re.compile('^\\s*<\\s*object')¶
-
optionals
= re.compile('\\[(.+?)\\]')¶
-
placeholder
= re.compile('\\x00(\\d+)\\x00')¶
-
redir_tag
= re.compile('\\{@(.+?)\\}')¶
-
set_tag
= re.compile('<set (.+?)=(.+?)>')¶
-
tag_search
= re.compile('<([^<]+?)>')¶
-
topic_tag
= re.compile('\\{topic=(.+?)\\}')¶
-
trig_syntax
= re.compile('[^a-z0-9(\\|)\\[\\]*_#@{}<>=\\s]')¶
-
utf8_meta
= re.compile('[\\\\<>]')¶
-
utf8_punct
= re.compile('[.?,!;:@#$%^&*()]')¶
-
utf8_trig
= re.compile('[A-Z\\\\.]')¶
-
weight
= re.compile('\\{weight=(\\d+)\\}')¶
-
wilds
= re.compile('[\\s\\*\\#\\_]+')¶
-
ws
= re.compile('\\s+')¶
-
zero_star
= re.compile('^\\*$')¶
-
rivescript.sorting module¶
-
rivescript.sorting.
init_sort_track
()[source]¶ Returns a new dict for keeping track of triggers for sorting.
-
rivescript.sorting.
sort_trigger_set
(triggers, exclude_previous=True, say=None)[source]¶ Sort a group of triggers in optimal sorting order.
The optimal sorting order is, briefly: * Atomic triggers (containing nothing but plain words and alternation
groups) are on top, with triggers containing the most words coming first. Triggers with equal word counts are sorted by length, and then alphabetically if they have the same length.- Triggers containing optionals are sorted next, by word count like atomic triggers.
- Triggers containing wildcards are next, with
_
(alphabetic) wildcards on top, then#
(numeric) and finally*
. - At the bottom of the sorted list are triggers consisting of only a
single wildcard, in the order:
_
,#
,*
.
Triggers that have
{weight}
tags are grouped together by weight value and sorted amongst themselves. Higher weighted groups are then ordered before lower weighted groups regardless of the normal sorting algorithm.Triggers that come from topics which inherit other topics are also sorted with higher priority than triggers from the inherited topics.
Parameters: - triggers ([]str) – Array of triggers to sort.
- exclude_previous (bool) – Create a sort buffer for ‘previous’ triggers.
- say (function) – A reference to
RiveScript._say()
or provide your own function.
rivescript.utils module¶
-
rivescript.utils.
is_atomic
(trigger)[source]¶ Determine if a trigger is atomic or not.
In this context we’re deciding whether or not the trigger needs to use the regular expression engine for testing. So any trigger that contains nothing but plain words is considered atomic, whereas a trigger with any “regexp-like” parts (even alternations) is not.
Parameters: trigger – The trigger to test. Return bool: Whether it’s atomic or not.
-
rivescript.utils.
string_format
(msg, method)[source]¶ Format a string (upper, lower, formal, sentence).
Parameters: - msg (str) – The user’s message.
- method (str) – One of
uppercase
,lowercase
,sentence
orformal
.
Return str: The reformatted string.
-
rivescript.utils.
word_count
(trigger, all=False)[source]¶ Count the words that aren’t wildcards in a trigger.
Parameters: - trigger (str) – The trigger to count words for.
- all (bool) – Count purely based on whitespace separators, or consider wildcards not to be their own words.
Return int: The word count.