def run_render_test(args, outfile, benchmark, size=(640, 480), scene='ortho', threshold=50): glver = os.environ.get('FSLEYES_TEST_GL', '2.1') glver = [int(v) for v in glver.split('.')] args = '-gl {} {}'.format(*glver) .split() + \ '-of {}' .format(outfile).split() + \ '-sz {} {}'.format(*size) .split() + \ '-s {}' .format(scene) .split() + \ list(args) fslrender.main(args) # gaaargh, why is macos case insensitive?? if not op.exists(benchmark): benchmark = benchmark.lower() testimg = mplimg.imread(outfile) benchimg = mplimg.imread(benchmark) result, diff = compare_images(testimg, benchimg, threshold) assert result
def main(args=None): """*FSLeyes* entry point. Shows a :class:`.FSLeyesSplash` screen, parses command line arguments, and shows a :class:`.FSLeyesFrame`. Returns an exit code. """ if args is None: args = sys.argv[1:] # Hack to allow render to # be called via fsleyes.main if len(args) >= 1 and args[0] == 'render': import fsleyes.render as render render.main(args[1:]) sys.exit(0) # the fsleyes.initialise function figures # out the path to asset files (e.g. cmaps) fsleyes.initialise() # Hook which allows us to run a jupyter # notebook server from a frozen version # of FSLeyes if len(args) >= 1 and args[0] == 'notebook': from fsleyes.actions.notebook import nbmain fsleyes.configLogging() sys.exit(nbmain(args)) # initialise colour maps - this must be # done before parsing arguments, as if # the user asks for help, available # colourmaps/luts will be listed. colourmaps.init() # Function to bootstrap the GUI - keep # reading below. def initgui(): # First thing's first. Create a wx.App, # and initialise the FSLeyes package. app = FSLeyesApp() # Create a splash screen frame splash = fslsplash.FSLeyesSplash(None) return app, splash # If it looks like the user is asking for # help, or using cliserver to pass arguments # to an existing FSLeyes instance, then we # parse command line arguments before # creating a wx.App and showing the splash # screen. This means that FSLeyes help/ # version information can be retrieved # without a display, and hopefully fairly # quickly. # # Otherwise we create the app and splash # screen first, so the splash screen gets # shown as soon as possible. Arguments # will get parsed in the init function below. # # The argparse.Namespace object is kept in a # list so it can be shared between the sub- # functions below # # If argument parsing bombs out, we put the # exit code here and return it at the bottom. namespace = [None] exitCode = [0] # user asking for help - parse args first if (len(args) > 0) and (args[0] in ('-V', '-h', '-fh', '-cs', '--version', '--help', '--fullhelp', '--cliserver')): namespace = [parseArgs(args)] app, splash = initgui() # otherwise parse arguments on wx.MainLoop # below else: app, splash = initgui() # We are going do all processing on the # wx.MainLoop, so the GUI can be shown # as soon as possible, and because it is # difficult to force immediate GUI # refreshes when not running on the main # loop - this is important for FSLeyes, # which displays status updates to the # user while it is loading overlays and # setting up the interface. # # All of the work is defined in a series # of functions, which are chained together # via ugly callbacks, but which are # ultimately scheduled and executed on the # wx main loop. def init(splash): # See FSLeyesSplash.Show # for horribleness. splash.Show() # Parse command line arguments if necessary. # If arguments are invalid, the parseargs # module will raise SystemExit. try: if namespace[0] is None: errmsg = strings.messages['main.parseArgs.error'] errtitle = strings.titles['main.parseArgs.error'] with status.reportIfError(errtitle, errmsg, raiseError=True): namespace[0] = parseArgs(args) # But the wx.App.MainLoop eats SystemExit # exceptions for unknown reasons, and # causes the application to exit # immediately. This makes testing FSLeyes # (e.g. code coverage) impossible. So I'm # catching SystemExit here, and then # telling the wx.App to exit gracefully. except (SystemExit, Exception) as e: app.ExitMainLoop() exitCode[0] = getattr(e, 'code', 1) return # Configure logging (this has to be done # after cli arguments have been parsed, # but before initialise is called). fsleyes.configLogging(namespace[0].verbose, namespace[0].noisy) # Initialise sub-modules/packages. The # buildGui function is passed through # as a callback, which gets called when # initialisation is complete. initialise(splash, namespace[0], buildGui) def buildGui(): # Now the main stuff - create the overlay # list and the master display context, # and then create the FSLeyesFrame. overlayList, displayCtx = makeDisplayContext(namespace[0], splash) app.SetOverlayListAndDisplayContext(overlayList, displayCtx) frame = makeFrame(namespace[0], displayCtx, overlayList, splash) app.SetTopWindow(frame) frame.Show() # Check that $FSLDIR is set, complain # to the user if it isn't if not namespace[0].skipfslcheck: wx.CallAfter(fslDirWarning, frame) # Check for updates. Ignore point # releases, otherwise users might # get swamped with update notifications. if namespace[0].updatecheck: import fsleyes.actions.updatecheck as updatecheck wx.CallAfter(updatecheck.UpdateCheckAction(), showUpToDateMessage=False, showErrorMessage=False, ignorePoint=False) # start notebook server if namespace[0].notebookFile is not None: namespace[0].notebook = True namespace[0].notebookFile = op.abspath(namespace[0].notebookFile) if namespace[0].notebook: from fsleyes.actions.notebook import NotebookAction frame.menuActions[NotebookAction](namespace[0].notebookFile) # start CLI server if namespace[0].cliserver: cliserver.runserver(overlayList, displayCtx) # Shut down cleanly on sigint/sigterm. # We do this so that any functions # registered with atexit will actually # get called. nsignals = [0] def sigHandler(signo, frame): log.debug('Signal received - FSLeyes is shutting down...') # first signal - try to exit cleanly if nsignals[0] == 0: nsignals[0] += 1 exitCode[0] = signo # kill any modal windows # that are open for mdlg in app.modals: mdlg.EndModal(wx.ID_CANCEL) wx.CallAfter(app.ExitMainLoop) # subsequent signals - exit immediately else: sys.exit(signo) signal.signal(signal.SIGINT, sigHandler) signal.signal(signal.SIGTERM, sigHandler) # Note: If no wx.Frame is created, the # wx.MainLoop call will exit immediately, # even if we have scheduled something via # wx.CallAfter. In this case, we have # already created the splash screen, so # all is well. wx.CallAfter(init, splash) # under mac, use appnope to make sure # we don't get put to sleep. This is # primarily for the jupyter notebook # integration - if the user is working # with a notebook in the web browser, # macos might put FSLeyes to sleep, # causing the kernel to become # unresponsive. try: import appnope appnope.nope() except ImportError: pass app.MainLoop() shutdown() return exitCode[0]
def main(args=None): """*FSLeyes* entry point. Shows a :class:`.FSLeyesSplash` screen, parses command line arguments, and shows a :class:`.FSLeyesFrame`. Returns an exit code. """ if args is None: args = sys.argv[1:] # Hack to allow render to # be called via fsleyes.main if len(args) >= 1 and args[0] == 'render': import fsleyes.render as render render.main(args[1:]) sys.exit(0) # Implement various hacks and workarounds hacksAndWorkarounds() # Then, first thing's first. Create a wx.App, # and initialise the FSLeyes package. app = FSLeyesApp() fsleyes.initialise() # Show the splash screen as soon as # possible, unless it looks like the # user is asking for the software # version or command line help. splash = fslsplash.FSLeyesSplash(None) if (len(args) > 0) and (args[0] in ('-V', '-h', '-fh', '--version', '--help', '--fullhelp')): splash.Hide() # We are going do all processing on the # wx.MainLoop, so the GUI can be shown # as soon as possible, and because it is # difficult to force immediate GUI # refreshes when not running on the main # loop - this is important for FSLeyes, # which displays status updates to the # user while it is loading overlays and # setting up the interface. # # All of the work is defined in a series # of functions, which are chained together # via ugly callbacks, but which are # ultimately scheduled and executed on the # wx main loop. # This is a container, shared amongst # the callbacks, which contains the # parsed argparse.Namespace object. namespace = [None] # If argument parsing bombs out, # we put the exit code here and # return it at the bottom. exitCode = [0] def init(splash): # Parse command line arguments. If the # user has asked for help (see above), # the parseargs module will raise # SystemExit. Hence we make sure the # splash screen is shown only after # arguments have been parsed. try: namespace[0] = parseArgs(args) # But the wx.App.MainLoop eats SystemExit # exceptions for unknown reasons, and # and causes the application to exit # immediately. This makes testing FSLeyes # (e.g. code coverage) impossible. So I'm # catching SystemExit here, and then # telling the wx.App to exit gracefully. except SystemExit as e: app.ExitMainLoop() exitCode[0] = e.code return # See FSLeyesSplash.Show # for horribleness. splash.Show() # Configure logging (this has to be done # after cli arguments have been parsed, # but before initialise is called). fsleyes.configLogging(namespace[0]) # Initialise sub-modules/packages. The # buildGui function is passed through # as a callback, which gets called when # initialisation is complete. initialise(splash, namespace[0], buildGui) def buildGui(): # Now the main stuff - create the overlay # list and the master display context, # and then create the FSLeyesFrame. overlayList, displayCtx = makeDisplayContext(namespace[0], splash) app.SetOverlayListAndDisplayContext(overlayList, displayCtx) frame = makeFrame(namespace[0], displayCtx, overlayList, splash) app.SetTopWindow(frame) frame.Show() # Check that $FSLDIR is set, complain # to the user if it isn't if not namespace[0].skipfslcheck: wx.CallAfter(fslDirWarning, frame) # Check for updates. Ignore point # releases, otherwise users might # get swamped with update notifications. if namespace[0].updatecheck: import fsleyes.actions.updatecheck as updatecheck wx.CallAfter(updatecheck.UpdateCheckAction(), showUpToDateMessage=False, showErrorMessage=False, ignorePoint=False) # Note: If no wx.Frame is created, the # wx.MainLoop call will exit immediately, # even if we have scheduled something via # wx.CallAfter. In this case, we have # already created the splash screen, so # all is well. wx.CallAfter(init, splash) app.MainLoop() shutdown() return exitCode[0]