comparison roundup/rest.py @ 5740:abbea26a11df

Clean up pylint reports of unused modules, duplicate imports, indent issues, relative import, extra ';', unneeded pass. Also added support for TypeError as I restructured accept header parsing a bit to remove uneeded "version" variable assignments
author John Rouillard <rouilj@ieee.org>
date Tue, 28 May 2019 21:03:41 -0400
parents 0e6ed3d72f92
children d4de45cde106
comparison
equal deleted inserted replaced
5739:e225f403cc35 5740:abbea26a11df
11 from urllib.parse import urlparse 11 from urllib.parse import urlparse
12 except ImportError: 12 except ImportError:
13 from urlparse import urlparse 13 from urlparse import urlparse
14 import os 14 import os
15 import json 15 import json
16 import pprint
17 import sys 16 import sys
18 import time 17 import time
19 import traceback 18 import traceback
20 import re 19 import re
21 20
22 try: 21 try:
23 # if dicttoxml installed in roundup directory, use it 22 # if dicttoxml installed in roundup directory, use it
24 from .dicttoxml import dicttoxml 23 from roundup.dicttoxml import dicttoxml
25 except ImportError: 24 except ImportError:
26 try: 25 try:
27 # else look in sys.path 26 # else look in sys.path
28 from dicttoxml import dicttoxml 27 from dicttoxml import dicttoxml
29 except ImportError: 28 except ImportError:
55 import roundup.anypy.random_ as random_ 54 import roundup.anypy.random_ as random_
56 if not random_.is_weak: 55 if not random_.is_weak:
57 logger.debug("Importing good random generator") 56 logger.debug("Importing good random generator")
58 else: 57 else:
59 logger.warning("**SystemRandom not available. Using poor random generator") 58 logger.warning("**SystemRandom not available. Using poor random generator")
60
61 import time
62 59
63 chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 60 chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
64 61
65 def _data_decorator(func): 62 def _data_decorator(func):
66 """Wrap the returned data into an object.""" 63 """Wrap the returned data into an object."""
181 178
182 def obtain_etags(headers,input): 179 def obtain_etags(headers,input):
183 '''Get ETags value from headers or payload data''' 180 '''Get ETags value from headers or payload data'''
184 etags = [] 181 etags = []
185 if '@etag' in input: 182 if '@etag' in input:
186 etags.append(input['@etag'].value); 183 etags.append(input['@etag'].value)
187 etags.append(headers.get("If-Match", None)) 184 etags.append(headers.get("If-Match", None))
188 return etags 185 return etags
189 186
190 def parse_accept_header(accept): 187 def parse_accept_header(accept):
191 """ 188 """
226 if '-v' in vnd: 223 if '-v' in vnd:
227 vnd, sep, rest = vnd.rpartition('-v') 224 vnd, sep, rest = vnd.rpartition('-v')
228 if len(rest): 225 if len(rest):
229 # add the version as a media param 226 # add the version as a media param
230 try: 227 try:
231 version = media_params.append(('version', 228 media_params.append(('version',
232 rest)) 229 rest))
233 except ValueError: 230 except ValueError:
234 version = 1.0 # could not be parsed 231 pass # return no version value; use rest default
235 # add the vendor code as a media param 232 # add the vendor code as a media param
236 media_params.append(('vendor', vnd)) 233 media_params.append(('vendor', vnd))
237 # and re-write media_type to something like application/json so 234 # and re-write media_type to something like application/json so
238 # it can be used usefully when looking up emitters 235 # it can be used usefully when looking up emitters
239 media_type = '{}/{}'.format(typ, extra) 236 media_type = '{}/{}'.format(typ, extra)
538 if self.api_version == None: 535 if self.api_version == None:
539 version = self.__default_api_version 536 version = self.__default_api_version
540 else: 537 else:
541 version = self.api_version 538 version = self.api_version
542 539
540 # version never gets used since we only
541 # support version 1 at this time. Set it as
542 # placeholder for later use.
543 result = {} 543 result = {}
544 try: 544 try:
545 # pn = propname 545 # pn = propname
546 for pn in sorted(props): 546 for pn in sorted(props):
547 prop = props[pn] 547 prop = props[pn]
779 k, v = item_id.split('=', 1) 779 k, v = item_id.split('=', 1)
780 if k != keyprop: 780 if k != keyprop:
781 raise UsageError ("Field %s is not key property"%k) 781 raise UsageError ("Field %s is not key property"%k)
782 except ValueError: 782 except ValueError:
783 v = item_id 783 v = item_id
784 pass
785 if not self.db.security.hasPermission( 784 if not self.db.security.hasPermission(
786 'View', uid, class_name, itemid=item_id, property=keyprop 785 'View', uid, class_name, itemid=item_id, property=keyprop
787 ): 786 ):
788 raise Unauthorised( 787 raise Unauthorised(
789 'Permission to view %s%s.%s denied' 788 'Permission to view %s%s.%s denied'
1171 dict: 1170 dict:
1172 status (string): 'ok' 1171 status (string): 'ok'
1173 count (int): number of deleted objects 1172 count (int): number of deleted objects
1174 """ 1173 """
1175 raise Unauthorised('Deletion of a whole class disabled') 1174 raise Unauthorised('Deletion of a whole class disabled')
1175 ''' Hide original code to silence pylint.
1176 Leave it here in case we need to re-enable.
1177 FIXME: Delete in December 2020 if not used.
1176 if class_name not in self.db.classes: 1178 if class_name not in self.db.classes:
1177 raise NotFound('Class %s not found' % class_name) 1179 raise NotFound('Class %s not found' % class_name)
1178 if not self.db.security.hasPermission( 1180 if not self.db.security.hasPermission(
1179 'Retire', self.db.getuid(), class_name 1181 'Retire', self.db.getuid(), class_name
1180 ): 1182 ):
1198 'status': 'ok', 1200 'status': 'ok',
1199 'count': count 1201 'count': count
1200 } 1202 }
1201 1203
1202 return 200, result 1204 return 200, result
1205 '''
1203 1206
1204 @Routing.route("/data/<:class_name>/<:item_id>", 'DELETE') 1207 @Routing.route("/data/<:class_name>/<:item_id>", 'DELETE')
1205 @_data_decorator 1208 @_data_decorator
1206 def delete_element(self, class_name, item_id, input): 1209 def delete_element(self, class_name, item_id, input):
1207 """DELETE (retire) an object in a class 1210 """DELETE (retire) an object in a class
1268 "for class %s."%(attr_name, class_name)) 1271 "for class %s."%(attr_name, class_name))
1269 else: 1272 else:
1270 raise UsageError("Attribute '%s' not valid for class %s."%( 1273 raise UsageError("Attribute '%s' not valid for class %s."%(
1271 attr_name, class_name)) 1274 attr_name, class_name))
1272 if attr_name in class_obj.get_required_props(): 1275 if attr_name in class_obj.get_required_props():
1273 raise UsageError("Attribute '%s' is required by class %s and can not be deleted."%( 1276 raise UsageError("Attribute '%s' is required by class %s and can not be deleted."%(
1274 attr_name, class_name)) 1277 attr_name, class_name))
1275 props = {} 1278 props = {}
1276 prop_obj = class_obj.get(item_id, attr_name) 1279 prop_obj = class_obj.get(item_id, attr_name)
1277 if isinstance(prop_obj, list): 1280 if isinstance(prop_obj, list):
1278 props[attr_name] = [] 1281 props[attr_name] = []
1279 else: 1282 else:
1744 # use default if version = None 1747 # use default if version = None
1745 try: 1748 try:
1746 self.api_version = int(part[1]['version']) 1749 self.api_version = int(part[1]['version'])
1747 except KeyError: 1750 except KeyError:
1748 self.api_version = None 1751 self.api_version = None
1749 except ValueError: 1752 except (ValueError, TypeError):
1753 # TypeError if int(None)
1750 msg=( "Unrecognized version: %s. " 1754 msg=( "Unrecognized version: %s. "
1751 "See /rest without specifying version " 1755 "See /rest without specifying version "
1752 "for supported versions."%( 1756 "for supported versions."%(
1753 part[1]['version'])) 1757 part[1]['version']))
1754 output = self.error_obj(400, msg) 1758 output = self.error_obj(400, msg)
1828 # version? This may be a good thing to require. Note that: 1832 # version? This may be a good thing to require. Note that:
1829 # Accept: application/json; version=1 may not be legal but.... 1833 # Accept: application/json; version=1 may not be legal but....
1830 # Use default if not specified for now. 1834 # Use default if not specified for now.
1831 self.api_version = self.__default_api_version 1835 self.api_version = self.__default_api_version
1832 elif self.api_version not in self.__supported_api_versions: 1836 elif self.api_version not in self.__supported_api_versions:
1833 raise UsageError(msg%self.api_version) 1837 raise UsageError(msg%self.api_version)
1834 1838
1835 # sadly del doesn't work on FieldStorage which can be the type of 1839 # sadly del doesn't work on FieldStorage which can be the type of
1836 # input. So we have to ignore keys starting with @ at other 1840 # input. So we have to ignore keys starting with @ at other
1837 # places in the code. 1841 # places in the code.
1838 # else: 1842 # else:

Roundup Issue Tracker: http://roundup-tracker.org/