shellbot.machines.input module¶
-
class
shellbot.machines.input.
Input
(bot=None, states=None, transitions=None, initial=None, during=None, on_enter=None, on_exit=None, **kwargs)[source]¶ Bases:
shellbot.machines.base.Machine
Asks for some input
This implements a state machine that can get one piece of input from chat participants. It can ask a question, wait for some input, check provided data and provide guidance when needed.
Example:
machine = Input(bot=bot, question="PO Number?", key="order.id") machine.start() ...
In normal operation mode, the machine asks a question in the chat space, then listen for an answer, captures it, and stops.
When no adequate answer is provided, the machine will provide guidance in the chat space after some delay, and ask for a retry. Multiple retries can take place, until correct input is provided, or the machine is timed out.
The machine can also time out after a (possibly) long duration, and send a message in the chat space when giving up.
If correct input is mandatory, no time out will take place and the machine will really need a correct answer to stop.
Data that has been captured can be read from the machine itself. For example:
value = machine.get('answer')
If the machine is given a key, this is used for feeding the bot store. For example:
machine.build(key='my_field', ...) ... value = bot.recall('input')['my_field']
The most straightforward way to process captured data in real-time is to subclass
Input
, like in the following example:class MyInput(Input): def on_input(self, value): mail.send_message(value) machine = MyInput(...) machine.start()
-
ANSWER_MESSAGE
= u'Ok, this has been noted'¶
-
CANCEL_DELAY
= 40.0¶
-
CANCEL_MESSAGE
= u'Ok, forget about it'¶
-
RETRY_DELAY
= 20.0¶
-
RETRY_MESSAGE
= u'Invalid input, please retry'¶
-
elapsed
¶ Measures time since the question has been asked
Used in the state machine for repeating the question and on time out.
-
execute
(arguments=None, **kwargs)[source]¶ Receives data from the chat
Parameters: arguments (str) – data captured from the chat space This function checks data that is provided, and provides guidance if needed. It can extract information from the provided mask or regular expression, and save it for later use.
-
filter
(text)[source]¶ Filters data from user input
Parameters: text (str) – Text coming from the chat space Returns: Data to be captured, or None If a mask is provided, or a regular expression, they are used to extract useful information from provided data.
Example to read a PO mumber:
machine.build(mask='9999A', ...) ... po = machine.filter('PO Number is 2413v') assert po == '2413v'
-
listen
()[source]¶ Listens for data received from the chat space
This function starts a separate process to scan the
bot.fan
queue until time out.
-
on_init
(question=None, question_content=None, mask=None, regex=None, on_answer=None, on_answer_content=None, on_answer_file=None, on_retry=None, on_retry_content=None, on_retry_file=None, retry_delay=None, on_cancel=None, on_cancel_content=None, on_cancel_file=None, cancel_delay=None, is_mandatory=False, key=None, **kwargs)[source]¶ Asks for some input
Parameters: - question (str) – Message to ask for some input
- question_content (str) – Rich message to ask for some input
- mask (str) – A mask to filter the input
- regex (str) – A regular expression to filter the input
- on_answer (str) – Message on successful data capture
- on_answer_content (str in Markdown or HTML format) – Rich message on successful data capture
- on_answer_file (str) – File to be uploaded on successful data capture
- on_retry (str) – Message to provide guidance and ask for retry
- on_retry_content (str in Markdown or HTML format) – Rich message on retry
- on_retry_file (str) – File to be uploaded on retry
- retry_delay (int) – Repeat the on_retry message after this delay in seconds
- on_cancel (str) – Message on time out
- on_cancel_content (str in Markdown or HTML format) – Rich message on time out
- on_cancel_file (str) – File to be uploaded on time out
- is_mandatory (boolean) – If the bot will insist and never give up
- cancel_delay (int) – Give up on this input after this delay in seconds
- key (str) – The label associated with data captured in bot store
If a mask is provided, it is used to filter provided input. Use following conventions to build the mask:
A
- Any kind of unicode symbol such asg
orç
9
- A digit such as0
or2
+
- When following#
or9
, indicates optional extensions- of the same type
- Any other symbol, including punctuation or white space, has to match
- exactly.
For example:
9999A
will match 4 digits and 1 additional character#9-A+
will match#3-June 2017
Alternatively, you can provide a regular expression (regex) to extract useful information from the input.
You can use almost every regular expression that is supported by python. If parenthesis are used, the function returns the first matching group.
For example, you can capture an identifier with a given prefix:
machine.build(question="What is the identifier?", regex=r'ID-\d\w\d+', ...) ... id = machine.filter('The id is ID-1W27 I believe') assert id == 'ID-1W27'
As a grouping example, you can capture a domain name by asking for some e-mail address like this:
machine.build(question="please enter your e-mail address", regex=r'@([\w.]+)', ...) ... domain_name = machine.filter('my address is foo.bar@acme.com') assert domain_name == 'acme.com'
-
on_input
(value, **kwargs)[source]¶ Processes input data
Parameters: value (str) – data that has been captured This function is called as soon as some input has been captured. It can be overlaid in subclass, as in the following example:
class MyInput(Input): def on_input(self, value): mail.send_message(value) machine = MyInput(...) machine.start()
The extra parameters wil be used in case of attachment with the value.
-
receive
()[source]¶ Receives data from the chat space
This function implements a loop until some data has been actually captured, or until the state machine stops for some reason.
The loop is also stopped when the parameter
general.switch
is changed in the context. For example:engine.set('general.switch', 'off')
-
say_answer
(input)[source]¶ Responds on correct capture
Parameters: input (str) – the text that has been noted
-
search_expression
(regex, text)[source]¶ Searches for a regular expression in text
Parameters: - regex (str) – A regular expression to be matched
- text (str) – The string from the chat space
Returns: either the matching expression, or None
You can use almost every regular expression that is supported by python. If parenthesis are used, the function returns the first matching group.
For example, you can capture an identifier with a given prefix:
machine.build(question="What is the identifier?", regex=r'ID-\d\w\d+', ...) ... id = machine.filter('The id is ID-1W27 I believe') assert id == 'ID-1W27'
As a grouping example, you can capture a domain name by asking for some e-mail address like this:
machine.build(question="please enter your e-mail address", regex=r'@([\w.]+)', ...) ... domain_name = machine.filter('my address is foo.bar@acme.com') assert domain_name == 'acme.com'
-
search_mask
(mask, text)[source]¶ Searches for structured data in text
Parameters: - mask (str) – A simple expression to be searched
- text (str) – The string from the chat space
Returns: either the matching expression, or None
Use following conventions to build the mask:
A
- Any kind of unicode symbol, such asg
orç
9
- A digit, such as0
or2
+
- When following#
or9
, indicates optional extensions- of the same type
- Any other symbol, including punctuation or white space, has to match
- exactly.
Some mask examples:
9999A
will match 4 digits and 1 additional character#9-A+
will match#3-June 2017
Example to read a PO mumber:
machine.build(question="What is the PO number?", mask='9999A', ...) ... po = machine.filter('PO Number is 2413v') assert po == '2413v'
-