debian-python-redmine/redmine/resultsets.py

184 lines
6.0 KiB
Python

import itertools
from .exceptions import (
ResourceSetIndexError,
ResourceSetFilterParamError,
ResultSetTotalCountError
)
class ResourceSet(object):
"""Represents a set of Redmine resources as objects"""
limit = 0
offset = 0
_total_count = -1
def __init__(self, manager, resources=None):
"""Accepts manager instance object, optionally can be prefilled with an iterable of resources"""
self.manager = manager
self.resources = resources
def get(self, resource_id, default=None):
"""Returns a single item from a ResourceSet by resource id"""
for resource in self:
if resource_id == resource.internal_id:
return resource
return default
def filter(self, resource_ids):
"""Returns a ResourceSet with requested resource ids"""
if not isinstance(resource_ids, (tuple, list)):
raise ResourceSetFilterParamError
resources = []
for resource in self:
if resource.internal_id in resource_ids:
resources.append(resource)
return ResourceSet(self.manager, resources)
def update(self, **fields):
"""Updates fields of all resources in a ResourceSet with the given values"""
resources = []
for resource in self:
for field in fields:
setattr(resource, field, fields[field])
resource.save()
resources.append(resource)
return ResourceSet(self.manager, resources)
def delete(self):
"""Deletes all resources in a ResourceSet"""
for resource in self:
self.manager.delete(resource.internal_id)
return True
def values(self, *fields):
"""Returns ValuesResourceSet object which represents Resource as a dictionary"""
return ValuesResourceSet(self.manager, resources=self.resources, fields=fields)
@property
def total_count(self):
"""Returns total count of available resources, this is known only after ResourceSet evaluation"""
if self._total_count == -1:
if self.resources is None:
raise ResultSetTotalCountError
else:
self._total_count = len(self)
return self._total_count
def _evaluate(self):
"""Evaluates current ResourceSet object"""
self.resources, self._total_count = self.manager.retrieve(
limit=self.manager.params.get('limit', self.limit),
offset=self.manager.params.get('offset', self.offset)
)
def __getitem__(self, item):
"""Sets limit and offset or returns a resource by requested index"""
if isinstance(item, slice):
if item.stop is not None:
self.limit = item.stop
if item.start is not None:
self.offset = item.start
elif isinstance(item, int):
try:
return next(itertools.islice(self, item, item + 1))
except StopIteration:
raise ResourceSetIndexError
return self
def __iter__(self):
"""Returns requested resources in a lazy fashion"""
if self.resources is None:
self._evaluate()
return (self.manager.to_resource(resource) for resource in self.resources)
def __len__(self):
"""Allows len() to be called on an instance object"""
return sum(1 for _ in self)
def __repr__(self):
"""Official representation of ResourceSet object"""
return '<{0}.{1} object with {2} resources>'.format(
self.__class__.__module__,
self.__class__.__name__,
self.manager.resource_class.__name__
)
class ValuesResourceSet(ResourceSet):
"""Represents a set of Redmine resources as dictionaries"""
def __init__(self, manager, resources=None, fields=()):
"""Accepts optional fields iterable which sets field names each resource will contain"""
super(ValuesResourceSet, self).__init__(manager, resources)
self.fields = fields
self.resource_internal_id = 'title' if self.manager.resource_class.__name__ == 'WikiPage' else 'id'
def get(self, resource_id, default=None):
"""Returns a single item from a ValuesResourceSet by resource id"""
for resource in self:
if int(resource_id) == resource[self.resource_internal_id]:
return resource
return default
def filter(self, resource_ids):
"""Returns a ValuesResourceSet with requested resource ids"""
if not isinstance(resource_ids, (tuple, list)):
raise ResourceSetFilterParamError
resources = []
for resource in self:
if resource[self.resource_internal_id] in resource_ids:
resources.append(resource)
return ValuesResourceSet(self.manager, resources=resources, fields=self.fields)
def update(self, **fields):
"""Updates fields of all resources in a ValuesResourceSet with the given values"""
resources = []
for resource in self:
for field in fields:
resource[field] = fields[field]
self.manager.update(resource[self.resource_internal_id], **fields)
resources.append(resource)
return ValuesResourceSet(self.manager, resources=resources, fields=self.fields)
def delete(self):
"""Deletes all resources in a ValuesResourceSet"""
for resource in self:
self.manager.delete(resource[self.resource_internal_id])
return True
def __iter__(self):
"""Returns requested resources in a lazy fashion"""
if self.resources is None:
self._evaluate()
for resource in self.resources:
if not self.fields:
yield resource
else:
fields = {}
for field in resource:
if field in self.fields:
fields.update({field: resource[field]})
yield fields