mirror of
https://github.com/oddluck/limnoria-plugins.git
synced 2025-04-25 12:31:07 -05:00
WolframAlpha: float btc input/output
This commit is contained in:
parent
5b9997ff9e
commit
a51bc196da
@ -38,19 +38,22 @@ 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.02.24+git"
|
||||
__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'))
|
||||
__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/'
|
||||
__url__ = "https://github.com/oddluck/limnoria-plugins/"
|
||||
|
||||
from . import config
|
||||
from . import plugin
|
||||
|
@ -30,13 +30,16 @@
|
||||
|
||||
import supybot.conf as conf
|
||||
import supybot.registry as registry
|
||||
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
_ = PluginInternationalization('WolframAlpha')
|
||||
|
||||
_ = PluginInternationalization("WolframAlpha")
|
||||
except:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x:x
|
||||
_ = lambda x: x
|
||||
|
||||
|
||||
def configure(advanced):
|
||||
# This will be called by supybot to configure this module. advanced is
|
||||
@ -44,14 +47,38 @@ def configure(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)
|
||||
|
||||
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."""))
|
||||
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:
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
# my libs
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
import xml.etree.cElementTree as ElementTree
|
||||
except ImportError:
|
||||
@ -41,17 +42,21 @@ 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')
|
||||
|
||||
_ = PluginInternationalization("WolframAlpha")
|
||||
except:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
_ = lambda x:x
|
||||
_ = 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
|
||||
|
||||
######################
|
||||
@ -59,7 +64,7 @@ class WolframAlpha(callbacks.Plugin):
|
||||
######################
|
||||
|
||||
def _red(self, s):
|
||||
return ircutils.mircColor(s, 'red')
|
||||
return ircutils.mircColor(s, "red")
|
||||
|
||||
def _bold(self, s):
|
||||
return ircutils.bold(s)
|
||||
@ -82,40 +87,47 @@ class WolframAlpha(callbacks.Plugin):
|
||||
"""
|
||||
|
||||
# check for API key before we can do anything.
|
||||
apiKey = self.registryValue('apiKey')
|
||||
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'.")
|
||||
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' }
|
||||
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'
|
||||
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 }
|
||||
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'
|
||||
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)
|
||||
url = "http://api.wolframalpha.com/v2/query?" + utils.web.urlencode(urlArgs)
|
||||
try:
|
||||
page = utils.web.getUrl(url)
|
||||
except Exception as e:
|
||||
@ -129,33 +141,47 @@ class WolframAlpha(callbacks.Plugin):
|
||||
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'))
|
||||
# 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':
|
||||
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
|
||||
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))
|
||||
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':
|
||||
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']
|
||||
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
|
||||
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
|
||||
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))
|
||||
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.
|
||||
@ -163,53 +189,109 @@ class WolframAlpha(callbacks.Plugin):
|
||||
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.
|
||||
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'):
|
||||
for plaintext in pod.findall(".//plaintext"):
|
||||
if plaintext.text:
|
||||
output[title].append(plaintext.text.replace('\n',' '))
|
||||
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.
|
||||
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(": | ", ": "))
|
||||
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.
|
||||
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(": | ", ": "))
|
||||
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(": | ", ": "))
|
||||
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 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(": | ", ": "))
|
||||
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(": | ", ": "))
|
||||
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')])
|
||||
wolframalpha = wrap(
|
||||
wolframalpha,
|
||||
[
|
||||
getopts(
|
||||
{
|
||||
"num": "int",
|
||||
"reinterpret": "",
|
||||
"usemetric": "",
|
||||
"shortest": "",
|
||||
"fulloutput": "",
|
||||
}
|
||||
),
|
||||
"text",
|
||||
],
|
||||
)
|
||||
|
||||
def btc(self, irc, msg, args, amount, currency):
|
||||
"""<amount> <currency>
|
||||
@ -217,17 +299,22 @@ class WolframAlpha(callbacks.Plugin):
|
||||
Convert bitcoin to another currency"""
|
||||
|
||||
# check for API key before we can do anything.
|
||||
apiKey = self.registryValue('apiKey')
|
||||
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'.")
|
||||
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':'%d btc to %s' % (amount,currency),
|
||||
'appid':apiKey,
|
||||
'reinterpret':'false',
|
||||
'format':'plaintext',
|
||||
'units':'nonmetric' }
|
||||
url = 'http://api.wolframalpha.com/v2/query?' + utils.web.urlencode(urlArgs)
|
||||
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)
|
||||
@ -244,19 +331,20 @@ class WolframAlpha(callbacks.Plugin):
|
||||
return
|
||||
|
||||
# each answer has a different amount of pods.
|
||||
for pod in document.findall('.//pod'):
|
||||
title = pod.attrib['title'] # title of it.
|
||||
for pod in document.findall(".//pod"):
|
||||
title = pod.attrib["title"] # title of it.
|
||||
if title == "Result":
|
||||
for plaintext in pod.findall('.//plaintext'):
|
||||
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)
|
||||
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('%s%d = %s' % ('\u0e3f', amount, converted_amount))
|
||||
converted_amount = plaintext.text.split("(")[0].strip()
|
||||
irc.reply("{}{:.2f} = {}".format("\u0e3f", amount, converted_amount))
|
||||
|
||||
btc = wrap(btc, ["float", "text"])
|
||||
|
||||
btc = wrap(btc,['float', 'text'])
|
||||
|
||||
Class = WolframAlpha
|
||||
|
||||
|
@ -33,12 +33,13 @@ from supybot.test import *
|
||||
|
||||
|
||||
class WolframAlphaTestCase(PluginTestCase):
|
||||
plugins = ('WolframAlpha',)
|
||||
plugins = ("WolframAlpha",)
|
||||
|
||||
def testWolframAlpha(self):
|
||||
apiKey = os.environ.get('apiKey')
|
||||
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')
|
||||
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…
x
Reference in New Issue
Block a user