text: from aioriak.content import RiakContent
  from aioriak.error import ConflictError
  
  
  def content_property(name, doc=None):
      '''
      Delegates a property to the first sibling in a RiakObject, raising
      an error when the object is in conflict.
      '''
      def _setter(self, value):
          if len(self.siblings) == 0:
              # In this case, assume that what the user wants is to
              # create a new sibling inside an empty object.
              self.siblings = [RiakContent(self)]
          if len(self.siblings) != 1:
              raise ConflictError()
          setattr(self.siblings[0], name, value)
  
      def _getter(self):
          if len(self.siblings) == 0:
              return
          if len(self.siblings) != 1:
              raise ConflictError()
          return getattr(self.siblings[0], name)
  
      return property(_getter, _setter, doc=doc)
  
  
  class RiakObject:
      '''
      The RiakObject holds meta information about a Riak object, plus the
      object's data.
      '''
      siblings = []
  
      def __init__(self, client, bucket, key=None):
          '''
          Construct a new RiakObject.
  
          :param client: A RiakClient object.
          :type client: :class:`RiakClient <aioriak.client.RiakClient>`
          :param bucket: A RiakBucket object.
          :type bucket: :class:`RiakBucket <aioriak.bucket.RiakBucket>`
          :param key: An optional key. If not specified, then the key
           is generated by the server when :func:`store` is called.
          :type key: string
          '''
  
          if key is not None and len(key) == 0:
              raise ValueError('Key name must either be "None"'
                               ' or a non-empty string.')
          self.client = client
          self.bucket = bucket
          self.key = key
          self.vclock = None
          self.siblings = [RiakContent(self)]
          self._resolver = None
  
      def _exists(self):
          if len(self.siblings) == 0:
              return False
          elif len(self.siblings) > 1:
              # Even if all of the siblings are tombstones, the object
              # essentially exists.
              return True
          else:
              return self.siblings[0].exists
  
      exists = property(_exists, None, doc='''
          Whether the object exists. This is only ``False`` when there
          are no siblings (the object was not found), or the solitary
          sibling is a tombstone.
          ''')
  
      async def reload(self):
          '''
          Reload the object from Riak. When this operation completes, the
          object could contain new metadata and a new value, if the object
          was updated in Riak since it was last retrieved.
  
          .. note:: Even if the key is not found in Riak, this will
             return a :class:`RiakObject`. Check the :attr:`exists`
             property to see if the key was found.
  
          :rtype: :class:`RiakObject`
          '''
  
          await self.client.get(self)
          return self
  
      async def store(self, w=None, dw=None, pw=None, return_body=True,
                      if_none_match=False, timeout=None):
          '''
          Store the object in Riak. When this operation completes, the
          object could contain new metadata and possibly new data if Riak
          contains a newer version of the object according to the object's
          vector clock.
  
          :param return_body: if the newly stored object should be retrieved
          :type return_body: bool
          :rtype: :class:`RiakObject` '''
          if len(self.siblings) != 1:
              raise ConflictError("Attempting to store an invalid object, "
                                  "resolve the siblings first")
  
          await self.client.put(self, w=w, dw=dw, pw=pw,
                                return_body=return_body,
                                if_none_match=if_none_match, timeout=timeout)
          return self
  
      async def delete(self):
          '''
          Delete this object from Riak.
  
          :rtype: :class:`RiakObject`
          '''
          await self.client.delete(self)
          self.clear()
          return self
  
      def clear(self):
          '''
          Reset this object.
  
          :rtype: RiakObject
          '''
          self.siblings = []
          return self
  
      data = content_property('data', doc='''
          The data stored in this object, as Python objects. For the raw
          data, use the `encoded_data` property. If unset, accessing
          this property will result in decoding the `encoded_data`
          property into Python values. The decoding is dependent on the
          `content_type` property and the bucket's registered decoders.
          ''')
  
      encoded_data = content_property('encoded_data', doc='''
          The raw data stored in this object, essentially the encoded
          form of the `data` property. If unset, accessing this property
          will result in encoding the `data` property into a string. The
          encoding is dependent on the `content_type` property and the
          bucket's registered encoders.
          ''')
  
      charset = content_property('charset', doc='''
          The character set of the encoded data as a string
          ''')
  
      content_encoding = content_property('content_encoding', doc='''
          The encoding (compression) of the encoded data. Valid values
          are identity, deflate, gzip
          ''')
  
      usermeta = content_property('usermeta', doc='''
          Arbitrary user-defined metadata dict, mapping strings to strings.
          ''')
  
      links = content_property('links', doc='''
          A set of bucket/key/tag 3-tuples representing links to other
          keys.
          ''')
  
      content_type = content_property('content_type', doc='''
          The MIME media type of the encoded data as a string
          ''')
  
      indexes = content_property('indexes', doc='''
          The set of secondary index entries, consisting of
          index-name/value tuples
          ''')
  
      def _get_resolver(self):
          if callable(self._resolver):
              return self._resolver
          elif self._resolver is None:
              return self.bucket.resolver
          else:
              raise TypeError("resolver is not a function")
  
      def _set_resolver(self, value):
          if value is None or callable(value):
              self._resolver = value
          else:
              raise TypeError("resolver is not a function")
  
      resolver = property(_get_resolver, _set_resolver,
                          doc='''The sibling-resolution function for this
                          object. If the resolver is not set, the
                          bucket's resolver will be used.''')
  