Skip to content
This repository was archived by the owner on Sep 28, 2023. It is now read-only.

Commit 5ee4410

Browse files
author
Andy Harris
committed
add support for all API objects
1 parent 32f830a commit 5ee4410

1 file changed

Lines changed: 129 additions & 25 deletions

File tree

optimizely/__init__.py

Lines changed: 129 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@
55
api_base = 'https://www.optimizelyapis.com/experiment/v1/'
66

77

8-
class APIResource(object):
8+
class APIResource(dict):
99
endpoint = ''
1010

11-
def __init__(self):
12-
raise NotImplementedError(self.__class__.__name__ +
13-
' contains only class methods and should not be instantiated.')
11+
def __init__(self, *arg, **kw):
12+
super(APIResource, self).__init__(*arg, **kw)
1413

15-
@staticmethod
16-
def _parse_response(r):
17-
if r.status_code in [200, 201, 202, 204]:
18-
return r.json()
14+
@classmethod
15+
def from_json(cls, r):
16+
if r.status_code in [200, 201, 202]:
17+
if type(r.json()) == list:
18+
return [cls(resource) for resource in r.json()]
19+
else:
20+
return cls(r.json())
21+
elif r.status_code == 204:
22+
return
1923
elif r.status_code == 400:
2024
raise BadRequestError(r.text)
2125
elif r.status_code == 401:
@@ -32,48 +36,143 @@ def _parse_response(r):
3236
raise OptimizelyError(r.text)
3337

3438
@classmethod
35-
def all(cls):
36-
return cls._parse_response(requests.get(api_base + cls.endpoint, headers={'Token': api_key}))
39+
def list(cls):
40+
return cls.from_json(requests.get(api_base + cls.endpoint, headers={'Token': api_key}))
3741

3842
@classmethod
39-
def get(cls, pid):
40-
return cls._parse_response(requests.get(api_base + cls.endpoint + str(pid), headers={'Token': api_key}))
43+
def read(cls, pid):
44+
return cls.from_json(requests.get(api_base + cls.endpoint + str(pid), headers={'Token': api_key}))
4145

4246
@classmethod
4347
def create(cls, data):
44-
return cls._parse_response(requests.post(api_base + cls.endpoint, data=json.dumps(data),
45-
headers={'Token': api_key, 'Content-Type': 'application/json'}))
48+
return cls.from_json(requests.post(api_base + cls.endpoint, data=json.dumps(data),
49+
headers={'Token': api_key, 'Content-Type': 'application/json'}))
4650

4751
@classmethod
48-
def update(cls, pid, data):
49-
return cls._parse_response(requests.put(api_base + cls.endpoint + str(pid), data=json.dumps(data),
50-
headers={'Token': api_key, 'Content-Type': 'application/json'}))
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'}))
5155

5256
@classmethod
5357
def delete(cls, pid):
54-
return cls._parse_response(requests.delete(api_base + cls.endpoint + str(pid), headers={'Token': api_key}))
58+
return cls.from_json(requests.delete(api_base + cls.endpoint + str(pid), headers={'Token': api_key}))
5559

5660

5761
class Project(APIResource):
5862
endpoint = 'projects/'
5963

64+
@classmethod
65+
def delete(cls, pid):
66+
raise NotImplementedError('Projects may not be deleted through the API.')
67+
68+
def experiments(self):
69+
if not self.get('id'):
70+
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}))
73+
74+
def audiences(self):
75+
if not self.get('id'):
76+
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}))
79+
6080

6181
class Experiment(APIResource):
6282
endpoint = 'experiments/'
6383

6484
@classmethod
65-
def all(cls):
66-
raise NotImplementedError('There is no method to get all experiments. Try using get_from_project() instead.')
85+
def list(cls):
86+
raise NotImplementedError('There is no method to list all experiments. '
87+
'Try using Project.experiments() instead.')
6788

6889
@classmethod
69-
def get_from_project(cls, pid):
70-
return cls._parse_response(requests.get(api_base + Project.endpoint + str(pid) + '/' + cls.endpoint,
90+
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'}))
94+
95+
def results(self):
96+
return Result.from_json(requests.get(api_base + self.endpoint + str(self['id']) + '/results',
97+
headers={'Token': api_key}))
98+
99+
def variations(self):
100+
return Variation.from_json(requests.get(api_base + self.endpoint + str(self['id']) + '/variations',
71101
headers={'Token': api_key}))
72102

103+
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'])}))
107+
108+
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}))
112+
113+
114+
class Result(APIResource):
73115
@classmethod
74-
def get_results(cls, eid):
75-
return cls._parse_response(requests.get(api_base + cls.endpoint + str(eid) + '/results',
76-
headers={'Token': api_key}))
116+
def list(cls):
117+
raise NotImplementedError('There is no method to list all results. Try using Experiment.results() instead.')
118+
119+
@classmethod
120+
def read(cls, pid):
121+
raise NotImplementedError('There is no method to get a single result.')
122+
123+
@classmethod
124+
def create(cls, data):
125+
return NotImplementedError('There is no method to create a result.')
126+
127+
@classmethod
128+
def put(cls, pid, data):
129+
return NotImplementedError('There is no method to update a result.')
130+
131+
@classmethod
132+
def delete(cls, pid):
133+
return NotImplementedError('There is no method to delete a result.')
134+
135+
136+
class Variation(APIResource):
137+
endpoint = 'variations/'
138+
139+
@classmethod
140+
def list(cls):
141+
raise NotImplementedError('There is no method to list all results. Try using Experiment.variations() instead.')
142+
143+
@classmethod
144+
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'}))
148+
149+
150+
class Goal(APIResource):
151+
endpoint = 'goals/'
152+
153+
@classmethod
154+
def list(cls):
155+
raise NotImplementedError('There is no method to list all goals.')
156+
157+
@classmethod
158+
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'}))
162+
163+
164+
class Audience(APIResource):
165+
endpoint = 'audiences/'
166+
167+
@classmethod
168+
def list(cls):
169+
raise NotImplementedError('There is no method to list all results. Try using Experiment.variations() instead.')
170+
171+
@classmethod
172+
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'}))
77176

78177

79178
class OptimizelyError(Exception):
@@ -109,4 +208,9 @@ class TooManyRequestsError(OptimizelyError):
109208

110209
class ServiceUnavailableError(OptimizelyError):
111210
""" 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."""
112216
pass

0 commit comments

Comments
 (0)