Mercurial > p > roundup > code
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: |
