Skip to content
This repository has been archived by the owner on Jul 15, 2022. It is now read-only.

Commit

Permalink
Docs upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
UniversalSuperBox committed Nov 9, 2017
1 parent 6d04019 commit b24ded5
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 28 deletions.
11 changes: 11 additions & 0 deletions docs/Installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,14 @@ Now all you'll need to do is run ``run.py`` and your bot will be ready to rock!.

TODO: Setting up nginx for reverse proxying
TODO: Automatic start

Good proxy configuration, if you have a proxy in front::

server {
listen 80
server_name [DOMAIN]
root /var/www/default
location / {
proxy_pass http://localhost:5000/;
}
}
7 changes: 1 addition & 6 deletions docs/Internals.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
Internals
*********

Core
----

Core is the

Internal Errors
---------------

Expand All @@ -15,7 +10,7 @@ Internal errors are thrown back and forth inside of bc3cb. While it's valid for

More will be added when the need arises.

bc3cbCommNotFound
bc3cbCommandNotFound
^^^^^^^^^^^^^^^^^

Used when the bot user requests a command that hasn't been defined by the user. For example, they called the bot with `!bot weqyasdrvjklase`, but you don't have a `weqyasdrvjklase` function in `usercommands.py`.
91 changes: 75 additions & 16 deletions docs/WritingBehavior.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,110 @@
Writing Behavior
****************

The Bot Creator defines the behavior for all commands that users can run in usercommands.py.
The Bot Creator defines the behavior for all commands that users can run in ``usercommands.py``.

Introduction
------------

Creating new behavior:
Creating new behavior consists of two easy steps:

#. Think about what word you want the user to call to invoke the behavior
#. Define a function with that word as its name. From that function, return whatever you want to reply to the user with. bc3cb will handle the rest.

Easy. Just like you've always wanted.


Writing your First Command
--------------------------

Consider the default `ping` command::

# bc3cb/usercommands.py
def ping(commandline, commandinfo):
"""
Usage: !bot ping
Returns 'pong'.
"""
return 'pong'
When someone says ``!bot ping`` or directly messages the bot saying ping, the bot replies with pong.
In Basecamp, when someone says '!bot ping' or directly messages the bot saying 'ping', the bot replies with 'pong'.

Easy. Just like you've always wanted.
We're going to create a simple command that performs a dice roll.

Every command starts with your function header::

Writing your First Command
--------------------------
# bc3cb/usercommands.py

def diceroll(commandline, commandinfo):
# statements go here!

Just like that, you've created a new command. If a user calls your bot by saying '!botname diceroll', it will be executed.

Note that all of your functions must take exactly two arguments. It is recommended to call them commandline and commandinfo, just like the example above. commandline and commandinfo will be discussed later on this page.

Now, let's add some code that generates a random number between 1 and 6.::

# bc3cb/usercommands.py

def diceroll(commandline, commandinfo):
import random

return random.randint(1, 6)

This will reply to the user with a random number between 1 and 6.

Notice that the ``import`` statement is inside of the function rather than at the top of the file. This is called lazy importing and is used because every invocation of the bot is started in a new process. Importing *everything* that *any* of your commands may require every time your bot is invoked is wasteful, whereas lazy importing takes less time.

What is 'commandline'?
----------------------

``commandline`` is always sent as the first argument of your functions. It is the message that the user sent to your bot, split into a token list using `shlex <https://docs.python.org/3.5/library/shlex.html>`_.

For example, if the user sends "this is a command", commandline will be the following list::

['this', 'is', 'a', 'command']

This gets more exciting, of course. Shlex also allows the use of quoted strings. The user may send "this is 'a command'" and you will see::

['this', 'is', 'a command']

This allows you to create command line-like syntaxes for your bot.

What is 'commandinfo'?
----------------------

``commandinfo`` is always sent as the second argument of your functions. It is a dictionary that represents the JSON payload sent by Basecamp. This includes important information such as the user's name and title. You can read more about this JSON payload on the `Basecamp 3 API Chatbots page <https://github.com/basecamp/bc3-api/blob/master/sections/chatbots.md>`_.

Raising Exceptions
------------------

bc3cb tries its hardest to always reply to the user that invokes it. This includes a statement that catches any exception and replies with an error message.

You can throw any type of exception you would like, including the base Exception::

# bc3cb/usercommands.py

def neverworks(commandline, commandinfo):
raise Exception('ShortDescriptiveName', 'Long error message that will show as the summary of the error')

This will be caught by bc3cb. It will then send a message to the user saying "Long error message that will show as the summary of the error". The ShortDescriptiveName will be found by clicking to expand the message. It will also be logged to stdout as the following::

bc3cbCore - ERROR - "Basecamp User Name" caused: ShortDescriptiveName with the command: [user message to bot]

Consider making the ShortDescriptiveName field different every time you write an exception. This will aid you in debugging.

Replying Before Returning
-------------------------

bc3cb passes Basecamp's "Callback URL" to you as part of commandinfo. You can also import bc3cb.respond in your behavior. Together, this means that you can send a response to your caller before your command has completed.
bc3cb passes Basecamp's "Callback URL" to you as part of commandinfo. This is the URL that you can use to create a new message with an HTTP POST. You can also import bc3cb.respond in your behavior, which handles the POST for you. Together, this means that you can easily send a response to the user before your command has completed.

For example, you can tell them that you're processing their long-running request::

def reallylongcommand(commandline, commandinfo):
from . import respond
interimresponse = ' '.join(["I'm working on it!"])
interimresponse = "I'm working on it!"
respond.respond(interimresponse, commandinfo['callback_url'])
# Do some more stuff that'll take a while
Expand All @@ -53,13 +118,7 @@ The important lines are these::
from . import respond
respond.respond(string, commandinfo['callback_url'])


Raising Errors
--------------



Some Notes
----------

* You can't call anything within bc3cb from your commands as `core.py` imports `usercommands.py`.
* You can't call anything within bc3cb.core from your commands as `core.py` imports `usercommands.py`.
62 changes: 62 additions & 0 deletions docs/bc3cb.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
bc3cb package
=============

Submodules
----------

bc3cb\.core module
------------------

.. automodule:: bc3cb.core
:members:
:undoc-members:
:show-inheritance:

bc3cb\.creatorprivate module
----------------------------

.. automodule:: bc3cb.creatorprivate
:members:
:undoc-members:
:show-inheritance:

bc3cb\.log module
-----------------

.. automodule:: bc3cb.log
:members:
:undoc-members:
:show-inheritance:

bc3cb\.receiver module
----------------------

.. automodule:: bc3cb.receiver
:members:
:undoc-members:
:show-inheritance:

bc3cb\.respond module
---------------------

.. automodule:: bc3cb.respond
:members:
:undoc-members:
:show-inheritance:

bc3cb\.usercommands module
--------------------------

.. automodule:: bc3cb.usercommands
:members:
:undoc-members:
:show-inheritance:


Module contents
---------------

.. automodule:: bc3cb
:members:
:undoc-members:
:show-inheritance:
15 changes: 9 additions & 6 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
import bc3cb


# -- General configuration ------------------------------------------------
Expand All @@ -31,8 +32,10 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.coverage']
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.coverage'
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Expand Down Expand Up @@ -84,7 +87,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
Expand Down
9 changes: 9 additions & 0 deletions docs/modindex.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _modindex:

Module index
============

.. toctree::
:maxdepth: 4

bc3cb

0 comments on commit b24ded5

Please sign in to comment.