arsenal-user team mailing list archive
-
arsenal-user team
-
Mailing list archive
-
Message #00022
[RFC] lpltk Entity base class
Along the lines of the Collection class I posted earlier, here is a
similarly abstracted Entity class.
Essentially, instead of writing wrapper functions for each function in a
given launchpad api object, we ask the launchpad object what functions
it has, and then dynamically create our own getter functions from that.
Further, for Collection type properties (e.g. bug.messages) it figures
out what the Launchpad data type is via the object's
'resource_type_link' field and then creates the appropriate lpltk
collection class (e.g. Messages).
You can see in the example below that with this, the Distribution class
can be represented in 3 lines (plus custom functions), yet supports more
properties than our current Distribution class.
This class would enable us to more easily wrap ALL of the remaining LP
API, and do it in a more consistent, predictable way. If new routines
are added to the LP API, this will allow them to be picked up
automatically. This does add a bit more complexity which might make
things trickier to debug, however that's offset by reducing the size of
the codebase. It may also require some rejiggering of how classes are
instantiated (so that they all match), and other refactoring, which may
be a bit disruptive.
I'd like to get some feedback on this (and the Collection class) before
I add it to the codebase.
#!/usr/bin/python
def lp_to_tk(service, obj):
'''Factory function to convert lp objects to corresponding lpltk classes'''
# Look up the proper tk class to cast to
if not hasattr(obj, 'resource_type_link'):
return obj
lpclass = obj.resource_type_link.split('#')[-1:][0]
# Entry types
if lpclass == 'team':
from person import Person
return Person(None, obj)
elif lpclass == 'distro_series':
from distro_series import DistroSeries
return DistroSeries(service, None, obj)
# Collection types
elif lpclass == 'milestone-page-resource':
from milestones import Milestones
return Milestones(service, obj)
elif lpclass == 'specification-page-resource':
from specifications import Specifications
return Specifications(service, obj)
return None
class TKEntry(object):
def __init__(self, service, lp_entry):
self.__dict__ = {
'_service': service,
'_lp_entry': lp_entry,
}
attrs = []
attrs.extend(self._lp_entry.lp_attributes)
attrs.extend(self._lp_entry.lp_entries)
attrs.extend(self._lp_entry.lp_collections)
for key in attrs:
if key[0] != '_':
self.__dict__["_"+key] = None
def __getattr__(self, attr_name):
if attr_name[0] != '_':
assert(self._lp_entry is not None)
assert("_"+attr_name in self.__dict__.keys())
if self.__dict__["_"+attr_name] is None:
obj = self._lp_entry.__getattr__(attr_name)
self.__dict__["_"+attr_name] = lp_to_tk(self._service, obj)
return self.__dict__["_"+attr_name]
if __name__ == "__main__":
from lpltk import LaunchpadService
class Distribution(TKEntry):
def __init__(self, service, lp_distribution):
super(Distribution, self).__init__(service, lp_distribution)
def my_function(self):
'''This shows that the dynamically added parameters are available in any member function'''
return "%s %s" %(self._display_name, self._current_series.name)
lp = LaunchpadService(config={'read_only':True})
lp_distro = lp.launchpad.distributions['ubuntu']
obj = Distribution(lp, lp_distro)
print "Name:", obj.display_name
print "Owner:", obj.owner
print "Driver:", obj.driver
print "Registrant:", obj.registrant
print "Current:", obj.current_series
print "Date Created:", obj.date_created
print "Active Milestones:", obj.active_milestones
print "All Milestones:", obj.all_milestones
print "All Specifications:", obj.all_specifications
print "Valid Specifications:", obj.valid_specifications
print "Calculated:", obj.my_function()