Browse Source

Docstring fixes

merge-requests/1/head
Kirk Strauser 4 years ago
parent
commit
303a11b6d2
  1. 129
      botstreamlisteners.py
  2. 4
      custom_logic/example_custom_rss_include.py
  3. 2
      setup.py
  4. 4
      tests/test_toot_bot.py
  5. 4
      toot.py
  6. 24
      toot_bot.py

129
botstreamlisteners.py

@ -1,6 +1,6 @@
#!/usr/bin/env python3
''' Different stream listener implementations used by bots '''
"""Different stream listener implementations used by bots."""
import copy
import sqlite3
@ -10,7 +10,7 @@ from mastodon import Mastodon, StreamListener
class WelcomeBot(StreamListener):
''' Implementation of the Mastodon.py StreamListener class for welcome bot purposes '''
"""Implementation of the Mastodon.py StreamListener class for welcome bot purposes."""
def __init__(self, bot_config):
StreamListener.__init__(self)
@ -20,16 +20,17 @@ class WelcomeBot(StreamListener):
self.cursor = self.conn.cursor()
# Ensure cache table has been created
self.cursor.execute('''\
self.cursor.execute("""\
CREATE TABLE IF NOT EXISTS welcome_cache (
username VARCHAR(2048) PRIMARY KEY,
seen_timestamp TIMESTAMP
);
''')
self.cursor.execute('''\
""")
self.cursor.execute("""\
CREATE TABLE IF NOT EXISTS toot_cache (
toot_id INTEGER PRIMARY KEY
);''')
);
""")
self.conn.commit()
# Replay any toots that were missed while offline and welcome new users
@ -41,7 +42,8 @@ CREATE TABLE IF NOT EXISTS toot_cache (
self.conn.close()
def fetch_remaining(self, mastodon, first_page):
''' Work around for odd behavior in Mastodon.py's official fetch_remaining code '''
"""Work around for odd behavior in Mastodon.py's official fetch_remaining code."""
# FIXME: Remove this method when below GitHub issue is closed
# and a new release available FIXME: Don't forget to update
# minimum version of Mastodon.py to match when the fix is
@ -58,13 +60,12 @@ CREATE TABLE IF NOT EXISTS toot_cache (
return all_pages
def replay_toots(self, recurse=False):
''' Replay toots that were posted while the bot was offline '''
"""Replay toots that were posted while the bot was offline."""
# Setup Mastodon API
mastodon = Mastodon(
client_id=self.bot_config['config']['client_cred_file'],
access_token=self.bot_config['config']['user_cred_file'],
api_base_url=self.bot_config['config']['api_base_url']
)
api_base_url=self.bot_config['config']['api_base_url'])
self.cursor.execute('select max(toot_id) from toot_cache;')
last_seen_toot_id = self.cursor.fetchone()[0]
@ -87,7 +88,8 @@ CREATE TABLE IF NOT EXISTS toot_cache (
new_last_seen_toot_id = all_pages[0]['id']
if new_last_seen_toot_id > last_seen_toot_id:
self.cursor.execute('insert into toot_cache values (?)', (new_last_seen_toot_id,))
self.cursor.execute('insert into toot_cache values (?)',
(new_last_seen_toot_id, ))
self.conn.commit()
# Recurse in case the catch up took long enough for more toots to enter the public timeline
@ -97,9 +99,9 @@ CREATE TABLE IF NOT EXISTS toot_cache (
self.replay_toots()
def welcome_user(self, status):
'''Method that sets up toot and welcomes new users (method due to use
in multiple places)
'''
"""Method that sets up toot and welcomes new users.
Method due to use in multiple places."""
toot_id = status['id']
federated = '@' in status['account']['acct']
username = status['account']['acct']
@ -107,14 +109,15 @@ CREATE TABLE IF NOT EXISTS toot_cache (
visibility = status['visibility']
# Cache toot
self.cursor.execute('insert into toot_cache values (?)', (toot_id,))
self.cursor.execute('insert into toot_cache values (?)', (toot_id, ))
self.conn.commit()
# Welcome any user who's posted publicly
if visibility == 'public' and not federated:
# Check if username has been seen for welcome
self.cursor.execute('select count(1) as found from welcome_cache where username = ?',
(username,))
self.cursor.execute(
'select count(1) as found from welcome_cache where username = ?',
(username, ))
if self.cursor.fetchone()[0] > 0:
return
@ -122,40 +125,55 @@ CREATE TABLE IF NOT EXISTS toot_cache (
toot(self.bot_config, username=username)
# Cache user to avoid duping welcome messages
self.cursor.execute('insert into welcome_cache values (?, ?)', (username, timestamp))
self.cursor.execute('insert into welcome_cache values (?, ?)',
(username, timestamp))
self.conn.commit()
def on_update(self, status):
'''A new status has appeared! 'status' is the parsed JSON dictionary
describing the status.'''
"""A new status has appeared!
'status' is the parsed JSON dictionary describing the
status.
"""
self.welcome_user(status)
def on_notification(self, notification):
'''A new notification. 'notification' is the parsed JSON dictionary
describing the notification.'''
"""A new notification.
'notification' is the parsed JSON dictionary describing the
notification.
"""
# We don't care if notifications come through our bot / curation account
# Leave handling notifications/folow up to the admins and e-mail notifications
pass
def on_delete(self, status_id):
'''A status has been deleted. status_id is the status' integer ID.'''
"""A status has been deleted.
status_id is the status' integer ID.
"""
# Remove the status from the toot_cache if we see a delete
self.cursor.execute('delete from toot_cache where toot_id = ?', (status_id,))
self.cursor.execute('delete from toot_cache where toot_id = ?',
(status_id, ))
self.conn.commit()
def handle_heartbeat(self):
'''The server has sent us a keep-alive message. This callback may be
useful to carry out periodic housekeeping tasks, or just to confirm
that the connection is still open.'''
"""The server has sent us a keep-alive message.
This callback may be useful to carry out periodic housekeeping
tasks, or just to confirm that the connection is still
open.
"""
# Consistently/constantly trim the toot cache to the most recent seen toot
self.cursor.execute('''\
self.cursor.execute("""\
DELETE FROM toot_cache WHERE toot_id <= ((SELECT MAX(toot_id) FROM toot_cache) - 1);
''')
""")
self.conn.commit()
class CurationBot(StreamListener):
''' Implementation of the Mastodon.py StreamListener class for curation bot purposes '''
"""Implementation of the Mastodon.py StreamListener class for curation bot purposes."""
def __init__(self, bot_config):
StreamListener.__init__(self)
self.bot_config = bot_config
@ -164,7 +182,7 @@ class CurationBot(StreamListener):
self.cursor = self.conn.cursor()
# Ensure cache table has been created
self.cursor.execute('''\
self.cursor.execute("""\
CREATE TABLE IF NOT EXISTS toot_cache (
toot_id INTEGER PRIMARY KEY,
federated BOOL,
@ -174,7 +192,8 @@ CREATE TABLE IF NOT EXISTS toot_cache (
toot_timestamp TIMESTAMP,
favorites INTEGER,
boosts INTEGER
);''')
);
""")
self.conn.commit()
@ -183,8 +202,11 @@ CREATE TABLE IF NOT EXISTS toot_cache (
self.conn.close()
def on_update(self, status):
'''A new status has appeared! 'status' is the parsed JSON dictionary
describing the status.'''
"""A new status has appeared!
'status' is the parsed JSON dictionary describing the
status.
"""
if status['visibility'] == 'public':
toot_id = status['id']
federated = '@' in status['account']['acct']
@ -198,35 +220,48 @@ CREATE TABLE IF NOT EXISTS toot_cache (
# tags = status['tags']
# Ensure a toot isn't cached twice for some odd reason
self.cursor.execute('select count(1) as found from toot_cache where toot_id = ?',
(toot_id,))
self.cursor.execute(
'select count(1) as found from toot_cache where toot_id = ?',
(toot_id, ))
if self.cursor.fetchone()[0] > 0:
return
# Cache toot
self.cursor.execute(
'insert into toot_cache values (?, ?, ?, ?, ?, ?, ?, ?)',
(toot_id, federated, username, is_reply, is_boost, timestamp, favorites, boosts)
)
(toot_id, federated, username, is_reply, is_boost, timestamp,
favorites, boosts))
self.conn.commit()
def on_notification(self, notification):
'''A new notification. 'notification' is the parsed JSON dictionary
describing the notification.'''
"""A new notification.
'notification' is the parsed JSON dictionary describing the
notification.
"""
# We don't care if notifications come through our bot / curation account
# Leave handling notifications/folow up to the admins and e-mail notifications
pass
def on_delete(self, status_id):
'''A status has been deleted. status_id is the status' integer ID.'''
"""A status has been deleted.
status_id is the status' integer ID.
"""
# Remove the status from the toot_cache if we see a delete
self.cursor.execute('delete from toot_cache where toot_id = ?', (status_id,))
self.cursor.execute('delete from toot_cache where toot_id = ?',
(status_id, ))
self.conn.commit()
def handle_heartbeat(self):
'''The server has sent us a keep-alive message. This callback may be
useful to carry out periodic housekeeping tasks, or just to confirm
that the connection is still open.'''
"""The server has sent us a keep-alive message.
This callback may be useful to carry out periodic housekeeping
tasks, or just to confirm that the connection is still
open.
"""
print('!!!!!!!!heartbeat!!!!!!!!')
print(' we should probably update statuses and whatnot here or at least do some '
'housekeeping for old toots')
print(
' we should probably update statuses and whatnot here or at least do some '
'housekeeping for old toots')

4
custom_logic/example_custom_rss_include.py

@ -1,5 +1,7 @@
"""Example of how to build an article filter."""
def include_article(article):
'''Custom include logic for dPS photog challenges posted on main RSS feed.'''
"""Custom include logic for dPS photog challenges posted on main RSS feed."""
if 'Weekly' in article.title and 'Challenge' in article.title:
return True

2
setup.py

@ -1,3 +1,5 @@
"""mastodon_bot installer."""
from setuptools import setup
setup(

4
tests/test_toot_bot.py

@ -1,3 +1,7 @@
"""Tests for the toot_bot module."""
# pylint: disable=missing-docstring
import toot_bot
def test_default_include_article():

4
toot.py

@ -1,12 +1,12 @@
#!/usr/bin/env python3
''' Various Toot help method for bots '''
"""Various Toot help method for bots."""
from mastodon import Mastodon
def toot(config, article=None, username=None):
''' Send a toot '''
"""Send a toot."""
# Setup Mastodon API
mastodon = Mastodon(
client_id=config['config']['client_cred_file'],

24
toot_bot.py

@ -1,6 +1,6 @@
#!/usr/bin/env python3
''' Various Mastodon bots and their implementations '''
"""Various Mastodon bots and their implementations."""
import argparse
import codecs
@ -20,8 +20,10 @@ from toot import toot
def init(config):
''' Initialize the Mastdon API app and cache the API key
Auto login if app creation succeeds '''
"""Initialize the Mastdon API app and cache the API key.
Auto login if app creation succeeds.
"""
# Prompt user to find out if they want to continue if the client_cred_file exists already
# Shouldn't happen twice per docs
if os.path.exists(config['config']['client_cred_file']):
@ -43,7 +45,7 @@ def init(config):
def login(config):
''' Login to API and cache API access token(s) '''
"""Login to API and cache API access token(s)."""
# Prompt for user/password (NEVER store them on disk!)
email = input(
'what is the e-mail that was used to setup the bot account on {}? '.format(
@ -84,8 +86,10 @@ def login(config):
# Default implementation on whether or not to include an RSS article
# Returns true and has the same method signature as what end users can setup for custom logic
def default_include_article(article):
''' Default implementation of RSS processing logic
Extended via external file if necessary '''
"""Default implementation of RSS processing logic.
Extended via external file if necessary.
"""
if article is None:
return False
@ -93,7 +97,7 @@ def default_include_article(article):
def rss(config):
''' Parse RSS feed and toot any new articles '''
"""Parse RSS feed and toot any new articles."""
# Setup custom include logic before opening any database connections
include_article_fn = default_include_article
@ -141,7 +145,7 @@ def rss(config):
def curate(config):
''' Curate (fav/boost) popular posts on local and/or federated timelines '''
"""Curate (fav/boost) popular posts on local and/or federated timelines."""
# Setup Mastodon API
mastodon = Mastodon(
client_id=config['config']['client_cred_file'],
@ -153,7 +157,7 @@ def curate(config):
def welcome(config):
''' Welcome new users to the instance '''
"""Welcome new users to the instance."""
# Setup Mastodon API
mastodon = Mastodon(
client_id=config['config']['client_cred_file'],
@ -165,7 +169,7 @@ def welcome(config):
def handle_command_line():
'''Parse and act on the command line.'''
"""Parse and act on the command line."""
# Global CLI arguments/options
parser = argparse.ArgumentParser()
parser.add_argument('--config', help='path to config file', required=True)

Loading…
Cancel
Save