From 650a69ec17918bf37ec6d60168fc7debfa52e8ff Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Thu, 24 Nov 2011 13:15:23 +0000 Subject: [PATCH 1/3] Allow for easier debugging/development, by registering endpoints directly into Twython. --- twython/twython.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/twython/twython.py b/twython/twython.py index d8db763..bb67474 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -168,6 +168,9 @@ class Twython(object): else: # If they don't do authentication, but still want to request unprotected resources, we need an opener. self.client = httplib2.Http(**client_args) + # register available funcs to allow listing name when debugging. + for key in api_table.keys(): + self.__dict__[key] = self.__getattr__(key) def __getattr__(self, api_call): """ From 4710c49b2865b0d1fd8a253b4bdaa980c66a08fa Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Wed, 30 Nov 2011 14:29:51 +0000 Subject: [PATCH 2/3] Allow for easier debugging/development, by registering endpoints directly into Twython3k. --- twython3k/twython.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/twython3k/twython.py b/twython3k/twython.py index f30cfcd..53cab7c 100644 --- a/twython3k/twython.py +++ b/twython3k/twython.py @@ -156,6 +156,9 @@ class Twython(object): else: # If they don't do authentication, but still want to request unprotected resources, we need an opener. self.client = httplib2.Http(**client_args) + # register available funcs to allow listing name when debugging. + for key in api_table.keys(): + self.__dict__[key] = self.__getattr__(key) def __getattr__(self, api_call): """ From 262b7441d41510010dad0cbe590e3aeac110f616 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Mon, 12 Dec 2011 07:32:40 +0000 Subject: [PATCH 3/3] Get rid of __getattr__ since the endpoints are directly registered into Twython by the constructor. --- twython/twython.py | 58 ++++++++++++++++---------------------------- twython3k/twython.py | 53 ++++++++++++---------------------------- 2 files changed, 37 insertions(+), 74 deletions(-) diff --git a/twython/twython.py b/twython/twython.py index bb67474..4f8c3a4 100644 --- a/twython/twython.py +++ b/twython/twython.py @@ -170,46 +170,30 @@ class Twython(object): self.client = httplib2.Http(**client_args) # register available funcs to allow listing name when debugging. for key in api_table.keys(): - self.__dict__[key] = self.__getattr__(key) + self.__dict__[key] = lambda **kwargs: self._constructFunc(key, **kwargs) - def __getattr__(self, api_call): - """ - The most magically awesome block of code you'll see in 2010. + def _constructFunc(self, api_call, **kwargs): + # Go through and replace any mustaches that are in our API url. + fn = api_table[api_call] + base = re.sub( + '\{\{(?P[a-zA-Z_]+)\}\}', + # The '1' here catches the API version. Slightly + # hilarious. + lambda m: "%s" % kwargs.get(m.group(1), '1'), + base_url + fn['url'] + ) - Rather than list out 9 million damn methods for this API, we just keep a table (see above) of - every API endpoint and their corresponding function id for this library. This pretty much gives - unlimited flexibility in API support - there's a slight chance of a performance hit here, but if this is - going to be your bottleneck... well, don't use Python. ;P - - For those who don't get what's going on here, Python classes have this great feature known as __getattr__(). - It's called when an attribute that was called on an object doesn't seem to exist - since it doesn't exist, - we can take over and find the API method in our table. We then return a function that downloads and parses - what we're looking for, based on the keywords passed in. - - I'll hate myself for saying this, but this is heavily inspired by Ruby's "method_missing". - """ - def get(self, **kwargs): - # Go through and replace any mustaches that are in our API url. - fn = api_table[api_call] - base = re.sub( - '\{\{(?P[a-zA-Z_]+)\}\}', - lambda m: "%s" % kwargs.get(m.group(1), '1'), # The '1' here catches the API version. Slightly hilarious. - base_url + fn['url'] - ) - - # Then open and load that shiiit, yo. TODO: check HTTP method and junk, handle errors/authentication - if fn['method'] == 'POST': - resp, content = self.client.request(base, fn['method'], urllib.urlencode(dict([k, Twython.encode(v)] for k, v in kwargs.items())), headers = self.headers) - else: - url = base + "?" + "&".join(["%s=%s" %(key, value) for (key, value) in kwargs.iteritems()]) - resp, content = self.client.request(url, fn['method'], headers = self.headers) - - return simplejson.loads(content.decode('utf-8')) - - if api_call in api_table: - return get.__get__(self) + # Then open and load that shiiit, yo. TODO: check HTTP method + # and junk, handle errors/authentication + if fn['method'] == 'POST': + myargs = urllib.urlencode(dict([k, Twython.encode(v)] for k, v in kwargs.items())) + resp, content = self.client.request(base, fn['method'], myargs, headers = self.headers) else: - raise TwythonError, api_call + myargs = ["%s=%s" %(key, value) for (key, value) in kwargs.iteritems()] + url = "%s?%s" %(base, "&".join(myargs)) + resp, content = self.client.request(url, fn['method'], headers=self.headers) + + return simplejson.loads(content.decode('utf-8')) def get_authentication_tokens(self): """ diff --git a/twython3k/twython.py b/twython3k/twython.py index 53cab7c..fe7bcb8 100644 --- a/twython3k/twython.py +++ b/twython3k/twython.py @@ -158,46 +158,25 @@ class Twython(object): self.client = httplib2.Http(**client_args) # register available funcs to allow listing name when debugging. for key in api_table.keys(): - self.__dict__[key] = self.__getattr__(key) + self.__dict__[key] = lambda **kwargs: self._constructFunc(key, **kwargs) - def __getattr__(self, api_call): - """ - The most magically awesome block of code you'll see in 2010. + def _constructFunc(self, api_call, **kwargs): + # Go through and replace any mustaches that are in our API url. + fn = api_table[api_call] + base = re.sub( + '\{\{(?P[a-zA-Z_]+)\}\}', + lambda m: "%s" % kwargs.get(m.group(1), '1'), # The '1' here catches the API version. Slightly hilarious. + base_url + fn['url'] + ) - Rather than list out 9 million damn methods for this API, we just keep a table (see above) of - every API endpoint and their corresponding function id for this library. This pretty much gives - unlimited flexibility in API support - there's a slight chance of a performance hit here, but if this is - going to be your bottleneck... well, don't use Python. ;P - - For those who don't get what's going on here, Python classes have this great feature known as __getattr__(). - It's called when an attribute that was called on an object doesn't seem to exist - since it doesn't exist, - we can take over and find the API method in our table. We then return a function that downloads and parses - what we're looking for, based on the keywords passed in. - - I'll hate myself for saying this, but this is heavily inspired by Ruby's "method_missing". - """ - def get(self, **kwargs): - # Go through and replace any mustaches that are in our API url. - fn = api_table[api_call] - base = re.sub( - '\{\{(?P[a-zA-Z_]+)\}\}', - lambda m: "%s" % kwargs.get(m.group(1), '1'), # The '1' here catches the API version. Slightly hilarious. - base_url + fn['url'] - ) - - # Then open and load that shiiit, yo. TODO: check HTTP method and junk, handle errors/authentication - if fn['method'] == 'POST': - resp, content = self.client.request(base, fn['method'], urllib.parse.urlencode(dict([k, Twython.encode(v)] for k, v in list(kwargs.items()))), headers = self.headers) - else: - url = base + "?" + "&".join(["%s=%s" %(key, value) for (key, value) in list(kwargs.items())]) - resp, content = self.client.request(url, fn['method'], headers = self.headers) - - return simplejson.loads(content.decode('utf-8')) - - if api_call in api_table: - return get.__get__(self) + # Then open and load that shiiit, yo. TODO: check HTTP method and junk, handle errors/authentication + if fn['method'] == 'POST': + resp, content = self.client.request(base, fn['method'], urllib.parse.urlencode(dict([k, Twython.encode(v)] for k, v in list(kwargs.items()))), headers = self.headers) else: - raise TwythonError(api_call) + url = base + "?" + "&".join(["%s=%s" %(key, value) for (key, value) in list(kwargs.items())]) + resp, content = self.client.request(url, fn['method'], headers = self.headers) + + return simplejson.loads(content.decode('utf-8')) def get_authentication_tokens(self): """