Skip to content

Commit 367e78f

Browse files
committed
Added docstring
committer: Ralf Schlatterbeck <[email protected]>
1 parent 881b0cf commit 367e78f

File tree

1 file changed

+145
-19
lines changed

1 file changed

+145
-19
lines changed

roundup/rest.py

Lines changed: 145 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818

1919

2020
class RestfulInstance(object):
21-
"""Dummy Handler for REST
22-
"""
21+
"""The RestfulInstance performs REST request from the client"""
2322

2423
def __init__(self, client, db):
2524
self.client = client # it might be unnecessary to receive the client
@@ -31,6 +30,18 @@ def __init__(self, client, db):
3130
self.base_path = '%s://%s/%s/rest/' % (protocol, host, tracker)
3231

3332
def props_from_args(self, cl, args, itemid=None):
33+
"""Construct a list of properties from the given arguments,
34+
and return them after validation.
35+
36+
Args:
37+
cl (string): class object of the resource
38+
args (list): the submitted form of the user
39+
itemid (string, optional): itemid of the object
40+
41+
Returns:
42+
dict: dictionary of validated properties
43+
44+
"""
3445
class_props = cl.properties.keys()
3546
props = {}
3647
# props = dict.fromkeys(class_props, None)
@@ -63,6 +74,8 @@ def props_from_args(self, cl, args, itemid=None):
6374

6475
@staticmethod
6576
def error_obj(status, msg, source=None):
77+
"""Wrap the error data into an object. This function is temporally and
78+
will be changed to a decorator later."""
6679
result = {
6780
'error': {
6881
'status': status,
@@ -76,12 +89,29 @@ def error_obj(status, msg, source=None):
7689

7790
@staticmethod
7891
def data_obj(data):
92+
"""Wrap the returned data into an object. This function is temporally
93+
and will be changed to a decorator later."""
7994
result = {
8095
'data': data
8196
}
8297
return result
8398

8499
def get_collection(self, class_name, input):
100+
"""GET resource from class URI.
101+
102+
This function returns only items have View permission
103+
class_name should be valid already
104+
105+
Args:
106+
class_name (string): class name of the resource (Ex: issue, msg)
107+
input (list): the submitted form of the user
108+
109+
Returns:
110+
int: http status code 200 (OK)
111+
list: list of reference item in the class
112+
id: id of the object
113+
link: path to the object
114+
"""
85115
if not self.db.security.hasPermission(
86116
'View', self.db.getuid(), class_name
87117
):
@@ -100,6 +130,24 @@ def get_collection(self, class_name, input):
100130
return 200, result
101131

102132
def get_element(self, class_name, item_id, input):
133+
"""GET resource from object URI.
134+
135+
This function returns only properties have View permission
136+
class_name and item_id should be valid already
137+
138+
Args:
139+
class_name (string): class name of the resource (Ex: issue, msg)
140+
item_id (string): id of the resource (Ex: 12, 15)
141+
input (list): the submitted form of the user
142+
143+
Returns:
144+
int: http status code 200 (OK)
145+
dict: a dictionary represents the object
146+
id: id of the object
147+
type: class name of the object
148+
link: link to the object
149+
attributes: a dictionary represent the attributes of the object
150+
"""
103151
if not self.db.security.hasPermission(
104152
'View', self.db.getuid(), class_name, itemid=item_id
105153
):
@@ -127,6 +175,21 @@ def get_element(self, class_name, item_id, input):
127175
return 200, result
128176

129177
def post_collection(self, class_name, input):
178+
"""POST a new object to a class
179+
180+
If the item is successfully created, the "Location" header will also
181+
contain the link to the created object
182+
183+
Args:
184+
class_name (string): class name of the resource (Ex: issue, msg)
185+
input (list): the submitted form of the user
186+
187+
Returns:
188+
int: http status code 201 (Created)
189+
dict: a reference item to the created object
190+
id: id of the object
191+
link: path to the object
192+
"""
130193
if not self.db.security.hasPermission(
131194
'Create', self.db.getuid(), class_name
132195
):
@@ -171,12 +234,32 @@ def post_collection(self, class_name, input):
171234
return 201, result
172235

173236
def post_element(self, class_name, item_id, input):
237+
"""POST to an object of a class is not allowed"""
174238
raise Reject('POST to an item is not allowed')
175239

176240
def put_collection(self, class_name, input):
241+
"""PUT a class is not allowed"""
177242
raise Reject('PUT a class is not allowed')
178243

179244
def put_element(self, class_name, item_id, input):
245+
"""PUT a new content to an object
246+
247+
Replace the content of the existing object
248+
249+
Args:
250+
class_name (string): class name of the resource (Ex: issue, msg)
251+
item_id (string): id of the resource (Ex: 12, 15)
252+
input (list): the submitted form of the user
253+
254+
Returns:
255+
int: http status code 200 (OK)
256+
dict: a dictionary represents the modified object
257+
id: id of the object
258+
type: class name of the object
259+
link: link to the object
260+
attributes: a dictionary represent only changed attributes of
261+
the object
262+
"""
180263
class_obj = self.db.getclass(class_name)
181264

182265
props = self.props_from_args(class_obj, input.value, item_id)
@@ -203,6 +286,18 @@ def put_element(self, class_name, item_id, input):
203286
return 200, result
204287

205288
def delete_collection(self, class_name, input):
289+
"""DELETE all objects in a class
290+
291+
Args:
292+
class_name (string): class name of the resource (Ex: issue, msg)
293+
input (list): the submitted form of the user
294+
295+
Returns:
296+
int: http status code 200 (OK)
297+
dict:
298+
status (string): 'ok'
299+
count (int): number of deleted objects
300+
"""
206301
if not self.db.security.hasPermission(
207302
'Delete', self.db.getuid(), class_name
208303
):
@@ -230,6 +325,18 @@ def delete_collection(self, class_name, input):
230325
return 200, result
231326

232327
def delete_element(self, class_name, item_id, input):
328+
"""DELETE an object in a class
329+
330+
Args:
331+
class_name (string): class name of the resource (Ex: issue, msg)
332+
item_id (string): id of the resource (Ex: 12, 15)
333+
input (list): the submitted form of the user
334+
335+
Returns:
336+
int: http status code 200 (OK)
337+
dict:
338+
status (string): 'ok'
339+
"""
233340
if not self.db.security.hasPermission(
234341
'Delete', self.db.getuid(), class_name, itemid=item_id
235342
):
@@ -246,6 +353,7 @@ def delete_element(self, class_name, item_id, input):
246353
return 200, result
247354

248355
def patch_collection(self, class_name, input):
356+
"""PATCH a class is not allowed"""
249357
raise Reject('PATCH a class is not allowed')
250358

251359
def patch_element(self, class_name, item_id, input):
@@ -290,9 +398,21 @@ def patch_element(self, class_name, item_id, input):
290398
return 200, result
291399

292400
def options_collection(self, class_name, input):
401+
"""OPTION return the HTTP Header for the class uri
402+
403+
Returns:
404+
int: http status code 204 (No content)
405+
body (string): an empty string
406+
"""
293407
return 204, ""
294408

295409
def options_element(self, class_name, item_id, input):
410+
"""OPTION return the HTTP Header for the object uri
411+
412+
Returns:
413+
int: http status code 204 (No content)
414+
body (string): an empty string
415+
"""
296416
self.client.setHeader(
297417
"Accept-Patch",
298418
"application/x-www-form-urlencoded, "
@@ -301,6 +421,7 @@ def options_element(self, class_name, item_id, input):
301421
return 204, ""
302422

303423
def dispatch(self, method, uri, input):
424+
"""format and process the request"""
304425
# PATH is split to multiple pieces
305426
# 0 - rest
306427
# 1 - resource
@@ -327,40 +448,43 @@ def dispatch(self, method, uri, input):
327448
except KeyError:
328449
pretty_output = False
329450

451+
# add access-control-allow-* to support CORS
330452
self.client.setHeader("Access-Control-Allow-Origin", "*")
331453
self.client.setHeader(
332454
"Access-Control-Allow-Headers",
333455
"Content-Type, Authorization, X-HTTP-Method-Override"
334456
)
457+
if resource_uri in self.db.classes:
458+
self.client.setHeader(
459+
"Allow",
460+
"HEAD, OPTIONS, GET, POST, DELETE"
461+
)
462+
self.client.setHeader(
463+
"Access-Control-Allow-Methods",
464+
"HEAD, OPTIONS, GET, POST, DELETE"
465+
)
466+
else:
467+
self.client.setHeader(
468+
"Allow",
469+
"HEAD, OPTIONS, GET, PUT, DELETE, PATCH"
470+
)
471+
self.client.setHeader(
472+
"Access-Control-Allow-Methods",
473+
"HEAD, OPTIONS, GET, PUT, DELETE, PATCH"
474+
)
335475

476+
# Call the appropriate method
336477
output = None
337478
try:
338479
if resource_uri in self.db.classes:
339-
self.client.setHeader(
340-
"Allow",
341-
"HEAD, OPTIONS, GET, POST, DELETE"
342-
)
343-
self.client.setHeader(
344-
"Access-Control-Allow-Methods",
345-
"HEAD, OPTIONS, GET, POST, DELETE"
346-
)
347480
response_code, output = getattr(
348481
self, "%s_collection" % method.lower()
349482
)(resource_uri, input)
350483
else:
351484
class_name, item_id = hyperdb.splitDesignator(resource_uri)
352-
self.client.setHeader(
353-
"Allow",
354-
"HEAD, OPTIONS, GET, PUT, DELETE, PATCH"
355-
)
356-
self.client.setHeader(
357-
"Access-Control-Allow-Methods",
358-
"HEAD, OPTIONS, GET, PUT, DELETE, PATCH"
359-
)
360485
response_code, output = getattr(
361486
self, "%s_element" % method.lower()
362487
)(class_name, item_id, input)
363-
364488
output = RestfulInstance.data_obj(output)
365489
self.client.response_code = response_code
366490
except IndexError, msg:
@@ -408,6 +532,8 @@ def dispatch(self, method, uri, input):
408532

409533

410534
class RoundupJSONEncoder(json.JSONEncoder):
535+
"""RoundupJSONEncoder overrides the default JSONEncoder to handle all
536+
types of the object without returning any error"""
411537
def default(self, obj):
412538
try:
413539
result = json.JSONEncoder.default(self, obj)

0 commit comments

Comments
 (0)