Classes, Constraints, Events and more in v0.14

Jacob Tomlinson
opsdroid
Published in
4 min readJan 29, 2019

There have been some big changes under the hood in this latest release. These changes should result in more powerfull and flexible skill development. We’ve also seen the Matrix and GitHub connectors and Redis database make their way into the core library.

Classes

After much consideration and debate we’ve decided to start moving skills from bare functions to classes. When I started working on opsdroid in 2016 I wanted to make the bar for creating skills as low as possible. I wanted people who had never written python before to be able to get started simply and easily. Therefore I decided to implement skills are bare functions with a decorator, similar to the getting started examples in flask. However it has become aparent that this is becoming a problem when trying to build complex skills. Therefore we have created a new Skill class which you can import and subclass to create your skills. All the same matchers work but methods now only need to take the message as an argument as the opsdroid and config arguments are passed into the __init__ of the class. You can override __init__ instead of using the setup function to run some code on startup.

from opsdroid.matchers import match_regex
from opsdroid.skill import Skill

_LOGGER = logging.getLogger(__name__)

class TestSkill(Skill):
def __init__(self, opsdroid, config):
super(TestSkill, self).__init__(opsdroid, config)
# You can put your setup code in here.
@match_regex(r'Hello')
async def describe_project(self, message):
await message.respond('world.')

Constraints

This release makes an excellent start on adding new ways to control how skills are matched to messages. You can now add constraints to your skills, this is a way of limiting when skills are matched. For example you may want to match a regex phrase but only from a specific user or in a certain room.

from opsdroid.skill import Skill
from opsdroid.matchers import match_regex
from opsdroid.constraints import constrain_rooms

class MySkill(Skill):
@match_regex(r'hi')
@constrain_rooms(['#general', '#random'])
async def hello(self, message):
await message.respond('Hey')

This example will respond to “hi” with “Hey” but only in the #general or #random rooms.

The old style of skills will continue being supported but will now raise deprecation warnings when you use them.

Events

We are also moving to a new event class system. Until now when a message comes from a chat service it gets turned into a Message object in opsdroid which is matched and parsed and then when it makes its way to your skill it has useful helper methods for responding and reacting to it.

We’ve now added a higher level Event class which Message now inherits from. It has also moved from the message subpackage to the events package so you will need to import from opsdroid.events import Message in connector classes and other places where you need to construct a message.

The plan going forwards is to introduce new event types which we can match and handle in different ways. For example we might want to match GitHub events like Pull Requests and notify in Slack. In the future we can do this with the GitHub and Slack connectors matching on the Pull Request event.

Python module skills

We can now configure skills to use modules from the Python path. This will allow people to package and install their skills separately to the opsdroid packaging system and import them directly.

skills:
- name: mymoduleskill
module: somepackage.someskill

Setuptools entry points

When looking for builtin connectors, databases and skills opsdroid will now check for entrypoints in third party libraries. This means you can create your own connectors, database modules and skills, publish them to PyPI and when a user installs them they can configure them as they would a builtin module.

You just need to add the following section to your setup.py to register the entrypoint in the right place (opsdroid_databases, opsdroid_skills or opsdroid_connectors).

setup(
...
entry_points = {
'opsdroid_databases': [
'customdatabase = mypackage.mydatabasemodule'
]
},
...
)

You can then configure customdatabase like it was a built in module.

databases:
- name: customdatabase
# Some config

Slack reactions

The last enhancement I want to highlight is the addition of reactions for Slack. We’ve supported reactions in opsdroid for a while but each connector needs to add support for them in themselves. This release adds support to the Slack connector so you can now react to messages.

from opsdroid.skill import Skill
from opsdroid.matchers import match_regex
class ReactSkill(Skill): @match_regex(r'Hello')
async def wave_back(self, message):
await message.react('👋')

Full Release Notes

Enhancements

Add basic constraints to opsdroid(#745)
First pass at Events (#721)
Make it possible to create class-based skills (#734)
Add Matrix connector to opsdroid (#731)
Support custom webhook response (replacement for #793) (#807)
Add Redis database to core (#785)
Refactor connector opsdroid pointer (#749)
setuptools entry points support for loading contributed extensions (issue #767) (#771)
load module from pythonpath (#755)
Add reactions to slack connector (#742)
Merge github connector into core (#741)

Bug fixes

Workaround for pip no cache bug (#816)
Bump Pyyaml to avoid CVE-2017–18342 (#803)
Cancel pending tasks on unload (#729)
Remove unused dependency requests_mock (#778)
Remove self from disconnect() method when unload is called (#775)
Fix slack error on connect by calling disconnect if exception is raised (#754)
Refactoring tests — replaces logmock for self.assertLogs (#752)
Make shell connector optional (#747)
Fix the signature of Database.disconnect (#737)
Add config_lang() to tests setup (#730)
Call skills correctly depending on function or class skills (#820)
Fix broken websocket handler (#819)

Breaking changes

None 🎉

Documentation updates

Update version number info (#818)
fixed typos and grammatical errors in the docs (#814)
Add tweet button with text below the badges (#812)
Fix markdown format error (#809)
Update example_configuration.yaml database connectors reference (#788)
fixed some grammatical errors (#787)
fixed typos in the docs and added syntax highlighting (#786)
Fix code annotation created in #779
Removing a line of dead code in the tests (#753)
add Google style docstring to web.py (#746)
Fix a typo in the skills documentation (#736)

v0.14.1

Docker Hub builds were not triggering correctly. This next release should build now. There are no actual changes to opsdroid.

v0.14.2

Bug Fixes

Fix _constrain_skills method (#902)

--

--