forked from oddluck
This commit is contained in:
commit
a94e1d8fa3
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 spline
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,83 @@
|
|||
Retrieve info from WolframAlpha based on your queries.
|
||||
|
||||
Forked from https://github.com/ormanya/Supyiel/tree/master/WolframAlpha
|
||||
|
||||
# Limnoria plugin for WolframAlpha
|
||||
|
||||
## Introduction
|
||||
|
||||
There are at least 3 plugins floating around for WA. One of the big differences with each variant from users
|
||||
is the differences in output due to the verbosity from how WA answers questions. Some answers can be
|
||||
10+ lines and easily flood a channel, either having the bot flood off or getting it banned from a channel.
|
||||
WA's API also has some input options that can be handy, along with some verbose "error" messages that can help
|
||||
the user, which the other plugins do not utilize. I wanted to use the getopts power and make some configuration
|
||||
options to display the data in a more friendly manner.
|
||||
|
||||
## Install
|
||||
|
||||
You will need a working Limnoria bot on Python 2.7 for this to work.
|
||||
|
||||
Go into your Limnoria plugin dir, usually ~/supybot/plugins and run:
|
||||
|
||||
```
|
||||
git clone https://github.com/reticulatingspline/WolframAlpha
|
||||
```
|
||||
|
||||
To install additional requirements, run:
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
or if you don't have or don't want to use root,
|
||||
|
||||
```
|
||||
pip install -r requirements.txt --user
|
||||
```
|
||||
|
||||
Next, load the plugin:
|
||||
|
||||
```
|
||||
/msg bot load WolframAlpha
|
||||
```
|
||||
|
||||
[Fetch an API key for WA](http://products.wolframalpha.com/developers/) by signing up (free).
|
||||
Once getting this key, you will need to set it on your bot before things will work.
|
||||
Reload once you perform this operation to start using it.
|
||||
|
||||
```
|
||||
/msg bot config plugins.WolframAlpha.apiKey APIKEY
|
||||
```
|
||||
|
||||
Now, reload the bot and you should be good to go:
|
||||
|
||||
```
|
||||
/msg bot reload WolframAlpha
|
||||
```
|
||||
|
||||
Optional: There are some config variables that can be set for the bot. They mainly control output stuff.
|
||||
|
||||
```
|
||||
/msg bot config search WolframAlpha
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
<spline> @wolframalpha 2+2
|
||||
<myybot> Input :: 2+2
|
||||
<myybot> Result :: 4
|
||||
<myybot> Number name :: four
|
||||
<myybot> Manipulatives illustration :: | + | | = | 2 | | 2 | | 4
|
||||
<spline> @wolframalpha --shortest 2+2
|
||||
<myybot> 2+2 :: 4
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
All of my plugins are free and open source. When I first started out, one of the main reasons I was
|
||||
able to learn was due to other code out there. If you find a bug or would like an improvement, feel
|
||||
free to give me a message on IRC or fork and submit a pull request. Many hours do go into each plugin,
|
||||
so, if you're feeling generous, I do accept donations via Amazon or browse my [wish list](http://amzn.com/w/380JKXY7P5IKE).
|
||||
|
||||
I'm always looking for work, so if you are in need of a custom feature, plugin or something bigger, contact me via GitHub or IRC.
|
|
@ -0,0 +1,75 @@
|
|||
###
|
||||
# Copyright (c) 2014, spline
|
||||
# Copyright (c) 2020, oddluck <oddluck@riseup.net>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
###
|
||||
|
||||
"""
|
||||
WolframAlpha: retrieve info from the Wolfram Alpha API
|
||||
"""
|
||||
|
||||
import supybot
|
||||
import supybot.world as world
|
||||
import importlib
|
||||
|
||||
# Use this for the version of this plugin. You may wish to put a CVS keyword
|
||||
# in here if you're keeping the plugin in CVS or some similar system.
|
||||
__version__ = "2020.06.23+git"
|
||||
|
||||
# XXX Replace this with an appropriate author or supybot.Author instance.
|
||||
__author__ = supybot.Author("reticulatingspline", "spline", "")
|
||||
__maintainer__ = getattr(
|
||||
supybot.authors,
|
||||
"oddluck",
|
||||
supybot.Author("oddluck", "oddluck", "oddluck@riseup.net"),
|
||||
)
|
||||
|
||||
# This is a dictionary mapping supybot.Author instances to lists of
|
||||
# contributions.
|
||||
__contributors__ = {}
|
||||
|
||||
# This is a url where the most recent plugin package can be downloaded.
|
||||
__url__ = "https://github.com/oddluck/limnoria-plugins/"
|
||||
|
||||
from . import config
|
||||
from . import plugin
|
||||
from imp import reload
|
||||
|
||||
# In case we're being reloaded.
|
||||
importlib.reload(config)
|
||||
importlib.reload(plugin)
|
||||
# Add more reloads here if you add third-party modules and want them to be
|
||||
# reloaded when this plugin is reloaded. Don't forget to import them as well!
|
||||
|
||||
if world.testing:
|
||||
from . import test
|
||||
|
||||
Class = plugin.Class
|
||||
configure = config.configure
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -0,0 +1,84 @@
|
|||
###
|
||||
# Copyright (c) 2014, spline
|
||||
# Copyright (c) 2020, oddluck <oddluck@riseup.net>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
###
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.registry as registry
|
||||
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
|
||||
_ = PluginInternationalization("WolframAlpha")
|
||||
except:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x: x
|
||||
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by supybot to configure this module. advanced is
|
||||
# a bool that specifies whether the user identified himself as an advanced
|
||||
# user or not. You should effect your configuration by manipulating the
|
||||
# registry as appropriate.
|
||||
from supybot.questions import expect, anything, something, yn
|
||||
|
||||
conf.registerPlugin("WolframAlpha", True)
|
||||
|
||||
|
||||
WolframAlpha = conf.registerPlugin("WolframAlpha")
|
||||
conf.registerGlobalValue(
|
||||
WolframAlpha,
|
||||
"apiKey",
|
||||
registry.String("", """Your Wolfram Alpha API key.""", private=True),
|
||||
)
|
||||
conf.registerGlobalValue(
|
||||
WolframAlpha,
|
||||
"maxOutput",
|
||||
registry.Integer(4, """How many lines by default to output."""),
|
||||
)
|
||||
conf.registerGlobalValue(
|
||||
WolframAlpha,
|
||||
"useImperial",
|
||||
registry.Boolean(True, """Use imperial units? Defaults to yes."""),
|
||||
)
|
||||
conf.registerGlobalValue(
|
||||
WolframAlpha,
|
||||
"reinterpretInput",
|
||||
registry.Boolean(
|
||||
False,
|
||||
"""Reinterpret input string if WA API cannot understand. Best to leave false.""",
|
||||
),
|
||||
)
|
||||
conf.registerChannelValue(
|
||||
WolframAlpha,
|
||||
"disableANSI",
|
||||
registry.Boolean(False, """Do not display any ANSI (color/bold) for channel."""),
|
||||
)
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=250:
|
|
@ -0,0 +1,354 @@
|
|||
###
|
||||
# Copyright (c) 2014, spline
|
||||
# Copyright (c) 2020, oddluck <oddluck@riseup.net>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
###
|
||||
|
||||
# my libs
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
import xml.etree.cElementTree as ElementTree
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
# supybot libs
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
import supybot.ircutils as ircutils
|
||||
import supybot.callbacks as callbacks
|
||||
import re
|
||||
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
|
||||
_ = PluginInternationalization("WolframAlpha")
|
||||
except:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x: x
|
||||
|
||||
|
||||
class WolframAlpha(callbacks.Plugin):
|
||||
"""Add the help for "@plugin help WolframAlpha" here
|
||||
This should describe *how* to use this plugin."""
|
||||
|
||||
threaded = True
|
||||
|
||||
######################
|
||||
# INTERNAL FUNCTIONS #
|
||||
######################
|
||||
|
||||
def _red(self, s):
|
||||
return ircutils.mircColor(s, "red")
|
||||
|
||||
def _bold(self, s):
|
||||
return ircutils.bold(s)
|
||||
|
||||
####################
|
||||
# PUBLIC FUNCTIONS #
|
||||
####################
|
||||
|
||||
# API Documentation. http://products.wolframalpha.com/api/documentation.html
|
||||
def wolframalpha(self, irc, msg, args, optlist, optinput):
|
||||
"""[--num #|--reinterpret|--usemetric|--shortest|--fulloutput] <query>
|
||||
|
||||
Returns answer from Wolfram Alpha API.
|
||||
|
||||
Use --num number to display a specific amount of lines.
|
||||
Use --reinterpret to have WA logic to interpret question if not understood.
|
||||
Use --usemetric to not display in imperial units.
|
||||
Use --shortest for the shortest output (ignores lines).
|
||||
Use --fulloutput to display everything from the API (can flood).
|
||||
"""
|
||||
|
||||
# check for API key before we can do anything.
|
||||
apiKey = self.registryValue("apiKey")
|
||||
if not apiKey or apiKey == "Not set":
|
||||
irc.reply(
|
||||
"Wolfram Alpha API key not set. see 'config help"
|
||||
" supybot.plugins.WolframAlpha.apiKey'."
|
||||
)
|
||||
return
|
||||
# first, url arguments, some of which getopts and config variables can manipulate.
|
||||
urlArgs = {
|
||||
"input": optinput,
|
||||
"appid": apiKey,
|
||||
"reinterpret": "false",
|
||||
"format": "plaintext",
|
||||
"units": "nonmetric",
|
||||
}
|
||||
# check for config variables to manipulate URL arguments.
|
||||
if not self.registryValue("useImperial"):
|
||||
urlArgs["units"] = "metric"
|
||||
if self.registryValue("reinterpretInput"):
|
||||
urlArgs["reinterpret"] = "true"
|
||||
# now handle input. default input arguments.
|
||||
args = {
|
||||
"maxoutput": self.registryValue("maxOutput"),
|
||||
"shortest": None,
|
||||
"fulloutput": None,
|
||||
}
|
||||
# handle getopts (optlist)
|
||||
if optlist:
|
||||
for (key, value) in optlist:
|
||||
if key == "shortest":
|
||||
args["shortest"] = True
|
||||
if key == "fulloutput":
|
||||
args["fulloutput"] = True
|
||||
if key == "num":
|
||||
args["maxoutput"] = value
|
||||
if key == "usemetric":
|
||||
urlArgs["units"] = "metric"
|
||||
if key == "reinterpret":
|
||||
urlArgs["reinterpret"] = "true"
|
||||
# build url and query.
|
||||
url = "http://api.wolframalpha.com/v2/query?" + utils.web.urlencode(urlArgs)
|
||||
try:
|
||||
page = utils.web.getUrl(url)
|
||||
except Exception as e:
|
||||
self.log.error("ERROR opening {0} message: {1}".format(url, e))
|
||||
irc.reply("ERROR: Failed to open WolframAlpha API: {0}".format(url))
|
||||
return
|
||||
# now try to process XML.
|
||||
try:
|
||||
document = ElementTree.fromstring(page)
|
||||
except Exception as e:
|
||||
self.log.error("ERROR: Broke processing XML: {0}".format(e))
|
||||
irc.reply("ERROR: Something broke processing XML from WolframAlpha's API.")
|
||||
return
|
||||
# document = ElementTree.fromstring(page) #.decode('utf-8'))
|
||||
# check if we have an error. reports to irc but more detailed in the logs.
|
||||
if document.attrib["success"] == "false" and document.attrib["error"] == "true":
|
||||
errormsgs = []
|
||||
for error in document.findall(".//error"):
|
||||
errorcode = error.find("code").text
|
||||
errormsg = error.find("msg").text
|
||||
errormsgs.append("{0} - {1}".format(errorcode, errormsg))
|
||||
# log and report to irc if we have these.
|
||||
self.log.debug(
|
||||
"ERROR processing request for: {0} message: {1}".format(
|
||||
optinput, errormsgs
|
||||
)
|
||||
)
|
||||
irc.reply(
|
||||
"ERROR: Something went wrong processing request for: {0} ERROR: {1}"
|
||||
.format(optinput, errormsgs)
|
||||
)
|
||||
return
|
||||
# check if we have no success but also no error. (Did you mean?)
|
||||
elif (
|
||||
document.attrib["success"] == "false"
|
||||
and document.attrib["error"] == "false"
|
||||
):
|
||||
errormsgs = [] # list to contain whatever is there.
|
||||
for error in document.findall(".//futuretopic"):
|
||||
errormsg = error.attrib["msg"]
|
||||
errormsgs.append("FUTURE TOPIC: {0}".format(errormsg))
|
||||
for error in document.findall(".//didyoumeans"):
|
||||
errormsg = error.find("didyoumean").text
|
||||
errormsgs.append("Did you mean? {0}".format(errormsg))
|
||||
for error in document.findall(".//tips"):
|
||||
errormsg = error.find("tip").attrib["text"].text
|
||||
errormsgs.append("TIPS: {0}".format(errormsg))
|
||||
# now output the messages to irc and log.
|
||||
self.log.debug(
|
||||
"ERROR with input: {0} API returned: {1}".format(optinput, errormsgs)
|
||||
)
|
||||
irc.reply(
|
||||
"ERROR with input: {0} API returned: {1}".format(optinput, errormsgs)
|
||||
)
|
||||
return
|
||||
else: # this means we have success and no error messages.
|
||||
# each pod has a title, position and a number of subtexts. output contains the plaintext.
|
||||
# outputlist is used in sorting since defaultdict does not remember order/position.
|
||||
output = defaultdict(list)
|
||||
outputlist = {}
|
||||
# each answer has a different amount of pods.
|
||||
for pod in document.findall(".//pod"):
|
||||
title = pod.attrib["title"] # title of it.
|
||||
position = int(pod.attrib["position"]) # store pods int when we sort.
|
||||
outputlist[position] = title # pu
|
||||
for plaintext in pod.findall(".//plaintext"):
|
||||
if plaintext.text:
|
||||
output[title].append(plaintext.text.replace("\n", " "))
|
||||
# last sanity check...
|
||||
if len(output) == 0:
|
||||
irc.reply("ERROR: I received no output looking up: {0}".format(optinput))
|
||||
return
|
||||
# done processing the XML so lets work on the output.
|
||||
# the way we output is based on args above, controlled by getopts.
|
||||
if args["shortest"]: # just show the question and answer.
|
||||
# outputlist has pod titles, ordered by importance, not every input has a clear Input/Result (question/answer).
|
||||
outputlist = [outputlist[item] for item in sorted(outputlist.keys())]
|
||||
question = output.get(outputlist[0]) # get first (question).
|
||||
answer = output.get(outputlist[1]) # get second (answer).
|
||||
# output time. display with color or not?
|
||||
if self.registryValue("disableANSI"):
|
||||
irc.reply(
|
||||
re.sub(
|
||||
"\s+",
|
||||
" ",
|
||||
"{0} :: {1}".format(
|
||||
"".join([i for i in question]),
|
||||
" | ".join([i for i in answer]),
|
||||
),
|
||||
).replace(": | ", ": ")
|
||||
)
|
||||
else: # with ansi.
|
||||
irc.reply(
|
||||
re.sub(
|
||||
"\s+",
|
||||
" ",
|
||||
"{0} :: {1}".format(
|
||||
self._bold("".join([i for i in question])),
|
||||
" | ".join([i for i in answer]),
|
||||
),
|
||||
).replace(": | ", ": ")
|
||||
)
|
||||
elif args["fulloutput"]: # show everything. no limits.
|
||||
# grab all values, sorted via the position number. output one per line.
|
||||
for (k, v) in sorted(outputlist.items()):
|
||||
itemout = output.get(v) # items out will be a list of items.
|
||||
# now decide to output with ANSI or not.
|
||||
if self.registryValue("disableANSI"):
|
||||
irc.reply(
|
||||
re.sub(
|
||||
"\s+", " ", "{0} :: {1}".format(v, " | ".join(itemout))
|
||||
).replace(": | ", ": ")
|
||||
)
|
||||
else: # with ansi.
|
||||
irc.reply(
|
||||
re.sub(
|
||||
"\s+",
|
||||
" ",
|
||||
"{0} :: {1}".format(self._red(v), " | ".join(itemout)),
|
||||
).replace(": | ", ": ")
|
||||
)
|
||||
else: # regular output, dictated by --lines or maxoutput.
|
||||
for q, k in enumerate(sorted(outputlist.keys())):
|
||||
if q < args["maxoutput"]: # if less than max.
|
||||
itemout = output.get(
|
||||
outputlist[k]
|
||||
) # have the key, get the value, use for output.
|
||||
if itemout:
|
||||
if self.registryValue("disableANSI"): # display w/o formatting.
|
||||
irc.reply(
|
||||
re.sub(
|
||||
"\s+",
|
||||
" ",
|
||||
"{0} :: {1}".format(
|
||||
outputlist[k], " | ".join(itemout)
|
||||
),
|
||||
).replace(": | ", ": ")
|
||||
)
|
||||
else: # display w/formatting.
|
||||
irc.reply(
|
||||
re.sub(
|
||||
"\s+",
|
||||
" ",
|
||||
"{0} :: {1}".format(
|
||||
self._red(outputlist[k]), " | ".join(itemout)
|
||||
),
|
||||
).replace(": | ", ": ")
|
||||
)
|
||||
|
||||
wolframalpha = wrap(
|
||||
wolframalpha,
|
||||
[
|
||||
getopts(
|
||||
{
|
||||
"num": "int",
|
||||
"reinterpret": "",
|
||||
"usemetric": "",
|
||||
"shortest": "",
|
||||
"fulloutput": "",
|
||||
}
|
||||
),
|
||||
"text",
|
||||
],
|
||||
)
|
||||
|
||||
def btc(self, irc, msg, args, amount, currency):
|
||||
"""<amount> <currency>
|
||||
|
||||
Convert bitcoin to another currency"""
|
||||
|
||||
# check for API key before we can do anything.
|
||||
apiKey = self.registryValue("apiKey")
|
||||
if not apiKey or apiKey == "Not set":
|
||||
irc.reply(
|
||||
"Wolfram Alpha API key not set. see 'config help"
|
||||
" supybot.plugins.WolframAlpha.apiKey'."
|
||||
)
|
||||
return
|
||||
# first, url arguments, some of which getopts and config variables can manipulate.
|
||||
urlArgs = {
|
||||
"input": "{:.2f} btc to {}".format(amount, currency),
|
||||
"appid": apiKey,
|
||||
"reinterpret": "false",
|
||||
"format": "plaintext",
|
||||
"units": "nonmetric",
|
||||
}
|
||||
url = "http://api.wolframalpha.com/v2/query?" + utils.web.urlencode(urlArgs)
|
||||
print(url)
|
||||
try:
|
||||
page = utils.web.getUrl(url)
|
||||
except Exception as e:
|
||||
self.log.error("ERROR opening {0} message: {1}".format(url, e))
|
||||
irc.reply("ERROR: Failed to open WolframAlpha API: {0}".format(url))
|
||||
return
|
||||
# now try to process XML.
|
||||
try:
|
||||
document = ElementTree.fromstring(page)
|
||||
except Exception as e:
|
||||
self.log.error("ERROR: Broke processing XML: {0}".format(e))
|
||||
irc.reply("ERROR: Something broke processing XML from WolframAlpha's API.")
|
||||
return
|
||||
|
||||
# each answer has a different amount of pods.
|
||||
for pod in document.findall(".//pod"):
|
||||
title = pod.attrib["title"] # title of it.
|
||||
if title == "Result":
|
||||
for plaintext in pod.findall(".//plaintext"):
|
||||
print((plaintext.text))
|
||||
|
||||
if "not compatible" in plaintext.text:
|
||||
irc.reply("Conversion from btc to %s not available" % currency)
|
||||
else:
|
||||
converted_amount = plaintext.text.split("(")[0].strip()
|
||||
irc.reply(
|
||||
"{}{:.2f} = {}".format("\u0e3f", amount, converted_amount)
|
||||
)
|
||||
|
||||
btc = wrap(btc, ["float", "text"])
|
||||
|
||||
|
||||
Class = WolframAlpha
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=250:
|
|
@ -0,0 +1,45 @@
|
|||
###
|
||||
# Copyright (c) 2014, spline
|
||||
# Copyright (c) 2020, oddluck <oddluck@riseup.net>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
###
|
||||
|
||||
import os
|
||||
from supybot.test import *
|
||||
|
||||
|
||||
class WolframAlphaTestCase(PluginTestCase):
|
||||
plugins = ("WolframAlpha",)
|
||||
|
||||
def testWolframAlpha(self):
|
||||
apiKey = os.environ.get("apiKey")
|
||||
conf.supybot.plugins.WolframAlpha.apiKey.setValue(apiKey)
|
||||
conf.supybot.plugins.WolframAlpha.disableANSI.setValue("True")
|
||||
self.assertResponse("wolframalpha --shortest 2+2", "2+2 :: 4")
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
Loading…
Reference in New Issue