def _getObject( self, t, key, request, response, depth ): queue = [ ( t, depth, 0 ) ] while len(queue) > 0: t, depth, ignore = queue.pop(0) reduce_depth_by = 1 if ignore == 0: if 'get' in t.handlers: reduce_depth_by = t.handlers['get'].depth + 1 t.handlers['get']( self, key, response, request, reduce_depth_by if depth is None else min( depth, reduce_depth_by ) ) elif schema.is_a( t.schema_type, schema.Container ): response[t.schema_type][key] = request[t.schema_type][key] elif schema.is_a( t.schema_type, schema.Object ): raise Error( 405, 'Object at "%s" does not have a get() method associated' % t.schema_type._url.replace( '%s', '*' ) ) if depth is not None: depth = depth - reduce_depth_by ignore = reduce_depth_by if t.children and depth is None or depth >= 0: if schema.is_a( t.schema_type, schema.Container ): queue.append( ( t.children, depth, max( 0, ignore-1 ) ) ) else: for child in t.children.itervalues(): queue.append( ( child, depth, max( 0, ignore-1 ) ) )
def _getAffected(self, t, key, request, response): queue = [(t, 0)] while len(queue) > 0: t, ignore = queue.pop(0) if ignore == 0: ignore = 1 if schema.is_a(t.schema_type, schema.Object): all_of_type = request[t.schema_type] if key not in all_of_type: continue all_of_type = all_of_type[key] if 'get' not in t.handlers: raise Error( 405, 'Object at "%s" does not have a get() method associated' % t.schema_type._url.replace('%s', '*')) ignore = t.depth + 1 for k in all_of_type.iterkeys(): t.handlers['get'](self, k, response, request, None) if t.children: if schema.is_a(t.schema_type, schema.Container): queue.append((t.children, ignore - 1)) else: for child in t.children.itervalues(): queue.append((child, ignore - 1))
def _getObject(self, t, key, request, response, depth): queue = [(t, depth, 0)] while len(queue) > 0: t, depth, ignore = queue.pop(0) reduce_depth_by = 1 if ignore == 0: if 'get' in t.handlers: reduce_depth_by = t.handlers['get'].depth + 1 t.handlers['get'](self, key, response, request, reduce_depth_by if depth is None else min(depth, reduce_depth_by)) elif schema.is_a(t.schema_type, schema.Container): response[t.schema_type][key] = request[t.schema_type][key] elif schema.is_a(t.schema_type, schema.Object): raise Error( 405, 'Object at "%s" does not have a get() method associated' % t.schema_type._url.replace('%s', '*')) if depth is not None: depth = depth - reduce_depth_by ignore = reduce_depth_by if t.children and depth is None or depth >= 0: if schema.is_a(t.schema_type, schema.Container): queue.append((t.children, depth, max(0, ignore - 1))) else: for child in t.children.itervalues(): queue.append((child, depth, max(0, ignore - 1)))
def get(schema_type, depth=None, key_depth=0): if depth is None: depth = 1 if schema.is_a(schema_type, schema.Container) else 0 def wrapper(method): return _SvcGetMethod(method, schema_type, depth=depth, key_depth=key_depth) return wrapper
def _getAffected( self, t, key, request, response ): queue = [ ( t, 0 ) ] while len(queue) > 0: t, ignore = queue.pop(0) if ignore==0: ignore = 1 if schema.is_a( t.schema_type, schema.Object ): all_of_type = request[t.schema_type] if key not in all_of_type: continue all_of_type = all_of_type[key] if 'get' not in t.handlers: raise Error( 405, 'Object at "%s" does not have a get() method associated' % t.schema_type._url.replace( '%s', '*' ) ) ignore = t.depth + 1 for k in all_of_type.iterkeys(): t.handlers['get']( self, k, response, request, None ) if t.children: if schema.is_a( t.schema_type, schema.Container ): queue.append( ( t.children, ignore-1 ) ) else: for child in t.children.itervalues(): queue.append( ( child, ignore-1 ) )
def _modifyObject(self, t, key, request, response, add): queue = [(t.children, 0, True, True)] if add else [(t, 0, False, False)] while len(queue) > 0: t, ignore, add, is_item = queue.pop(0) all_of_type = request[t.schema_type] if key not in all_of_type: continue all_of_type = all_of_type.slice(key) if ignore == 0: ignore = 1 if add: if 'create' in t.handlers: ignore = t.handlers['create'].depth + 1 t.handlers['create']( self, ((key + tuple( (response.replaces[kpart] if schema._is_fake_key(kpart) else kpart for kpart in (k[:-1] if is_item else k))), v) for k, v in all_of_type.iteritems() if (schema._is_fake_key(k[-1]) if is_item else _is_new_key(k))), response, request) elif is_item or schema.is_a(t.schema_type, schema.Object): raise Error( 405, '%s at "%s" does not have a create() method associated' % ('Item' if is_item else 'Object', t.schema_type._url.replace('%s', '*'))) else: if 'update' in t.handlers: ignore = t.handlers['update'].depth + 1 t.handlers['update'](self, ( v for k, v in all_of_type.iteritems() if not _is_new_key(k) and not _is_deleted_item(v)), response, request) elif schema.is_a(t.schema_type, schema.Container): all_of_type = request[t.children.schema_type].slice( key) # Process deleted items immediately all_deleted = [(k, _version_of(v)) for k, v in all_of_type.iteritems() if _is_deleted_item(v)] if len(all_deleted) > 0: if 'delete' in t.children.handlers: t.children.handlers['delete'](self, all_deleted, response, request) else: raise Error( 405, 'Item at "%s" does not have a delete() method associated' % t.children.schema_type._url.replace( '%s', '*')) # Add processing of added items to the queue if not packet._is_empty( (k for k in all_of_type.iterkeys() if _is_new_key(k))): queue.append((t.children, 0, True, True)) elif schema.is_a(t.schema_type, schema.Object): raise Error( 405, 'Object at "%s" does not have an update() method associated' % t.schema_type._url.replace('%s', '*')) if t.children: if schema.is_a(t.schema_type, schema.Container): queue.append((t.children, ignore - 1, add, add)) else: for child in t.children.itervalues(): queue.append((child, ignore - 1, add, False))
def __call__(self, verb, url, body=None): url = urlparse.urlparse(url) url_args = dict( ((name, val if len(val) > 1 else val[0]) for name, val in urlparse.parse_qs(url.query).iteritems())) url = url.path[1:] if url.path[:1] == '/' else url.path request = packet.Packet(self.schema) if body is None: body = {} body[url] = {} try: request.deserialize(body, url_args=url_args) t = self._url_tree key = () is_item = False for name in url.split('/'): if schema.is_a(t.schema_type, schema.Container): key = key + (schema._key_convert( name, t.schema_type._schema['key']), ) t = t.children is_item = True else: if t.children is None or name not in t.children: return _wrapError(404, 'No handlers associated with ' + url) t = t.children[name] is_item = False is_container = schema.is_a(t.schema_type, schema.Container) except: return _wrap500(sys.exc_info()) allow_verbs = set(('GET', 'PUT', 'POST', 'DELETE')) if not is_item: allow_verbs.remove('DELETE') if not is_container: allow_verbs.remove('POST') if verb not in allow_verbs: return _wrap405(verb + ' is not supported by ' + url, allow_verbs) response = packet.Packet(self.schema) need_rollback = False try: if verb == 'GET': depth = url_args.get('depth', None) self._getObject(t, key, request, response, depth and int(depth)) elif verb == 'PUT': self.begin(verb, url, request, response) need_rollback = True self._modifyObject(t, key, request, response, False) need_rollback = False self.commit(verb, url, request, response) elif verb == 'DELETE': self.begin(verb, url, request, response) need_rollback = True self._deleteObject(t, key, request, response) need_rollback = False self.commit(verb, url, request, response) elif verb == 'POST': self.begin(verb, url, request, response) need_rollback = True self._modifyObject(t, key, request, response, True) need_rollback = False self.commit(verb, url, request, response) return _wrap200(response) except Error as err: if need_rollback: self.rollback(verb, url, request, response) if err.status == 405: allow_verbs.remove(verb) return _wrap405(err.message, allow_verbs) elif err.status == 409: try: response = packet.Packet(self.schema) if verb == 'DELETE': self._getObject(t, key, request, response, None) else: self._getAffected(t, key, request, response) return _wrap409(err.message, response) except: return _wrap500(sys.exc_info()) else: return _wrapError(err.status, err.message) except: if need_rollback: self.rollback(verb, url, request, response) return _wrap500(sys.exc_info())
def get( schema_type, depth=None, key_depth=0 ): if depth is None: depth = 1 if schema.is_a( schema_type, schema.Container ) else 0 def wrapper( method ): return _SvcGetMethod( method, schema_type, depth = depth, key_depth = key_depth ) return wrapper
def _modifyObject( self, t, key, request, response, add ): queue = [ ( t.children, 0, True, True ) ] if add else [ ( t, 0, False, False ) ] while len(queue) > 0: t, ignore, add, is_item = queue.pop(0) all_of_type = request[t.schema_type] if key not in all_of_type: continue all_of_type = all_of_type.slice( key ) if ignore == 0: ignore = 1 if add: if 'create' in t.handlers: ignore = t.handlers['create'].depth + 1 t.handlers['create']( self, ( ( key + tuple( ( response.replaces[kpart] if schema._is_fake_key( kpart ) else kpart for kpart in ( k[:-1] if is_item else k ) ) ), v ) for k,v in all_of_type.iteritems() if ( schema._is_fake_key( k[-1] ) if is_item else _is_new_key( k ) ) ), response, request ) elif is_item or schema.is_a( t.schema_type, schema.Object ): raise Error( 405, '%s at "%s" does not have a create() method associated' % ( 'Item' if is_item else 'Object', t.schema_type._url.replace( '%s', '*' ) ) ) else: if 'update' in t.handlers: ignore = t.handlers['update'].depth + 1 t.handlers['update']( self, ( v for k,v in all_of_type.iteritems() if not _is_new_key( k ) and not _is_deleted_item( v ) ), response, request ) elif schema.is_a( t.schema_type, schema.Container ): all_of_type = request[t.children.schema_type].slice( key ) # Process deleted items immediately all_deleted = [ ( k, _version_of( v ) ) for k,v in all_of_type.iteritems() if _is_deleted_item( v ) ] if len( all_deleted ) > 0: if 'delete' in t.children.handlers: t.children.handlers['delete']( self, all_deleted, response, request ) else: raise Error( 405, 'Item at "%s" does not have a delete() method associated' % t.children.schema_type._url.replace( '%s', '*' ) ) # Add processing of added items to the queue if not packet._is_empty( ( k for k in all_of_type.iterkeys() if _is_new_key( k ) ) ): queue.append( ( t.children, 0, True, True ) ) elif schema.is_a( t.schema_type, schema.Object ): raise Error( 405, 'Object at "%s" does not have an update() method associated' % t.schema_type._url.replace( '%s', '*' ) ) if t.children: if schema.is_a( t.schema_type, schema.Container ): queue.append( ( t.children, ignore-1, add, add ) ) else: for child in t.children.itervalues(): queue.append( ( child, ignore-1, add, False ) )
def __call__( self, verb, url, body = None ): url = urlparse.urlparse( url ) url_args = dict(( ( name, val if len(val)>1 else val[0] ) for name,val in urlparse.parse_qs( url.query ).iteritems() )) url = url.path[1:] if url.path[:1]=='/' else url.path request = packet.Packet( self.schema ) if body is None: body = {} body[ url ] = {} try: request.deserialize( body, url_args = url_args ) t = self._url_tree key = () is_item = False for name in url.split( '/' ): if schema.is_a( t.schema_type, schema.Container ): key = key + ( schema._key_convert( name, t.schema_type._schema['key'] ), ) t = t.children is_item = True else: if t.children is None or name not in t.children: return _wrapError( 404, 'No handlers associated with ' + url ) t = t.children[name] is_item = False is_container = schema.is_a( t.schema_type, schema.Container ) except: return _wrap500( sys.exc_info() ) allow_verbs = set(( 'GET', 'PUT', 'POST', 'DELETE' )) if not is_item: allow_verbs.remove( 'DELETE' ) if not is_container: allow_verbs.remove( 'POST' ) if verb not in allow_verbs: return _wrap405( verb + ' is not supported by ' + url, allow_verbs ) response = packet.Packet( self.schema ) need_rollback = False try: if verb=='GET': depth = url_args.get( 'depth', None ) self._getObject( t, key, request, response, depth and int(depth) ) elif verb=='PUT': self.begin( verb, url, request, response ) need_rollback = True self._modifyObject( t, key, request, response, False ) need_rollback = False self.commit( verb, url, request, response ) elif verb=='DELETE': self.begin( verb, url, request, response ) need_rollback = True self._deleteObject( t, key, request, response ) need_rollback = False self.commit( verb, url, request, response ) elif verb=='POST': self.begin( verb, url, request, response ) need_rollback = True self._modifyObject( t, key, request, response, True ) need_rollback = False self.commit( verb, url, request, response ) return _wrap200( response ) except Error as err: if need_rollback: self.rollback( verb, url, request, response ) if err.status == 405: allow_verbs.remove( verb ) return _wrap405( err.message, allow_verbs ) elif err.status == 409: try: response = packet.Packet( self.schema ) if verb=='DELETE': self._getObject( t, key, request, response, None ) else: self._getAffected( t, key, request, response ) return _wrap409( err.message, response ) except: return _wrap500( sys.exc_info() ) else: return _wrapError( err.status, err.message ) except: if need_rollback: self.rollback( verb, url, request, response ) return _wrap500( sys.exc_info() )