arsenal-user team mailing list archive
-
arsenal-user team
-
Mailing list archive
-
Message #00021
[RFC] lpltk Collection base class
lpltk includes classes for objects and for object-collections.
For example, Message and Messages or Bug and Bugs.
All of the collection classes have certain functions defined, __iter__,
__get__, et al. These are all more or less identical functions.
I'd like to propose we establish a common (abstract) base class called
Collection for all of these collection classes, that provides those
identical functions.
The benefits of doing this are a) to eliminate code duplication and thus
make maintenace easier, and b) to reduce the amount of boilerplate
needed when adding a new collection class. The net result of adding
this class should be an overall reduction in line count.
With this base class, a simple class like Distributions can be reduced
from 45 lines to 8. It would look like this:
from distribution import Distribution
class Distributions(Collection):
def __init__(self, lp):
Collection.__init__(self, Distribution, lp)
def _fetch_all(self):
return self._service.launchpad.distributions
For more complex classes like Bugs or BugTasks, the difference will not
be as stark, but should still help eliminate redundancy.
For classes that need to customize behaviors beyond what the base class
does, all routines will be named with a single underscore so they can
easily overridden as necessary.
Below is my draft of the class. Questions and critique (and +1's)
welcomed.
Bryce
#!/usr/bin/python
from utils import typecheck_Collection
class Collection(object):
def __init__(self, tk_type, service, lp_objects=None):
'''Initialize the instance from a Launchpad bug.'''
self._tk_type = tk_type
self._service = service
self._lp_objects = None
if lp_objects:
self._lp_objects = typecheck_Collection(lp_objects)
def __len__(self):
return len(list(self.__iter__()))
def __getitem__(self, key):
self._fetch_if_needed()
return self._tk_type(self._service, self._lp_objects[key])
def __iter__(self):
self._fetch_if_needed()
for obj in self._lp_objects:
o = self._get(obj)
yield o
def __contains__(self, item):
return item in self.__iter__()
def _fetch_if_needed(self):
if self._lp_objects == None:
self._lp_objects = self._fetch_all()
assert(self._lp_objects is not None)
def _get(self, obj):
return self._tk_type(self._service, obj)
def _fetch_all(self):
'''Override this routine in the subclass to retrieve the necessary
data from launchpad and return it as a LPCollection of LP objects.'''
import inspect
raise TypeError('Abstract method `%s.%s` called' %(
type(self).__name__, inspect.stack()[0][3]))
if __name__ == "__main__":
from lpltk import LaunchpadService
from distribution import Distribution
class MyDists(Collection):
def __init__(self, lp):
Collection.__init__(self, Distribution, lp)
def _fetch_all(self):
return self._service.launchpad.distributions
lp = LaunchpadService(config={'read_only':True})
objects = MyDists(lp)
for obj in objects:
print obj.display_name,
if obj.current_series:
print obj.current_series.name
else:
print "<no series>"
# vi:set ts=4 sw=4 expandtab:
Follow ups