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] )
示例#2
0
 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])
示例#3
0
    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
示例#8
0
    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