PageRenderTime 45ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/calc.py

https://github.com/0x705h/jenni
Python | 197 lines | 145 code | 18 blank | 34 comment | 12 complexity | 549ef5a954bbe730398187c8e734004d MD5 | raw file
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. """
  4. calc.py - jenni Calculator Module
  5. Copyright 2009-2013, Michael Yanovich (yanovich.net)
  6. Copyright 2008-2013, Sean B. Palmer (inamidst.com)
  7. Licensed under the Eiffel Forum License 2.
  8. More info:
  9. * jenni: https://github.com/myano/jenni/
  10. * Phenny: http://inamidst.com/phenny/
  11. """
  12. import HTMLParser
  13. import json
  14. import re
  15. import string
  16. import urllib
  17. import web
  18. from modules import search
  19. from modules import unicode as uc
  20. from socket import timeout
  21. c_pattern = r'(?ims)<(?:h2 class="r"|div id="aoba")[^>]*>(.*?)</(?:h2|div)>'
  22. c_answer = re.compile(c_pattern)
  23. r_tag = re.compile(r'<(?!!)[^>]+>')
  24. def c(jenni, input):
  25. '''.c -- Google calculator.'''
  26. ## let's not bother if someone doesn't give us input
  27. if not input.group(2):
  28. return jenni.reply('Nothing to calculate.')
  29. ## handle some unicode conversions
  30. q = input.group(2).encode('utf-8')
  31. q = q.replace('\xcf\x95', 'phi') # utf-8 U+03D5
  32. q = q.replace('\xcf\x80', 'pi') # utf-8 U+03C0
  33. ## Attempt #1 (Google)
  34. uri = 'https://www.google.com/search?gbv=1&q='
  35. uri += web.urllib.quote(q)
  36. ## To the webs!
  37. try:
  38. page = web.get(uri)
  39. except:
  40. ## if we can't access Google for calculating
  41. ## let us move on to Attempt #2
  42. page = None
  43. answer = None
  44. if page:
  45. ## if we get a response from Google
  46. ## let us parse out an equation from Google Search results
  47. answer = c_answer.findall(page)
  48. if answer:
  49. ## if the regex finding found a match we want the first result
  50. answer = answer[0]
  51. #answer = answer.replace(u'\xc2\xa0', ',')
  52. answer = answer.decode('unicode-escape')
  53. answer = ''.join(chr(ord(c)) for c in answer)
  54. answer = uc.decode(answer)
  55. answer = answer.replace('<sup>', '^(')
  56. answer = answer.replace('</sup>', ')')
  57. answer = web.decode(answer)
  58. answer = answer.strip()
  59. jenni.say(answer)
  60. else:
  61. #### Attempt #2 (DuckDuckGo's API)
  62. ddg_uri = 'https://api.duckduckgo.com/?format=json&q='
  63. ddg_uri += urllib.quote(q)
  64. ## Try to grab page (results)
  65. ## If page can't be accessed, we shall fail!
  66. try:
  67. page = web.get(ddg_uri)
  68. except:
  69. page = None
  70. ## Try to take page source and json-ify it!
  71. try:
  72. json_response = json.loads(page)
  73. except:
  74. ## if it can't be json-ified, then we shall fail!
  75. json_response = None
  76. ## Check for 'AnswerType' (stolen from search.py)
  77. ## Also 'fail' to None so we can move on to Attempt #3
  78. if (not json_response) or (hasattr(json_response, 'AnswerType') and json_response['AnswerType'] != 'calc'):
  79. answer = None
  80. else:
  81. ## If the json contains an Answer that is the result of 'calc'
  82. ## then continue
  83. answer = re.sub(r'\<.*?\>', '', json_response['Answer']).strip()
  84. if answer:
  85. ## If we have found answer with Attempt #2
  86. ## go ahead and display it
  87. jenni.say(answer)
  88. else:
  89. #### Attempt #3 (DuckDuckGo's HTML)
  90. ## This relies on BeautifulSoup; if it can't be found, don't even bother
  91. try:
  92. from BeautifulSoup import BeautifulSoup
  93. except:
  94. return jenni.say('No results. (Please install BeautifulSoup for additional checking.)')
  95. ddg_html_page = web.get('https://duckduckgo.com/html/?q=%s&kl=us-en&kp=-1' % (web.urllib.quote(q)))
  96. soup = BeautifulSoup(ddg_html_page)
  97. ## use BeautifulSoup to parse HTML for an answer
  98. zero_click = str()
  99. if soup('div', {'class': 'zero-click-result'}):
  100. zero_click = str(soup('div', {'class': 'zero-click-result'})[0])
  101. ## remove some excess text
  102. output = r_tag.sub('', zero_click).strip()
  103. output = output.replace('\n', '').replace('\t', '')
  104. ## test to see if the search module has 'remove_spaces'
  105. ## otherwise, let us fail
  106. try:
  107. output = search.remove_spaces(output)
  108. except:
  109. output = str()
  110. if output:
  111. ## If Attempt #3 worked, display the answer
  112. jenni.say(output)
  113. else:
  114. ## If we made it this far, we have tried all available resources
  115. jenni.say('Absolutely no results!')
  116. c.commands = ['c', 'cal', 'calc']
  117. c.example = '.c 5 + 3'
  118. def py(jenni, input):
  119. """.py <code> -- evaluates python code"""
  120. code = input.group(2)
  121. if not code:
  122. return jenni.reply('No code provided.')
  123. query = code.encode('utf-8')
  124. uri = 'https://tumbolia.appspot.com/py/'
  125. try:
  126. answer = web.get(uri + web.urllib.quote(query))
  127. if answer is not None and answer != "\n":
  128. jenni.say(answer)
  129. else:
  130. jenni.reply('Sorry, no result.')
  131. except Exception, e:
  132. jenni.reply('The server did not return an answer.')
  133. print '[.py]', e
  134. py.commands = ['py', 'python']
  135. py.example = '.py print "Hello world, %s!" % ("James")'
  136. def wa(jenni, input):
  137. """.wa <input> -- queries WolframAlpha with the given input."""
  138. if not input.group(2):
  139. return jenni.reply("No search term.")
  140. query = input.group(2).encode('utf-8')
  141. uri = 'https://tumbolia.appspot.com/wa/'
  142. try:
  143. answer = web.get(uri + web.urllib.quote(query.replace('+', '%2B')))
  144. except timeout as e:
  145. return jenni.say("Request timd out")
  146. if answer:
  147. answer = answer.decode("string_escape")
  148. answer = HTMLParser.HTMLParser().unescape(answer)
  149. match = re.search('\\\:([0-9A-Fa-f]{4})', answer)
  150. if match is not None:
  151. char_code = match.group(1)
  152. char = unichr(int(char_code, 16))
  153. answer = answer.replace('\:' + char_code, char)
  154. waOutputArray = string.split(answer, ";")
  155. newOutput = list()
  156. for each in waOutputArray:
  157. temp = each.replace('\/', '/')
  158. newOutput.append(temp)
  159. waOutputArray = newOutput
  160. if (len(waOutputArray) < 2):
  161. jenni.say(answer)
  162. else:
  163. jenni.say(waOutputArray[0] + " = " + waOutputArray[1])
  164. waOutputArray = list()
  165. else:
  166. jenni.say('Sorry, no result from WolframAlpha.')
  167. wa.commands = ['wa', 'wolfram']
  168. wa.example = '.wa land area of the European Union'
  169. if __name__ == '__main__':
  170. print __doc__.strip()