def _enum_items( self, op, key=() ): new_url = _fill_key( self._url, key ) split = self._first_key_part.split( new_url, 1 ) if len(split) > 1: ct = self._packet._descend( split[0], Packet._forced_get_op ) if ct is None: return container, typ = ct for k in container.iterkeys(): for result in self._enum_items( op, key + ( _key_convert( k, typ._schema['key'] ),) ): yield result else: if new_url in self._packet: yield key if op == self._keys_op else self._packet[new_url] if op == self._values_op else ( key, self._packet[new_url] )
def _enum_items(self, op, key=()): new_url = _fill_key(self._url, key) split = self._first_key_part.split(new_url, 1) if len(split) > 1: ct = self._packet._descend(split[0], Packet._forced_get_op) if ct is None: return container, typ = ct for k in container.iterkeys(): for result in self._enum_items( op, key + (_key_convert(k, typ._schema['key']), )): yield result else: if new_url in self._packet: yield key if op == self._keys_op else self._packet[ new_url] if op == self._values_op else ( key, self._packet[new_url])
def __setitem__(self, url_or_type, item_or_items): if isinstance(url_or_type, type): self[url_or_type][()] = item_or_items return psn = self._descend(url_or_type, self._set_op) if psn is None: extra = [i for i in self.itervalues()] new = _convert(item_or_items, self._schema) old_key = getattr(new, '_key_', None) self._top = new else: p, s, n = psn if n in p: extra = [ i for i in self._all_data_items(p[n], url_or_type, self._items_op) if i[0] != url_or_type ] else: extra = [] new = _convert(item_or_items, s) old_key = getattr(new, '_key_', None) p[n] = new if type(p) == dict and new is not None: # Have to take care of _key_ new._set_key( tuple((_key_convert(val, typ) for typ, val in zip( self._descend(url_or_type, self._schema_op)[1], re.search(s._url.replace('%s', '([^/]+)'), url_or_type).groups())))) if old_key is not None and len(old_key) == len(new._key_) and len(old_key)>0 and \ _is_fake_key( old_key[-1] ) and not _is_fake_key( new._key_[-1] ): if new._ is None: new._ = s._(replaces=old_key[-1]) else: new._.replaces = old_key[-1] if new is not None and new._ and getattr(new._, 'replaces', None): self.replaces[new._.replaces] = new._key_[-1] for k, v in extra: self[k] = v
def __setitem__( self, url_or_type, item_or_items ): if isinstance( url_or_type, type ): self[url_or_type][()] = item_or_items return psn = self._descend( url_or_type, self._set_op ) if psn is None: extra = [ i for i in self.itervalues() ] new = _convert( item_or_items, self._schema ) old_key = getattr( new, '_key_', None ) self._top = new else: p,s,n = psn if n in p: extra = [ i for i in self._all_data_items( p[n], url_or_type, self._items_op ) if i[0] != url_or_type ] else: extra = [] new = _convert( item_or_items, s ) old_key = getattr( new, '_key_', None ) p[n] = new if type(p) == dict and new is not None: # Have to take care of _key_ new._set_key( tuple( ( _key_convert( val, typ ) for typ, val in zip( self._descend( url_or_type, self._schema_op )[1], re.search( s._url.replace( '%s', '([^/]+)' ), url_or_type ).groups() ) ) ) ) if old_key is not None and len(old_key) == len(new._key_) and len(old_key)>0 and \ _is_fake_key( old_key[-1] ) and not _is_fake_key( new._key_[-1] ): if new._ is None: new._ = s._( replaces = old_key[-1] ) else: new._.replaces = old_key[-1] if new is not None and new._ and getattr( new._, 'replaces', None ): self.replaces[new._.replaces] = new._key_[-1] for k,v in extra: self[k] = v
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 __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 _descend( self, url, op ): p = self._top s = self._schema in_data = type(p) != dict sm = _StructMapping() key_types = [] if len(url): url = url.split( '/' ) for part in url[:-1] if op == self._set_op else url: if op != self._schema_op and in_data and p is not None and not hasattr( s, '__getitem__' ): sm.struct = p p = sm if hasattr( s, '__getitem__' ): ss = s._schema['item'] if in_data: part = schema._key_convert( part, s._schema['key'] ) else: ss = s._schema[part] if op != self._schema_op: if p is None or part not in p: if op == self._check_op: return False elif op == self._get_op: raise KeyError( "No data at URL '%s'" % url ) elif op == self._forced_get_op: return None elif p is None: raise TypeError( "Cannot add children to deleted item at '%s'" % s._url_() ) p[part] = ss( _= ss._( partial = True ) ) if in_data else {} if type(p[part]) != dict: in_data = True p = p[part] else: if hasattr( s, '__getitem__' ): key_types.append( s._schema['key'] ) s = ss elif op == self._set_op: return None if op == self._schema_op: return ( s, key_types ) elif op == self._check_op: return in_data elif op == self._set_op: if hasattr( s, '__getitem__' ): return ( p, s._schema['item'], url[-1] ) elif in_data: sm.struct = p return ( sm, s._schema[url[-1]], url[-1] ) else: return ( p, s._schema[url[-1]], url[-1] ) elif op == self._forced_get_op : return ( p, s ) else: if not in_data: raise KeyError( "No data at URL '%s'" % ( '/'.join( url ) ) ) return p
def _descend(self, url, op): p = self._top s = self._schema in_data = type(p) != dict sm = _StructMapping() key_types = [] if len(url): url = url.split('/') for part in url[:-1] if op == self._set_op else url: if op != self._schema_op and in_data and p is not None and not hasattr( s, '__getitem__'): sm.struct = p p = sm if hasattr(s, '__getitem__'): ss = s._schema['item'] if in_data: part = schema._key_convert(part, s._schema['key']) else: ss = s._schema[part] if op != self._schema_op: if p is None or part not in p: if op == self._check_op: return False elif op == self._get_op: raise KeyError("No data at URL '%s'" % url) elif op == self._forced_get_op: return None elif p is None: raise TypeError( "Cannot add children to deleted item at '%s'" % s._url_()) p[part] = ss(_=ss._(partial=True)) if in_data else {} if type(p[part]) != dict: in_data = True p = p[part] else: if hasattr(s, '__getitem__'): key_types.append(s._schema['key']) s = ss elif op == self._set_op: return None if op == self._schema_op: return (s, key_types) elif op == self._check_op: return in_data elif op == self._set_op: if hasattr(s, '__getitem__'): return (p, s._schema['item'], url[-1]) elif in_data: sm.struct = p return (sm, s._schema[url[-1]], url[-1]) else: return (p, s._schema[url[-1]], url[-1]) elif op == self._forced_get_op: return (p, s) else: if not in_data: raise KeyError("No data at URL '%s'" % ('/'.join(url))) return p