From 0a51ea7c0564953c87ca7e772134e6abb2ca5fe7 Mon Sep 17 00:00:00 2001 From: Russ P Date: Fri, 19 Nov 2010 16:34:08 -0500 Subject: [PATCH] Initial commit --- README.rst | 111 +++++++++++++++++++++++ aweber_api.egg-info/PKG-INFO | 10 ++ aweber_api.egg-info/SOURCES.txt | 11 +++ aweber_api.egg-info/dependency_links.txt | 1 + aweber_api.egg-info/top_level.txt | 1 + aweber_api/.base.py.swp | Bin 0 -> 12288 bytes aweber_api/.collection.py.swp | Bin 0 -> 12288 bytes aweber_api/.entry.py.swp | Bin 0 -> 12288 bytes aweber_api/.oauth.py.swp | Bin 0 -> 12288 bytes aweber_api/.response.py.swp | Bin 0 -> 12288 bytes aweber_api/__init__.py | 99 ++++++++++++++++++++ aweber_api/__init__.pyc | Bin 0 -> 4815 bytes aweber_api/base.py | 54 +++++++++++ aweber_api/base.pyc | Bin 0 -> 2836 bytes aweber_api/collection.py | 81 +++++++++++++++++ aweber_api/collection.pyc | Bin 0 -> 4166 bytes aweber_api/entry.py | 42 +++++++++ aweber_api/entry.pyc | Bin 0 -> 2162 bytes aweber_api/oauth.py | 45 +++++++++ aweber_api/oauth.pyc | Bin 0 -> 1754 bytes aweber_api/response.py | 29 ++++++ aweber_api/response.pyc | Bin 0 -> 1248 bytes setup.py | 10 ++ tests/data/account.json | 1 + tests/data/accounts.json | 9 ++ tests/data/error.json | 1 + tests/data/lists.json | 1 + tests/data/lists/303449.json | 1 + tests/data/lists/303449/campaigns.json | 1 + tests/data/lists_page2.json | 1 + tests/data/web_forms.json | 1 + tests/mock_adapter.py | 43 +++++++++ tests/mock_adapter.pyc | Bin 0 -> 1929 bytes tests/test_aweber_ | 0 tests/test_aweber_api.py | 105 +++++++++++++++++++++ tests/test_aweber_api.pyc | Bin 0 -> 6237 bytes tests/test_aweber_collection.py | 37 ++++++++ tests/test_aweber_collection.pyc | Bin 0 -> 2491 bytes tests/test_aweber_entry.py | 63 +++++++++++++ tests/test_aweber_entry.pyc | Bin 0 -> 4437 bytes 40 files changed, 758 insertions(+) create mode 100644 README.rst create mode 100644 aweber_api.egg-info/PKG-INFO create mode 100644 aweber_api.egg-info/SOURCES.txt create mode 100644 aweber_api.egg-info/dependency_links.txt create mode 100644 aweber_api.egg-info/top_level.txt create mode 100644 aweber_api/.base.py.swp create mode 100644 aweber_api/.collection.py.swp create mode 100644 aweber_api/.entry.py.swp create mode 100644 aweber_api/.oauth.py.swp create mode 100644 aweber_api/.response.py.swp create mode 100644 aweber_api/__init__.py create mode 100644 aweber_api/__init__.pyc create mode 100644 aweber_api/base.py create mode 100644 aweber_api/base.pyc create mode 100644 aweber_api/collection.py create mode 100644 aweber_api/collection.pyc create mode 100644 aweber_api/entry.py create mode 100644 aweber_api/entry.pyc create mode 100644 aweber_api/oauth.py create mode 100644 aweber_api/oauth.pyc create mode 100644 aweber_api/response.py create mode 100644 aweber_api/response.pyc create mode 100644 setup.py create mode 100644 tests/data/account.json create mode 100644 tests/data/accounts.json create mode 100644 tests/data/error.json create mode 100644 tests/data/lists.json create mode 100644 tests/data/lists/303449.json create mode 100644 tests/data/lists/303449/campaigns.json create mode 100644 tests/data/lists_page2.json create mode 100644 tests/data/web_forms.json create mode 100644 tests/mock_adapter.py create mode 100644 tests/mock_adapter.pyc create mode 100644 tests/test_aweber_ create mode 100644 tests/test_aweber_api.py create mode 100644 tests/test_aweber_api.pyc create mode 100644 tests/test_aweber_collection.py create mode 100644 tests/test_aweber_collection.pyc create mode 100644 tests/test_aweber_entry.py create mode 100644 tests/test_aweber_entry.pyc diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..9231629 --- /dev/null +++ b/README.rst @@ -0,0 +1,111 @@ +About +----- + +The AWeber API Python Library allows you to quickly get up and running with +integrating access to the AWeber API into your Python applications. This +egg requires the python-oauth2 to handle the authentication. + +Installation +============ + +This egg can be installed by checking out the source:: + + $ sudo python setup.py install + +Or from Pypi:: + + $ easy_install -U aweber_api + +Usage +===== + +To connect the AWeber API Python Libray, you simply include the main class, +AWeberAPI in your application, then create an instace of it with your +application's consumer key and secret:: + + from aweber import AWeberAPI + aweber = AWeberAPI(consumer_key, consumer_secret) + account = aweber.get_account(access_token, token_secret) + + for list in account.lists: + print list.name + + +Getting request tokens / access tokens +++++++++++++++++++++++++++++++++++++++ + +You can also use the AWeberAPI object to handle retrieving request tokens:: + + from aweber import AWeberAPI + aweber = AWeberAPI(consumer_key, consumer_secret) + request_token, request_token_secret = aweber.get_request_token(callback_url) + print aweber.authorize_url + +As well as access tokens:: + + from aweber import AWeberAPI + aweber = AWeberAPI(consumer_key, consumer_secret) + aweber.user.verifier = verifier + aweber.user.request_token = request_token + aweber.user.token_secret = request_token_secret + access_token, access_token_secret = aweber.get_access_token() + + +Full Pylons example ++++++++++++++++++++ + +Here is a simple Pylons example that uses the AWeber API Python Library to get +a request token, have it authorized, and then print some basic stats about the +web forms in that user's first list:: + + from pylons import session, request, tmpl_context as c + from pylons.controllers.util import redirect + + from awebertest.lib.base import BaseController, render + + from aweber_api import AWeberAPI + + url = 'http://localhost:5000' + consumer_key = "vjckgsr5y4gfOa3PWnf" + consumer_secret = "u3sQ7vGGJBfds4q5dfgsTESi685c5x2wm6gZuIj" + class DemoController(BaseController): + + def __before__(self): + self.aweber = AWeberAPI(consumer_key, consumer_secret) + + def index(self): + token, secret = self.aweber.get_request_token(url+'/demo/get_access') + session['request_token_secret'] = secret + session.save() + redirect(self.aweber.authorize_url) + + def get_access(self): + self.aweber.user.request_token = request.params['oauth_token'] + self.aweber.user.token_secret = session['request_token_secret'] + self.aweber.user.verifier = request.params['oauth_verifier'] + session['token'], session['secret'] = self.aweber.get_access_token() + session.save() + redirect(url+'/demo/show') + + def show(self): + c.account = self.aweber.get_account(session['token'], session['secret']) + return render('data.mako') + + +In `data.mako`:: + + + + +

Web Forms

+ % for list in c.account.lists: + List Id: ${list.id}, name: ${list.name}
+ Currently has: ${len(list.web_forms)} web forms + + % endfor + + diff --git a/aweber_api.egg-info/PKG-INFO b/aweber_api.egg-info/PKG-INFO new file mode 100644 index 0000000..f53dc95 --- /dev/null +++ b/aweber_api.egg-info/PKG-INFO @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: aweber-api +Version: 1.0.0 +Summary: UNKNOWN +Home-page: UNKNOWN +Author: UNKNOWN +Author-email: UNKNOWN +License: UNKNOWN +Description: UNKNOWN +Platform: UNKNOWN diff --git a/aweber_api.egg-info/SOURCES.txt b/aweber_api.egg-info/SOURCES.txt new file mode 100644 index 0000000..30a7136 --- /dev/null +++ b/aweber_api.egg-info/SOURCES.txt @@ -0,0 +1,11 @@ +setup.py +aweber_api/__init__.py +aweber_api/base.py +aweber_api/collection.py +aweber_api/entry.py +aweber_api/oauth.py +aweber_api/response.py +aweber_api.egg-info/PKG-INFO +aweber_api.egg-info/SOURCES.txt +aweber_api.egg-info/dependency_links.txt +aweber_api.egg-info/top_level.txt \ No newline at end of file diff --git a/aweber_api.egg-info/dependency_links.txt b/aweber_api.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/aweber_api.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/aweber_api.egg-info/top_level.txt b/aweber_api.egg-info/top_level.txt new file mode 100644 index 0000000..5ca1f7a --- /dev/null +++ b/aweber_api.egg-info/top_level.txt @@ -0,0 +1 @@ +aweber_api diff --git a/aweber_api/.base.py.swp b/aweber_api/.base.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..7080f1944736a761c1901436e352ad01c98e485a GIT binary patch literal 12288 zcmeI2O=}ZD7{{j`)%toCA0xOaq?=j~NbP#{1_Iz zc=F^2@FVyEJSmD7zkr}8U!K`bH;uJeyjh-s|890>p10pj4x3DSX65!BxE#(hY$q6d z@ag&D=8skOI>Y5g-CYfCvx)B0vO)01+Sp z2ZR8R8T)vIvCdH}2><{0zX5zc&e#Xk3)B|s8R{wO7U}{DP-jsmQQwa-_8#>P^&0gG zB~fdrDb%+~#=fH7pkAW7r~q{s^%i4pp?vHWAD>Y5g-EpApsaR z!=)9lG{|;!h#S2j0w znu^Ftt^PfwsPZwM*T{Dj-zVoQkiz~U!&oHHGJ?l=Daq75mS4jepDi8vvWD1SU1-d(2;$i zVENu+SozrY=j%;1mg^_CFyT?Tdlfm{BVlfZDg1dK{-H2ME5LRwGddH-;kk4F_@ub{ zPXUi2ohui>9IOVZw9W==qfy^c4&ib3R-#SMB8nj5y^PC_Djsa!wvmyzkb P`TeX7=msvqK%tNRRGz_L-UYecq4N*}Fb} z@%*dwS^pHlc$AR!-><&%(LX(M`yN6>E@h_Y?=TF{Plur&vq&6F{=g8say#i}EZkxn zTz0du+Dwx|JQ#5xb+Aj*MaYW zFM!X0W#9;K`(Z+U20jPQ0Teg^90BeHemRb{z%}4&fCJA1%fJcXC~)&3LcRh%0X_!a z20FkW#|XIr`~X}7hQM>cUk?)UC-4*S4e&m&1Dpe900P{4fRG=78^CwKm%vrvQ{WP? z1Uv!!eLo?;0lxy*fnDGk;52XyxCtG;1wI7&fYv1d+;9pw1)Ks-0jI$KR)7{maFvUM zN*)jWfG0{sT=vr8P;%8LB}so;MkqK_+z`iYOPigb)zmm;gCN73biptcf#ptJ5)EmR zDry-tY8o>R228QV>V!k6uzL~D{KgP0lAK;-an4tSNJZOw&GuS8OL zK5QH@RoYkkgcA$H&eD0Bit=iCsZc~4*z;7XSRBacJ?{0bxdT3=L9oG9r1&TZ+FHL( zv3j;)skQPAm1gG^7fioTSb0%so(qA<&?P!w-O+9~Lf4yM&Miz0U9ru{CAv`U1NSDD z(zEuu_NVqH;a8M#W5WD8f6S)VZTKt-pAR7W^$Cr2F;Au}vli}2PRQ}XTl&q+6(sGr zor}0bbu2p80XAS6jHm+%0+zH8`|i%dZmSHq*}GcY^P+**pRMyq?}%l!1vVr1Rmf1J zBWhm^^|hg68jZ44sHTmzpA%K2_nw*t?O8CfrDJTj&`RY$Oj%b*thQ zAD4}$Ex63mMDjXJMf z4vGiG2-6&eI8i}*+B#<9ZW>n4@J^P#^gJ8Bejlb87SXHpK-;l1y6@F|O+rH}dx>V+ zqsty(bZ;tYtuA+H7Ttc;?Tk+CS~y!vt3^EgAc&GkRc)&(kPfX1i)gF#u-k=Gx|F?B z>jL+8Y&AEr$^G}t%n-BzWy+X@Ejhig zdft;Jc^KV@ws}I+^>^?xI#uJ0cWA_I*Iwlr?1KK1vW6&l3Q-x2qL|@vX4Xlc(v>7+ znapE6-=%dgV8FaCk@?s@%dop!&>NUDyfcNH6ytd3In_`)4mX4?IW_jOq G9`YaUEeb>c literal 0 HcmV?d00001 diff --git a/aweber_api/.entry.py.swp b/aweber_api/.entry.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..f4cdc5546bb445d5dd46692076dce41d9c2d041f GIT binary patch literal 12288 zcmeI2O=}cM7{^P&i|^qai-*7p5^z<5+thSdXKL-~YO1Q0A!I*+ z;?0vM!K258-J|zCtOxPz7ZAbw?*6N~GttDDspsWaPs2=7lkv}MH|a{U zA~4PhQN4fu)02NT#HXV|*w(ow%pWqMU1G{Ssid|C8~+v!Q}?h=8<{_lo64ol+)qtC zl8@9x*^z8?>TO#;NV|zt)!xpNW`3|!USR@E;BW%1FGp8TiOVa?NfC(@GCcp%k025#W-xUGh91;JbB7EH!7oj7)@QVi%U;<2l2`~XBzyz286JP>N zfC(@GCh(mQkcALWj|-8WKtcHbfA|}~n=?ZE4ZVV1LieE4(1+7Pyn}v+rVv3Vp%c*S zQ$qX+{Q*6O)}awJgpNUPPYUq@`UP5s#?Tq)BjWxAJ%dW4dp^(!G#DfVi0Vco% zm;e)C0!)Aj{BH#4vtgxnidMb1deVAz!&+mPB;H;UJ65W4>e}L6n6=8cwkD^lGRg9( zu8J%-Ri$#TO}%foE-5%9-S5~nb=gcd8_|uQH|qX3q7>50jo{|~B9py-vtZM?C{#&V zwyAvBk!4FE#4u)Y=^8%t_v4#oxINLrp05|&ThjGzy)v@MN^53WYpW$_mt^pP30Mxc z#@p%E^7bGpjh#s!Gfc47XDNbd7$~wf{!4)Skh{;S-gg{dul;~hklNO^h>`JQ^-j3b zyslhhYNwJc)3x>soH5(L961-V@v85c4*p@L{W%N@>7NO>k=B0Yx5~d*MZmg9vCurjmmYYbLwth$2l|k6<&w*XsWS8!&QM* zoy#hO2u?#GJB=MqFHYWGUn3k4UP~YS{3vUZl`}L^w5e)krB?+l?4y%D%Md*zEv=Pv zGI$7RxAUVj1&OW^76f|dLkfOTy_$q_ zW+#_UGbsFfTnvaR1rh1s|L7H3ko5p>&;4aTz3wm>k(SLwbpr=Ds83B yr}ITl2%w^`aMpPxaje~@8{uaB(w9vZp3knlc%44Ob^2uIyh+a*WBs1C6#oHR_{pCD literal 0 HcmV?d00001 diff --git a/aweber_api/.oauth.py.swp b/aweber_api/.oauth.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..61684b5a8cba0ba1979fe1d5714e736c136a53a3 GIT binary patch literal 12288 zcmeI2zmMER6vrnNDe@CR5z67hv0mi!UM?WeNiL!&1>%>4NSf2h%z9^Uedo2!%s9Et zY3Y)`06Iz}{sTG)H9z{C1c;UvL;(fxow2>%-LPEJMsK9Ay?*oN&CKV$S!wUw-@Nta zJN)%vi=jQs*bl#a_V)XK@37yWVN8`;7uJ44bACZSjDu7pYPIvn&atO&XT3ti2Vzg^ zUNJGFJlha=WM8TcQ6xR1%Iu(58G5-W%_t})tAkPx5g-C56DZAaeiLb%WE(4 z=byWI@)+_U0z`la5CI}U1c(3;AOb|-sUl#CQ|uq?2tW7P26UFGFKxd%ibBsNNzJ%^W_n;Vh3ksn> z&NB8L^eyxibQih_b)iepX~?eq7gqV42i$hA?60hQE+&+GA^7pDmV z1xkKYf~i-k)aPS~H)RJt@8^R_XfN$NMoqTa!mQ0Io4ZX^a3Ckz>vr35w%10&jGdP| z!G4}(-dGe~D#rbR;D_6M?Pzlv9$lHP1;bp8h4BvkD(Q#2U7t14WvZ75)lnC+4HBu$ zy!oYA7@JE=$7bz%*7dsX@OADv!gw(_>I*G>j_!5?2$|)^+IF^IMcHB8$e5zD6tcpJ zsMYJl*B#v|FqrFdEL9ux(ak)@aG#s}KxU!4wy`WAXPV9Zfpzno&F5}wrIspihDgg8 zWz`P1wPXF;VsVcM){fkhCK@GsBh*P$s3cd3nMBUbs{#$=5T~OmBs;9FBv)289pTZm zJBO?;ZCjL}vv^$p<8-vEv)io)+px?&&$s^zT&L2GY?|7Noft zXs=mji_IMeJIHRmKAY9fXTEd0bts$q0$N*UvngF?QzNq^UayPB!-)!=3qII%+VoY1 zvXk|idJT&4Q9tC<7e0$8QZS)AhQiobUaugPB4+?@Ouin+~+g-O=XvkH{8~A23?|t{Zna`Zk&Y<`3&ONyv^aaLgA>8+O zci;Zr5xc1VsG{QiadK}YrzYgW&%ur2`~XB zzyz286JP>N;II+!W=Z_PrtouLoP(As;lYCmFaajO1egF5U;<2l2`~XBzyz286F4LU z)JTZ;Cxi%>u_65bpZ*5$?UWE-p-<39=ndqdE$A9_0XhyHgMOZb4|)YXf^I=Kq07(; zbQJo5+Fzj0&q@iu72T|`n#DfVi0Vco%m;e)C0!)AjFaaj;KM{~K!>ZV6x#_)) z2f5d`t<7v(VcHS@Tsm=jqn=UJYMJblup@ zXzOt=o2E3X&iAwQpq^AfUX}C+oJnHeZmqUDfyvCw0;o)7oFUZ0HSjFA!*ab*5~q_^ zgV;faxdfY=ueKzpGmWyXPI0K(VZF~^h$3F6=*$qOM>CV#1aW*e!)m0A*A}VjTQgl8 z0g^Sf@|5E=_Vp2?=33DZr(IT~10N>JIk~w_H|HNz_vG8<^oDYpEMuGP$?__FguC@J N-ZPo?)jMPoe*yJg5~u(G literal 0 HcmV?d00001 diff --git a/aweber_api/__init__.py b/aweber_api/__init__.py new file mode 100644 index 0000000..3d0717f --- /dev/null +++ b/aweber_api/__init__.py @@ -0,0 +1,99 @@ +from urlparse import parse_qs + +from aweber_api.base import (AWeberBase, API_BASE, ACCESS_TOKEN_URL, + REQUEST_TOKEN_URL, AUTHORIZE_URL) +from aweber_api.collection import AWeberCollection +from aweber_api.entry import AWeberEntry +from aweber_api.oauth import OAuthAdapter +from aweber_api.response import AWeberResponse + +class AWeberAPI(AWeberBase): + """ Base class for connecting to the AWeberAPI. Created with a consumer key + and secret, then used to either generate tokens for authorizing a user, or + can be provided tokens and used to access that user's resources. """ + + def __init__(self, consumer_key, consumer_secret): + self.adapter = OAuthAdapter(consumer_key, consumer_secret, API_BASE) + self.adapter.user = AWeberUser() + + @property + def authorize_url(self): + """ + Returns the authorize url, potentially containing the request token + parameter + """ + if self.user.request_token: + return "{0}?oauth_token={1}".format(AUTHORIZE_URL, + self.user.request_token) + return AUTHORIZE_URL + + def get_request_token(self, callback_url): + """ + Gets a new request token / token secret for the given callback URL + and the current consumer. Returns token / secret, and sets properties + on the AWeberUser object (self.user) + """ + data = { 'oauth_callback' : callback_url } + response = self.adapter.request('POST', + REQUEST_TOKEN_URL, + data) + self.user.request_token, self.user.token_secret = self.\ + _parse_token_response(response) + return (self.user.request_token, self.user.token_secret) + + def get_access_token(self): + """ + Gets an access token for the given request token / token secret / + verifier combination in the AWeberUser object at self.user + Updates the user object and returns the tokens + """ + + data = { 'oauth_verifier' : self.user.verifier } + response = self.adapter.request('POST', + ACCESS_TOKEN_URL, + data) + self.user.access_token, self.user.token_secret = self.\ + _parse_token_response(response) + return (self.user.access_token, self.user.token_secret) + + def _parse_token_response(self, response): + if not type(response) == str: + raise TypeError('Expected response to be a string') + + data = parse_qs(response) + + if not 'oauth_token' in data and not 'oauth_token_secret' in data: + raise ValueError('OAuth parameters not returned') + return (data['oauth_token'][0], data['oauth_token_secret'][0]) + + def get_account(self, access_token=False, token_secret=False): + """ + Returns the AWeberEntry object for the account specified by the + access_token and token_secret currently in the self.user object. + Optionally, access_token and token_secret can be provided to replace + the properties in self.user.access_token and self.user.token_secret, + respectively. + """ + if access_token: + self.user.access_token = access_token + if token_secret: + self.user.token_secret = token_secret + url = '/accounts' + response = self.adapter.request('GET', url) + accounts = self._read_response(url, response) + return accounts[0] + +class AWeberUser(object): + """ + Simple data storage object representing the user in the OAuth model. Has + properties for request_token, token_secret, access_token, and verifier. + """ + + request_token = None + token_secret = None + access_token = None + verifier = None + + def get_highest_priority_token(self): + return self.access_token or self.request_token + diff --git a/aweber_api/__init__.pyc b/aweber_api/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c9acc4c9709aade5366996e2cc8532c8b5dc117 GIT binary patch literal 4815 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 literal 0 HcmV?d00001 diff --git a/aweber_api/collection.py b/aweber_api/collection.py new file mode 100644 index 0000000..a22bc25 --- /dev/null +++ b/aweber_api/collection.py @@ -0,0 +1,81 @@ +from math import floor +from urlparse import parse_qs +from aweber_api.response import AWeberResponse + +class AWeberCollection(AWeberResponse): + """ + Represents a collection of similar objects. Encapsulates data that is + found at the base URI's for a given object type, ie: + /accounts + /accounts/XXX/lists + Parses the data from the response and provides basic sequence like + operations, such as iteration and indexing to access the entries that + are contained in this collection. + """ + page_size = 100 + + def __init__(self, url, data, adapter): + self._entry_data = {} + self._current = 0 + + AWeberResponse.__init__(self, url, data, adapter) + self._key_entries(self._data) + + def get_by_id(self, id): + """ + Returns an entry from this collection, as found by its actual + AWeber id, not its offset. Will actually request the data from + the API. + """ + return self.load_from_url("{0}/{1}".format(self.url, id)) + + def _key_entries(self, response): + count = 0 + for entry in response['entries']: + self._entry_data[count+response['start']] = entry + count += 1 + + def _load_page_for_offset(self, offset): + page = self._get_page_params(offset) + response = self.adapter.request('GET', self.url, page) + self._key_entries(response) + + def _get_page_params(self, offset): + next_link = self._data['next_collection_link'] + url, query = next_link.split('?') + query_parts = parse_qs(query) + self.page_size = int(query_parts['ws.size'][0]) + page_number = int(floor(offset / self.page_size)) + start = page_number * self.page_size + return { 'ws.start' : start, 'ws.size' : self.page_size } + + def _create_entry(self, offset): + from aweber_api.entry import AWeberEntry + data = self._entry_data[offset] + + url = "{0}/{1}".format(self.url, data['id']) + self._entries[offset] = AWeberEntry(url, data, self.adapter) + + def __len__(self): + return self.total_size + + def __iter__(self): + return self + + def next(self): + if self._current < self.total_size: + self._current += 1 + return self[self._current-1] + self._current = 0 + raise StopIteration + + def __getitem__(self, offset): + if offset < 0 or offset >= self._data['total_size']: + raise ValueError('Offset {0} does not exist'.format(offset)) + + if not offset in self._entries: + if not offset in self._entry_data: + self._load_page_for_offset(offset) + self._create_entry(offset) + return self._entries[offset] + diff --git a/aweber_api/collection.pyc b/aweber_api/collection.pyc new file mode 100644 index 0000000000000000000000000000000000000000..70d02e556d5b9d25ee415d565ff7980456383d75 GIT binary patch literal 4166 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 literal 0 HcmV?d00001 diff --git a/aweber_api/oauth.py b/aweber_api/oauth.py new file mode 100644 index 0000000..8524648 --- /dev/null +++ b/aweber_api/oauth.py @@ -0,0 +1,45 @@ +import oauth2 as oauth +import json + +class OAuthAdapter(object): + + def __init__(self, key, secret, base): + self.key = key + self.secret = secret + self.consumer = oauth.Consumer(key=self.key, secret=self.secret) + self.api_base = base + + def _parse(self, response): + try: + data = json.loads(response) + if not data or data == '': + return response + return data + except: + pass + return response + + def request(self, method, url, data={}): + token = self.user.get_highest_priority_token() + if token: + token = oauth.Token(token, self.user.token_secret) + client = oauth.Client(self.consumer, token=token) + else: + client = oauth.Client(self.consumer) + + if not url[:4] == 'http': + url = '%s%s' % (self.api_base, url) + + if len(data.keys()) == 0: + body = None + else: + body = '&'.join(map(lambda x: "{0}={1}".format(x, data[x]), + data.keys())) + + try: + resp, content = client.request(url, method, body=body) + if type(content) == str: + return self._parse(content) + except e: + pass + return None diff --git a/aweber_api/oauth.pyc b/aweber_api/oauth.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2bc30ff46d0687dc9389fa16c66e7236636d60f8 GIT binary patch literal 1754 zcma)6OK;Oa5T4n*Lm$xc7D6BavV_D-9C`POg5)3p6_Vw|TjDgajdvr6NKQq--{Z=K z8$Wv#Ib(V$vOtXXU;&{iY>9U4@=Wnh z@;Gr?jIaf{##dTb0KZkJN$g{VbTlr(5*2ajtaOPxj*Ym+>wJnE+y+%=t#$|UE|#El z*HMeAq*_c`qLOvW?-ExP2eW@%r#&ObB5$a$sr>*s^RhwNW_9P_O!5R;JNpuv8aXP? z5GR$vmYnPuI*nW+O$^jukl~IrK5ixr&1o0IT0Hy9v(6~#v){!$q z{1TD$14&*_%jWZ4o261oEz-#Q!U=cPU3Hich^5W14P}=lXVQ}HBsSQB4%`AX_H#&W zKM*Y^E%4#i^8Sb0OBLww?BwM%_7yK$@0ASKKpx!_ZD`z^#M40%Kez(gVO8-C@?;)t z9B?y-sXGtujrGweeKWGoM@5%ev~Jw zH!CNal2BS-!x>iLoEBapkg-xfcw9W9(&YWk<-eYc@G|a-5hpn$j8u!y@&&VDPVgCX zj=Sa*Zfgc5S?{WmxMHpKtfbP;=siq1S)4h(25(%VRJy_vU1}sn7X#LyAg^MF2En; z%7q(0fIk3lW}Q@UKuI!_*$>aW_h$U<*TL||_n)s9)P4H+e*yCk;0pW{T@Y1@=89C2 zkX3Z9sOZsGqAx^m=Lr>knq_;qUjD`>Q;5P4?&TYMX5C5dZ5VHt+WNMsz1&nkl(zC3O#}@3^IN2%8AHx+yYa*j)-IE}pHDc^w zi5Nkj-p4ygNg%<{r&$UgINP+TZD3+1tXdoP5#>eR2J1o(@zPcCw8%pquJJuv2Ul7z zpd^L2)w$*rvf_)HGiR{q{4GTJM^?(@ZTZ-B`aEh^F{LT%G8n@-JgZ7-(0vySml@;g4#96=HIP;{Kceb`J53%+LJDxLb{rWi=BAid+~4$8Ut1sGj2@4Jj6yE zw5|!G4G8QW%@kxrfChY)N&gF($SN;Oz#yG1gMH;(1MH$}?j-;Z1xYXW!oJ&g{-JGtbU1zpr9EUD>@|_D>_o7c<#}uM@OFMAp3OWQ|^;)&_Ge%pqE7FL{E>JY}yZ-IL5rf6Dmlq zgJJ)PKGyYPtLp=|hWWQ;cDkRZmDBYF3?J)^z#0si*gKr#Y7}FNT{qQw-%NQuX9^NnT z+8zccVaxog;;B&IMfNm`IC`z9spX_l4K!dctKQnZ>m zHd{?N(-)fPw&TK#4IEhx`cIljRvn)NM9HA6C)U3ESDOdV?RHu14YflpAF+j0Qg$X) zI@EV82mOyzd7pJ@?e^~M++x}Ms3F=ejAe6lcjxZCd-v^I|F(Ojyzw{dC`%_*YKDci z@BhcXOS6p2!^vT`ONoDmfD+GqGK%?ojw&k}c~l)E#U9NY^uyCj^_Sm&Me`=j8dPqO zn&CEh^zq!IVr?<=W#)X|2ki_5ZO|q-0tc9E;rLCqfA%3gDR8ma2KS^%qZXA-T(lH9#&TQcq;HZX=c@M35F;`V%d zWXmGtIY1)!x)1`N>N6|CclA^YMINPNtHs8;+O5O3*3YIOD9Y?ktm6zaMN%h3%u|;p zxvAw4_94Q!Omh*+N*97NX0Nh&qCx&#JWT7cSn(m^d|+zpL^;FaAs-DVLeSvR}5a%NZNG@12S2R;(JkF>=rKKt$(M@mz zjcVx8rj&`fcOWe>ej8%UIh8gEnh}+Dk!)Q_yra?-%bPziW1S?D7h8>uTl5~uBcqZF zcQvghev={bnT(aZwhFoVEO8X+gmG{uPm)QQPZ?Ismhl@at7T4Y{N8G%s!{veon4&0 zfGV~8zpXLm__-p|HUh8h`>5UJuj2<^_w|seDzH=Ov`JbSY27iGKEBCXHYty}E6bUe XOuG`ClE6)n#{PP$tGeDF$2_Ex literal 0 HcmV?d00001 diff --git a/tests/test_aweber_ b/tests/test_aweber_ new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_aweber_api.py b/tests/test_aweber_api.py new file mode 100644 index 0000000..ff26c44 --- /dev/null +++ b/tests/test_aweber_api.py @@ -0,0 +1,105 @@ +from unittest import TestCase +from mock_adapter import MockAdapter +from dingus import Dingus +from aweber_api import (AWeberAPI, AWeberUser, ACCESS_TOKEN_URL, AUTHORIZE_URL, + REQUEST_TOKEN_URL, AWeberEntry) + +key = 'XXXXX' +secret = '3434534534534' +class AWeberAPITest(TestCase): + + def setUp(self): + self.aweber = AWeberAPI(key, secret) + + def test_should_exist(self): + self.assertTrue(self.aweber) + +class WhenGettingARequestToken(AWeberAPITest): + + def setUp(self): + AWeberAPITest.setUp(self) + self.response = "oauth_token=1234&oauth_token_secret=abcd" + self.aweber.adapter = Dingus() + self.aweber.adapter.user = AWeberUser() + self.aweber.adapter.request = Dingus(return_value=self.response) + + def test_should_get_request_token(self): + token, secret = self.aweber.get_request_token('http://localhost/demo') + self.assertEqual(token, '1234') + self.assertEqual(secret, 'abcd') + + def test_should_pass_args_to_request(self): + self.called = False + def _request(method, url, params): + self.assertEqual(url, REQUEST_TOKEN_URL) + self.assertEqual(method, 'POST') + self.assertEqual(params['oauth_callback'], 'http://localhost/demo') + self.called = True + return self.response + self.aweber.adapter.request = _request + token, secret = self.aweber.get_request_token('http://localhost/demo') + self.assertTrue(self.called, 'Called _request') + + def test_should_set_up_user(self): + token, secret = self.aweber.get_request_token('http://localhost/demo') + + self.assertEqual(self.aweber.user.request_token, token) + self.assertEqual(self.aweber.user.token_secret, secret) + + def test_should_have_authorize_url(self): + token, secret = self.aweber.get_request_token('http://localhost/demo') + self.assertEqual(self.aweber.authorize_url, + "{0}?oauth_token={1}".format(AUTHORIZE_URL, token)) + + +class WhenGettingAnAccessToken(AWeberAPITest): + + def setUp(self): + AWeberAPITest.setUp(self) + self.response = "oauth_token=cheeseburger&oauth_token_secret=hotdog" + self.aweber.adapter = Dingus() + self.aweber.adapter.user = AWeberUser() + self.aweber.adapter.request = Dingus(return_value=self.response) + + self.aweber.user.request_token = '1234' + self.aweber.user.token_secret = 'abcd' + self.aweber.user.verifier = '234a35a1' + + + def test_should_get_access_token(self): + access_token, token_secret = self.aweber.get_access_token() + self.assertEqual(access_token, 'cheeseburger') + self.assertEqual(token_secret, 'hotdog') + + def test_should_pass_args_to_request(self): + self.called = False + def _request(method, url, params={}): + self.assertEqual(url, ACCESS_TOKEN_URL) + self.assertEqual(method, 'POST') + self.assertEqual(params['oauth_verifier'], '234a35a1') + self.called = True + return self.response + self.aweber.adapter.request = _request + token, secret = self.aweber.get_access_token() + self.assertTrue(self.called, 'Called _request') + + def test_should_set_up_user(self): + token, secret = self.aweber.get_access_token() + self.assertEqual(self.aweber.user.access_token, token) + self.assertEqual(self.aweber.user.token_secret, secret) + +class WhenGettingAnAccount(TestCase): + + def setUp(self): + self.aweber = AWeberAPI(key, secret) + self.aweber.adapter = MockAdapter() + + self.access_token = '1234' + self.token_secret = 'abcd' + + def test_when_getting_an_account(self): + account = self.aweber.get_account(self.access_token, self.token_secret) + self.assertEqual(type(account), AWeberEntry) + self.assertEqual(account.id, 910) + self.assertEqual(account.type, 'account') + diff --git a/tests/test_aweber_api.pyc b/tests/test_aweber_api.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4732a9d1c2dea9015f6a04bbbe427f864c102e11 GIT binary patch literal 6237 zcmcgw+jbmB6+JyO8fkQ~6ekuj=3*9!8E#P=+gw7NpeO=D%-ED90t2jG?dh^+P-|w= zRpVe1KPe0H#AoF_ue{`q58wx2?^Dw=Em?AswMJ;EOV!n-y6m&hIlJo9|Ew&2_OE~6 z>B#tJ9)Ew1$9;k##cw1BB3UHuNFu&h2q4BwZ?6mnW^yNV-ytaADGVQPNe}X|7=_z5n8;8KLGEQ0!Xgw-RSV%Mx0CGw2*_ zrpeITJT%tP_*SpKKXOf0eFMejyY{}#H}Ade7bkCf&gPy|Y;J9B@9f08ci-7=#e3$C zUt#0k?yv5ex7*v=@(fzc_HXyLcXmttIDHs-yYKTyeh%-y=Z}tXb}r%^o!ISF~`iqqae;+(tffZn$wTAN<93 zyxX|<$ae?*P5pO3yWz1br)3<*jFVySrD4FuS-&?VV2=BcXtEQ&>Q0_R1*`9cGLoY} z++rW>r`Agx4Y!+*ths-SsL5F_MGR0;|(aV%E>tHCxFNxTB(WVWR(W~AjoV2N0%2|q0a8gq`8BYcBo@n-}-nAMlgma8-rVJ zzc)&<(4Q`;AyExx7*uEK1ODrrpyZ)XtcwBFG1^J=e6$vzq)GX3OK!~Cj}bE?`G;u6 zisbJ?Gyx*o!O31#;#yIMF96wqI6$vzdtFO_eiGykXDJ>v?ptW!urMJaHjD?OjNdh9 zm)>Etid-I#iQvvvhWTm;?%YF5Ep+eh&aMWg;0-Wkc0cJHoNZurVe<_PV90A7gyB@P z0sq~m<}3K1X4J+*i%6ep0vY9*HVu}Z>(VCNVFK6v@@8>P&3`-AI`Ps3ETh;B*10o;(GM`f7Z*m*Lkz^~md9lI5n9hd z4^@?)kVo?pHz>dGA4QeD0XNd{^TA z6q7ls@Tr`-QdtE{pA4hyI&pm%?-WIKEOcseKJN9ZI?Kpvo(xb1Pvz-BPn=XLiLx*V zC__J+db5sn>^otby37o`#j8b6h^O+D+n90e*OxwDJ9VWbpP)p~mQQ1BpVUsJ1f)Uq zytR{|xG3qSf{=#JQj$o_4(8h|R6IM-Tg$Rm>&}ibtv*oL(e&h z5lweIV@w?Baun8eB0>Iy3z;OysiSLc2HtL%rMYjnfC9O3nYqz3Lzk}%m>CD7{;aO1 zI3aT2iK{6bHxL78Z=9=eoC@~@_3<45?gLWZU1mN}}=*&t`+Ilu*VAPB~R*pCW;yz@o z$W@*rv-3=UtSKBi(KLmo_fO0hE-Zr00z#T$cp4vP7+P~mcug~U-1Coy)(}&iE3uwb zFBgL={0t2<#ci5u-pBP+jFs_zDo*-Lfm|SVRbYB0T92NM!a?kWkGyegUAn?q81+>Q zON$j3Y4fcnCsvIz>i0a=uR()oQa;3Gb6i{zk!G6XQ@w3g`4es^^-7etpMkP9bTpbr zD97~Bt>BlqOq;2KRaZ4!)zk>H+N^HswQxWAI#=&_JIRyvTJ%!29@V4uh4pLeFZ>U4 C3jH|% literal 0 HcmV?d00001 diff --git a/tests/test_aweber_collection.py b/tests/test_aweber_collection.py new file mode 100644 index 0000000..51bac1e --- /dev/null +++ b/tests/test_aweber_collection.py @@ -0,0 +1,37 @@ +from unittest import TestCase +from aweber_api import AWeberAPI, AWeberCollection, AWeberEntry +from mock_adapter import MockAdapter + + +class TestAWeberCollection(TestCase): + + def setUp(self): + self.aweber = AWeberAPI('1', '2') + self.aweber.adapter = MockAdapter() + self.lists = self.aweber.load_from_url('/accounts/1/lists') + + def test_should_be_a_collection(self): + self.assertTrue(type(self.lists), AWeberCollection) + + def test_should_have_24_lists(self): + self.assertTrue(len(self.lists), 24) + + def test_should_be_able_get_each_via_offset(self): + for i in range(0, 23): + list = self.lists[i] + self.assertEqual(type(list), AWeberEntry) + self.assertEqual(list.type, 'list') + + def test_should_be_able_to_iterate_on_collection(self): + list_number = 0 + for list in self.lists: + self.assertEqual(type(list), AWeberEntry) + self.assertEqual(list.type, 'list') + list_number += 1 + self.assertEqual(list_number, 24) + + def test_should_support_get_by_id(self): + list = self.lists.get_by_id(303449) + self.assertEqual(type(list), AWeberEntry) + self.assertEqual(list.type, 'list') + self.assertEqual(list.id, 303449) diff --git a/tests/test_aweber_collection.pyc b/tests/test_aweber_collection.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b358b92761768d70ec4cd313ab63ce8f33aff46 GIT binary patch literal 2491 zcmcIm&5j#I5U%#v-XGY+BoK%Q2Tu5auo595P!zH3?g5EdtJw`vEJdwZPdhv8*yBw1 zgjh;W%ZuMSr@Ol9tFNm4$KN~K^5^nUTCFzlofS zJeh1t-j}1{222s5 zCJz>&UPVisd{|A-cJpi*Tpd2dGc8A3Z+2fq%kzK0@DCuIFi6A*cPAZ2P9HP7H1v~ zhU2<%L4#f`T}m>f9SB{VzE2I~(!=@`HW|A0r&Uwt_Qct2EplS+>4yC8K*79=K)G{V zd;+PZkzRuaAdoe;&=9XUy4yT&ExOa}g|qj*wn`dS=6Y=Oi})+^kD6;yME0Tr|Gdcw}g93^G$d~(Vne0FPR$45zxwKeD;9{F0mS}3)gbc6; zs^7o_QEeAsE`qNp^SFqzB7;T+yp@NEx&%XCY;O7uRn*|O04RBsS%7=dQy g_;q31>s0SoJ>|+`P#^C{ARn*-_1YYmJ7$pl3ux0CLI3~& literal 0 HcmV?d00001 diff --git a/tests/test_aweber_entry.py b/tests/test_aweber_entry.py new file mode 100644 index 0000000..dd7d6a6 --- /dev/null +++ b/tests/test_aweber_entry.py @@ -0,0 +1,63 @@ +from unittest import TestCase +from aweber_api import AWeberAPI, AWeberCollection, AWeberEntry +from mock_adapter import MockAdapter +import re + +class TestAWeberEntry(TestCase): + + def setUp(self): + self.aweber = AWeberAPI('1', '2') + self.aweber.adapter = MockAdapter() + self.list = self.aweber.load_from_url('/accounts/1/lists/303449') + + def test_should_be_an_entry(self): + self.assertEqual(type(self.list), AWeberEntry) + self.assertEqual(self.list.type, 'list') + + def test_should_have_id(self): + self.assertEqual(self.list.id, 303449) + + def test_should_have_other_properties(self): + self.assertEqual(self.list.name, 'default303449') + + def test_should_have_child_collections(self): + campaigns = self.list.campaigns + self.assertEqual(type(campaigns), AWeberCollection) + +class TestAWeberAccountEntry(TestCase): + + def setUp(self): + self.aweber = AWeberAPI('1', '2') + self.aweber.adapter = MockAdapter() + self.account = self.aweber.load_from_url('/accounts/1') + + def test_should_be_an_entry(self): + self.assertEqual(type(self.account), AWeberEntry) + self.assertEqual(self.account.type, 'account') + + def test_should_be_able_get_web_forms(self): + forms = self.account.get_web_forms() + +class TestAccountGetWebForms(TestAWeberAccountEntry): + + def setUp(self): + TestAWeberAccountEntry.setUp(self) + self.forms = self.account.get_web_forms() + + def test_should_be_a_list(self): + self.assertEqual(type(self.forms), list) + + def test_should_have_23_web_forms(self): + self.assertEqual(len(self.forms), 23) + + def test_each_should_be_entry(self): + for entry in self.forms: + self.assertEqual(type(entry), AWeberEntry) + self.assertEqual(entry.type, 'web_form') + + def test_each_should_have_correct_url(self): + url_regex = '/accounts\/1\/lists\/\d*/web_forms/\d*' + for entry in self.forms: + self.assertTrue(re.match(url_regex, entry.url)) + + diff --git a/tests/test_aweber_entry.pyc b/tests/test_aweber_entry.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a52c6ef8d351a54b1d661c463fbcac50811343dd GIT binary patch literal 4437 zcmcInTW=dh6h7-)V)qsb4HU|yEf)g<)22L7A=EUq2nnKUo2sf6wA$`YYLm6s-5En8 zrBC6R|G-b;Pw;}o1AhR%?~G$_lSoL&wz88mv$HdEzH`oZ&iwxOnbu!_{_$NRliw2l z-@;>mMU&z$kX?~1kZvFW`xV)(NLH0@RkE6NYm(KaTlep(vfGesNxDnEUz6Qs=`KrJ z7Zb=%AZbH>5jhZf)NM+-bU3;^9c@Y46w}hVt?B3~No#VyeF{hF|ASvUfaI3ZY#Hk| zVr$w}jx^D%KQxa`v3~Dcw=(T*DPraOlL zE?t^AMTmRf#$!K6V}!r}7pT>(5G@K-!bG7aX;p=U9gsXz@HbYuokyFQrEspK( zJRQegPq#NRIwho$RO9e8B|P)g_EjuLFe2N_$5|RZHc>qEV9)@TC`)kh1npnPiuL3CP;#7JW>z7sP#Xp&-pT2})%f01)Dx)5mnw@x@xrry! zHYLpn)-WEJ#p!k#I~>z3cRf=?qaq){h5E+6f=OjfsWeZz!SVOec(cJPpC9@yoOT}` z3h%AW{FEWOsf^(bM~+M4!6@!O8CtJ4*(&7v>eT9?;VQd$=IN$au-q}dlU^Sln@kzj z(wQe7dpc;7Oq8jkh(?Jb*TP5?4f1rHp&Qb{LsE5kp3Ma|Tw->3mF7Y#A!&tVVtI&0 zrCD#*n$>325v{E$->-Yh)C7^>js9qd+j#6%H2+EaAbA@5I9<(yIQAE2|~^q%{TaVYWb60`&}^*0U9In`t|l-lzu1k_|; zX;>A^tQ7@n36vLV=m>=vs|jyk(o0AcJXGqEm)K=IEH>gk#tsv|Jaa;74L%F*xg=gk{!mCvob*a%u5QMlwaix%w4@QNdjI9o z7*Gld((iAo8d`NtljU~j+P1$DZFjcQ zk2;4iS@t~hsU4X({k>qT7#ppd3!@x8h+WcCm%_cs*Vnup=q(f@QDL5#XW_dTnm3x4 zxebZDjHY^7k{1Q;TD++dvI(jU#Z_yu@Ccp1gIVDfHt(?^jm%D~(p(%Md>adYi082K z(z>fzZ!2Q7{dm}S)G354S|m>Hgz>1a_f)NLHN!i8G{Aj5np{(To$~=kwZiih%pDh@ ciU!q}zJC3Rq-1%VmEcma5}dBAURXW*FRrDl?f?J) literal 0 HcmV?d00001