# 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
[docs]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
[docs] 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)
[docs] 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)
[docs] 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
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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)
[docs] def desc(self):
''' get the `desc` `query` attribute. Syntactic sugar
for :meth:`surf.resource.Resource.query_attribute` method.
'''
return self.__query_attribute().desc()
[docs] def get_by(self, **kwargs):
''' get the `get_by` `query` attribute. Syntactic sugar
for :meth:`surf.resource.Resource.query_attribute` method.
'''
return self.__query_attribute().get_by(**kwargs)
[docs] 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)