From 262b7441d41510010dad0cbe590e3aeac110f616 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Mon, 12 Dec 2011 07:32:40 +0000 Subject: [PATCH] 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): """