home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / launchpadbugs / html_blueprint.py < prev    next >
Encoding:
Python Source  |  2008-02-06  |  11.9 KB  |  392 lines

  1. import re
  2. import libxml2
  3.  
  4. from blueprintbase import LPBluePrint
  5. from lphelper import _gen_getter, user, unicode_for_libxml2
  6. from lptime import LPTime
  7. from bugbase import LPBugInfo
  8. from subscribersbase import LPSubscribers
  9.  
  10. def _get_content(xml, path):
  11.     x = xml.xpathEval(path)
  12.     assert x
  13.     res = x[0].content.strip("\n ")
  14.     x = res.split("\n")
  15.     if len(x) > 1:
  16.         res = " ".join([i.strip() for i in x if i])
  17.     return res
  18.     
  19. def _get_user(xml, path):
  20.     m = xml.xpathEval(path)
  21.     if m:
  22.         return user.parse_html_user(m[0])
  23.     else:
  24.         m = xml.xpathEval("td")
  25.         assert m
  26.         assert "None" in m[0].content
  27.         # in this case this attribute is set to 'None'
  28.         return user(None)
  29.  
  30. class InfoBox(object):
  31.     def __init__(self, xml):
  32.         self.xmldoc = xml[0]
  33.         self.parsed = False
  34.         self.__priority = None
  35.         self.__status = None
  36.         self.__delivery = None
  37.         self.__goal = None
  38.         self.__assignee = user(None)
  39.         self.__drafter = user(None)
  40.         self.__approver = user(None)
  41.         self.__sprints = set()
  42.         
  43.     def parse(self):
  44.         if self.parsed:
  45.             return True
  46.         
  47.         rows = self.xmldoc.xpathEval("tr")
  48.         #count = len(rows)
  49.         #print count
  50.         
  51.         for row in rows:
  52.             if row.xpathEval('th[contains(.,"Priority")]'):
  53.                 assert not self.__priority
  54.                 self.__priority = _get_content(row, "td")
  55.             elif row.xpathEval('th[contains(.,"Definition")]'):
  56.                 assert not self.__status
  57.                 self.__status = _get_content(row, "td")
  58.             elif row.xpathEval('th[contains(.,"Implementation")]'):
  59.                 assert not self.__delivery
  60.                 self.__delivery = _get_content(row, "td")
  61.             elif row.xpathEval('th[contains(.,"Series goal")]'):
  62.                 # currently not used
  63.                 assert not self.__goal
  64.                 self.__goal = _get_content(row, "td")
  65.             elif row.xpathEval('th[contains(.,"Assignee")]'):
  66.                 assert not self.__assignee
  67.                 self.__assignee = _get_user(row, "td/a")
  68.             elif row.xpathEval('th[contains(.,"Drafter")]'):
  69.                 assert not self.__drafter
  70.                 self.__drafter = _get_user(row, "td/a")
  71.             elif row.xpathEval('th[contains(.,"Approver")]'):
  72.                 assert not self.__approver
  73.                 self.__approver = _get_user(row, "td/a")
  74.             elif row.xpathEval('th[contains(.,"Sprints")]'):
  75.                 m = row.xpathEval("td//a")
  76.                 for i in m:
  77.                     self.__sprints.add(i.content)
  78.             else:
  79.                 assert None, "unknown attribute in InfoBox: %s" %row.xpathEval('th').content
  80.         self.parsed = True
  81.         
  82.     @property
  83.     def priority(self):
  84.         return self.__priority
  85.         
  86.     @property
  87.     def status(self):
  88.         return self.__status
  89.         
  90.     @property
  91.     def delivery(self):
  92.         return self.__delivery
  93.         
  94.     @property
  95.     def assignee(self):
  96.         return self.__assignee
  97.         
  98.     @property
  99.     def drafter(self):
  100.         return self.__drafter
  101.         
  102.     @property
  103.     def approver(self):
  104.         return self.__approver
  105.         
  106.     @property
  107.     def sprints(self):
  108.         return self.__sprints
  109.     
  110.  
  111. class Subscribers(LPSubscribers):
  112.     def __init__(self, xml):
  113.         self.parsed = False
  114.         self.xmldoc = xml
  115.         LPSubscribers.__init__(self, ("essential", "inessential"))
  116.         
  117.     def parse(self):
  118.         if self.parsed:
  119.             return True
  120.             
  121.         for i in self.xmldoc:
  122.             m = i.xpathEval("a")
  123.             assert m
  124.             x = user.parse_html_user(m[0])
  125.             
  126.             m = i.xpathEval("img")
  127.             assert m
  128.             if "inessential" in m[0].prop("src"):
  129.                 self["inessential"].add(x)
  130.             elif "essential" in m[0].prop("src"):
  131.                 self["essential"].add(x)
  132.             else:
  133.                 assert None, "unsupported type"
  134.             
  135.         self.parsed = True
  136.         
  137.     def add(self):
  138.         raise NotImplementedError, 'read-only'
  139.         
  140.         
  141. class Lifecycle(object):
  142.     def __init__(self, xml):
  143.         self.xmldoc = xml[0]
  144.         self.parsed = False
  145.         
  146.         self.registrant = user(None)
  147.         self.date_registered = None
  148.         
  149.         self.starter = user(None)
  150.         self.date_started = None
  151.         
  152.         self.completer = user(None)
  153.         self.date_completed = None
  154.         
  155.         
  156.         
  157.     def parse(self):
  158.         if self.parsed:
  159.             return True
  160.             
  161.         rows = self.xmldoc.xpathEval("tr")
  162.         #count = len(rows)
  163.         #print count
  164.         
  165.         for row in rows:
  166.             if row.xpathEval('th[contains(.,"Registered by")]'):
  167.                 assert not self.registrant
  168.                 self.registrant = _get_user(row, "td/a")
  169.             elif row.xpathEval('th[contains(.,"When")]'):
  170.                 assert not self.date_registered
  171.                 x = _get_content(row, "td/span/@title")
  172.                 self.date_registered = LPTime(x)
  173.             elif row.xpathEval('th[contains(.,"Started")]'):
  174.                 assert not self.date_started
  175.                 x = _get_content(row, "td")
  176.                 self.date_started = LPTime(x)
  177.             elif row.xpathEval('th[contains(.,"Completed")]'):
  178.                 assert not self.date_completed
  179.                 x = _get_content(row, "td")
  180.                 self.date_completed = LPTime(x)
  181.             elif row.xpathEval('th[contains(.,"by")]'):
  182.                 #print row.xpathEval('th')[0].content
  183.                 i = row.xpathEval('preceding-sibling::tr/th')
  184.                 assert i
  185.                 if "started" in i[-1].content.lower():
  186.                     #print "Started by"
  187.                     assert not self.starter
  188.                     self.starter = _get_user(row, "td/a")
  189.                 elif "completed" in i[-1].content.lower():
  190.                     #print "completed by"
  191.                     assert not self.completer
  192.                     self.completer = _get_user(row, "td/a")                  
  193.                 else:
  194.                     assert None, "wrong xpath"
  195.             else:
  196.                 assert None, "unknown attribute in InfoBox: %s" %row.xpathEval('th').content
  197.         
  198.         self.parsed = True
  199.  
  200.  
  201. class BugInfo(LPBugInfo):
  202.     def __init__(self, nr, url, summary):
  203.         LPBugInfo.__init__(self, nr, url, None, None, summary, None, False)
  204.         
  205.     def __str__(self):
  206.         return "[Bug %s]" %self.url
  207.     
  208.  
  209. class RelatedBugs(set):
  210.     def __init__(self, xml):
  211.         self.xmldoc = xml
  212.         self.parsed = False
  213.         set.__init__(self)
  214.         
  215.     def parse(self):
  216.         if self.parsed:
  217.             return True
  218.             
  219.         for i in self.xmldoc:
  220.             m = i.xpathEval("a")
  221.             assert m
  222.             u = m[0].prop("href")
  223.             nr = int(u.split("/").pop())
  224.             s = m[0].content.split(":").pop()
  225.             summary = s.strip("\n ")
  226.             self.add(BugInfo(nr, u, summary))
  227.             
  228.         self.parsed = True
  229.         
  230.  
  231. class Overview(object):
  232.     def __init__(self, xml):
  233.         self.xmldoc = xml
  234.         self.parsed = False
  235.         
  236.     def parse(self):
  237.         if self.parsed:
  238.             return True
  239.             
  240.         assert self.xmldoc
  241.         self.text = self.xmldoc[0].content
  242.         self.parsed = True
  243.         
  244.  
  245. class FullSpec(object):
  246.     def __init__(self, xml):
  247.         self.xmldoc = xml
  248.         self.parsed = False
  249.         
  250.     def parse(self):
  251.         if self.parsed:
  252.             return True
  253.             
  254.         assert self.xmldoc
  255.         self.url = self.xmldoc[0].prop("href")
  256.         self.parsed = True    
  257.  
  258.  
  259. class Mentors(set):
  260.     def __init__(self, xml):
  261.         self.xmldoc = xml
  262.         self.parsed = False
  263.         set.__init__(self)
  264.         
  265.     def parse(self):
  266.         if self.parsed:
  267.             return True
  268.             
  269.         for i in self.xmldoc:
  270.             x = user.parse_html_user(i)
  271.             self.add(x)
  272.             
  273.         self.parsed = True
  274.         
  275.  
  276. class WhiteBoard(object):
  277.     def __init__(self, xml):
  278.         self.xmldoc = xml
  279.         self.parsed = False
  280.         self.text = ""
  281.         
  282.     def parse(self):
  283.         if self.parsed:
  284.             return True
  285.             
  286.         if self.xmldoc:
  287.             self.text = self.xmldoc[0].content
  288.         self.parsed = True
  289.         
  290. class _Request(object):
  291.     def __init__(self, user, target, text):
  292.         self.user = user
  293.         self.target = target
  294.         self.text = text
  295.         
  296.     def __repr__(self):
  297.         return "<FeedbackRequest from '%s' to '%s'>" %(self.user, self.target)
  298.  
  299.  
  300. class FeedbackRequest(list):
  301.     def __init__(self, xml):
  302.         self.xmldoc = xml
  303.         self.parsed = False
  304.         list.__init__(self)
  305.         
  306.     def parse(self):
  307.         if self.parsed:
  308.             return True
  309.             
  310.         for i in self.xmldoc:
  311.             m = i.xpathEval("a")
  312.             assert m
  313.             r_user = user.parse_html_user(m[0])
  314.             
  315.             m = i.xpathEval("strong/a")
  316.             assert m
  317.             r_target = user.parse_html_user(m[0])
  318.             
  319.             m = i.xpathEval('div[@style="font-style: italic;"]')
  320.             assert m
  321.             r_text = m[0].content
  322.             
  323.             self.append(_Request(r_user,r_target,r_text))
  324.             
  325.         self.parsed = True
  326.         
  327.         
  328.  
  329. class Blueprint(LPBluePrint):
  330.     def __init__(self, url, connection):
  331.         LPBluePrint.__init__(self, url, connection)
  332.         
  333.         page = self._connection.get(self.url)
  334.         #TODO: check redirection
  335.         
  336.         self.xmldoc = libxml2.htmlParseDoc(unicode_for_libxml2(page.text), "UTF-8")
  337.         
  338.         self.__info_box = InfoBox(self.xmldoc.xpathEval('//table[@class="summary"]/tbody'))
  339.         self.__subscribers = Subscribers(self.xmldoc.xpathEval('//div[@id="portlet-subscribers"]/div[@class="portletBody"]//div'))
  340.         self.__lifecycle = Lifecycle(self.xmldoc.xpathEval('//div[@id="portlet-lifecycle"]/div/table/tbody'))
  341.         self.__related_bugs = RelatedBugs(self.xmldoc.xpathEval('//div[@id="portlet-related-bugs"]/div/ul//li'))
  342.         self.__overview = Overview(self.xmldoc.xpathEval('//table[@class="summary"]/following-sibling::p[1]'))
  343.         self.__full_spec = FullSpec(self.xmldoc.xpathEval('//table[@class="summary"]/following-sibling::ul[1]/li/a'))
  344.         self.__mentors = Mentors(self.xmldoc.xpathEval('//table[@class="summary"]/following-sibling::p[2]//a'))
  345.         self.__whiteboard = WhiteBoard(self.xmldoc.xpathEval('//h2[contains(.,"Whiteboard")]/following-sibling::div'))
  346.         self.__feedback_request = FeedbackRequest(self.xmldoc.xpathEval('//div[@id="portlet-feedback"]/div/ul//li'))
  347.         
  348.         
  349.     #######INFO-BOX
  350.     get_priority = _gen_getter("__info_box.priority")
  351.     get_status = _gen_getter("__info_box.status")
  352.     get_delivery = _gen_getter("__info_box.delivery")
  353.     get_assignee = _gen_getter("__info_box.assignee")
  354.     get_drafter = _gen_getter("__info_box.drafter")
  355.     get_approver = _gen_getter("__info_box.approver")
  356.     get_sprints = _gen_getter("__info_box.sprints")
  357.     ##########
  358.  
  359.  
  360.     #####subscribers
  361.     get_subscribers = _gen_getter("__subscribers")
  362.     def get_subscriptions_category(self, type):
  363.         return self.__subscribers.get_subscriptions(type)
  364.     #####
  365.     
  366.     get_lifecycle = _gen_getter("__lifecycle")
  367.     
  368.     get_related_bugs = _gen_getter("__related_bugs")
  369.  
  370.     get_overview = _gen_getter("__overview.text")
  371.     
  372.     get_full_spec = _gen_getter("__full_spec.url")
  373.     
  374.     get_mentors = _gen_getter("__mentors")
  375.     
  376.     get_whiteboard = _gen_getter("__whiteboard.text")
  377.     
  378.     get_feedback_request = _gen_getter("__feedback_request")
  379.     
  380.     def get_title(self):
  381.         x = self.xmldoc.xpathEval('//div[@class="main"]')
  382.         assert x
  383.         return x[0].content
  384.         
  385.     def get_spec(self):
  386.         return self.url.split("/").pop()
  387.         
  388.     def get_project(self):
  389.         x = self.xmldoc.xpathEval('//div[@class="intro"]')
  390.         assert x
  391.         return x[0].content.split("Blueprint for").pop().strip()
  392.