| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- """This is a web based inspector for the AI System. It can be accessed via
- http://hostname.domain:port/inspect
- The hostname.domain would of course be the computer that the AI is running on.
- The port will need to be defined when the instance is inited.
- """
- import string, time, direct, inspect
- from operator import itemgetter
- from direct.http import WebRequest
- from socket import gethostname
- from direct.task.Task import Task
- from sys import platform
- from pirates.uberdog.AIMagicWordTrade import AIMagicWordTrade
- from pirates.quest.QuestDB import QuestDict
- # Need to figure out which systeminfo module to import
- if platform == 'win32':
- from windowsSystemInfo import SystemInformation
- else:
- from linuxSystemInfo import SystemInformation
- class aiWebServer(SystemInformation):
- def __init__(self, air, listenPort=8080):
- SystemInformation.__init__(self)
- self.listenPort = listenPort
- self.air = simbase.air
- # self.taskMgr = Task.TaskManager()
- if __debug__:
- print "Listen port set to: %d" % self.listenPort
- # Start dispatcher
- self.web = WebRequest.WebRequestDispatcher()
- self.web.listenOnPort(self.listenPort)
- self.localHostName = gethostname()
- self.web.registerGETHandler('inspect', self.inspect)
- self.web.registerGETHandler('systemInfo', self.systemInfo)
- self.web.registerGETHandler('oMenu', self.oMenu)
- self.web.registerGETHandler('oType', self.oType)
- self.web.registerGETHandler('oInst', self.oInst)
- self.web.registerGETHandler('blank', self.blank)
- self.web.registerGETHandler('magicWord', self.magicWord)
- self.startCheckingIncomingHTTP()
- def magicWord(self, replyTo, **kw):
- # This will process Magic Word requests
- # Currently the following words are supported:
- # ~aiobjectcount
- # ~aitaskmgr
- # ~aijobmgr
- # ~assignQuest
- # ~money
-
- # First we need to figure out which magic word is being called
- try:
- theMagicWord = kw['magicWord']
- except KeyError:
- # MagicWord issue. Malformed URL
- 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>')
- return
- # Next we execute the magic word request
- if theMagicWord == 'aiobjectcount':
- 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()))
- return
- elif theMagicWord == 'aitaskmgr':
- 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))
- return
- elif theMagicWord == 'aijobmgr':
- 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))
- elif theMagicWord == 'money':
- # First, generate the Avatar HTML Select widget.
-
- selectWidget = self.genAvSelect()
- # Now that we've built the avatar list, we can repond with the HTML
- 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)
- elif theMagicWord == 'MONEY_ADD':
- av = kw['avatarId']
- count = kw['amount']
- try:
- av = int(av)
- count = int(count)
- except ValueError:
- # One or both of the two args could not be converted into a int
- # This being the case, the transaction mut be stopped.
- # The most likely cause is the input of a non num type into
- # the amount field
-
- print 'Incorrect value entered.'
- 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>')
- return
-
- try:
- av = simbase.air.doId2do[av]
- except KeyError:
- 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>')
- return
- curGold = av.getInventory().getGoldInPocket()
- # print "Debug: Args being passed to AIMAgicWordTrade:\t%s" % av
- trade = AIMagicWordTrade(av, av.getDoId(), avatarId = av.getDoId())
- if count > curGold:
- trade.giveGoldInPocket(count - curGold)
- else:
- trade.takeGoldInPocket(curGold - count)
- trade.sendTrade()
- # I don't think I need to issue a tradeRejected or
- # tradeSucceesed call here.
- 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>')
- return
- elif theMagicWord == 'assignQuest':
- avSelectWidget = self.genAvSelect()
- questSelectWidget = self.genQuestSelect()
- # Present HTML menu with options
- 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))
- elif theMagicWord == 'QUEST_ADD':
- av = kw['avatarId']
- av = int(av)
- questId = kw['questId']
- # print 'Avatarid = %s\nQuestID = %s' % (av, questId)
- try:
- av = simbase.air.doId2do[av]
- except KeyError:
- 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>')
- return
- av.assignQuest(questId)
- 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))
- return
- else:
- # No word Matches
- 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>')
- return
- def timeStamp(self):
- # Returns the local time in the following string format:
- # Month-Day-Year Hour:Minute:Seconds
- # Example: 09-17-2007 15:36:04
- return time.strftime("%m-%d-%Y %H:%M:%S", time.localtime())
- def oMenu(self, replyTo, **kw):
- # Menu listing Magic words and Raw object list (all HTML links)
- 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>')
- return
- def genAvSelect(self):
- # We will need to populate HTML FORM menus to make this work.
- # We will need to provide a list of Avatars on the AI
- # along with a field to allow an int value to be sent
- # First, we need to get a dict of DistributedPlayerPirateAI's
- playerPirates = []
- objList = self.generateSortedIDList()
- objList.reverse()
- while objList:
- tempObjElement = objList.pop()
- if str(tempObjElement[0]).find('DistributedPlayerPirateAI') != -1:
- playerPirates.append(tempObjElement[1])
- # OK, now playerPirates should be a list of avatar ids
- # We should build a HTML select widget with the new list
- selectWidget = '<select name="avatarId">\n'
- while playerPirates:
- selectWidget = '%s<option>%s</option>\n' % (selectWidget, str(playerPirates.pop()))
- selectWidget = '%s</select><br>\n' % selectWidget
- return selectWidget
- def genQuestSelect(self):
- # Will generate an HTML select widget, with the Key vals from the QuestDB
- selectWidget = '<select name="questId">\n'
- for k, v in QuestDict.iteritems():
- selectWidget = '%s<option>%s</option>\n' % (selectWidget, k)
- selectWidget = '%s</select><br>\n' % selectWidget
- return selectWidget
- def blank(self, replyTo, **kw):
- # This simple generates a blank page for the middle and right
- # frames;( for when the page is first accessed)
- 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>')
- def oInst(self, replyTo, **kw):
- # This will populate the middle frame with list of the members of
- # the object selected in the left frame
- #print "%s|oInst Frame Accessed, Request ID %s" % (self.timeStamp(), str(kw))
-
- 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>'
- foot = '</ul></body></HTML>'
- body = ''
- doIdRequested = ''
- for j, k in kw.iteritems():
- doIdRequested = int(k)
- #print j,k
- try:
- memberList = inspect.getmembers(simbase.air.doId2do[doIdRequested])
- except KeyError:
- 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>')
- return
- memberList.sort()
- memberList.reverse()
- while memberList:
- tempMember = memberList.pop()
- if (type(tempMember[1]) == str or type(tempMember[1]) == int or type(tempMember[1]) == float or type(tempMember[1]) == dict):
- body = '%s<LI>%s\n' % (body, str(tempMember))
- replyTo.respond('%s%s%s' % (head,body,foot))
-
- def oType(self, replyTo, **kw):
- # This will populate the left frame with a alpha sorted list of
- # objects.
- # print "%s|oType Frame Accessed" % self.timeStamp()
- 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>'
- foot = '</ul></body></HTML>'
- objList = self.generateSortedIDList()
- # Need to sort objList by second col (the doid)
- objList = sorted(objList, key=itemgetter(1))
- objList.reverse()
- body = ''
- # Pop off the Null entry
- while objList:
- tempObjElement = objList.pop()
- # tempObjElement[0].replace('<','')
- # tempObjElement[0].replace('>','')
- # if str(tempObjElement[0]).find('render') == -1:
- body = '%s<LI><A HREF="oInst?id=%s" target="oInst">%s:%s</A>\n' % (body, tempObjElement[1], tempObjElement[1], str(tempObjElement[0]).replace('<','').replace('>',''))
- replyTo.respond('%s%s%s' % (head,body,foot))
- def inspect(self, replyTo, **kw):
- # This is the index. Basically, it will generate the frames for the
- # other functions to populate: systemInfo, oType, oInst, oAttrib
- # Three frames on the bottom row
- # 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>'
- # Two Frames on the bottom row
- 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>'
- #print "%s|Index Frame Accessed" % self.timeStamp()
- # print str(simbase.air.doid2do)
- 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))
- def systemInfo(self, replyTo, **kw):
- # This is the contents of the top frame; i.e. system information
- self.refresh()
- #print "%s|SystemInfo Frame Accessed" % self.timeStamp()
- 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))
- def startCheckingIncomingHTTP(self):
- taskMgr.remove('pollHTTPTask')
- taskMgr.doMethodLater(0.3,self.pollHTTPTask,'pollHTTPTask')
- def stopCheckingIncomingHTTP(self):
- taskMgr.remove('pollHTTPTask')
- def pollHTTPTask(self,task):
- """
- Task that polls the HTTP server for new requests.
- """
- # print 'Polling...'
- self.web.poll()
- #taskMgr.doMethodLater(0.3,self.pollHTTPTask,'pollHTTPTask')
- return Task.again
- def generateSortedIDList(self):
- # looks at the simbase.air.doID2do dict, and returns a list
- # sorted by alpha order.
- IDlist = []
- for key, val in simbase.air.doId2do.iteritems():
- IDlist.append([val,key])
- IDlist.sort()
- return IDlist
- def inspectObject(anObject):
- inspector = inspectorFor(anObject)
- # inspectorWindow = InspectorWindow(inspector)
- # inspectorWindow.open()
- # return inspectorWindow
- return inspector
- ### private
- def inspectorFor(anObject):
- typeName = string.capitalize(type(anObject).__name__) + 'Type'
- if _InspectorMap.has_key(typeName):
- inspectorName = _InspectorMap[typeName]
- else:
- print "Can't find an inspector for " + typeName
- inspectorName = 'Inspector'
- inspector = eval(inspectorName + '(anObject)')
- return inspector
- def initializeInspectorMap():
- global _InspectorMap
- notFinishedTypes = ['BufferType', 'EllipsisType', 'FrameType', 'TracebackType', 'XRangeType']
- _InspectorMap = {
- 'Builtin_function_or_methodType': 'FunctionInspector',
- 'BuiltinFunctionType': 'FunctionInspector',
- 'BuiltinMethodType': 'FunctionInspector',
- 'ClassType': 'ClassInspector',
- 'CodeType': 'CodeInspector',
- 'ComplexType': 'Inspector',
- 'DictionaryType': 'DictionaryInspector',
- 'DictType': 'DictionaryInspector',
- 'FileType': 'Inspector',
- 'FloatType': 'Inspector',
- 'FunctionType': 'FunctionInspector',
- 'Instance methodType': 'InstanceMethodInspector',
- 'InstanceType': 'InstanceInspector',
- 'IntType': 'Inspector',
- 'LambdaType': 'Inspector',
- 'ListType': 'SequenceInspector',
- 'LongType': 'Inspector',
- 'MethodType': 'FunctionInspector',
- 'ModuleType': 'ModuleInspector',
- 'NoneType': 'Inspector',
- 'SliceType': 'SliceInspector',
- 'StringType': 'SequenceInspector',
- 'TupleType': 'SequenceInspector',
- 'TypeType': 'Inspector',
- 'UnboundMethodType': 'FunctionInspector',
- 'DistributedshipcannonaiType': 'ClassInspector'}
- for each in notFinishedTypes:
- _InspectorMap[each] = 'Inspector'
- class Inspector:
- def __init__(self, anObject):
- self.object = anObject
- self.lastPartNumber = 0
- self.initializePartsList()
- self.initializePartNames()
- def __str__(self):
- return __name__ + '(' + str(self.object) + ')'
- def initializePartsList(self):
- self._partsList = []
- keys = self.namedParts()
- keys.sort()
- for each in keys:
- self._partsList.append(each)
- #if not callable(eval('self.object.' + each)):
- # self._partsList.append(each)
- def initializePartNames(self):
- self._partNames = ['up'] + map(lambda each: str(each), self._partsList)
- def title(self):
- "Subclasses may override."
- return string.capitalize(self.objectType().__name__)
- def getLastPartNumber(self):
- return self.lastPartNumber
- def selectedPart(self):
- return self.partNumber(self.getLastPartNumber())
-
- def namedParts(self):
- return dir(self.object)
- def stringForPartNumber(self, partNumber):
- object = self.partNumber(partNumber)
- doc = None
- if callable(object):
- try:
- doc = object.__doc__
- except:
- pass
- if doc:
- return (str(object) + '\n' + str(doc))
- else:
- return str(object)
- def partNumber(self, partNumber):
- self.lastPartNumber = partNumber
- if partNumber == 0:
- return self.object
- else:
- part = self.privatePartNumber(partNumber)
- return eval('self.object.' + part)
- def inspectorFor(self, part):
- return inspectorFor(part)
- def privatePartNumber(self, partNumber):
- return self._partsList[partNumber - 1]
- def partNames(self):
- return self._partNames
-
- def objectType(self):
- return type(self.object)
- ###
-
- class ModuleInspector(Inspector):
- def namedParts(self):
- return ['__dict__']
- class ClassInspector(Inspector):
- def namedParts(self):
- return ['__bases__'] + self.object.__dict__.keys()
- def title(self):
- return self.object.__name__ + ' Class'
- class InstanceInspector(Inspector):
- def title(self):
- return self.object.__class__.__name__
- def namedParts(self):
- return ['__class__'] + dir(self.object)
- ###
-
- class FunctionInspector(Inspector):
- def title(self):
- return self.object.__name__ + "()"
- class InstanceMethodInspector(Inspector):
- def title(self):
- return str(self.object.im_class) + "." + self.object.__name__ + "()"
- class CodeInspector(Inspector):
- def title(self):
- return str(self.object)
- ###
- class ComplexInspector(Inspector):
- def namedParts(self):
- return ['real', 'imag']
- ###
- class DictionaryInspector(Inspector):
- def initializePartsList(self):
- Inspector.initializePartsList(self)
- keys = self.object.keys()
- keys.sort()
- for each in keys:
- self._partsList.append(each)
- def partNumber(self, partNumber):
- self.lastPartNumber = partNumber
- if partNumber == 0:
- return self.object
- key = self.privatePartNumber(partNumber)
- if self.object.has_key(key):
- return self.object[key]
- else:
- return eval('self.object.' + key)
-
- class SequenceInspector(Inspector):
- def initializePartsList(self):
- Inspector.initializePartsList(self)
- for each in range(len(self.object)):
- self._partsList.append(each)
- def partNumber(self, partNumber):
- self.lastPartNumber = partNumber
- if partNumber == 0:
- return self.object
- index = self.privatePartNumber(partNumber)
- if type(index) == IntType:
- return self.object[index]
- else:
- return eval('self.object.' + index)
-
- class SliceInspector(Inspector):
- def namedParts(self):
- return ['start', 'stop', 'step']
- ### Initialization
- initializeInspectorMap()
|