commit
8b31e9701d
|
@ -1,84 +1,179 @@
|
||||||
from xml.etree import ElementTree as etree
|
|
||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
|
import xmltodict
|
||||||
|
|
||||||
from . import compat
|
from . import compat
|
||||||
|
|
||||||
compat.fix_HTTPMessage()
|
compat.fix_HTTPMessage()
|
||||||
|
|
||||||
class Result(object):
|
|
||||||
def __init__(self, stream):
|
|
||||||
self.tree = etree.parse(stream)
|
|
||||||
self._handle_error()
|
|
||||||
|
|
||||||
def _handle_error(self):
|
|
||||||
error = self.tree.find('error')
|
|
||||||
if not error:
|
|
||||||
return
|
|
||||||
|
|
||||||
code = error.find('code').text
|
|
||||||
msg = error.find('msg').text
|
|
||||||
tmpl = 'Error {code}: {msg}'
|
|
||||||
raise Exception(tmpl.format(code=code, msg=msg))
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return (Pod(node) for node in self.tree.findall('pod'))
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.tree)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pods(self):
|
|
||||||
return list(iter(self))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def results(self):
|
|
||||||
return (pod for pod in self if pod.title=='Result')
|
|
||||||
|
|
||||||
class Pod(object):
|
|
||||||
def __init__(self, node):
|
|
||||||
self.node = node
|
|
||||||
self.__dict__.update(node.attrib)
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return (Content(node) for node in self.node.findall('subpod'))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def main(self):
|
|
||||||
"The main content of this pod"
|
|
||||||
return next(iter(self))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def text(self):
|
|
||||||
return self.main.text
|
|
||||||
|
|
||||||
@property
|
|
||||||
def img(self):
|
|
||||||
return self.main.img
|
|
||||||
|
|
||||||
class Content(object):
|
|
||||||
def __init__(self, node):
|
|
||||||
self.node = node
|
|
||||||
self.__dict__.update(node.attrib)
|
|
||||||
self.text = node.find('plaintext').text
|
|
||||||
self.img = node.find('img').attrib['src']
|
|
||||||
|
|
||||||
class Client(object):
|
class Client(object):
|
||||||
"""
|
"""
|
||||||
Wolfram|Alpha v2.0 client
|
Wolfram|Alpha v2.0 client
|
||||||
"""
|
"""
|
||||||
def __init__(self, app_id):
|
def __init__(self, app_id='Q59EW4-7K8AHE858R'):
|
||||||
self.app_id = app_id
|
self.app_id = app_id
|
||||||
|
|
||||||
def query(self, query):
|
def query(self, query, assumption=None):
|
||||||
"""
|
"""
|
||||||
Query Wolfram|Alpha with query using the v2.0 API
|
Query Wolfram|Alpha with query using the v2.0 API
|
||||||
"""
|
"""
|
||||||
query = urllib.parse.urlencode(dict(
|
data = {
|
||||||
input=query,
|
'input': query,
|
||||||
appid=self.app_id,
|
'appid': self.app_id
|
||||||
))
|
}
|
||||||
|
if assumption:
|
||||||
|
data.update({'assumption': assumption})
|
||||||
|
|
||||||
|
query = urllib.parse.urlencode(data)
|
||||||
url = 'https://api.wolframalpha.com/v2/query?' + query
|
url = 'https://api.wolframalpha.com/v2/query?' + query
|
||||||
resp = urllib.request.urlopen(url)
|
resp = urllib.request.urlopen(url)
|
||||||
assert resp.headers.get_content_type() == 'text/xml'
|
assert resp.headers.get_content_type() == 'text/xml'
|
||||||
assert resp.headers.get_param('charset') == 'utf-8'
|
assert resp.headers.get_param('charset') == 'utf-8'
|
||||||
return Result(resp)
|
return Result(resp)
|
||||||
|
|
||||||
|
class Result(object):
|
||||||
|
def __init__(self, stream):
|
||||||
|
self.tree = xmltodict.parse(stream, dict_constructor=dict)['queryresult']
|
||||||
|
self._handle_error()
|
||||||
|
self.info = []
|
||||||
|
try:
|
||||||
|
self.pods = list(map(Pod, self.tree['pod']))
|
||||||
|
self.info.append(self.pods)
|
||||||
|
except KeyError:
|
||||||
|
self.pods = None
|
||||||
|
try:
|
||||||
|
self.assumptions = list(map(Assumption, self.tree['assumptions']))
|
||||||
|
self.info.append(self.assumptions)
|
||||||
|
except KeyError:
|
||||||
|
self.assumptions = None
|
||||||
|
try:
|
||||||
|
self.warnings = list(map(Warning, self.tree['warnings']))
|
||||||
|
self.info.append(self.warnings)
|
||||||
|
except KeyError:
|
||||||
|
self.warnings = None
|
||||||
|
|
||||||
|
def _handle_error(self):
|
||||||
|
error_state = self.tree['@error']
|
||||||
|
if error_state == 'false':
|
||||||
|
return
|
||||||
|
|
||||||
|
error = self.tree['error']
|
||||||
|
code = error['code']
|
||||||
|
msg = error['msg']
|
||||||
|
template = 'Error {code}: {msg}'
|
||||||
|
raise Exception(template.format(code=code, msg=msg))
|
||||||
|
|
||||||
|
def _flatten(self, lists):
|
||||||
|
'''
|
||||||
|
src: http://stackoverflow.com/a/952952/4241708
|
||||||
|
usr: intuited
|
||||||
|
'''
|
||||||
|
from itertools import chain
|
||||||
|
return list(chain.from_iterable(lists))
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.info)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.tree)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def results(self):
|
||||||
|
return self._flatten([pod.details for pod in self.pods if pod.primary or pod.title=='Result'])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def details(self):
|
||||||
|
return {pod.title: pod.details for pod in self.pods}
|
||||||
|
|
||||||
|
class Pod(object):
|
||||||
|
def __init__(self, node):
|
||||||
|
self.node = node
|
||||||
|
self._handle_error()
|
||||||
|
self.title = node['@title']
|
||||||
|
self.scanner = node['@scanner']
|
||||||
|
self.id = node['@id']
|
||||||
|
self.position = float(node['@position'])
|
||||||
|
self.error = node['@error']
|
||||||
|
self.number_of_subpods = int(node['@numsubpods'])
|
||||||
|
self.subpods = node['subpod']
|
||||||
|
# Allow subpods to be accessed in a consistent way,
|
||||||
|
# as a list, regardless of how many there are.
|
||||||
|
if type(self.subpods) != list:
|
||||||
|
self.subpods = [self.subpods]
|
||||||
|
self.subpods = list(map(Subpod, self.subpods))
|
||||||
|
self.primary = '@primary' in node and node['@primary'] != 'false'
|
||||||
|
|
||||||
|
def _handle_error(self):
|
||||||
|
error_state = self.node['@error']
|
||||||
|
if error_state == 'false':
|
||||||
|
return
|
||||||
|
|
||||||
|
error = self.tree['error']
|
||||||
|
code = error['code']
|
||||||
|
msg = error['msg']
|
||||||
|
template = 'Error {code}: {msg}'
|
||||||
|
raise Exception(template.format(code=code, msg=msg))
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.subpods)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return self.number_of_subpods
|
||||||
|
|
||||||
|
@property
|
||||||
|
def details(self):
|
||||||
|
return [subpod.text for subpod in self.subpods]
|
||||||
|
|
||||||
|
# Needs work. At the moment this should be considered a placeholder.
|
||||||
|
class Assumption(object):
|
||||||
|
def __init__(self, node):
|
||||||
|
self.assumption = node
|
||||||
|
#self.description = self.assumption[0]['desc'] # We only care about our given assumption.
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.assumption)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.assumption)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
text = self.template.replace('${desc1}', self.description)
|
||||||
|
try:
|
||||||
|
text = text.replace('${word}', self.word)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return text[:text.index('. ') + 1]
|
||||||
|
|
||||||
|
# Needs work. At the moment this should be considered a placeholder.
|
||||||
|
class Warning(object):
|
||||||
|
def __init__(self, node):
|
||||||
|
self.node = node
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(node)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(node)
|
||||||
|
|
||||||
|
class Subpod(object):
|
||||||
|
def __init__(self, node):
|
||||||
|
self.node = node
|
||||||
|
self.title = node['@title']
|
||||||
|
self.text = node['plaintext']
|
||||||
|
self.img = node['img']
|
||||||
|
# Allow images to be accessed in a consistent way,
|
||||||
|
# as a list, regardless of how many there are.
|
||||||
|
if type(self.img) != list:
|
||||||
|
self.img = [self.img]
|
||||||
|
self.img = list(map(Image, self.img))
|
||||||
|
|
||||||
|
class Image(object):
|
||||||
|
def __init__(self, node):
|
||||||
|
self.node = node
|
||||||
|
self.title = node['@title']
|
||||||
|
self.alt = node['@alt']
|
||||||
|
self.height = node['@height']
|
||||||
|
self.width = node['@width']
|
||||||
|
self.src = node['@src']
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user