+'''
+This is a development script, intended for office use only.
+
+This script generates output the _POST_ACTIONS variable
+for placement in the twitter_globals.py
+
+Example Util:
+
+ python update.py >twitter_globals.py
+
+Dependencies:
+
+ * (easy_install) BeautifulSoup
+'''
+
+import sys
+from urllib import urlopen as _open
+from BeautifulSoup import BeautifulSoup
+from htmlentitydefs import codepoint2name
+
+def uni2html(u):
+ '''
+ Convert unicode to html.
+
+ Basically leaves ascii chars as is, and attempts to encode unicode chars as
+ HTML entities. If the conversion fails the character is skipped.
+ '''
+ htmlentities = list()
+ for c in u:
+ ord_c = ord(c)
+ if ord_c < 128:
+ # ignoring all ^chars like ^M ^R ^E
+ if ord_c >31:
+ htmlentities.append(c)
+ else:
+ try:
+ htmlentities.append('&%s;' % codepoint2name[ord_c])
+ except KeyError:
+ pass # Charachter unknown
+ return ''.join(htmlentities)
+
+def print_fw(iterable, joins=', ', prefix='', indent=0, width=79, trail=False):
+ '''
+ PPrint an iterable (of stringable elements).
+
+ Entries are joined using `joins`
+ A fixed_width (fw) is maintained of `width` chars per line
+ Each line is indented with `indent`*4 spaces
+ Lines are then prefixed with `prefix` string
+ if `trail` a trailing comma is sent to stdout
+ A newline is written after all is printed.
+ '''
+ shift_width = 4
+ preline = '%s%s' %(' '*shift_width, prefix)
+ linew = len(preline)
+ sys.stdout.write(preline)
+ for i, entry in enumerate(iterable):
+ if not trail and i == len(iterable) - 1:
+ sentry = str(entry)
+ else:
+ sentry = '%s%s' %(str(entry), joins)
+ if linew + len(sentry) > width:
+ sys.stdout.write('\n%s' %(preline))
+ linew = len(preline)
+ sys.stdout.write(sentry)
+ linew += len(sentry)
+ sys.stdout.write('\n')
+
+
+def main():
+ '''
+ Main function the prints twitter's _POST_ACTIONS to stdout
+
+ TODO: look at possibly dividing up this function
+ '''
+
+ apifile = _open('http://apiwiki.twitter.com/REST+API+Documentation')
+ try:
+ apihtml = uni2html(apifile.read())
+ finally:
+ apifile.close()
+
+ ## Parsing the ApiWiki Page
+
+ apidoc = BeautifulSoup(apihtml)
+ toc = apidoc.find('div', {'class':'toc'})
+ toc_entries = toc.findAll('li', text=lambda text: 'Methods' in text)
+ method_links = {}
+ for entry in toc_entries:
+ links = entry.parent.parent.findAll('a')
+ method_links[links[0].string] = [x['href'] for x in links[1:]]
+
+ # Create unique hash of mehods with POST_ACTIONS
+ POST_ACTION_HASH = {}
+ for method_type, methods in method_links.items():
+ for method in methods:
+ # Strip the hash (#) mark from the method id/name
+ method = method[1:]
+ method_body = apidoc.find('a', {'name': method})
+ value = list(method_body.findNext(
+ 'b', text=lambda text: 'Method' in text
+ ).parent.parent.childGenerator())[-1]
+ if 'POST' in value:
+ method_name = method_body.findNext('h3').string
+ try:
+ POST_ACTION_HASH[method_name] += (method_type,)
+ except KeyError:
+ POST_ACTION_HASH[method_name] = (method_type,)
+
+ # Reverse the POST_ACTION_HASH
+ # this is really only done to generate comment strings
+ POST_ACTION_HASH_R = {}
+ for method, method_types in POST_ACTION_HASH.items():
+ try:
+ POST_ACTION_HASH_R[method_types].append(method)
+ except KeyError:
+ POST_ACTION_HASH_R[method_types] = [method]
+
+ ## Print the _POST_ACTIONS to stdout as a Python List
+ print """'''
+ This module is automatically generated using `update.py`
+
+ ..data::
+
+ `_POST_ACTIONS`: Methods that require the use of POST
+'''
+"""
+ print '_POST_ACTIONS = [\n'
+ for method_types, methods in POST_ACTION_HASH_R.items():
+ print_fw(method_types, prefix='# ', indent=1)
+ print_fw([repr(str(x)) for x in methods], indent=1, trail=True)
+ print ""
+ print ']'
+
+if __name__ == "__main__":
+ main()