IdeaMonk

thoughts, ideas, code and other things...

Monday, June 28, 2010

Yet another Google Calculator shell in Python

For the sake of weekend hack and getting rid of some headache of post bangpypers meetup chicken overload of today's evening -
import re
import urllib
import mechanize
import unittest

class GCalc:
def __init__(self):
self.browser = mechanize.Browser()
self.browser.set_handle_robots(False)
self.browser.addheaders = \
[('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')]

def cleanup(self,text):
strip_tags = re.compile("<.*?>")
return strip_tags.sub('', text.replace("<sup>","^").replace("</sup>","").replace("×","X"))

def calc(self, query):
try:
raw_result = self.browser.open("http://www.google.com/search?hl=en&q="+urllib.quote_plus(query)).read()
return self.parse(raw_result)
except:
return "Failed to reach Google"

def parse(self, raw_result):
try:
result = raw_result.split('''<td style="vertical-align:top" >''')[1].split('</h2>')[0] + '</h2>'
return self.cleanup(result)
except:
return "Not a calculator query"

class TestGCalc(unittest.TestCase):
def setUp(self):
self.g = GCalc()

def test_numeric(self):
self.assertEqual(self.g.calc("4+5"), "4 + 5 = 9")

def test_bignumbers(self):
self.assertEqual(self.g.calc("234623476 * 59999999999"), "234 623 476 * 59 999 999 999 = 1.40774086 X 10^19")

def test_units(self):
self.assertEqual(self.g.calc("14 inch in mm"), "14 inch = 355.6 millimeters")
self.assertEqual(self.g.calc("one acre"), "one acre = 4\xc2\xa0046.85642 m^2")

def test_cacl(self):
self.assertEqual(self.g.calc("3 * PI / sin(3)"), "(3 * PI) / sin(3) = 66.7855543")

def test_facts(self):
self.assertEqual(self.g.calc("speed of light"), "the speed of light = 299\xc2\xa0792\xc2\xa0458 m / s")


if __name__=='__main__':
unittest.main()

Fork it here, have fun, curse me for crappy splits :)
Just learnt unittest a bit, ah so easy and useful :D

I guess you can notice the grand theme here - Its just ~ 50 lines of code packed up with a unit test and does the job!

I suggest you better not miss PyCon India 2010 in case you too are eager to do some productivity magic with you/your employees/students/etc.

Adios

Labels: ,

3 Comments:

At June 29, 2010 at 1:02 PM , Blogger Abhishek Mishra said...

I came across doctests while working on a bulk uploader for pykata, they're using it in a very interesting way to create self testing problem formats

Though I could write a parser for their format but doctest was still looked like magic to me. Would look into it later as have been pointed to this by multiple people.

After all this is a very lame hackish code with lot of magic strings inside, once things change on google's side, even a minor formatting, it would fail.

 
At June 29, 2010 at 4:29 PM , Blogger Abhishek Mishra said...

"confusing docstrings and doctests" - seriously wouldn't that be kinda extra lame.

Well the problem format in pykata has a doctest attached to it, so that it can be easily tested before submission by a problem setter. Which is what I was pointing out as my first encounter with doctests, in case you failed to see the import or doctest.testmod

 
At June 29, 2010 at 9:21 PM , Blogger Abhishek Mishra said...

Normally people would keep problem descriptions etc in a database, and keep the correction logic elsewhere, what David and Andrew have done here is to pack a problem description and its logic into a single executable, testable for its own correctness, portable entity, allowing easy import exports :)

But then one would understand all this when one reads the page properly before making a lame comment.

 

Post a Comment

Subscribe to Post Comments [Atom]

<< Home