def _debug_print_object_counts(self): #bruce 060327 for debugging memory leaks: report Atom & Bond refcounts, and objs that might refer to them # Note: these counts include not only instances, but imports of classes into modules. # That's probably why the initial counts seem too high: # 40 Atoms, 24 Bonds, 40 Chunks, 34 Groups, 8 Parts, 10 Assemblies # [as of 080403] from utilities.Log import _graymsg msglater = "" # things to print all in one line for clasname, modulename in ( #bruce 080403 fixed modulenames (since the modules were moved into # packages); the dotted names seem to work. ('Atom', 'model.chem'), ('Bond', 'model.bonds'), # ('Node', 'Utility'), # Node or Jig is useless here, we need the specific subclasses! ('Chunk', 'model.chunk'), # DnaLadderRailChunk ## ('PiBondSpChain', 'pi_bond_sp_chain'), # no module pi_bond_sp_chain -- due to lazy load or atom-debug reload?? ( 'Group', 'foundation.Group' ), # doesn't cover subclasses PartGroup, ClipboardItemGroup, RootGroup(sp?), Dna groups ('Part', 'model.part'), ('Assembly', 'model.assembly')): # should also have a command to look for other classes with high refcounts if sys.modules.has_key(modulename): module = sys.modules[modulename] clas = getattr(module, clasname, None) if clas: msg = "%d %ss" % (sys.getrefcount(clas), clasname) msg = msg.replace("ys", "ies") # for spelling of Assemblies # print these things all at once if msglater: msglater += ', ' msglater += msg msg = None else: msg = "%s not found in %s" % (clasname, modulename) else: msg = "no module %s" % (modulename, ) if msg: env.history.message(_graymsg(msg)) if msglater: env.history.message(_graymsg(msglater)) return
def _debug_print_object_counts(self): #bruce 060327 for debugging memory leaks: report Atom & Bond refcounts, and objs that might refer to them # Note: these counts include not only instances, but imports of classes into modules. # That's probably why the initial counts seem too high: # 40 Atoms, 24 Bonds, 40 Chunks, 34 Groups, 8 Parts, 10 Assemblies # [as of 080403] from utilities.Log import _graymsg msglater = "" # things to print all in one line for clasname, modulename in ( #bruce 080403 fixed modulenames (since the modules were moved into # packages); the dotted names seem to work. ('Atom', 'model.chem'), ('Bond', 'model.bonds'), # ('Node', 'Utility'), # Node or Jig is useless here, we need the specific subclasses! ('Chunk', 'model.chunk'), # DnaLadderRailChunk ## ('PiBondSpChain', 'pi_bond_sp_chain'), # no module pi_bond_sp_chain -- due to lazy load or atom-debug reload?? ('Group', 'foundation.Group'), # doesn't cover subclasses PartGroup, ClipboardItemGroup, RootGroup(sp?), Dna groups ('Part', 'model.part'), ('Assembly', 'model.assembly')): # should also have a command to look for other classes with high refcounts if sys.modules.has_key(modulename): module = sys.modules[modulename] clas = getattr(module, clasname, None) if clas: msg = "%d %ss" % (sys.getrefcount(clas), clasname) msg = msg.replace("ys","ies") # for spelling of Assemblies # print these things all at once if msglater: msglater += ', ' msglater += msg msg = None else: msg = "%s not found in %s" % (clasname, modulename) else: msg = "no module %s" % (modulename,) if msg: env.history.message( _graymsg( msg)) if msglater: env.history.message( _graymsg( msglater)) return
def debug_run_command(command, source="user debug input" ): #bruce 040913-16 in GLPane.py; modified 040928 """ Execute a python command, supplied by the user via some sort of debugging interface (named by source), in debug.py's globals. Return 1 for ok (incl empty command), 0 for any error. Caller should not print exception diagnostics -- this function does that (and does not reraise the exception). """ #e someday we might record time, history, etc command = "" + command # i.e. assert it's a string #k what's a better way to do the following? while command and command[0] == '\n': command = command[1:] while command and command[-1] == '\n': command = command[:-1] if not command: print "empty command (from %s), nothing executed" % (source, ) return 1 if '\n' not in command: msg = "will execute (from %s): %s" % (source, command) else: nlines = command.count('\n') + 1 msg = "will execute (from %s; %d lines):\n%s" % (source, nlines, command) print msg try: # include in history file, so one can search old history files for useful things to execute [bruce 060409] from utilities.Log import _graymsg, quote_html env.history.message(_graymsg(quote_html(msg))) except: print_compact_traceback("exception in printing that to history: ") command = command + '\n' #k probably not needed try: ## exec command in globals() legally_exec_command_in_globals(command, globals()) except: print_compact_traceback("exception from that: ") return 0 else: print "did it!" return 1 pass
def debug_run_command(command, source = "user debug input"): #bruce 040913-16 in GLPane.py; modified 040928 """ Execute a python command, supplied by the user via some sort of debugging interface (named by source), in debug.py's globals. Return 1 for ok (incl empty command), 0 for any error. Caller should not print exception diagnostics -- this function does that (and does not reraise the exception). """ #e someday we might record time, history, etc command = "" + command # i.e. assert it's a string #k what's a better way to do the following? while command and command[0] == '\n': command = command[1:] while command and command[-1] == '\n': command = command[:-1] if not command: print "empty command (from %s), nothing executed" % (source,) return 1 if '\n' not in command: msg = "will execute (from %s): %s" % (source, command) else: nlines = command.count('\n')+1 msg = "will execute (from %s; %d lines):\n%s" % (source, nlines, command) print msg try: # include in history file, so one can search old history files for useful things to execute [bruce 060409] from utilities.Log import _graymsg, quote_html env.history.message( _graymsg( quote_html( msg))) except: print_compact_traceback("exception in printing that to history: ") command = command + '\n' #k probably not needed try: ## exec command in globals() legally_exec_command_in_globals( command, globals() ) except: print_compact_traceback("exception from that: ") return 0 else: print "did it!" return 1 pass
def editClearUndoStack(win): """ This is called from MWsemantics.editClearUndoStack, which is documented as: "Slot for clearing the Undo Stack. Requires the user to confirm." """ #bruce 060304, modified from Mark's prototype in MWsemantics #e the following message should specify the amount of data to be lost... #e and the menu item text also should msg = "Please confirm that you want to clear the Undo/Redo Stack.<br>" + \ _graymsg("(This operation cannot be undone.)") confirmed = PleaseConfirmMsgBox( msg) # TODO: I bet this needs a "don't show this again" checkbox... # with a prefs key... if not confirmed: env.history.message("Clear Undo Stack: Cancelled.") #k needed?? return # do it env.history.message(greenmsg("Clear Undo Stack")) # no further message needed if it works, I think try: ##e Note: the following doesn't actually free storage. # [update, 060309 -- i think as of a few days ago it does try to... ##k] # Once the UI seems to work, we'll either add that to it, # or destroy and remake assy.undo_manager itself before doing this # (and make sure destroying it frees storage). ##e Make sure this can be called with or without auto-checkpointing # enabled, and leaves that setting unchanged. #####@@@@@ win.assy.clear_undo_stack() except: print_compact_traceback("exception in clear_undo_stack: ") msg = "Internal error in Clear Undo Stack. " \ "Undo/Redo might be unsafe until a new file is opened." env.history.message(redmsg(msg)) #e that wording assumes we can't open more than one file at a time... return
def editClearUndoStack(win): """ This is called from MWsemantics.editClearUndoStack, which is documented as: "Slot for clearing the Undo Stack. Requires the user to confirm." """ #bruce 060304, modified from Mark's prototype in MWsemantics #e the following message should specify the amount of data to be lost... #e and the menu item text also should msg = "Please confirm that you want to clear the Undo/Redo Stack.<br>" + \ _graymsg("(This operation cannot be undone.)") confirmed = PleaseConfirmMsgBox(msg) # TODO: I bet this needs a "don't show this again" checkbox... # with a prefs key... if not confirmed: env.history.message("Clear Undo Stack: Cancelled.") #k needed?? return # do it env.history.message(greenmsg("Clear Undo Stack")) # no further message needed if it works, I think try: ##e Note: the following doesn't actually free storage. # [update, 060309 -- i think as of a few days ago it does try to... ##k] # Once the UI seems to work, we'll either add that to it, # or destroy and remake assy.undo_manager itself before doing this # (and make sure destroying it frees storage). ##e Make sure this can be called with or without auto-checkpointing # enabled, and leaves that setting unchanged. #####@@@@@ win.assy.clear_undo_stack() except: print_compact_traceback("exception in clear_undo_stack: ") msg = "Internal error in Clear Undo Stack. " \ "Undo/Redo might be unsafe until a new file is opened." env.history.message(redmsg(msg)) #e that wording assumes we can't open more than one file at a time... return
def raytrace_scene(self, tmpscene=False): """ Render scene. If tmpscene is False, the INI and pov files are written to the 'POV-Ray Scene Files' directory. If tmpscene is True, the INI and pov files are written to a temporary directory (~/Nanorex/POV-Ray). Callers should set <tmpscene> = True when they want to render the scene but don't need to save the files and create a POV-Ray Scene node in the MT (i.e. 'View > POV-Ray'). The caller is responsible for adding the POV-Ray Scene node (self) to the model tree, if desired. Prints any necessary error messages to history; returns nothing. """ #bruce 060710 corrected inaccuracies in docstring cmd = greenmsg("POV-Ray: ") if env.debug(): #bruce 060707 (after Windows A8, before Linux/Mac A8) # compromise with what's best, so it can be ok for A8 even if only on some platforms env.history.message(_graymsg("POV-Ray: ")) env.history.h_update() env.history.widget.update( ) ###@@@ will this help? is it safe? should h_update do it? ini, pov, out = self.get_povfile_trio(tmpscene) if not ini: ## return 1, "Problem getting POV-Ray filename trio." # [bruce 060710 replaced the above with the following, since it no longer matches the other return statements, or any calls] env.history.message( cmd + redmsg("Problem getting POV-Ray filename trio.")) ###e should fix this to improve the message, by including errortext from get_povfile_trio retval (which is nim) return if tmpscene or not os.path.isfile(self.povrayscene_file): # write a new .pov file and save its name in self # #bruce 060711 comment (about a bug, not yet reported): ###@@@ # If an existing pov file has unexpectedly gone missing, # this code (I think) rerenders the current model, without even informing the user of the apparent error. # That is extremely bad behavior, IMHO. What it ought to do is put up a dialog to inform the # user that the file is missing, and allow one of three actions: cancel, rerender current model, # or browse for the file to try to find it. If that browse is cancelled, it should offer the other # options, or if that finds the file but it's external, it should offer to copy it or make an # external link (or cancel), and then to continue or do no more. All this is desirable for any kind # of file node, not just PovrayScene. As it is, this won't be fixed for Mac A8; don't know about 8.1. self.povrayscene_file = pov writepovfile(self.assy.part, self.assy.o, self.povrayscene_file) # bruce 060711 question (possible bug): what sets self.width, self.height, self.output_type in this case, # if the ones used by writepovfile differ from last time they were set in this node? # Guess: nothing does (bug, not yet reported). ###@@@ # figure out renderer to use (POV-Ray or MegaPOV), its path, and its include_dir # (note: this contains most of the error checks that used to be inside launch_povray_or_megapov) # [bruce 060711 for Mac A8] win = self.assy.w ask_for_help = True # give user the chance to fix problems in the prefs dialog errorcode, errortext_or_info = decode_povray_prefs(win, ask_for_help, greencmd=cmd) if errorcode: errortext = errortext_or_info env.history.message( cmd + redmsg(errortext) ) # redmsg in Mac A8, orangemsg in Windows A8 [bruce 060711] return info = errortext_or_info (program_nickname, program_path, include_dir) = info pov = self.povrayscene_file ###k btw, is this already true? #k is out equal to whatever in self might store it, if anything? maybe it's not stored in self. write_povray_ini_file(ini, pov, out, info, self.width, self.height, self.output_type) if tmpscene: msg = "Rendering scene. Please wait..." else: msg = "Rendering raytrace image from POV-Ray Scene file. Please wait..." env.history.message(cmd + msg) env.history.h_update( ) #bruce 060707 (after Windows A8, before Linux/Mac A8): try to make this message visible sooner # (doesn't work well enough, at least on Mac -- do we need to emit it before write_povray_ini_file?) env.history.widget.update( ) ###@@@ will this help? is it safe? should h_update do it? ###e these history widget updates fail to get it to print. Guess: we'd need qapp process events. Fix after Mac A8. # besides, we need this just before the launch call, not here. if os.path.exists( out ): #bruce 060711 in Mac A8 not Windows A8 (probably all of Mac A8 code will also be in Linux A8) #e should perhaps first try moving the file to a constant name, so user could recover it manually if they wanted to #e (better yet, we should also try to avoid this situation when choosing the filename) msg = "Warning: image file already exists; removing it first [%s]" % out env.history.message(cmd + orangemsg(msg)) try: os.remove(out) except: # this code was tested with a fake exception [060712 1041am] msg1 = "Problem removing old image file" msg2a = " [%s]" % out msg2b = "-- will try to overwrite it, "\ "but undetected rendering errors might leave it unchanged [%s]" % out print_compact_traceback("%s: " % (msg1 + msg2a)) msg = redmsg(msg1) + msg2b #e should report the exception text in the history, too env.history.message(msg) pass # Launch raytrace program (POV-Ray or MegaPOV) errorcode, errortext = launch_povray_or_megapov(win, info, ini) if errorcode: env.history.message( cmd + redmsg(errortext) ) # redmsg in Mac A8, orangemsg in Windows A8 [bruce 060711] return #bruce 060707 (after Windows A8, before Linux/Mac A8): make sure the image file exists. # (On Mac, on that date [not anymore, 060710], we get this far (no error return, or maybe another bug hid one), # but the file is not there.) if not os.path.exists(out): msg = "Error: %s program finished, but failed to produce expected image file [%s]" % ( program_nickname, out) env.history.message(cmd + redmsg(msg)) return env.history.message(cmd + "Rendered image: " + out) # Display image in a window. imageviewer = ImageViewer(out, win) #bruce 060707 comment: if the file named <out> doesn't exist, on Mac, # this produces a visible and draggable tiny window, about 3 pixels wide and maybe 30 pixels high. imageviewer.display() return # from raytrace_scene out
def raytrace_scene(self, tmpscene = False): """ Render scene. If tmpscene is False, the INI and pov files are written to the 'POV-Ray Scene Files' directory. If tmpscene is True, the INI and pov files are written to a temporary directory (~/Nanorex/POV-Ray). Callers should set <tmpscene> = True when they want to render the scene but don't need to save the files and create a POV-Ray Scene node in the MT (i.e. 'View > POV-Ray'). The caller is responsible for adding the POV-Ray Scene node (self) to the model tree, if desired. Prints any necessary error messages to history; returns nothing. """ #bruce 060710 corrected inaccuracies in docstring cmd = greenmsg("POV-Ray: ") if env.debug(): #bruce 060707 (after Windows A8, before Linux/Mac A8) # compromise with what's best, so it can be ok for A8 even if only on some platforms env.history.message(_graymsg("POV-Ray: ")) env.history.h_update() env.history.widget.update() ###@@@ will this help? is it safe? should h_update do it? ini, pov, out = self.get_povfile_trio(tmpscene) if not ini: ## return 1, "Problem getting POV-Ray filename trio." # [bruce 060710 replaced the above with the following, since it no longer matches the other return statements, or any calls] env.history.message(cmd + redmsg("Problem getting POV-Ray filename trio.")) ###e should fix this to improve the message, by including errortext from get_povfile_trio retval (which is nim) return if tmpscene or not os.path.isfile(self.povrayscene_file): # write a new .pov file and save its name in self # #bruce 060711 comment (about a bug, not yet reported): ###@@@ # If an existing pov file has unexpectedly gone missing, # this code (I think) rerenders the current model, without even informing the user of the apparent error. # That is extremely bad behavior, IMHO. What it ought to do is put up a dialog to inform the # user that the file is missing, and allow one of three actions: cancel, rerender current model, # or browse for the file to try to find it. If that browse is cancelled, it should offer the other # options, or if that finds the file but it's external, it should offer to copy it or make an # external link (or cancel), and then to continue or do no more. All this is desirable for any kind # of file node, not just PovrayScene. As it is, this won't be fixed for Mac A8; don't know about 8.1. self.povrayscene_file = pov writepovfile(self.assy.part, self.assy.o, self.povrayscene_file) # bruce 060711 question (possible bug): what sets self.width, self.height, self.output_type in this case, # if the ones used by writepovfile differ from last time they were set in this node? # Guess: nothing does (bug, not yet reported). ###@@@ # figure out renderer to use (POV-Ray or MegaPOV), its path, and its include_dir # (note: this contains most of the error checks that used to be inside launch_povray_or_megapov) # [bruce 060711 for Mac A8] win = self.assy.w ask_for_help = True # give user the chance to fix problems in the prefs dialog errorcode, errortext_or_info = decode_povray_prefs(win, ask_for_help, greencmd = cmd) if errorcode: errortext = errortext_or_info env.history.message(cmd + redmsg(errortext)) # redmsg in Mac A8, orangemsg in Windows A8 [bruce 060711] return info = errortext_or_info (program_nickname, program_path, include_dir) = info pov = self.povrayscene_file ###k btw, is this already true? #k is out equal to whatever in self might store it, if anything? maybe it's not stored in self. write_povray_ini_file(ini, pov, out, info, self.width, self.height, self.output_type) if tmpscene: msg = "Rendering scene. Please wait..." else: msg = "Rendering raytrace image from POV-Ray Scene file. Please wait..." env.history.message(cmd + msg) env.history.h_update() #bruce 060707 (after Windows A8, before Linux/Mac A8): try to make this message visible sooner # (doesn't work well enough, at least on Mac -- do we need to emit it before write_povray_ini_file?) env.history.widget.update() ###@@@ will this help? is it safe? should h_update do it? ###e these history widget updates fail to get it to print. Guess: we'd need qapp process events. Fix after Mac A8. # besides, we need this just before the launch call, not here. if os.path.exists(out): #bruce 060711 in Mac A8 not Windows A8 (probably all of Mac A8 code will also be in Linux A8) #e should perhaps first try moving the file to a constant name, so user could recover it manually if they wanted to #e (better yet, we should also try to avoid this situation when choosing the filename) msg = "Warning: image file already exists; removing it first [%s]" % out env.history.message(cmd + orangemsg(msg)) try: os.remove(out) except: # this code was tested with a fake exception [060712 1041am] msg1 = "Problem removing old image file" msg2a = " [%s]" % out msg2b = "-- will try to overwrite it, "\ "but undetected rendering errors might leave it unchanged [%s]" % out print_compact_traceback("%s: " % (msg1 + msg2a)) msg = redmsg(msg1) + msg2b #e should report the exception text in the history, too env.history.message(msg) pass # Launch raytrace program (POV-Ray or MegaPOV) errorcode, errortext = launch_povray_or_megapov(win, info, ini) if errorcode: env.history.message(cmd + redmsg(errortext)) # redmsg in Mac A8, orangemsg in Windows A8 [bruce 060711] return #bruce 060707 (after Windows A8, before Linux/Mac A8): make sure the image file exists. # (On Mac, on that date [not anymore, 060710], we get this far (no error return, or maybe another bug hid one), # but the file is not there.) if not os.path.exists(out): msg = "Error: %s program finished, but failed to produce expected image file [%s]" % (program_nickname, out) env.history.message(cmd + redmsg(msg)) return env.history.message(cmd + "Rendered image: " + out) # Display image in a window. imageviewer = ImageViewer(out, win) #bruce 060707 comment: if the file named <out> doesn't exist, on Mac, # this produces a visible and draggable tiny window, about 3 pixels wide and maybe 30 pixels high. imageviewer.display() return # from raytrace_scene out