11import json
22import requests
33
4+ from errors import *
5+
46api_key = ''
57api_base = 'https://www.optimizelyapis.com/experiment/v1/'
68
79
8- class APIResource (dict ):
10+ class APIResource (object ):
911 endpoint = ''
1012
11- def __init__ (self , * arg , ** kw ):
12- super (APIResource , self ).__init__ (* arg , ** kw )
13+ def __init__ (self , params ):
14+ if type (params ) == dict :
15+ for (k , v ) in params .iteritems ():
16+ self .__setattr__ (k , v )
17+ else :
18+ raise ValueError ('%s can only be initiated with a dict.' % self .__class__ .__name__ )
19+
20+ def __repr__ (self ):
21+ if hasattr (self , 'id' ):
22+ return '<%s object with ID: %s>' % (self .__class__ .__name__ , self .id )
23+ else :
24+ return '<%s object without ID>' % self .__class__ .__name__
25+
1326
1427 @classmethod
15- def from_json (cls , r ):
28+ def from_api_response (cls , r ):
1629 if r .status_code in [200 , 201 , 202 ]:
1730 if type (r .json ()) == list :
1831 return [cls (resource ) for resource in r .json ()]
@@ -21,41 +34,41 @@ def from_json(cls, r):
2134 elif r .status_code == 204 :
2235 return
2336 elif r .status_code == 400 :
24- raise BadRequestError (r .text )
37+ raise BadRequestError (r .json (). get ( 'message' ) )
2538 elif r .status_code == 401 :
26- raise UnauthorizedError (r .text )
39+ raise UnauthorizedError (r .json (). get ( 'message' ) )
2740 elif r .status_code == 403 :
28- raise ForbiddenError (r .text )
41+ raise ForbiddenError (r .json (). get ( 'message' ) )
2942 elif r .status_code == 404 :
30- raise NotFoundError (r .text )
43+ raise NotFoundError (r .json (). get ( 'message' ) )
3144 elif r .status_code == 429 :
32- raise TooManyRequestsError (r .text )
45+ raise TooManyRequestsError (r .json (). get ( 'message' ) )
3346 elif r .status_code == 503 :
34- raise ServiceUnavailableError (r .text )
47+ raise ServiceUnavailableError (r .json (). get ( 'message' ) )
3548 else :
3649 raise OptimizelyError (r .text )
3750
3851 @classmethod
3952 def list (cls ):
40- return cls .from_json (requests .get (api_base + cls .endpoint , headers = {'Token' : api_key }))
53+ return cls .from_api_response (requests .get (api_base + cls .endpoint , headers = {'Token' : api_key }))
4154
4255 @classmethod
43- def read (cls , pid ):
44- return cls .from_json (requests .get (api_base + cls .endpoint + str (pid ), headers = {'Token' : api_key }))
56+ def get (cls , pid ):
57+ return cls .from_api_response (requests .get (api_base + cls .endpoint + str (pid ), headers = {'Token' : api_key }))
4558
4659 @classmethod
4760 def create (cls , data ):
48- return cls .from_json (requests .post (api_base + cls .endpoint , data = json .dumps (data ),
49- headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
61+ return cls .from_api_response (requests .post (api_base + cls .endpoint , data = json .dumps (data ),
62+ headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
5063
5164 @classmethod
52- def put (cls , rid , data ):
53- return cls .from_json (requests .put (api_base + cls .endpoint + str (rid ), data = json .dumps (data ),
54- headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
65+ def update (cls , rid , data ):
66+ return cls .from_api_response (requests .put (api_base + cls .endpoint + str (rid ), data = json .dumps (data ),
67+ headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
5568
5669 @classmethod
5770 def delete (cls , pid ):
58- return cls .from_json (requests .delete (api_base + cls .endpoint + str (pid ), headers = {'Token' : api_key }))
71+ return cls .from_api_response (requests .delete (api_base + cls .endpoint + str (pid ), headers = {'Token' : api_key }))
5972
6073
6174class Project (APIResource ):
@@ -66,16 +79,16 @@ def delete(cls, pid):
6679 raise NotImplementedError ('Projects may not be deleted through the API.' )
6780
6881 def experiments (self ):
69- if not self . get ( 'id' ):
82+ if not hasattr ( self , 'id' ):
7083 raise InvalidIDError ('Project is missing its ID.' )
71- return Experiment .from_json (requests .get (api_base + self .endpoint + str (self [ 'id' ] ) + '/experiments' ,
72- headers = {'Token' : api_key }))
84+ return Experiment .from_api_response (requests .get (api_base + self .endpoint + str (self . id ) + '/experiments' ,
85+ headers = {'Token' : api_key }))
7386
7487 def audiences (self ):
75- if not self . get ( 'id' ):
88+ if not hasattr ( self , 'id' ):
7689 raise InvalidIDError ('Project is missing its ID.' )
77- return Audience .from_json (requests .get (api_base + self .endpoint + str (self [ 'id' ] ) + '/audiences' ,
78- headers = {'Token' : api_key }))
90+ return Audience .from_api_response (requests .get (api_base + self .endpoint + str (self . id ) + '/audiences' ,
91+ headers = {'Token' : api_key }))
7992
8093
8194class Experiment (APIResource ):
@@ -88,44 +101,46 @@ def list(cls):
88101
89102 @classmethod
90103 def create (cls , data ):
91- return cls .from_json (requests .post (api_base + 'projects/' + str (data ['project_id' ]) + '/' + cls . endpoint ,
92- data = json .dumps (data ),
93- headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
104+ return cls .from_api_response (requests .post (api_base + 'projects/' + str (data ['project_id' ]) + '/' +
105+ cls . endpoint , data = json .dumps (data ),
106+ headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
94107
95108 def results (self ):
96- return Result .from_json (requests .get (api_base + self .endpoint + str (self [ 'id' ] ) + '/results' ,
97- headers = {'Token' : api_key }))
109+ return Result .from_api_response (requests .get (api_base + self .endpoint + str (self . id ) + '/results' ,
110+ headers = {'Token' : api_key }))
98111
99112 def variations (self ):
100- return Variation .from_json (requests .get (api_base + self .endpoint + str (self [ 'id' ] ) + '/variations' ,
101- headers = {'Token' : api_key }))
113+ return Variation .from_api_response (requests .get (api_base + self .endpoint + str (self . id ) + '/variations' ,
114+ headers = {'Token' : api_key }))
102115
103116 def add_goal (self , gid ):
104- goal = Goal .read (gid )
105- return Goal .from_json (Goal .put (goal .get ('id' ),
106- {'experiment_ids' : goal .get ('experiment_ids' ).append (self ['id' ])}))
117+ goal = Goal .get (gid )
118+ return Goal .from_api_response (Goal .update (goal .id , {'experiment_ids' : goal .experiment_ids .append (self .id )}))
107119
108120 def remove_goal (self , gid ):
109- goal = Goal .read (gid )
110- experiment_ids = list (set (goal .get ( ' experiment_ids' )) .remove (self [ 'id' ] ))
111- return Goal .from_json (Goal .put (goal .get ( 'id' ) , {'experiment_ids' : experiment_ids }))
121+ goal = Goal .get (gid )
122+ experiment_ids = list (set (goal .experiment_ids ) .remove (self . id ))
123+ return Goal .from_api_response (Goal .update (goal .id , {'experiment_ids' : experiment_ids }))
112124
113125
114126class Result (APIResource ):
127+ def __repr__ (self ):
128+ return '<%s object>' % self .__class__ .__name__
129+
115130 @classmethod
116131 def list (cls ):
117132 raise NotImplementedError ('There is no method to list all results. Try using Experiment.results() instead.' )
118133
119134 @classmethod
120- def read (cls , pid ):
135+ def get (cls , pid ):
121136 raise NotImplementedError ('There is no method to get a single result.' )
122137
123138 @classmethod
124139 def create (cls , data ):
125140 return NotImplementedError ('There is no method to create a result.' )
126141
127142 @classmethod
128- def put (cls , pid , data ):
143+ def update (cls , pid , data ):
129144 return NotImplementedError ('There is no method to update a result.' )
130145
131146 @classmethod
@@ -142,9 +157,9 @@ def list(cls):
142157
143158 @classmethod
144159 def create (cls , data ):
145- return cls .from_json (requests .post (api_base + 'experiments/' + str (data ['experiment_id' ]) + '/' + cls . endpoint ,
146- data = json .dumps (data ),
147- headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
160+ return cls .from_api_response (requests .post (api_base + 'experiments/' + str (data ['experiment_id' ]) + '/' +
161+ cls . endpoint , data = json .dumps (data ),
162+ headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
148163
149164
150165class Goal (APIResource ):
@@ -156,9 +171,9 @@ def list(cls):
156171
157172 @classmethod
158173 def create (cls , data ):
159- return cls .from_json (requests .post (api_base + 'projects/' + str (data ['project_id' ]) + '/' + cls . endpoint ,
160- data = json .dumps (data ),
161- headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
174+ return cls .from_api_response (requests .post (api_base + 'projects/' + str (data ['project_id' ]) + '/' +
175+ cls . endpoint , data = json .dumps (data ),
176+ headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
162177
163178
164179class Audience (APIResource ):
@@ -170,47 +185,6 @@ def list(cls):
170185
171186 @classmethod
172187 def create (cls , data ):
173- return cls .from_json (requests .post (api_base + 'projects/' + str (data ['project_id' ]) + '/' + cls .endpoint ,
174- data = json .dumps (data ),
175- headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
176-
177-
178- class OptimizelyError (Exception ):
179- """ General exception for all Optimizely Experiments API related issues."""
180- pass
181-
182-
183- class BadRequestError (OptimizelyError ):
184- """ Exception for when request was not sent in valid JSON."""
185- pass
186-
187-
188- class UnauthorizedError (OptimizelyError ):
189- """ Exception for when API token is missing or included in the body rather than the header."""
190- pass
191-
192-
193- class ForbiddenError (OptimizelyError ):
194- """ Exception for when API token is provided but it is invalid or revoked."""
195- pass
196-
197-
198- class NotFoundError (OptimizelyError ):
199- """ Exception for when the id used in request is inaccurate or token user doesn't have permission to
200- view/edit it."""
201- pass
202-
203-
204- class TooManyRequestsError (OptimizelyError ):
205- """ Exception for when a rate limit for the API is hit."""
206- pass
207-
208-
209- class ServiceUnavailableError (OptimizelyError ):
210- """ Exception for when the API is overloaded or down for maintenance."""
211- pass
212-
213-
214- class InvalidIDError (OptimizelyError ):
215- """ Exception for when object is missing its ID."""
216- pass
188+ return cls .from_api_response (requests .post (api_base + 'projects/' + str (data ['project_id' ]) + '/' +
189+ cls .endpoint , data = json .dumps (data ),
190+ headers = {'Token' : api_key , 'Content-Type' : 'application/json' }))
0 commit comments