webAIInspector.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. """This is a web based inspector for the AI System. It can be accessed via
  2. http://hostname.domain:port/inspect
  3. The hostname.domain would of course be the computer that the AI is running on.
  4. The port will need to be defined when the instance is inited.
  5. """
  6. import string, time, direct, inspect
  7. from operator import itemgetter
  8. from direct.http import WebRequest
  9. from socket import gethostname
  10. from direct.task.Task import Task
  11. from sys import platform
  12. from pirates.uberdog.AIMagicWordTrade import AIMagicWordTrade
  13. from pirates.quest.QuestDB import QuestDict
  14. # Need to figure out which systeminfo module to import
  15. if platform == 'win32':
  16. from windowsSystemInfo import SystemInformation
  17. else:
  18. from linuxSystemInfo import SystemInformation
  19. class aiWebServer(SystemInformation):
  20. def __init__(self, air, listenPort=8080):
  21. SystemInformation.__init__(self)
  22. self.listenPort = listenPort
  23. self.air = simbase.air
  24. # self.taskMgr = Task.TaskManager()
  25. if __debug__:
  26. print "Listen port set to: %d" % self.listenPort
  27. # Start dispatcher
  28. self.web = WebRequest.WebRequestDispatcher()
  29. self.web.listenOnPort(self.listenPort)
  30. self.localHostName = gethostname()
  31. self.web.registerGETHandler('inspect', self.inspect)
  32. self.web.registerGETHandler('systemInfo', self.systemInfo)
  33. self.web.registerGETHandler('oMenu', self.oMenu)
  34. self.web.registerGETHandler('oType', self.oType)
  35. self.web.registerGETHandler('oInst', self.oInst)
  36. self.web.registerGETHandler('blank', self.blank)
  37. self.web.registerGETHandler('magicWord', self.magicWord)
  38. self.startCheckingIncomingHTTP()
  39. def magicWord(self, replyTo, **kw):
  40. # This will process Magic Word requests
  41. # Currently the following words are supported:
  42. # ~aiobjectcount
  43. # ~aitaskmgr
  44. # ~aijobmgr
  45. # ~assignQuest
  46. # ~money
  47. # First we need to figure out which magic word is being called
  48. try:
  49. theMagicWord = kw['magicWord']
  50. except KeyError:
  51. # MagicWord issue. Malformed URL
  52. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Magic Word Error</title>\n</head><body>Please check the URL. Transaction could not be completed. Malformed URL.</BODY>\n</HTML>')
  53. return
  54. # Next we execute the magic word request
  55. if theMagicWord == 'aiobjectcount':
  56. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>%s</title>\n</head><body><PRE>%s</PRE></body>\n</HTML>' % (theMagicWord, simbase.air.webPrintObjectCount()))
  57. return
  58. elif theMagicWord == 'aitaskmgr':
  59. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>%s</title>\n</head><body><PRE>%s</PRE></body>\n</HTML>' % (theMagicWord, taskMgr))
  60. return
  61. elif theMagicWord == 'aijobmgr':
  62. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>%s</title>\n</head><body><PRE>%s</PRE></body>\n</HTML>' % (theMagicWord, jobMgr))
  63. elif theMagicWord == 'money':
  64. # First, generate the Avatar HTML Select widget.
  65. selectWidget = self.genAvSelect()
  66. # Now that we've built the avatar list, we can repond with the HTML
  67. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Money</title>\n</head><body><form method="get" action="magicWord" name="magicWord">AvatarID: %s\nAmmount: <input maxlength="3" size="3" name="amount" value="100"><br><INPUT TYPE=HIDDEN NAME="magicWord" value="MONEY_ADD"><button value="Submit" name="Submit"></button><br></form></body>\n</HTML>' % selectWidget)
  68. elif theMagicWord == 'MONEY_ADD':
  69. av = kw['avatarId']
  70. count = kw['amount']
  71. try:
  72. av = int(av)
  73. count = int(count)
  74. except ValueError:
  75. # One or both of the two args could not be converted into a int
  76. # This being the case, the transaction mut be stopped.
  77. # The most likely cause is the input of a non num type into
  78. # the amount field
  79. print 'Incorrect value entered.'
  80. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Money Error</title>\n</head><body>Please check the Amount field. Transaction could not be completed.</BODY>\n</HTML>')
  81. return
  82. try:
  83. av = simbase.air.doId2do[av]
  84. except KeyError:
  85. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Money Error</title>\n</head><body>Please check the AvatarID field; the Avatar might have logged out. Transaction could not be completed.</BODY>\n</HTML>')
  86. return
  87. curGold = av.getInventory().getGoldInPocket()
  88. # print "Debug: Args being passed to AIMAgicWordTrade:\t%s" % av
  89. trade = AIMagicWordTrade(av, av.getDoId(), avatarId = av.getDoId())
  90. if count > curGold:
  91. trade.giveGoldInPocket(count - curGold)
  92. else:
  93. trade.takeGoldInPocket(curGold - count)
  94. trade.sendTrade()
  95. # I don't think I need to issue a tradeRejected or
  96. # tradeSucceesed call here.
  97. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Money Modified</title>\n</head><body>Transaction complete.</BODY>\n</HTML>')
  98. return
  99. elif theMagicWord == 'assignQuest':
  100. avSelectWidget = self.genAvSelect()
  101. questSelectWidget = self.genQuestSelect()
  102. # Present HTML menu with options
  103. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>AssignQuest</title>\n</head><body><form method="get" action="magicWord" name="magicWord">AvatarID: %s\nQuest to Assign: %s<br><INPUT TYPE=HIDDEN NAME="magicWord" value="QUEST_ADD"><button value="Submit" name="Submit"></button><br></form></body>\n</HTML>' % (avSelectWidget, questSelectWidget))
  104. elif theMagicWord == 'QUEST_ADD':
  105. av = kw['avatarId']
  106. av = int(av)
  107. questId = kw['questId']
  108. # print 'Avatarid = %s\nQuestID = %s' % (av, questId)
  109. try:
  110. av = simbase.air.doId2do[av]
  111. except KeyError:
  112. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Money Error</title>\n</head><body>Please check the AvatarID field; the Avatar might have logged out. Transaction could not be completed.</BODY>\n</HTML>')
  113. return
  114. av.assignQuest(questId)
  115. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Quest Assigned</title>\n</head><body>The avatar with id: %s<BR>Has been assigned Quest: %s</body>\n</HTML>' % (kw['avatarId'], questId))
  116. return
  117. else:
  118. # No word Matches
  119. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>No Word Matches</title>\n</head><body>The Magic word provided does not exist or is not accessable via the web interface at this time.</body>\n</HTML>')
  120. return
  121. def timeStamp(self):
  122. # Returns the local time in the following string format:
  123. # Month-Day-Year Hour:Minute:Seconds
  124. # Example: 09-17-2007 15:36:04
  125. return time.strftime("%m-%d-%Y %H:%M:%S", time.localtime())
  126. def oMenu(self, replyTo, **kw):
  127. # Menu listing Magic words and Raw object list (all HTML links)
  128. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Menu Options</title>\n</head><body>Magic Words:<BR><UL><LI><A HREF="magicWord?magicWord=money" TARGET="oInst">Money</a><LI><A HREF="magicWord?magicWord=assignQuest" TARGET="oInst">AssignQuest</A>\n<LI><A HREF="magicWord?magicWord=aijobmgr" TARGET="oInst">AIjobMgr</A>\n<LI><A HREF="magicWord?magicWord=aitaskmgr" TARGET="oInst">AITaskMgr</a><LI><A HREF="magicWord?magicWord=aiobjectcount" TARGET="oInst">AIObjectCount</A>\n</UL><P><A HREF="oType" TARGET="oType">Raw Object List</a></body>\n</HTML>')
  129. return
  130. def genAvSelect(self):
  131. # We will need to populate HTML FORM menus to make this work.
  132. # We will need to provide a list of Avatars on the AI
  133. # along with a field to allow an int value to be sent
  134. # First, we need to get a dict of DistributedPlayerPirateAI's
  135. playerPirates = []
  136. objList = self.generateSortedIDList()
  137. objList.reverse()
  138. while objList:
  139. tempObjElement = objList.pop()
  140. if str(tempObjElement[0]).find('DistributedPlayerPirateAI') != -1:
  141. playerPirates.append(tempObjElement[1])
  142. # OK, now playerPirates should be a list of avatar ids
  143. # We should build a HTML select widget with the new list
  144. selectWidget = '<select name="avatarId">\n'
  145. while playerPirates:
  146. selectWidget = '%s<option>%s</option>\n' % (selectWidget, str(playerPirates.pop()))
  147. selectWidget = '%s</select><br>\n' % selectWidget
  148. return selectWidget
  149. def genQuestSelect(self):
  150. # Will generate an HTML select widget, with the Key vals from the QuestDB
  151. selectWidget = '<select name="questId">\n'
  152. for k, v in QuestDict.iteritems():
  153. selectWidget = '%s<option>%s</option>\n' % (selectWidget, k)
  154. selectWidget = '%s</select><br>\n' % selectWidget
  155. return selectWidget
  156. def blank(self, replyTo, **kw):
  157. # This simple generates a blank page for the middle and right
  158. # frames;( for when the page is first accessed)
  159. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>Word not found</title>\n</head><body></body>\n</HTML>')
  160. def oInst(self, replyTo, **kw):
  161. # This will populate the middle frame with list of the members of
  162. # the object selected in the left frame
  163. #print "%s|oInst Frame Accessed, Request ID %s" % (self.timeStamp(), str(kw))
  164. head = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<title>member List</title>\n</head>\n<body>\n<UL>'
  165. foot = '</ul></body></HTML>'
  166. body = ''
  167. doIdRequested = ''
  168. for j, k in kw.iteritems():
  169. doIdRequested = int(k)
  170. #print j,k
  171. try:
  172. memberList = inspect.getmembers(simbase.air.doId2do[doIdRequested])
  173. except KeyError:
  174. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<TITLE>OBJ Gone</title>\n</head><body>The object is no longer on the system</body>\n</HTML>')
  175. return
  176. memberList.sort()
  177. memberList.reverse()
  178. while memberList:
  179. tempMember = memberList.pop()
  180. if (type(tempMember[1]) == str or type(tempMember[1]) == int or type(tempMember[1]) == float or type(tempMember[1]) == dict):
  181. body = '%s<LI>%s\n' % (body, str(tempMember))
  182. replyTo.respond('%s%s%s' % (head,body,foot))
  183. def oType(self, replyTo, **kw):
  184. # This will populate the left frame with a alpha sorted list of
  185. # objects.
  186. # print "%s|oType Frame Accessed" % self.timeStamp()
  187. head = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<title>Object List</title>\n</head>\n<body>\n<UL>'
  188. foot = '</ul></body></HTML>'
  189. objList = self.generateSortedIDList()
  190. # Need to sort objList by second col (the doid)
  191. objList = sorted(objList, key=itemgetter(1))
  192. objList.reverse()
  193. body = ''
  194. # Pop off the Null entry
  195. while objList:
  196. tempObjElement = objList.pop()
  197. # tempObjElement[0].replace('<','')
  198. # tempObjElement[0].replace('>','')
  199. # if str(tempObjElement[0]).find('render') == -1:
  200. body = '%s<LI><A HREF="oInst?id=%s" target="oInst">%s:%s</A>\n' % (body, tempObjElement[1], tempObjElement[1], str(tempObjElement[0]).replace('<','').replace('>',''))
  201. replyTo.respond('%s%s%s' % (head,body,foot))
  202. def inspect(self, replyTo, **kw):
  203. # This is the index. Basically, it will generate the frames for the
  204. # other functions to populate: systemInfo, oType, oInst, oAttrib
  205. # Three frames on the bottom row
  206. # frameset = '<frameset rows="35\%,65\%">\n<frame src="systemInfo" name="systemInfo" frameborder=1>\n<frameset cols="25\%,25\%,50\%">\n<frame src="oType" name="oType" frameborder=1>\n<frame src="blank" name="oInst" frameborder=1>\n<frame src="blank" name="oAttrib" frameborder=1>\n</frameset>\n</frameset>\n</html>'
  207. # Two Frames on the bottom row
  208. frameset = '<frameset rows="35\%,65\%">\n<frame src="systemInfo" name="systemInfo" frameborder=1>\n<frameset cols="50\%,50\%">\n<frame src="oMenu" name="oType" frameborder=1>\n<frame src="blank" name="oInst" frameborder=1>\n</frameset>\n</frameset>\n</html>'
  209. #print "%s|Index Frame Accessed" % self.timeStamp()
  210. # print str(simbase.air.doid2do)
  211. replyTo.respond('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">\n<html lang="en">\n<head>\n<title>AI HTTP Interface: %s</title>\n</head>\n%s' % (self.localHostName, frameset))
  212. def systemInfo(self, replyTo, **kw):
  213. # This is the contents of the top frame; i.e. system information
  214. self.refresh()
  215. #print "%s|SystemInfo Frame Accessed" % self.timeStamp()
  216. replyTo.respond('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n<head>\n<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">\n<title>System Info</title>\n</head>\n<body>\n<center><table style="text-align: left; width: 443px; height: 128px;" border="1" cellpadding="2" cellspacing="2">\n<tbody>\n<tr>\n<td style="text-align: center;" colspan="4">Hostname: %s<br>\nOperating System: %s<br>\nCPU: %s</td>\n</tr>\n<tr>\n<td>Total RAM:</td>\n<td>%d</td>\n<td>Total VM</td>\n<td>%d</td>\n</tr>\n<tr>\n<td>Available RAM:</td>\n<td>%d</td>\n<td>Available VM</td>\n<td>%d</td>\n</tr>\n</tbody>\n</table></center>\n</body>\n</html>' % (self.localHostName, self.os, self.cpu, self.totalRAM, self.totalVM, self.availableRAM, self.availableVM))
  217. def startCheckingIncomingHTTP(self):
  218. taskMgr.remove('pollHTTPTask')
  219. taskMgr.doMethodLater(0.3,self.pollHTTPTask,'pollHTTPTask')
  220. def stopCheckingIncomingHTTP(self):
  221. taskMgr.remove('pollHTTPTask')
  222. def pollHTTPTask(self,task):
  223. """
  224. Task that polls the HTTP server for new requests.
  225. """
  226. # print 'Polling...'
  227. self.web.poll()
  228. #taskMgr.doMethodLater(0.3,self.pollHTTPTask,'pollHTTPTask')
  229. return Task.again
  230. def generateSortedIDList(self):
  231. # looks at the simbase.air.doID2do dict, and returns a list
  232. # sorted by alpha order.
  233. IDlist = []
  234. for key, val in simbase.air.doId2do.iteritems():
  235. IDlist.append([val,key])
  236. IDlist.sort()
  237. return IDlist
  238. def inspectObject(anObject):
  239. inspector = inspectorFor(anObject)
  240. # inspectorWindow = InspectorWindow(inspector)
  241. # inspectorWindow.open()
  242. # return inspectorWindow
  243. return inspector
  244. ### private
  245. def inspectorFor(anObject):
  246. typeName = string.capitalize(type(anObject).__name__) + 'Type'
  247. if _InspectorMap.has_key(typeName):
  248. inspectorName = _InspectorMap[typeName]
  249. else:
  250. print "Can't find an inspector for " + typeName
  251. inspectorName = 'Inspector'
  252. inspector = eval(inspectorName + '(anObject)')
  253. return inspector
  254. def initializeInspectorMap():
  255. global _InspectorMap
  256. notFinishedTypes = ['BufferType', 'EllipsisType', 'FrameType', 'TracebackType', 'XRangeType']
  257. _InspectorMap = {
  258. 'Builtin_function_or_methodType': 'FunctionInspector',
  259. 'BuiltinFunctionType': 'FunctionInspector',
  260. 'BuiltinMethodType': 'FunctionInspector',
  261. 'ClassType': 'ClassInspector',
  262. 'CodeType': 'CodeInspector',
  263. 'ComplexType': 'Inspector',
  264. 'DictionaryType': 'DictionaryInspector',
  265. 'DictType': 'DictionaryInspector',
  266. 'FileType': 'Inspector',
  267. 'FloatType': 'Inspector',
  268. 'FunctionType': 'FunctionInspector',
  269. 'Instance methodType': 'InstanceMethodInspector',
  270. 'InstanceType': 'InstanceInspector',
  271. 'IntType': 'Inspector',
  272. 'LambdaType': 'Inspector',
  273. 'ListType': 'SequenceInspector',
  274. 'LongType': 'Inspector',
  275. 'MethodType': 'FunctionInspector',
  276. 'ModuleType': 'ModuleInspector',
  277. 'NoneType': 'Inspector',
  278. 'SliceType': 'SliceInspector',
  279. 'StringType': 'SequenceInspector',
  280. 'TupleType': 'SequenceInspector',
  281. 'TypeType': 'Inspector',
  282. 'UnboundMethodType': 'FunctionInspector',
  283. 'DistributedshipcannonaiType': 'ClassInspector'}
  284. for each in notFinishedTypes:
  285. _InspectorMap[each] = 'Inspector'
  286. class Inspector:
  287. def __init__(self, anObject):
  288. self.object = anObject
  289. self.lastPartNumber = 0
  290. self.initializePartsList()
  291. self.initializePartNames()
  292. def __str__(self):
  293. return __name__ + '(' + str(self.object) + ')'
  294. def initializePartsList(self):
  295. self._partsList = []
  296. keys = self.namedParts()
  297. keys.sort()
  298. for each in keys:
  299. self._partsList.append(each)
  300. #if not callable(eval('self.object.' + each)):
  301. # self._partsList.append(each)
  302. def initializePartNames(self):
  303. self._partNames = ['up'] + map(lambda each: str(each), self._partsList)
  304. def title(self):
  305. "Subclasses may override."
  306. return string.capitalize(self.objectType().__name__)
  307. def getLastPartNumber(self):
  308. return self.lastPartNumber
  309. def selectedPart(self):
  310. return self.partNumber(self.getLastPartNumber())
  311. def namedParts(self):
  312. return dir(self.object)
  313. def stringForPartNumber(self, partNumber):
  314. object = self.partNumber(partNumber)
  315. doc = None
  316. if callable(object):
  317. try:
  318. doc = object.__doc__
  319. except:
  320. pass
  321. if doc:
  322. return (str(object) + '\n' + str(doc))
  323. else:
  324. return str(object)
  325. def partNumber(self, partNumber):
  326. self.lastPartNumber = partNumber
  327. if partNumber == 0:
  328. return self.object
  329. else:
  330. part = self.privatePartNumber(partNumber)
  331. return eval('self.object.' + part)
  332. def inspectorFor(self, part):
  333. return inspectorFor(part)
  334. def privatePartNumber(self, partNumber):
  335. return self._partsList[partNumber - 1]
  336. def partNames(self):
  337. return self._partNames
  338. def objectType(self):
  339. return type(self.object)
  340. ###
  341. class ModuleInspector(Inspector):
  342. def namedParts(self):
  343. return ['__dict__']
  344. class ClassInspector(Inspector):
  345. def namedParts(self):
  346. return ['__bases__'] + self.object.__dict__.keys()
  347. def title(self):
  348. return self.object.__name__ + ' Class'
  349. class InstanceInspector(Inspector):
  350. def title(self):
  351. return self.object.__class__.__name__
  352. def namedParts(self):
  353. return ['__class__'] + dir(self.object)
  354. ###
  355. class FunctionInspector(Inspector):
  356. def title(self):
  357. return self.object.__name__ + "()"
  358. class InstanceMethodInspector(Inspector):
  359. def title(self):
  360. return str(self.object.im_class) + "." + self.object.__name__ + "()"
  361. class CodeInspector(Inspector):
  362. def title(self):
  363. return str(self.object)
  364. ###
  365. class ComplexInspector(Inspector):
  366. def namedParts(self):
  367. return ['real', 'imag']
  368. ###
  369. class DictionaryInspector(Inspector):
  370. def initializePartsList(self):
  371. Inspector.initializePartsList(self)
  372. keys = self.object.keys()
  373. keys.sort()
  374. for each in keys:
  375. self._partsList.append(each)
  376. def partNumber(self, partNumber):
  377. self.lastPartNumber = partNumber
  378. if partNumber == 0:
  379. return self.object
  380. key = self.privatePartNumber(partNumber)
  381. if self.object.has_key(key):
  382. return self.object[key]
  383. else:
  384. return eval('self.object.' + key)
  385. class SequenceInspector(Inspector):
  386. def initializePartsList(self):
  387. Inspector.initializePartsList(self)
  388. for each in range(len(self.object)):
  389. self._partsList.append(each)
  390. def partNumber(self, partNumber):
  391. self.lastPartNumber = partNumber
  392. if partNumber == 0:
  393. return self.object
  394. index = self.privatePartNumber(partNumber)
  395. if type(index) == IntType:
  396. return self.object[index]
  397. else:
  398. return eval('self.object.' + index)
  399. class SliceInspector(Inspector):
  400. def namedParts(self):
  401. return ['start', 'stop', 'step']
  402. ### Initialization
  403. initializeInspectorMap()