aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/accept_invite.py5
-rw-r--r--modules/auto_mode.py5
-rw-r--r--modules/birthday.py20
-rw-r--r--modules/bot_channel.py4
-rw-r--r--modules/channel_log/__init__.py5
-rw-r--r--modules/channel_op.py26
-rw-r--r--modules/check_mode.py11
-rw-r--r--modules/check_urls.py16
-rw-r--r--modules/commands/__init__.py43
-rw-r--r--modules/config.py9
-rw-r--r--modules/ctcp.py5
-rw-r--r--modules/ducks.py15
-rw-r--r--modules/git_webhooks/__init__.py15
-rw-r--r--modules/github.py16
-rw-r--r--modules/google.py5
-rw-r--r--modules/greeting.py6
-rw-r--r--modules/imgur.py5
-rw-r--r--modules/ip_addresses.py15
-rw-r--r--modules/ircv3.py2
-rw-r--r--modules/ircv3_sasl/__init__.py20
-rw-r--r--modules/karma.py10
-rw-r--r--modules/lastfm.py4
-rw-r--r--modules/location.py13
-rw-r--r--modules/nickserv.py5
-rw-r--r--modules/permissions/__init__.py5
-rw-r--r--modules/print_activity.py5
-rw-r--r--modules/pronouns.py4
-rw-r--r--modules/rest_api.py10
-rw-r--r--modules/sed.py10
-rw-r--r--modules/shorturl.py8
-rw-r--r--modules/strip_color.py10
-rw-r--r--modules/title.py16
-rw-r--r--modules/trakt.py4
-rw-r--r--modules/tweets/__init__.py5
-rw-r--r--modules/vote.py6
-rw-r--r--modules/words.py5
-rw-r--r--modules/youtube.py10
-rw-r--r--src/utils/__init__.py44
38 files changed, 203 insertions, 219 deletions
diff --git a/modules/accept_invite.py b/modules/accept_invite.py
index 61afb4e6..877a95f6 100644
--- a/modules/accept_invite.py
+++ b/modules/accept_invite.py
@@ -2,9 +2,8 @@
from src import ModuleManager, utils
-@utils.export("serverset", {"setting": "accept-invites",
- "help": "Set whether I accept invites on this server",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("serverset", utils.BoolSetting("accept-invites",
+ "Set whether I accept invites on this server"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.invite")
def on_invite(self, event):
diff --git a/modules/auto_mode.py b/modules/auto_mode.py
index db503133..93ea303c 100644
--- a/modules/auto_mode.py
+++ b/modules/auto_mode.py
@@ -5,9 +5,8 @@
from src import ModuleManager, utils
-@utils.export("channelset", {"setting": "automode",
- "help": "Disable/Enable automode", "validate": utils.bool_or_none,
- "example": "on"})
+@utils.export("channelset", utils.BoolSetting(
+ "automode", "Disable/Enable automode"))
class Module(ModuleManager.BaseModule):
_name = "AutoMode"
diff --git a/modules/birthday.py b/modules/birthday.py
index 46a1dde6..563c7a73 100644
--- a/modules/birthday.py
+++ b/modules/birthday.py
@@ -1,7 +1,7 @@
#--depends-on commands
#--depends-on config
-import datetime
+import datetime, typing
from src import ModuleManager, utils
DATE_YEAR_FORMAT = "%Y-%m-%d"
@@ -30,20 +30,22 @@ def _format(years, dt):
return _format_year(dt)
else:
return _format_noyear(dt)
-def _check(s):
- parsed = _parse(s)
- if parsed:
- years, parsed = parsed
- return _format(years, parsed)
- return None
+
+class BirthdaySetting(utils.Setting):
+ def parse(self, value: str) -> typing.Any:
+ parsed = _parse(value)
+ if parsed:
+ years, parsed = parsed
+ return _format(years, parsed)
+ return None
def _apostrophe(nickname):
if nickname[-1].lower() == "s":
return "%s'" % nickname
return "%s's" % nickname
-@utils.export("set", {"setting": "birthday", "help": "Set your birthday",
- "validate": _check, "example": "1995-09-15"})
+@utils.export("set", BirthdaySetting("birthday", "Set your birthday",
+ example="1995-09-15"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.command.birthday")
def birthday(self, event):
diff --git a/modules/bot_channel.py b/modules/bot_channel.py
index d7c7e8b2..32f3f1fc 100644
--- a/modules/bot_channel.py
+++ b/modules/bot_channel.py
@@ -2,8 +2,8 @@
from src import ModuleManager, utils
-@utils.export("serverset", {"setting": "bot-channel",
- "help": "Set main channel", "example": "#bitbot"})
+@utils.export("serverset", utils.Setting("bot-channel",
+ "Set main channel", example="#bitbot"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.001")
def do_join(self, event):
diff --git a/modules/channel_log/__init__.py b/modules/channel_log/__init__.py
index 583957a0..48fb93f4 100644
--- a/modules/channel_log/__init__.py
+++ b/modules/channel_log/__init__.py
@@ -7,9 +7,8 @@ from src import ModuleManager, utils
ROOT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
LOGS_DIRECTORY = os.path.join(ROOT_DIRECTORY, "logs")
-@utils.export("channelset", {"setting": "log",
- "help": "Enable/disable channel logging", "validate": utils.bool_or_none,
- "example": "on"})
+@utils.export("channelset", utils.BoolSetting("log",
+ "Enable/disable channel logging"))
class Module(ModuleManager.BaseModule):
def _log_file(self, server_name, channel_name):
return open(os.path.join(LOGS_DIRECTORY,
diff --git a/modules/channel_op.py b/modules/channel_op.py
index 02688626..11d5a0d5 100644
--- a/modules/channel_op.py
+++ b/modules/channel_op.py
@@ -10,21 +10,17 @@ class UserNotFoundException(Exception):
class InvalidTimeoutException(Exception):
pass
-@utils.export("channelset", {"setting": "highlight-spam-threshold",
- "help": "Set the number of nicknames in a message that qualifies as spam",
- "validate": utils.int_or_none, "example": "10"})
-@utils.export("channelset", {"setting": "highlight-spam-protection",
- "help": "Enable/Disable highlight spam protection",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "highlight-spam-ban",
- "help": "Enable/Disable banning highlight spammers "
- "instead of just kicking", "validate": utils.bool_or_none,
- "example": "on"})
-@utils.export("channelset", {"setting": "ban-format",
- "help": "Set ban format ($n = nick, $u = username, $h = hostname)",
- "example": "*!$u@$h"})
-@utils.export("serverset", {"setting": "mute-method",
- "help": "Set this server's method of muting users", "example": "qmode"})
+@utils.export("channelset", utils.IntSetting("highlight-spam-threshold",
+ "Set the number of nicknames in a message that qualifies as spam"))
+@utils.export("channelset", utils.BoolSetting("highlight-spam-protection",
+ "Enable/Disable highlight spam protection"))
+@utils.export("channelset", utils.BoolSetting("highlight-spam-ban",
+ "Enable/Disable banning highlight spammers instead of just kicking"))
+@utils.export("channelset", utils.Setting("ban-format",
+ "Set ban format ($n = nick, $u = username, $h = hostname)",
+ example="*!$u@$h"))
+@utils.export("serverset", utils.Setting("mute-method",
+ "Set this server's method of muting users", example="qmode"))
class Module(ModuleManager.BaseModule):
_name = "ChanOp"
diff --git a/modules/check_mode.py b/modules/check_mode.py
index 1ad96e10..67d48172 100644
--- a/modules/check_mode.py
+++ b/modules/check_mode.py
@@ -6,12 +6,11 @@ LOWHIGH = {
"low": "v",
"high": "o"
}
-@utils.export("channelset", {"setting": "mode-low",
- "help": "Set which channel mode is considered to be 'low' access",
- "example": "v"})
-@utils.export("channelset", {"setting": "mode-high",
- "help": "Set which channel mode is considered to be 'high' access",
- "example": "o"})
+
+@utils.export("channelset", utils.Setting("mode-low",
+ "Set which channel mode is considered to be 'low' access", example="v"))
+@utils.export("channelset", utils.Setting("mode-high",
+ "Set which channel mode is considered to be 'high' access", example="o"))
class Module(ModuleManager.BaseModule):
def _check_command(self, event, channel, require_mode):
if event["is_channel"] and require_mode:
diff --git a/modules/check_urls.py b/modules/check_urls.py
index 1ea83ebc..c8e81642 100644
--- a/modules/check_urls.py
+++ b/modules/check_urls.py
@@ -8,16 +8,12 @@ from src import ModuleManager, utils
URL_VIRUSTOTAL = "https://www.virustotal.com/vtapi/v2/url/report"
RE_URL = re.compile(r"https?://\S+", re.I)
-@utils.export("channelset", {"setting": "check-urls",
- "help": "Enable/Disable automatically checking for malicious URLs",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("serverset", {"setting": "check-urls",
- "help": "Enable/Disable automatically checking for malicious URLs",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "check-urls-kick",
- "help": "Enable/Disable automatically kicking users that "
- "send malicious URLs", "validate": utils.bool_or_none,
- "example": "on"})
+@utils.export("channelset", utils.BoolSetting("check-urls",
+ "Enable/Disable automatically checking for malicious URLs"))
+@utils.export("serverset", utils.BoolSetting("check-urls",
+ "Enable/Disable automatically checking for malicious URLs"))
+@utils.export("channelset", utils.BoolSetting("check-urls-kick",
+ "Enable/Disable automatically kicking users that send malicious URLs"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.message.channel")
def message(self, event):
diff --git a/modules/commands/__init__.py b/modules/commands/__init__.py
index 46f79ab3..fdb21075 100644
--- a/modules/commands/__init__.py
+++ b/modules/commands/__init__.py
@@ -1,7 +1,7 @@
#--depends-on config
#--depends-on permissions
-import re, string, typing
+import re, string, traceback, typing
from src import EventManager, ModuleManager, utils
from . import outs
@@ -20,25 +20,28 @@ def _command_method_validate(s):
if s.upper() in COMMAND_METHODS:
return s.upper()
-@utils.export("channelset", {"setting": "command-prefix",
- "help": "Set the command prefix used in this channel", "example": "!"})
-@utils.export("serverset", {"setting": "command-prefix",
- "help": "Set the command prefix used on this server", "example": "!"})
-@utils.export("serverset", {"setting": "command-method",
- "help": "Set the method used to respond to commands",
- "validate": _command_method_validate, "example": "NOTICE"})
-@utils.export("channelset", {"setting": "command-method",
- "help": "Set the method used to respond to commands",
- "validate": _command_method_validate, "example": "NOTICE"})
-@utils.export("channelset", {"setting": "hide-prefix",
- "help": "Disable/enable hiding prefix in command reponses",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "commands",
- "help": "Disable/enable responding to commands in-channel",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "prefixed-commands",
- "help": "Disable/enable responding to prefixed commands in-channel",
- "validate": utils.bool_or_none, "example": "on"})
+class CommandMethodSetting(utils.Setting):
+ example = "NOTICE"
+ def parse(self, value: str) -> typing.Any:
+ upper = value.upper()
+ if upper in COMMAND_METHODS:
+ return upper
+ return None
+
+@utils.export("channelset", utils.Setting("command-prefix",
+ "Set the command prefix used in this channel", example="!"))
+@utils.export("serverset", utils.Setting("command-prefix",
+ "Set the command prefix used on this server", example="!"))
+@utils.export("serverset", CommandMethodSetting("command-method",
+ "Set the method used to respond to commands"))
+@utils.export("channelset", CommandMethodSetting("command-method",
+ "Set the method used to respond to commands"))
+@utils.export("channelset", utils.BoolSetting("hide-prefix",
+ "Disable/enable hiding prefix in command reponses"))
+@utils.export("channelset", utils.BoolSetting("commands",
+ "Disable/enable responding to commands in-channel"))
+@utils.export("channelset", utils.BoolSetting("prefixed-commands",
+ "Disable/enable responding to prefixed commands in-channel"))
class Module(ModuleManager.BaseModule):
@utils.hook("new.user")
@utils.hook("new.channel")
diff --git a/modules/config.py b/modules/config.py
index 6ef50c05..8c070e0d 100644
--- a/modules/config.py
+++ b/modules/config.py
@@ -84,19 +84,18 @@ class Module(ModuleManager.BaseModule):
if setting_info:
value = target.get_setting(require_setting, None)
if value == None:
- example = setting_info.get("example", "<value>")
+ example = setting_info.exaple or "<value>"
return "Please set %s, e.g.: %sconfig %s %s %s" % (
require_setting, event["command_prefix"], context[0],
require_setting, example)
def _get_export_setting(self, context):
settings = self.exports.get_all(context)
- return {setting["setting"].lower(): setting for setting in settings}
+ return {setting.name.lower(): setting for setting in settings}
def _config(self, export_settings, target, setting, value=None):
if not value == None:
- validation = export_settings[setting].get("validate", lambda x: x)
- validated_value = validation(value)
+ validated_value = export_settings[setting].parse(value)
if not validated_value == None:
target.set_setting(setting, validated_value)
return ConfigResult(ConfigResults.Changed, validated_value)
@@ -181,7 +180,7 @@ class Module(ModuleManager.BaseModule):
try:
result = self._config(export_settings, target, setting, value)
except ConfigInvalidValue:
- example = export_settings[setting].get("example", None)
+ example = export_settings[setting].example
if not example == None:
raise utils.EventError("Invalid value. Example: %s" %
example)
diff --git a/modules/ctcp.py b/modules/ctcp.py
index 58f8d7e5..678cf833 100644
--- a/modules/ctcp.py
+++ b/modules/ctcp.py
@@ -4,9 +4,8 @@ import datetime
from src import IRCBot, ModuleManager, utils
-@utils.export("serverset", {"setting": "ctcp-responses",
- "help": "Set whether I respond to CTCPs on this server",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("serverset", utils.BoolSetting("ctcp-responses",
+ "Set whether I respond to CTCPs on this server"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.ctcp.request.version")
def ctcp_version(self, event):
diff --git a/modules/ducks.py b/modules/ducks.py
index 037c602b..afef16d2 100644
--- a/modules/ducks.py
+++ b/modules/ducks.py
@@ -9,15 +9,12 @@ NO_DUCK = "There was no duck!"
DEFAULT_MIN_MESSAGES = 100
-@utils.export("channelset", {"setting": "ducks-enabled",
- "help": "Whether or not to spawn ducks", "validate": utils.bool_or_none,
- "example": "on"})
-@utils.export("channelset", {"setting": "ducks-min-messages",
- "help": "Minimum messages between ducks spawning",
- "validate": utils.int_or_none, "example": "50"})
-@utils.export("channelset", {"setting": "ducks-kick",
- "help": "Whether or not to kick someone talking to non-existent ducks",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", utils.BoolSetting("ducks-enabled",
+ "Whether or not to spawn ducks"))
+@utils.export("channelset", utils.IntSetting("ducks-min-messages",
+ "Minimum messages between ducks spawning", example="50"))
+@utils.export("channelset", utils.BoolSetting("ducks-kick",
+ "Whether or not to kick someone talking to non-existent ducks"))
class Module(ModuleManager.BaseModule):
@utils.hook("new.channel")
def new_channel(self, event):
diff --git a/modules/git_webhooks/__init__.py b/modules/git_webhooks/__init__.py
index b76ec4a3..a86eda68 100644
--- a/modules/git_webhooks/__init__.py
+++ b/modules/git_webhooks/__init__.py
@@ -13,15 +13,12 @@ DEFAULT_EVENT_CATEGORIES = [
"ping", "code", "pr", "issue", "repo"
]
-@utils.export("channelset", {"setting": "git-prevent-highlight",
- "help": "Enable/disable preventing highlights",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "git-hide-organisation",
- "help": "Hide/show organisation in repository names",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "git-hide-prefix",
- "help": "Hide/show command-like prefix on git webhook outputs",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", utils.BoolSetting("git-prevent-highlight",
+ "Enable/disable preventing highlights"))
+@utils.export("channelset", utils.BoolSetting("git-hide-organisation",
+ "Hide/show organisation in repository names"))
+@utils.export("channelset", utils.BoolSetting("git-hide-prefix",
+ "Hide/show command-like prefix on git webhook outputs"))
class Module(ModuleManager.BaseModule):
_name = "Webhooks"
diff --git a/modules/github.py b/modules/github.py
index 102f3ab2..633f1a0a 100644
--- a/modules/github.py
+++ b/modules/github.py
@@ -22,15 +22,13 @@ REGEX_REF = re.compile(r"(?:\S+(?:\/\S+)?)?#\d+")
API_ISSUE_URL = "https://api.github.com/repos/%s/%s/issues/%s"
API_PULL_URL = "https://api.github.com/repos/%s/%s/pulls/%s"
-@utils.export("channelset", {"setting": "github-default-repo",
- "help": "Set the default github repo for the current channel",
- "example": "jesopo/bitbot"})
-@utils.export("channelset", {"setting": "auto-github",
- "help": "Enable/disable automatically getting github issue/PR info",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "auto-github-cooldown",
- "help": "Set amount of seconds between auto-github duplicates",
- "validate": utils.int_or_none, "example": "300"})
+@utils.export("channelset", utils.Setting("github-default-repo",
+ "Set the default github repo for the current channel",
+ example="jesopo/bitbot"))
+@utils.export("channelset", utils.Setting("auto-github",
+ "Enable/disable automatically getting github issue/PR info"))
+@utils.export("channelset", utils.IntSetting("auto-github-cooldown",
+ "Set amount of seconds between auto-github duplicates", example="300"))
class Module(ModuleManager.BaseModule):
def _parse_ref(self, channel, ref):
repo, _, number = ref.rpartition("#")
diff --git a/modules/google.py b/modules/google.py
index f365ee90..123c7a58 100644
--- a/modules/google.py
+++ b/modules/google.py
@@ -9,9 +9,8 @@ from src import ModuleManager, utils
URL_GOOGLESEARCH = "https://www.googleapis.com/customsearch/v1"
URL_GOOGLESUGGEST = "http://google.com/complete/search"
-@utils.export("channelset", {"setting": "google-safesearch",
- "help": "Turn safe search off/on",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", utils.BoolSetting("google-safesearch",
+ "Turn safe search off/on"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.command.g", alias_of="google")
@utils.hook("received.command.google")
diff --git a/modules/greeting.py b/modules/greeting.py
index a1005436..9f5b9b78 100644
--- a/modules/greeting.py
+++ b/modules/greeting.py
@@ -2,9 +2,9 @@
from src import ModuleManager, utils
-@utils.export("channelset", {"setting": "greeting",
- "help": "Set a greeting to send to users when they join",
- "example": "welcome to the channel!"})
+@utils.export("channelset", utils.Setting("greeting",
+ "Set a greeting to send to users when they join",
+ example="welcome to the channel!"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.join")
def join(self, event):
diff --git a/modules/imgur.py b/modules/imgur.py
index fd68ed00..9c9e8c57 100644
--- a/modules/imgur.py
+++ b/modules/imgur.py
@@ -16,9 +16,8 @@ URL_GALLERY = "https://api.imgur.com/3/gallery/%s"
NSFW_TEXT = "(NSFW)"
-@utils.export("channelset", {"setting": "auto-imgur",
- "help": "Disable/Enable automatically getting info from Imgur URLs",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", utils.BoolSetting("auto-imgur",
+ "Disable/Enable automatically getting info from Imgur URLs"))
class Module(ModuleManager.BaseModule):
def _prefix(self, data):
text = "%s: " % data["id"]
diff --git a/modules/ip_addresses.py b/modules/ip_addresses.py
index e13f59ff..62208504 100644
--- a/modules/ip_addresses.py
+++ b/modules/ip_addresses.py
@@ -1,6 +1,6 @@
#--depends-on commands
-import re, socket
+import re, socket, typing
from src import ModuleManager, utils
import dns.resolver
@@ -9,13 +9,14 @@ REGEX_IPv6 = r"(?:(?:[a-f0-9]{1,4}:){2,}|[a-f0-9:]*::)[a-f0-9:]*"
REGEX_IPv4 = r"(?:\d{1,3}\.){3}\d{1,3}"
REGEX_IP = re.compile("(%s)|(%s)" % (REGEX_IPv4, REGEX_IPv6), re.I)
-def _dns_validate(s):
- if utils.is_ip(s):
- return s
- return None
+class DnsSetting(utils.Setting):
+ def parse(self, value: str) -> typing.Any:
+ if utils.is_ip(value):
+ return value
+ return None
-@utils.export("serverset", {"setting": "dns-nameserver",
- "help": "Set DNS nameserver", "example": "8.8.8.8"})
+@utils.export("serverset", DnsSetting("dns-nameserver",
+ "Set DNS nameserver", example="8.8.8.8"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.command.dns", min_args=1)
def dns(self, event):
diff --git a/modules/ircv3.py b/modules/ircv3.py
index 8b3c388f..0628e7e7 100644
--- a/modules/ircv3.py
+++ b/modules/ircv3.py
@@ -11,7 +11,7 @@ class Module(ModuleManager.BaseModule):
supporting_servers = []
for server in self.bot.servers.values():
- if not server.connection_params.hostname == "localhost":
+ if server.get_setting("ircv3-stats", False):
if spec in server.server_capabilities:
port = str(server.connection_params.port)
if server.connection_params.tls:
diff --git a/modules/ircv3_sasl/__init__.py b/modules/ircv3_sasl/__init__.py
index c86796b0..b93c9b07 100644
--- a/modules/ircv3_sasl/__init__.py
+++ b/modules/ircv3_sasl/__init__.py
@@ -1,6 +1,6 @@
#--depends-on config
-import base64, hashlib, hmac, uuid
+import base64, hashlib, hmac, typing, uuid
from src import ModuleManager, utils
from . import scram
@@ -13,16 +13,16 @@ USERPASS_MECHANISMS = [
"PLAIN"
]
-def _validate(s):
- mechanism, _, arguments = s.partition(" ")
- return {"mechanism": mechanism, "args": arguments}
+class SaslSetting(utils.Setting):
+ def parse(self, value: str) -> typing.Any:
+ mechanism, _, arguments = value.partition(" ")
+ return {"mechanism": mechanism, "args": arguments}
-@utils.export("serverset", {"setting": "sasl",
- "help": "Set the sasl username/password for this server",
- "validate": _validate, "example": "PLAIN BitBot:hunter2"})
-@utils.export("serverset", {"setting": "sasl-hard-fail",
- "help": "Set whether a SASL failure should cause a disconnect",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("serverset", SaslSetting("sasl",
+ "Set the sasl username/password for this server",
+ example="PLAIN BitBot:hunter2"))
+@utils.export("serverset", utils.BoolSetting("sasl-hard-fail",
+ "Set whether a SASL failure should cause a disconnect"))
class Module(ModuleManager.BaseModule):
def _best_userpass_mechanism(self, mechanisms):
for potential_mechanism in USERPASS_MECHANISMS:
diff --git a/modules/karma.py b/modules/karma.py
index 7650e430..9f23244c 100644
--- a/modules/karma.py
+++ b/modules/karma.py
@@ -10,12 +10,10 @@ KARMA_DELAY_SECONDS = 3
REGEX_KARMA = re.compile(r"^(.*)(\+{2}|\-{2})$")
-@utils.export("channelset", {"setting": "karma-verbose",
- "help": "Enable/disable automatically responding to karma changes",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("serverset", {"setting": "karma-nickname-only",
- "help": "Enable/disable karma being for nicknames only",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", utils.BoolSetting("karma-verbose",
+ "Enable/disable automatically responding to karma changes"))
+@utils.export("serverset", utils.BoolSetting("karma-nickname-only",
+ "Enable/disable karma being for nicknames only"))
class Module(ModuleManager.BaseModule):
def _karma_str(self, karma):
karma_str = str(karma)
diff --git a/modules/lastfm.py b/modules/lastfm.py
index 2e08bdab..8078dc54 100644
--- a/modules/lastfm.py
+++ b/modules/lastfm.py
@@ -7,8 +7,8 @@ from src import ModuleManager, utils
URL_SCROBBLER = "http://ws.audioscrobbler.com/2.0/"
-@utils.export("set", {"setting": "lastfm", "help": "Set last.fm username",
- "example": "jesopo"})
+@utils.export("set", utils.Setting("lastfm", "Set last.fm username",
+ example="jesopo"))
class Module(ModuleManager.BaseModule):
_name = "last.fm"
diff --git a/modules/location.py b/modules/location.py
index 3f1eef65..84dcd691 100644
--- a/modules/location.py
+++ b/modules/location.py
@@ -1,14 +1,21 @@
#--depends-on config
+import typing
from src import ModuleManager, utils
URL_OPENCAGE = "https://api.opencagedata.com/geocode/v1/json"
+class LocationSetting(utils.Setting):
+ _func = None
+ def parse(self, value: str) -> typing.Any:
+ return self._func(value)
+
class Module(ModuleManager.BaseModule):
def on_load(self):
- self.exports.add("set", {"setting": "location",
- "help": "Set your location", "validate": self._get_location,
- "example": "London, GB"})
+ setting = LocationSetting("location", "Set your location",
+ example="London, GB")
+ setting._func = self._get_location
+ self.exports.add("set", setting)
def _get_location(self, s):
page = utils.http.request(URL_OPENCAGE, get_params={
diff --git a/modules/nickserv.py b/modules/nickserv.py
index ad8330d5..13f449a8 100644
--- a/modules/nickserv.py
+++ b/modules/nickserv.py
@@ -3,9 +3,8 @@
import base64
from src import EventManager, ModuleManager, utils
-@utils.export("serverset", {"setting": "nickserv-password",
- "help": "Set the nickserv password for this server",
- "example": "hunter2"})
+@utils.export("serverset", utils.Setting("nickserv-password",
+ "Set the nickserv password for this server", example="hunter2"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.001", priority=EventManager.PRIORITY_URGENT)
def on_connect(self, event):
diff --git a/modules/permissions/__init__.py b/modules/permissions/__init__.py
index 6003c256..f27033bf 100644
--- a/modules/permissions/__init__.py
+++ b/modules/permissions/__init__.py
@@ -9,9 +9,8 @@ REQUIRES_IDENTIFY = "You need to be identified to use that command"
REQUIRES_IDENTIFY_INTERNAL = ("You need to be identified to use that command "
"(/msg %s register | /msg %s identify)")
-@utils.export("serverset", {"setting": "identity-mechanism",
- "help": "Set the identity mechanism for this server",
- "example": "ircv3-account"})
+@utils.export("serverset", utils.Setting("identity-mechanism",
+ "Set the identity mechanism for this server", example="ircv3-account"))
class Module(ModuleManager.BaseModule):
@utils.hook("new.user")
def new_user(self, event):
diff --git a/modules/print_activity.py b/modules/print_activity.py
index 45b57e2a..f7e30feb 100644
--- a/modules/print_activity.py
+++ b/modules/print_activity.py
@@ -4,9 +4,8 @@
import datetime
from src import EventManager, ModuleManager, utils
-@utils.export("botset", {"setting": "print-motd",
- "help": "Set whether I print /motd", "validate": utils.bool_or_none,
- "example": "on"})
+@utils.export("botset",
+ utils.BoolSetting("print-motd", "Set whether I print /motd"))
class Module(ModuleManager.BaseModule):
def _print(self, event):
self.bot.log.info("%s%s | %s", [
diff --git a/modules/pronouns.py b/modules/pronouns.py
index e0d9b2c1..f800dad5 100644
--- a/modules/pronouns.py
+++ b/modules/pronouns.py
@@ -3,8 +3,8 @@
from src import ModuleManager, utils
-@utils.export("set", {"setting": "pronouns", "help": "Set your pronouns",
- "example": "she/her"})
+@utils.export("set", utils.Setting("pronouns", "Set your pronouns",
+ example="she/her"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.command.pronouns")
def pronouns(self, event):
diff --git a/modules/rest_api.py b/modules/rest_api.py
index a436bff3..19deff2d 100644
--- a/modules/rest_api.py
+++ b/modules/rest_api.py
@@ -110,12 +110,10 @@ class Handler(http.server.BaseHTTPRequestHandler):
def log_message(self, format, *args):
return
-@utils.export("botset", {"setting": "rest-api",
- "help": "Enable/disable REST API",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("botset", {"setting": "rest-api-minify",
- "help": "Enable/disable REST API minifying",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("botset",
+ utils.BoolSetting("rest-api", "Enable/disable REST API"))
+@utils.export("botset",
+ utils.BoolSetting("rest-api", "Enable/disable REST API minifying"))
class Module(ModuleManager.BaseModule):
def on_load(self):
global _bot
diff --git a/modules/sed.py b/modules/sed.py
index 20e85b68..0716d04d 100644
--- a/modules/sed.py
+++ b/modules/sed.py
@@ -7,12 +7,10 @@ from src import ModuleManager, utils
REGEX_SPLIT = re.compile("(?<!\\\\)/")
REGEX_SED = re.compile("^s/")
-@utils.export("channelset", {"setting": "sed",
- "help": "Disable/Enable sed in a channel",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "sed-sender-only",
- "help": "Disable/Enable sed only looking at the messages sent by the user",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset",
+ utils.BoolSetting("sed","Disable/Enable sed in a channel"))
+@utils.export("channelset", utils.BoolSetting("sed-sender-only",
+ "Disable/Enable sed only looking at the messages sent by the user"))
class Module(ModuleManager.BaseModule):
def _closest_setting(self, event, setting, default):
return event["target"].get_setting(setting,
diff --git a/modules/shorturl.py b/modules/shorturl.py
index 49b9f3cd..4959b53a 100644
--- a/modules/shorturl.py
+++ b/modules/shorturl.py
@@ -6,10 +6,10 @@ from src import ModuleManager, utils
URL_BITLYSHORTEN = "https://api-ssl.bitly.com/v3/shorten"
-@utils.export("serverset", {"setting": "url-shortener",
- "help": "Set URL shortener service", "example": "bitly"})
-@utils.export("botset", {"setting": "url-shortener",
- "help": "Set URL shortener service", "example": "bitly"})
+@utils.export("serverset", utils.Setting("url-shortener",
+ "Set URL shortener service", example="bitly"))
+@utils.export("botset", utils.Setting("url-shortener",
+ "Set URL shortener service", example="bitly"))
class Module(ModuleManager.BaseModule):
def on_load(self):
self.exports.add("shorturl", self._shorturl)
diff --git a/modules/strip_color.py b/modules/strip_color.py
index 28288209..736d066e 100644
--- a/modules/strip_color.py
+++ b/modules/strip_color.py
@@ -2,12 +2,10 @@
from src import ModuleManager, utils
-@utils.export("serverset", {"setting": "strip-color",
- "help": "Set whether I strip colors from my messages on this server",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "strip-color",
- "help": "Set whether I strip colors from my messages on in this channel",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("serverset", utils.BoolSetting("strip-color",
+ "Set whether I strip colors from my messages on this server"))
+@utils.export("channelset", utils.BoolSetting("strip-color",
+ "Set whether I strip colors from my messages on in this channel"))
class Module(ModuleManager.BaseModule):
@utils.hook("preprocess.send.privmsg")
@utils.hook("preprocess.send.notice")
diff --git a/modules/title.py b/modules/title.py
index a6e924cc..709b59ba 100644
--- a/modules/title.py
+++ b/modules/title.py
@@ -5,16 +5,12 @@
import hashlib, re, urllib.parse
from src import EventManager, ModuleManager, utils
-@utils.export("channelset", {"setting": "auto-title",
- "help": "Disable/Enable automatically getting info titles from URLs",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "title-shorten",
- "help": "Enable/disable shortening URLs when getting their title",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "auto-title-first",
- "help": ("Enable/disable showing who first posted a URL that was "
- "auto-titled"),
- "validate": utils.bool_or_none, "exaple": "on"})
+@utils.export("channelset", utils.BoolSetting("auto-title",
+ "Disable/Enable automatically getting info titles from URLs"))
+@utils.export("channelset", utils.BoolSetting("title-shorten",
+ "Enable/disable shortening URLs when getting their title"))
+@utils.export("channelset", utils.BoolSetting("auto-title-first",
+ "Enable/disable showing who first posted a URL that was auto-titled"))
class Module(ModuleManager.BaseModule):
def _url_hash(self, url):
return "sha256:%s" % hashlib.sha256(url.lower().encode("utf8")
diff --git a/modules/trakt.py b/modules/trakt.py
index faf3ee81..b394431b 100644
--- a/modules/trakt.py
+++ b/modules/trakt.py
@@ -7,8 +7,8 @@ from src import ModuleManager, utils
URL_TRAKT = "https://api-v2launch.trakt.tv/users/%s/watching"
URL_TRAKTSLUG = "https://trakt.tv/%s/%s"
-@utils.export("set", {"setting": "trakt", "help": "Set username on trakt.tv",
- "example": "jesopo"})
+@utils.export("set", utils.Setting("trakt", "Set username on trakt.tv",
+ example="jesopo"))
class Module(ModuleManager.BaseModule):
@utils.hook("received.command.nw", alias_of="nowwatching")
@utils.hook("received.command.nowwatching")
diff --git a/modules/tweets/__init__.py b/modules/tweets/__init__.py
index 07e41760..979b55b0 100644
--- a/modules/tweets/__init__.py
+++ b/modules/tweets/__init__.py
@@ -42,9 +42,8 @@ class BitBotStreamListener(tweepy.StreamListener):
_events.on("send.stdout").call(target=channel,
module_name="Tweets", server=server, message=tweet)
-@utils.export("channelset", {"setting": "auto-tweet",
- "help": "Enable/disable automatically getting tweet info",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("channelset", utils.BoolSetting("auto-tweet",
+ "Enable/disable automatically getting tweet info"))
class Module(ModuleManager.BaseModule):
_stream = None
def on_load(self):
diff --git a/modules/vote.py b/modules/vote.py
index 2ca3b6b2..060c849a 100644
--- a/modules/vote.py
+++ b/modules/vote.py
@@ -10,9 +10,9 @@ STR_NOVOTE = "Unknown vote '%s'"
class VoteCastResult(enum.Enum):
Cast = 1
Changed = 2
-@utils.export("channelset", {"setting": "votes-start-restricted",
- "help": "Whether starting a vote should be restricted to ops",
- "validate": utils.bool_or_none, "example": "on"})
+
+@utils.export("channelset", utils.BoolSetting("votes-start-restricted",
+ "Whether starting a vote should be restricted to ops"))
class Module(ModuleManager.BaseModule):
def _get_vote(self, channel, vote_id):
return channel.get_setting("vote-%s" % vote_id, None)
diff --git a/modules/words.py b/modules/words.py
index 513a26fe..6fe8f6f4 100644
--- a/modules/words.py
+++ b/modules/words.py
@@ -9,9 +9,8 @@ WORD_DELIM = "\"'…~*`"
WORD_START = WORD_DELIM+"“({<"
WORD_STOP = WORD_DELIM+"”)}>;:.,!?"
-@utils.export("set", {"setting": "word-tracking",
- "help": "Disable/enable tracking your wordcounts",
- "validate": utils.bool_or_none, "example": "on"})
+@utils.export("set", utils.BoolSetting(
+ "word-tracking", "Disable/enable tracking your wordcounts"))
class Module(ModuleManager.BaseModule):
def _channel_message(self, user, event):
if not user.get_setting("word-tracking", True):
diff --git a/modules/youtube.py b/modules/youtube.py
index f31b15ec..53460a49 100644
--- a/modules/youtube.py
+++ b/modules/youtube.py
@@ -18,12 +18,10 @@ URL_YOUTUBESHORT = "https://youtu.be/%s"
ARROW_UP = "↑"
ARROW_DOWN = "↓"
-@utils.export("channelset", {"setting": "auto-youtube",
- "help": "Disable/Enable automatically getting info from youtube URLs",
- "validate": utils.bool_or_none, "example": "on"})
-@utils.export("channelset", {"setting": "youtube-safesearch",
- "help": "Turn safe search off/on", "validate": utils.bool_or_none,
- "example": "on"})
+@utils.export("channelset", utils.BoolSetting("auto-youtube",
+ "Disable/Enable automatically getting info from youtube URLs"))
+@utils.export("channelset", utils.BoolSetting("youtube-safesearch",
+ "Turn safe search off/on"))
class Module(ModuleManager.BaseModule):
def on_load(self):
self.exports.add("search-youtube", self._search_youtube)
diff --git a/src/utils/__init__.py b/src/utils/__init__.py
index 7e1fce18..5ad057c8 100644
--- a/src/utils/__init__.py
+++ b/src/utils/__init__.py
@@ -138,21 +138,6 @@ def parse_number(s: str) -> str:
raise ValueError("Unknown unit '%s' given to parse_number" % unit)
return str(number)
-IS_TRUE = ["true", "yes", "on", "y"]
-IS_FALSE = ["false", "no", "off", "n"]
-def bool_or_none(s: str) -> typing.Optional[bool]:
- s = s.lower()
- if s in IS_TRUE:
- return True
- elif s in IS_FALSE:
- return False
- return None
-def int_or_none(s: str) -> typing.Optional[int]:
- stripped_s = s.lstrip("0")
- if stripped_s.isdigit():
- return int(stripped_s)
- return None
-
def prevent_highlight(nickname: str) -> str:
return nickname[0]+"\u200c"+nickname[1:]
@@ -243,3 +228,32 @@ def is_ip(s: str) -> bool:
def is_main_thread() -> bool:
return threading.current_thread() is threading.main_thread()
+
+class Setting(object):
+ def __init__(self, name: str, help: str=None, example: str=None):
+ self.name = name
+ self.help = help
+ self.example = example
+ def parse(self, value: str) -> typing.Any:
+ return value
+
+SETTING_TRUE = ["true", "yes", "on", "y"]
+SETTING_FALSE = ["false", "no", "off", "n"]
+class BoolSetting(Setting):
+ example = "on"
+ def parse(self, value: str) -> typing.Any:
+ value_lower = value.lower()
+ if value_lower in SETTING_TRUE:
+ return True
+ elif value_lower in SETTING_FALSE:
+ return False
+ return None
+
+class IntSetting(Setting):
+ example = "10"
+ def parse(self, value: str) -> typing.Any:
+ stripped = value.lstrip("0")
+ if stripped.isdigit():
+ return int(stripped)
+ return None
+