Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

browser.py 13KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. # basic module browser.
  2. # usage:
  3. # >>> import browser
  4. # >>> browser.Browse()
  5. # or
  6. # >>> browser.Browse(your_module)
  7. import sys
  8. import types
  9. import __main__
  10. import win32ui
  11. from pywin.mfc import dialog
  12. from . import hierlist
  13. special_names = ["__doc__", "__name__", "__self__"]
  14. #
  15. # HierList items
  16. class HLIPythonObject(hierlist.HierListItem):
  17. def __init__(self, myobject=None, name=None):
  18. hierlist.HierListItem.__init__(self)
  19. self.myobject = myobject
  20. self.knownExpandable = None
  21. if name:
  22. self.name = name
  23. else:
  24. try:
  25. self.name = myobject.__name__
  26. except (AttributeError, TypeError):
  27. try:
  28. r = repr(myobject)
  29. if len(r) > 20:
  30. r = r[:20] + "..."
  31. self.name = r
  32. except (AttributeError, TypeError):
  33. self.name = "???"
  34. def __lt__(self, other):
  35. return self.name < other.name
  36. def __eq__(self, other):
  37. return self.name == other.name
  38. def __repr__(self):
  39. try:
  40. type = self.GetHLIType()
  41. except:
  42. type = "Generic"
  43. return (
  44. "HLIPythonObject("
  45. + type
  46. + ") - name: "
  47. + self.name
  48. + " object: "
  49. + repr(self.myobject)
  50. )
  51. def GetText(self):
  52. try:
  53. return str(self.name) + " (" + self.GetHLIType() + ")"
  54. except AttributeError:
  55. return str(self.name) + " = " + repr(self.myobject)
  56. def InsertDocString(self, lst):
  57. ob = None
  58. try:
  59. ob = self.myobject.__doc__
  60. except (AttributeError, TypeError):
  61. pass
  62. # I don't quite grok descriptors enough to know how to
  63. # best hook them up. Eg:
  64. # >>> object.__getattribute__.__class__.__doc__
  65. # <attribute '__doc__' of 'wrapper_descriptor' objects>
  66. if ob and isinstance(ob, str):
  67. lst.insert(0, HLIDocString(ob, "Doc"))
  68. def GetSubList(self):
  69. ret = []
  70. try:
  71. for key, ob in self.myobject.__dict__.items():
  72. if key not in special_names:
  73. ret.append(MakeHLI(ob, key))
  74. except (AttributeError, TypeError):
  75. pass
  76. try:
  77. for name in self.myobject.__methods__:
  78. ret.append(HLIMethod(name)) # no MakeHLI, as cant auto detect
  79. except (AttributeError, TypeError):
  80. pass
  81. try:
  82. for member in self.myobject.__members__:
  83. if not member in special_names:
  84. ret.append(MakeHLI(getattr(self.myobject, member), member))
  85. except (AttributeError, TypeError):
  86. pass
  87. ret.sort()
  88. self.InsertDocString(ret)
  89. return ret
  90. # if the has a dict, it is expandable.
  91. def IsExpandable(self):
  92. if self.knownExpandable is None:
  93. self.knownExpandable = self.CalculateIsExpandable()
  94. return self.knownExpandable
  95. def CalculateIsExpandable(self):
  96. if hasattr(self.myobject, "__doc__"):
  97. return 1
  98. try:
  99. for key in self.myobject.__dict__.keys():
  100. if key not in special_names:
  101. return 1
  102. except (AttributeError, TypeError):
  103. pass
  104. try:
  105. self.myobject.__methods__
  106. return 1
  107. except (AttributeError, TypeError):
  108. pass
  109. try:
  110. for item in self.myobject.__members__:
  111. if item not in special_names:
  112. return 1
  113. except (AttributeError, TypeError):
  114. pass
  115. return 0
  116. def GetBitmapColumn(self):
  117. if self.IsExpandable():
  118. return 0
  119. else:
  120. return 4
  121. def TakeDefaultAction(self):
  122. ShowObject(self.myobject, self.name)
  123. class HLIDocString(HLIPythonObject):
  124. def GetHLIType(self):
  125. return "DocString"
  126. def GetText(self):
  127. return self.myobject.strip()
  128. def IsExpandable(self):
  129. return 0
  130. def GetBitmapColumn(self):
  131. return 6
  132. class HLIModule(HLIPythonObject):
  133. def GetHLIType(self):
  134. return "Module"
  135. class HLIFrame(HLIPythonObject):
  136. def GetHLIType(self):
  137. return "Stack Frame"
  138. class HLITraceback(HLIPythonObject):
  139. def GetHLIType(self):
  140. return "Traceback"
  141. class HLIClass(HLIPythonObject):
  142. def GetHLIType(self):
  143. return "Class"
  144. def GetSubList(self):
  145. ret = []
  146. for base in self.myobject.__bases__:
  147. ret.append(MakeHLI(base, "Base class: " + base.__name__))
  148. ret = ret + HLIPythonObject.GetSubList(self)
  149. return ret
  150. class HLIMethod(HLIPythonObject):
  151. # myobject is just a string for methods.
  152. def GetHLIType(self):
  153. return "Method"
  154. def GetText(self):
  155. return "Method: " + self.myobject + "()"
  156. class HLICode(HLIPythonObject):
  157. def GetHLIType(self):
  158. return "Code"
  159. def IsExpandable(self):
  160. return self.myobject
  161. def GetSubList(self):
  162. ret = []
  163. ret.append(MakeHLI(self.myobject.co_consts, "Constants (co_consts)"))
  164. ret.append(MakeHLI(self.myobject.co_names, "Names (co_names)"))
  165. ret.append(MakeHLI(self.myobject.co_filename, "Filename (co_filename)"))
  166. ret.append(MakeHLI(self.myobject.co_argcount, "Number of args (co_argcount)"))
  167. ret.append(MakeHLI(self.myobject.co_varnames, "Param names (co_varnames)"))
  168. return ret
  169. class HLIInstance(HLIPythonObject):
  170. def GetHLIType(self):
  171. return "Instance"
  172. def GetText(self):
  173. return (
  174. str(self.name)
  175. + " (Instance of class "
  176. + str(self.myobject.__class__.__name__)
  177. + ")"
  178. )
  179. def IsExpandable(self):
  180. return 1
  181. def GetSubList(self):
  182. ret = []
  183. ret.append(MakeHLI(self.myobject.__class__))
  184. ret = ret + HLIPythonObject.GetSubList(self)
  185. return ret
  186. class HLIBuiltinFunction(HLIPythonObject):
  187. def GetHLIType(self):
  188. return "Builtin Function"
  189. class HLIFunction(HLIPythonObject):
  190. def GetHLIType(self):
  191. return "Function"
  192. def IsExpandable(self):
  193. return 1
  194. def GetSubList(self):
  195. ret = []
  196. # ret.append( MakeHLI( self.myobject.func_argcount, "Arg Count" ))
  197. try:
  198. ret.append(MakeHLI(self.myobject.func_argdefs, "Arg Defs"))
  199. except AttributeError:
  200. pass
  201. try:
  202. code = self.myobject.__code__
  203. globs = self.myobject.__globals__
  204. except AttributeError:
  205. # must be py2.5 or earlier...
  206. code = self.myobject.func_code
  207. globs = self.myobject.func_globals
  208. ret.append(MakeHLI(code, "Code"))
  209. ret.append(MakeHLI(globs, "Globals"))
  210. self.InsertDocString(ret)
  211. return ret
  212. class HLISeq(HLIPythonObject):
  213. def GetHLIType(self):
  214. return "Sequence (abstract!)"
  215. def IsExpandable(self):
  216. return len(self.myobject) > 0
  217. def GetSubList(self):
  218. ret = []
  219. pos = 0
  220. for item in self.myobject:
  221. ret.append(MakeHLI(item, "[" + str(pos) + "]"))
  222. pos = pos + 1
  223. self.InsertDocString(ret)
  224. return ret
  225. class HLIList(HLISeq):
  226. def GetHLIType(self):
  227. return "List"
  228. class HLITuple(HLISeq):
  229. def GetHLIType(self):
  230. return "Tuple"
  231. class HLIDict(HLIPythonObject):
  232. def GetHLIType(self):
  233. return "Dict"
  234. def IsExpandable(self):
  235. try:
  236. self.myobject.__doc__
  237. return 1
  238. except (AttributeError, TypeError):
  239. return len(self.myobject) > 0
  240. def GetSubList(self):
  241. ret = []
  242. keys = list(self.myobject.keys())
  243. keys.sort()
  244. for key in keys:
  245. ob = self.myobject[key]
  246. ret.append(MakeHLI(ob, str(key)))
  247. self.InsertDocString(ret)
  248. return ret
  249. # In Python 1.6, strings and Unicode have builtin methods, but we dont really want to see these
  250. class HLIString(HLIPythonObject):
  251. def IsExpandable(self):
  252. return 0
  253. TypeMap = {
  254. type: HLIClass,
  255. types.FunctionType: HLIFunction,
  256. tuple: HLITuple,
  257. dict: HLIDict,
  258. list: HLIList,
  259. types.ModuleType: HLIModule,
  260. types.CodeType: HLICode,
  261. types.BuiltinFunctionType: HLIBuiltinFunction,
  262. types.FrameType: HLIFrame,
  263. types.TracebackType: HLITraceback,
  264. str: HLIString,
  265. int: HLIPythonObject,
  266. bool: HLIPythonObject,
  267. float: HLIPythonObject,
  268. }
  269. def MakeHLI(ob, name=None):
  270. try:
  271. cls = TypeMap[type(ob)]
  272. except KeyError:
  273. # hrmph - this check gets more and more bogus as Python
  274. # improves. Its possible we should just *always* use
  275. # HLIInstance?
  276. if hasattr(ob, "__class__"): # 'new style' class
  277. cls = HLIInstance
  278. else:
  279. cls = HLIPythonObject
  280. return cls(ob, name)
  281. #########################################
  282. #
  283. # Dialog related.
  284. class DialogShowObject(dialog.Dialog):
  285. def __init__(self, object, title):
  286. self.object = object
  287. self.title = title
  288. dialog.Dialog.__init__(self, win32ui.IDD_LARGE_EDIT)
  289. def OnInitDialog(self):
  290. import re
  291. self.SetWindowText(self.title)
  292. self.edit = self.GetDlgItem(win32ui.IDC_EDIT1)
  293. try:
  294. strval = str(self.object)
  295. except:
  296. t, v, tb = sys.exc_info()
  297. strval = "Exception getting object value\n\n%s:%s" % (t, v)
  298. tb = None
  299. strval = re.sub("\n", "\r\n", strval)
  300. self.edit.ReplaceSel(strval)
  301. def ShowObject(object, title):
  302. dlg = DialogShowObject(object, title)
  303. dlg.DoModal()
  304. # And some mods for a sizable dialog from Sam Rushing!
  305. import commctrl
  306. import win32api
  307. import win32con
  308. class dynamic_browser(dialog.Dialog):
  309. style = win32con.WS_OVERLAPPEDWINDOW | win32con.WS_VISIBLE
  310. cs = (
  311. win32con.WS_CHILD
  312. | win32con.WS_VISIBLE
  313. | commctrl.TVS_HASLINES
  314. | commctrl.TVS_LINESATROOT
  315. | commctrl.TVS_HASBUTTONS
  316. )
  317. dt = [
  318. ["Python Object Browser", (0, 0, 200, 200), style, None, (8, "MS Sans Serif")],
  319. ["SysTreeView32", None, win32ui.IDC_LIST1, (0, 0, 200, 200), cs],
  320. ]
  321. def __init__(self, hli_root):
  322. dialog.Dialog.__init__(self, self.dt)
  323. self.hier_list = hierlist.HierListWithItems(hli_root, win32ui.IDB_BROWSER_HIER)
  324. self.HookMessage(self.on_size, win32con.WM_SIZE)
  325. def OnInitDialog(self):
  326. self.hier_list.HierInit(self)
  327. return dialog.Dialog.OnInitDialog(self)
  328. def OnOK(self):
  329. self.hier_list.HierTerm()
  330. self.hier_list = None
  331. return self._obj_.OnOK()
  332. def OnCancel(self):
  333. self.hier_list.HierTerm()
  334. self.hier_list = None
  335. return self._obj_.OnCancel()
  336. def on_size(self, params):
  337. lparam = params[3]
  338. w = win32api.LOWORD(lparam)
  339. h = win32api.HIWORD(lparam)
  340. self.GetDlgItem(win32ui.IDC_LIST1).MoveWindow((0, 0, w, h))
  341. def Browse(ob=__main__):
  342. "Browse the argument, or the main dictionary"
  343. root = MakeHLI(ob, "root")
  344. if not root.IsExpandable():
  345. raise TypeError(
  346. "Browse() argument must have __dict__ attribute, or be a Browser supported type"
  347. )
  348. dlg = dynamic_browser(root)
  349. dlg.CreateWindow()
  350. return dlg
  351. #
  352. #
  353. # Classes for using the browser in an MDI window, rather than a dialog
  354. #
  355. from pywin.mfc import docview
  356. class BrowserTemplate(docview.DocTemplate):
  357. def __init__(self):
  358. docview.DocTemplate.__init__(
  359. self, win32ui.IDR_PYTHONTYPE, BrowserDocument, None, BrowserView
  360. )
  361. def OpenObject(self, root): # Use this instead of OpenDocumentFile.
  362. # Look for existing open document
  363. for doc in self.GetDocumentList():
  364. if doc.root == root:
  365. doc.GetFirstView().ActivateFrame()
  366. return doc
  367. # not found - new one.
  368. doc = BrowserDocument(self, root)
  369. frame = self.CreateNewFrame(doc)
  370. doc.OnNewDocument()
  371. self.InitialUpdateFrame(frame, doc, 1)
  372. return doc
  373. class BrowserDocument(docview.Document):
  374. def __init__(self, template, root):
  375. docview.Document.__init__(self, template)
  376. self.root = root
  377. self.SetTitle("Browser: " + root.name)
  378. def OnOpenDocument(self, name):
  379. raise TypeError("This template can not open files")
  380. return 0
  381. class BrowserView(docview.TreeView):
  382. def OnInitialUpdate(self):
  383. import commctrl
  384. rc = self._obj_.OnInitialUpdate()
  385. list = hierlist.HierListWithItems(
  386. self.GetDocument().root,
  387. win32ui.IDB_BROWSER_HIER,
  388. win32ui.AFX_IDW_PANE_FIRST,
  389. )
  390. list.HierInit(self.GetParent())
  391. list.SetStyle(
  392. commctrl.TVS_HASLINES | commctrl.TVS_LINESATROOT | commctrl.TVS_HASBUTTONS
  393. )
  394. return rc
  395. template = None
  396. def MakeTemplate():
  397. global template
  398. if template is None:
  399. template = (
  400. BrowserTemplate()
  401. ) # win32ui.IDR_PYTHONTYPE, BrowserDocument, None, BrowserView)
  402. def BrowseMDI(ob=__main__):
  403. """Browse an object using an MDI window."""
  404. MakeTemplate()
  405. root = MakeHLI(ob, repr(ob))
  406. if not root.IsExpandable():
  407. raise TypeError(
  408. "Browse() argument must have __dict__ attribute, or be a Browser supported type"
  409. )
  410. template.OpenObject(root)