Compare commits

...

3 Commits

@ -1,39 +0,0 @@
# This workflow will install Python dependencies, then run various linting programs on a single Python version
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Lint
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -U isort==5.6.4 flake8==3.8.4 flake8-comprehensions==3.3.1 black==20.8b1
- name: Check import statement sorting
run: |
isort -c --df molly/ molly tests
- name: Python syntax errors, undefined names, etc.
run: |
flake8 . --count --show-source --statistics
- name: PEP8 formatting
run: |
black --check --diff molly/ molly tests

@ -1,57 +0,0 @@
# This workflow will install Python dependencies, then run unit testing across the earliest and latest supported Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Run unit tests
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
python_36:
# We need to use 20.04 to get access to the libolm3 package
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.6
uses: actions/setup-python@v2
with:
python-version: 3.6
- name: Install project dependencies
run: |
# Install libolm, required for end-to-end encryption functionality
sudo apt install -y libolm-dev libolm3
# Install python dependencies
python setup.py install
- name: Run unit tests
run: |
python -m unittest
python_39:
# We need to use 20.04 to get access to the libolm3 package
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install project dependencies
run: |
# Install libolm, required for end-to-end encryption functionality
sudo apt install -y libolm-dev libolm3
# Install python dependencies
python setup.py install
- name: Run unit tests
run: |
python -m unittest

@ -1,96 +0,0 @@
# Contributing to nio-template
Thank you for taking interest in this little project. Below is some information
to help you with contributing.
## Setting up your development environment
See the
[Install the dependencies section of SETUP.md](SETUP.md#install-the-dependencies)
for help setting up a running environment for the bot.
If you would rather not or are unable to run docker, the following instructions
will explain how to install the project dependencies natively.
#### Install libolm
You can install [libolm](https://gitlab.matrix.org/matrix-org/olm) from source,
or alternatively, check your system's package manager. Version `3.0.0` or
greater is required.
**(Optional) postgres development headers**
By default, the bot uses SQLite as its storage backend. This is fine for a
few hundred users, but if you plan to support a much higher volume
of requests, you may consider using Postgres as a database backend instead.
If you want to use postgres as a database backend, you'll need to install
postgres development headers:
Debian/Ubuntu:
```
sudo apt install libpq-dev libpq5
```
Arch:
```
sudo pacman -S postgresql-libs
```
#### Install Python dependencies
Create and activate a Python 3 virtual environment:
```
virtualenv -p python3 env
source env/bin/activate
```
Install python dependencies:
```
pip install -e .
```
(Optional) If you want to use postgres as a database backend, use the following
command to install postgres dependencies alongside those that are necessary:
```
pip install ".[postgres]"
```
### Development dependencies
There are some python dependencies that are required for linting/testing etc.
You can install them with:
```
pip install -e ".[dev]"
```
## Code style
Please follow the [PEP8](https://www.python.org/dev/peps/pep-0008/) style
guidelines and format your import statements with
[isort](https://pypi.org/project/isort/).
## Linting
Run the following script to automatically format your code. This *should* make
the linting CI happy:
```
./scripts-dev/lint.sh
```
## What to work on
Take a look at the [issues
list](https://github.com/anoadragon453/nio-template/issues). What
feature would you like to see or bug do you want to be fixed?
If you would like to talk any ideas over before working on them, you can reach
me at [@andrewm:amorgan.xyz](https://matrix.to/#/@andrewm:amorgan.xyz)
on matrix.

@ -1,160 +0,0 @@
# Nio Template [![Built with matrix-nio](https://img.shields.io/badge/built%20with-matrix--nio-brightgreen)](https://github.com/poljar/matrix-nio) <a href="https://matrix.to/#/#nio-template:matrix.org"><img src="https://img.shields.io/matrix/nio-template:matrix.org?color=blue&label=Join%20the%20Matrix%20Room&server_fqdn=matrix-client.matrix.org" /></a>
A template for creating bots with
[matrix-nio](https://github.com/poljar/matrix-nio). The documentation for
matrix-nio can be found
[here](https://matrix-nio.readthedocs.io/en/latest/nio.html).
This repo contains a working Matrix echo bot that can be easily extended to your needs. Detailed documentation is included as well as a step-by-step guide on basic bot building.
Features include out-of-the-box support for:
* Bot commands
* SQLite3 and Postgres database backends
* Configuration files
* Multi-level logging
* Docker
* Participation in end-to-end encrypted rooms
## Projects using nio-template
* [anoadragon453/matrix-reminder-bot](https://github.com/anoadragon453/matrix-reminder-bot
) - A matrix bot to remind you about things
* [gracchus163/hopeless](https://github.com/gracchus163/hopeless) - COREbot for the Hope2020 conference Matrix server
* [alturiak/nio-smith](https://github.com/alturiak/nio-smith) - A modular bot for @matrix-org that can be dynamically
extended by plugins
* [anoadragon453/msc-chatbot](https://github.com/anoadragon453/msc-chatbot) - A matrix bot for matrix spec proposals
* [anoadragon453/matrix-episode-bot](https://github.com/anoadragon453/matrix-episode-bot) - A matrix bot to post episode links
* [TheForcer/vision-nio](https://github.com/TheForcer/vision-nio) - A general purpose matrix chatbot
* [anoadragon453/drawing-challenge-bot](https://github.com/anoadragon453/drawing-challenge-bot) - A matrix bot to
post historical, weekly art challenges from reddit to a room
* [8go/matrix-eno-bot](https://github.com/8go/matrix-eno-bot) - A bot to be used as a) personal assistant or b) as
an admin tool to maintain your Matrix installation or server
* [elokapina/bubo](https://github.com/elokapina/bubo) - Matrix bot to help with community management
* [elokapina/middleman](https://github.com/elokapina/middleman) - Matrix bot to act as a middleman, for example as a support bot
* [chc4/matrix-pinbot](https://github.com/chc4/matrix-pinbot) - Matrix bot for pinning messages to a dedicated channel
Want your project listed here? [Edit this
page!](https://github.com/anoadragon453/nio-template/edit/master/README.md)
## Getting started
See [SETUP.md](SETUP.md) for how to setup and run the template project.
## Project structure
*A reference of each file included in the template repository, its purpose and
what it does.*
The majority of the code is kept inside of the `molly` folder, which
is in itself a [python package](https://docs.python.org/3/tutorial/modules.html),
the `__init__.py` file inside declaring it as such.
To run the bot, the `molly` script in the root of the codebase is
available. It will import the `main` function from the `main.py` file in the
package and run it. To properly install this script into your python environment,
run `pip install -e .` in the project's root directory.
`setup.py` contains package information (for publishing your code to
[PyPI](https://pypi.org)) and `setup.cfg` just contains some configuration
options for linting tools.
`sample.config.yaml` is a sample configuration file. People running your bot
should be advised to copy this file to `config.yaml`, then edit it according to
their needs. Be sure never to check the edited `config.yaml` into source control
since it'll likely contain sensitive details such as passwords!
Below is a detailed description of each of the source code files contained within
the `molly` directory:
### `main.py`
Initialises the config file, the bot store, and nio's AsyncClient (which is
used to retrieve and send events to a matrix homeserver). It also registering
some callbacks on the AsyncClient to tell it to call some functions when
certain events are received (such as an invite to a room, or a new message in a
room the bot is in).
It also starts the sync loop. Matrix clients "sync" with a homeserver, by
asking constantly asking for new events. Each time they do, the client gets a
sync token (stored in the `next_batch` field of the sync response). If the
client provides this token the next time it syncs (using the `since` parameter
on the `AsyncClient.sync` method), the homeserver will only return new event
*since* those specified by the given token.
This token is saved and provided again automatically by using the
`client.sync_forever(...)` method.
### `config.py`
This file reads a config file at a given path (hardcoded as `config.yaml` in
`main.py`), processes everything in it and makes the values available to the
rest of the bot's code so it knows what to do. Most of the options in the given
config file have default values, so things will continue to work even if an
option is left out of the config file. Obviously there are some config values
that are required though, like the homeserver URL, username, access token etc.
Otherwise the bot can't function.
### `storage.py`
Creates (if necessary) and connects to a SQLite3 database and provides commands
to put or retrieve data from it. Table definitions should be specified in
`_initial_setup`, and any necessary migrations should be put in
`_run_migrations`. There's currently no defined method for how migrations
should work though.
### `callbacks.py`
Holds callback methods which get run when the bot get a certain type of event
from the homserver during sync. The type and name of the method to be called
are specified in `main.py`. Currently there are two defined methods, one that
gets called when a message is sent in a room the bot is in, and another that
runs when the bot receives an invite to the room.
The message callback function, `message`, checks if the message was for the
bot, and whether it was a command. If both of those are true, the bot will
process that command.
The invite callback function, `invite`, processes the invite event and attempts
to join the room. This way, the bot will auto-join any room it is invited to.
### `bot_commands.py`
Where all the bot's commands are defined. New commands should be defined in
`process` with an associated private method. `echo` and `help` commands are
provided by default.
A `Command` object is created when a message comes in that's recognised as a
command from a user directed at the bot (either through the specified command
prefix (defined by the bot's config file), or through a private message
directly to the bot. The `process` command is then called for the bot to act on
that command.
### `message_responses.py`
Where responses to messages that are posted in a room (but not necessarily
directed at the bot) are specified. `callbacks.py` will listen for messages in
rooms the bot is in, and upon receiving one will create a new `Message` object
(which contains the message text, amongst other things) and calls `process()`
on it, which can send a message to the room as it sees fit.
A good example of this would be a Github bot that listens for people mentioning
issue numbers in chat (e.g. "We should fix #123"), and the bot sending messages
to the room immediately afterwards with the issue name and link.
### `chat_functions.py`
A separate file to hold helper methods related to messaging. Mostly just for
organisational purposes. Currently just holds `send_text_to_room`, a helper
method for sending formatted messages to a room.
### `errors.py`
Custom error types for the bot. Currently there's only one special type that's
defined for when a error is found while the config file is being processed.
## Questions?
Any questions? Please ask them in
[#nio-template:amorgan.xyz](https://matrix.to/#/!vmWBOsOkoOtVHMzZgN:amorgan.xyz?via=amorgan.xyz)
and we'll help you out!

@ -60,7 +60,7 @@ RUN apk add --no-cache \
# This speeds up subsequent image builds when the source code is changed
RUN mkdir -p /src/molly
COPY molly/__init__.py /src/molly/
COPY README.md molly /src/
COPY readme.org molly /src/
# Build the dependencies
COPY setup.py /src/setup.py

@ -55,7 +55,7 @@ RUN apk add --no-cache \
# such that these dependencies can be cached
RUN mkdir -p /src/molly
COPY molly/__init__.py /src/molly/
COPY README.md run_molly /src/
COPY readme.org run_molly /src/
COPY setup.py /src/setup.py
RUN pip install -e "/src/"

@ -92,7 +92,7 @@ class Command:
async def _new_org_todo(self):
"""Given a plaintext string, return org-formatted todo line."""
formatted_string = " ".join(self.args)
new_string = f"* {formatted_string} \n"
new_string = f"* TODO {formatted_string} \n"
await send_text_to_room(self.client, self.room.room_id, f"creating new todo with {new_string}")
print(dir(self.config))
with open(self.config.orgmode_refile_path, "a") as orgfile:

@ -8,7 +8,7 @@
- Eventually, come back on your main computer and refile shit accordingly.
** Project Outline
- [-] Be able to write orgmode from within Python (use Karlicoss' library for this)
- [-] Be able to write orgmode from within Python
- [X] Write basic todo entries
- [ ] Add meta data (when was I captured, etc)
- [X] Be able to read matrix messages from within Python (use matrix nio, apparently its the Approved Shit now https://github.com/poljar/matrix-nio)

@ -1,20 +0,0 @@
#!/bin/sh
#
# Runs linting scripts over the local checkout
# isort - sorts import statements
# flake8 - lints and finds mistakes
# black - opinionated code formatter
set -e
if [ $# -ge 1 ]
then
files=$*
else
files="molly molly tests"
fi
echo "Linting these locations: $files"
isort $files
flake8 $files
python3 -m black $files

@ -1,64 +0,0 @@
#!/bin/bash -e
# Check that regex-rename is installed
if ! command -v regex-rename &> /dev/null
then
echo "regex-rename python module not found. Please run 'python -m pip install regex-rename'"
exit 1
fi
# GNU sed and BSD(Mac) sed handle -i differently :(
function is_gnu_sed(){
sed --version >/dev/null 2>&1
}
# Allow specifying either:
# * One argument, which is the new project name, assuming the old project name is "my project name"
# * Or two arguments, where one can specify 1. the old project name and 2. the new project name
if [ $# -eq 1 ]; then
PLACEHOLDER="my project name"
REPLACEMENT=$1
elif [ $# -eq 2 ]; then
PLACEHOLDER=$1
REPLACEMENT=$2
else
echo "Usage:"
echo "./"$(basename "$0") "\"new name\""
echo "./"$(basename "$0") "\"old name\" \"new name\""
exit 1
fi
PLACEHOLDER_DASHES="${PLACEHOLDER// /-}"
PLACEHOLDER_UNDERSCORES="${PLACEHOLDER// /_}"
REPLACEMENT_DASHES="${REPLACEMENT// /-}"
REPLACEMENT_UNDERSCORES="${REPLACEMENT// /_}"
echo "Updating file and folder names..."
# Iterate over all directories (besides venv's and .git) and rename files/folders
# Yes this looks like some crazy voodoo, but it's necessary as regex-rename does
# not provide any sort of recursive functionality...
find . -type d -not -path "./env*" -not -path "./.git" -not -path "./.git*" \
-exec sh -c "cd {} && \
regex-rename --rename \"(.*)$PLACEHOLDER_DASHES(.*)\" \"\1$REPLACEMENT_DASHES\2\" && \
regex-rename --rename \"(.*)$PLACEHOLDER_UNDERSCORES(.*)\" \"\1$REPLACEMENT_UNDERSCORES\2\"" \; > /dev/null
echo "Updating references within files..."
# Iterate through each file and replace strings within files
for file in $(grep --exclude-dir=env --exclude-dir=venv --exclude-dir=.git --exclude *.pyc -lEw "$PLACEHOLDER_DASHES|$PLACEHOLDER_UNDERSCORES" -R * .[^.]*); do
echo "Checking $file"
if [[ $file != $(basename "$0") ]]; then
if is_gnu_sed; then
sed -i "s/$PLACEHOLDER_DASHES/$REPLACEMENT_DASHES/g" $file
sed -i "s/$PLACEHOLDER_UNDERSCORES/$REPLACEMENT_UNDERSCORES/g" $file
else
sed -i "" "s/$PLACEHOLDER_DASHES/$REPLACEMENT_DASHES/g" $file
sed -i "" "s/$PLACEHOLDER_UNDERSCORES/$REPLACEMENT_UNDERSCORES/g" $file
fi
echo " - $file"
fi
done
echo "Done!"

@ -21,7 +21,7 @@ def read_file(path_segments):
version = exec_file(("molly", "__init__.py"))["__version__"]
long_description = read_file(("README.md",))
long_description = read_file(("readme.org",))
setup(

Loading…
Cancel
Save