remove debugging line; handle case where record has no researchers
[sface.git] / sface / xmlrpcwindow.py
1 import re
2 from lxml import etree
3 from PyQt4.QtXml import QDomDocument
4 from sface.xmlwidget import XmlWindow, DomModel
5
6 class XmlrpcReader():
7     def __init__(self):
8         self.rawOutput = None
9         self.responses = []
10
11     def getAndPrint(self, rawOutput):
12         self.store(rawOutput)
13         self.extractXml()
14         self.xmlrpcWindow.setData(self.xml)
15         if self.xml != "<debug></debug>":
16             # only popup the window if we have something to show
17             self.showXmlrpc()
18
19     def store(self, rawOutput):
20         self.rawOutput = rawOutput
21
22     def parseMethodResponse(self, mr):
23         mr = str(mr) # PyQT supplies a QByteArray; make it a string
24
25         response = {"kind": "unknown"}
26
27         try:
28             tree = etree.fromstring(mr)
29         except etree.XMLSyntaxError, e:
30             print "failed to parse XML response", str(e)
31             #file("badparse.xml","w").write(mr)
32             return response
33
34         if tree.tag != "methodResponse" or (len(list(tree))==0):
35             return response
36
37         # a fault should look like:
38         #     kind: "fault"
39         #     faultCode: "102"
40         #     faultString: "Register: Missing authority..."
41
42         faults = tree.xpath("//methodResponse/fault")
43         for fault in faults:
44             response["kind"] = "fault"
45             structs = fault.xpath("value/struct")
46             for struct in structs:
47                 members = struct.xpath("member")
48                 for member in members:
49                     names = member.xpath("name")
50                     values = member.xpath("value")
51                     if (names) and (values):
52                         name = names[0]
53                         value = values[0]
54                         if len(list(value))>0:
55                             data = list(value)[0]
56                             response[name.text] = data.text
57             # once we have the first fault, return
58             return response
59
60         # whatever didn't fault must have succeeded?
61         response["kind"] = "success"
62
63         return response
64
65     def extractXml(self):
66         pttrnAsk = '<methodCall>.*?</methodCall>'
67         pttrnAns = '<methodResponse>.*?</methodResponse>'
68         answers = re.compile(pttrnAsk, re.DOTALL).findall(self.rawOutput)
69         replies = re.compile(pttrnAns, re.DOTALL).findall(self.rawOutput)
70         # cleaning
71         answers = [ x.replace('\\n','\n') for x in answers ]
72         replies = [ x.replace('\\n','\n').replace("'\nbody: '", '').replace("\"\nbody: '", '') for x in replies ]
73         replies.reverse() # so that I use pop() as popleft
74         # A well-formed XML document must have one, and only one, top-level element
75
76         self.responses = []
77
78         self.xml = ""
79         for ans in answers:
80             self.xml += ans
81             # we could have less responses than calls, so guard the pop
82             if replies:
83                 replyXml = replies.pop()
84                 self.xml += replyXml
85                 self.responses.append(self.parseMethodResponse(replyXml))
86
87         # just in case somehow we ended up with more responses than calls
88         while replies:
89             replyXml = replies.pop()
90             self.xml += replyXml
91             self.responses.append(self.parseMethodResponse(replyXml))
92
93         return self.xml
94
95     def stats(self):
96         # statistics: round-trip time, size of the com
97         pass
98
99 class XmlrpcTracker(XmlrpcReader):
100     def __init__(self):
101         XmlrpcReader.__init__(self)
102         self.xmlrpcWindow = XmlrpcWindow()
103
104     def getAndPrint(self, rawOutput):
105         self.store(rawOutput)
106         self.extractXml()
107         self.xmlrpcWindow.setData(self.xml)
108         if self.xml != "<debug></debug>":
109             # only popup the window if we have something to show
110             self.showXmlrpc()
111
112     def showXmlrpc(self):
113         self.xmlrpcWindow.show()
114         self.xmlrpcWindow.resize(500, 640)
115         self.xmlrpcWindow.raise_()
116         self.xmlrpcWindow.activateWindow()
117
118     def extractXml(self):
119         self.xml = "<debug>" + XmlrpcReader.extractXml(self) + "</debug>"
120
121 class XmlrpcWindow(XmlWindow):
122     def __init__(self, parent=None):
123         # super __init__() calls updateView,
124         # which assumes you have some data
125         self.data = '<debug/>'
126         XmlWindow.__init__(self, parent, 'XMLRPC window')
127
128     def setData(self, XmlrpcCom):
129         self.data = XmlrpcCom
130
131     def updateView(self):
132         XmlWindow.updateView(self)
133
134         self.document.setContent(self.data)