# Copyright (c) 2009, Digital Enterprise Research Institute (DERI), # NUI Galway # All rights reserved. # author: Cosmin Basca # email: cosmin.basca@gmail.com # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with # the distribution. # * Neither the name of DERI nor the # names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # THIS SOFTWARE IS PROVIDED BY DERI ''AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DERI BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # -*- coding: utf-8 -*- __author__ = 'Cosmin Basca' from surf.exc import NoResultFound, MultipleResultsFound class ResourceValue(list): ''' the :class:`surf.resource.value.ResourceValue` class is used by the :class:`surf.resource.Resource` class to `lazy load` instances of resources. .. note:: the class also emulates a list, while in addition providing support for `SuRF` queries, as defined in the :mod:`surf.query` module. .. note:: instances of this class **must** not be created manually, instead they are automatically generated by `SuRF` as needed ''' def __init__(self, values_source, resource, attribute_name): list.__init__(self) self.resource = resource # So we know which attribute this ResourceValue object represents self.__attribute_name = attribute_name # For lazy loading list contents self.__values_source = values_source self.__data_loaded = False def __prepare_values(self): if not self.__data_loaded: self[:], self.__rdf_values = self.__values_source() self.__data_loaded = True def get_one(self): ''' return only one `resource`. If there are more `resources` available the :class:`surf.exc.NoResultFound` exception is raised ''' self.__prepare_values() if len(self) == 1: return self[0] elif len(self) == 0: raise NoResultFound('list is empty') else: raise MultipleResultsFound('list has more elements than one') one = property(fget=get_one) def get_first(self): ''' return the first `resource` or None otherwise. ''' self.__prepare_values() if len(self) > 0: return self[0] else: return None first = property(fget=get_first) def set_dirty(self, dirty): ''' mark this `resource` as **dirty**. By doing so, `SuRF` will refresh it's content as soon as it's necessary ''' if hasattr(self.resource, 'dirty'): self.resource.dirty = dirty def to_rdf(self, value): ''' return an **RDF** representation of the `resource` ''' if hasattr(self.resource, 'to_rdf'): return self.resource.to_rdf(value) raise Exception("to_rdf has no reference to resource") def __len__(self): self.__prepare_values() return list.__len__(self) def __contains__(self, key): # For now, load all values. In future, if the data is not yet loaded, # we can optimize and do ASK query here. self.__prepare_values() return self.to_rdf(key) in self.__rdf_values def __getitem__(self, key): self.__prepare_values() return list.__getitem__(self, key) def __setitem__(self, key, value): self.__prepare_values() self.set_dirty(True) self.__rdf_values[key] = self.to_rdf(value) return list.__setitem__(self, key, value) def __delitem__(self, key): self.__prepare_values() self.set_dirty(True) del self.__rdf_values[key] return list.__delitem__(self, key) def append(self, value): self.__prepare_values() self.set_dirty(True) self.__rdf_values.append(self.to_rdf(value)) return list.append(self, value) def extend(self, L): self.__prepare_values() self.set_dirty(True) self.__rdf_values.extend([self.to_rdf(value) for value in L]) return list.extend(self, L) def insert(self, i, value): self.__prepare_values() self.set_dirty(True) self.__rdf_values.insert(i, self.to_rdf(value)) return list.insert(self, i, value) def remove(self, value): self.__prepare_values() self.set_dirty(True) self.__rdf_values.remove(self.to_rdf(value)) return list.remove(self, value) def pop(self, i= -1): self.__prepare_values() self.set_dirty(True) self.__rdf_values.pop(i) return list.pop(self, i) def __iter__(self): self.__prepare_values() return list.__iter__(self) def __str__(self): self.__prepare_values() return list.__str__(self) def __repr__(self): self.__prepare_values() return list.__repr__(self) # Shortcuts for querying attributes. # It's syntactic sugar around resource.query_attribute(), so instead of # >>> resource.query_attribute("foaf_knows").limit(3) # we can use # >>> resource.foaf_knows.limit(3) def __query_attribute(self): return self.resource.query_attribute(self.__attribute_name) def limit(self, value): ''' get the `limit` `query` attribute. Syntactic sugar for :meth:`surf.resource.Resource.query_attribute` method. ''' return self.__query_attribute().limit(value) def offset(self, value): ''' get the `offset` `query` attribute. Syntactic sugar for :meth:`surf.resource.Resource.query_attribute` method. ''' return self.__query_attribute().offset(value) def full(self, only_direct=False): ''' get the `full` `query` attribute. Syntactic sugar for :meth:`surf.resource.Resource.query_attribute` method. ''' return self.__query_attribute().full(only_direct) def order(self, value=True): ''' get the `order` `query` attribute. Syntactic sugar for :meth:`surf.resource.Resource.query_attribute` method. ''' return self.__query_attribute().order(value) def desc(self): ''' get the `desc` `query` attribute. Syntactic sugar for :meth:`surf.resource.Resource.query_attribute` method. ''' return self.__query_attribute().desc() def get_by(self, *args, **kwargs): ''' get the `get_by` `query` attribute. Syntactic sugar for :meth:`surf.resource.Resource.query_attribute` method. ''' return self.__query_attribute().get_by(*args, **kwargs) def context(self, context): ''' get the `context` `query` attribute. Syntactic sugar for :meth:`surf.resource.Resource.query_attribute` method. ''' return self.__query_attribute().context(context)