Ejemplo n.º 1
0
    def __adjust_button_width_if_on_windows(self, i_button_width):

        WINDOWS_REQUIRED_WIDTH_INCREASE = 2

        i_adjusted_width = i_button_width

        b_is_windows_platform = pgut.is_windows_platform()

        if b_is_windows_platform:
            i_adjusted_width=i_button_width \
              + WINDOWS_REQUIRED_WIDTH_INCREASE
        #end if is windows platform

        return i_adjusted_width
    def __setup_tsv_file_loader(self):

        ENTRY_WIDTH = 70
        LABEL_WIDTH_NONWIN = 10
        LABEL_WIDTH_WINDOWS = 12

        i_label_width = LABEL_WIDTH_NONWIN

        if pgut.is_windows_platform():
            i_label_width = LABEL_WIDTH_WINDOWS
        #end if using windows, need wider label

        o_myc = PGNeEstimationBoxplotInterface

        self.__tsv_file_loader_subframe = LabelFrame(
            self.__master_frame,
            padding=o_myc.SUBFRAME_PADDING,
            relief=o_myc.SUBFRAME_STYLE,
            text="*tsv file")

        self.__tsv_loader_keyval = KeyValFrame(
            s_name="Load tsv file",
            v_value=self.__tsv_file_name,
            o_type=str,
            v_default_value="",
            o_master=self.__tsv_file_loader_subframe,
            i_entrywidth=ENTRY_WIDTH,
            i_labelwidth=i_label_width,
            b_is_enabled=False,
            s_entry_justify='left',
            s_label_justify='left',
            s_button_text="Select",
            def_button_command=self.__load_tsv_file,
            b_force_disable=False,
            s_tooltip="Load a tsv file, output from an Nb/Ne Estimation run")

        #The entry box should be disabled, but
        #we want the lable non-grayed-out:
        self.__tsv_loader_keyval.setLabelState("enabled")
        self.__tsv_loader_keyval.grid(row=0, sticky=(NW))

        self.__tsv_file_loader_subframe.grid(
            row=o_myc.ROW_NUM_SUBFRAME_TSV_FILE_LOADER,
            column=o_myc.COLNUM_SUBFRAME_TSV_LOADER,
            columnspan=o_myc.COLSPAN_SUBFRAME_TSV_LOADER,
            sticky=(N, W))

        return
	def __make_outfile_name( self ):
		o_strvar_outputdir=getattr( self.__interface, 
				self.__mangled_attribute_prefix \
								+ "output_directory" )

		s_outputdir=o_strvar_outputdir.get()

		s_outfile_basename=self.__interface.output_base_name

		if pgut.is_windows_platform():
			s_outputdir=pgut.fix_windows_path( s_outputdir )
			'''
			In case the GUI user entered a path separator into
			the basename entry
			'''
			s_outfile_basename=pgut.fix_windows_path( s_outfile_basename )
		#end if windows platform
		
		self.__config_outfile_name= \
				s_outputdir + "/" + s_outfile_basename \
				+ PGLineRegressConfigFileMaker.CONFIG_FILE_EXT
		return
Ejemplo n.º 4
0
	def __remove_temporary_directory_and_all_of_its_contents( self, s_temp_dir ):

		'''
		Note: shutil.rmtree fails on encountering readonly files
		We add a few paranoia-induced checks, in case the arg s_temp_dir
		is not, as intended, solely the garbage dump for NeEstimator
		'''

		CORRECT_TMP_DIR_PREFIX="tmp"
		CORRECT_TEMP_FILE_PREFIX="temp"
		NUMBER_SUBDIRS_EXPECTED=0
		SUSPICOUSLY_HIGH_FILE_COUNT=4

		tup_path_head_tail =  os.path.split( s_temp_dir )
		
		s_dir_name=tup_path_head_tail[ 1 ]

		if not( s_dir_name.startswith( CORRECT_TMP_DIR_PREFIX ) ):
				s_msg = "in PGOpNeEstimator instance, " \
							+ "def __remove_temporary_directory_and_all_its_contents, " \
							+ "s_temp_dir directory name, " \
							+ s_temp_dir \
							+ " should begin with \"tmp\"."

				raise Exception(  s_msg )
		#end if non-tmp name
		
		ls_files=pgut.get_list_file_objects( s_temp_dir )
		ls_directories=pgut.get_list_subdirectories( s_temp_dir )

		i_num_subdirs=len( ls_directories  )
		i_num_files=len( ls_files )

		#Abort if path looks wrong:				
		if i_num_subdirs > NUMBER_SUBDIRS_EXPECTED \
						or i_num_files >= SUSPICOUSLY_HIGH_FILE_COUNT:
			s_msg="in PGOpNeEstimator instance, " \
						+ "def __remove_temporary_directory_and_all_its_contents, " \
						+ "temp dir: " + s_temp_dir \
						+ ", not able to remove temp directory " \
						+ "due to unexpectedly high " \
						+ "file count, " + str( i_num_files )  \
						+ ", and/or subdirectory count, " + str(i_num_subdirs ) + "."

			'''
			2018_04_02. For easier debugging, we add the file and subdirectory lists 
			to the error message. 
			'''
			s_msg += "  Subdirectory names: " + str( ls_directories ) \
					+ ".  File names: " + str( ls_files ) + "." 

			raise Exception( s_msg )
		#end if dir/file counts look wrong

		#Abort if any file name looks wrong
		for s_file in ls_files:

			if not ( s_file.startswith( CORRECT_TEMP_FILE_PREFIX ) ):
				s_msg="in PGOpNeEstimator instance, " \
							+ "def __remove_temporary_directory_and_all_its_contents, " \
							+ "temp dir: " + s_temp_dir \
							+ ", not able to remove temp directory. " \
							+ "The program found that it contains a file that does " \
							+ "not start with the correct prefix.  File: " \
							+ s_file \
							+ ", correct prefix: " + CORRECT_TMP_DIR_PREFIX + "."
				
				raise Exception( s_msg )
			#end if file does not appear to be a temp file, abort	
		#end for each file

		'''
		2018_03_23 Sometimes, for reasons I do not understand, Windows will not remove
		one of these temp files because of a permissions error, which will then interrupt
		the program.  If we are using windows, we'll try callinbg rmtreecheck the permissions status of the files, 
		and, if we find the program can't delete we call rmtree with the flag set
		to ignore errors.
		'''
		if pgut.is_windows_platform():
			try:
				pgut.do_shutil_rmtree( s_temp_dir, b_ignore_errors=False )
			except WindowsError as owex:
				s_msg="Warning:  In PGOutputNeEstimator instance, def " \
							+ "__remove_temporary_directory_and_all_its_contents, " \
							+ "the call to do_shutil_rmtree idn the pgutilities module " \
							+ "generated a Windows Error with message, " \
							+ str( owex ) \
							+ "  The program is now calling do_shutil_rmtree again, " \
							+ "this time with the flag set to ignore errors."
				sys.stderr.write( s_msg + "\n" )
				pgut.do_shutil_rmtree( s_temp_dir, b_ignore_errors=True )
			#end try...except
		else:
			pgut.do_shutil_rmtree( s_temp_dir, b_ignore_errors=False)
		#end if using windows os else not

		return
def do_simulation_reps_in_subprocesses(
        o_multiprocessing_event,
        i_input_reps,
        i_total_processes_for_sims,
        s_temp_config_file_for_running_replicates,
        ls_life_table_files,
        s_param_names_file,
        s_output_basename,
        b_use_gui_messaging=True,
        i_output_mode=pgsim.PGOpSimuPop.OUTPUT_GENEPOP_ONLY):
    '''
	Failed to get independant initialization of population per-replicate
	when i used python's multiprocessing.process objects as hosts for 
	running replicates in parallel.  Solution as of now, 
	Sat Jul 30 22:38:42 MDT 2016, is to use OS processes via python's 
	subprocess module, creating them in this def, which gets its
	requisite info needed for the sim from the pgguisimupop instance
	that calls this def (this def is called by the GUI interface instance
	in a new python.multiprocessing.process instance, in order not to block the gui).

	Note that this def was originally inside the pgguisimupop instance that calls it,
	but on windows there was a pickling error not seen on linux or Mac.  Moving this
	target def for the python.multiprocessing.process outside the pgguisimupop instance
	seems to have solved the problem on windows (win 10).

	This def manages the replices via creating subprocesses, and 
	calling pgparallelopmanager.prep_and_call_do_pgopsimupop_replicate 
	(note: the call has been updated  2017_11_12, after the defs were
	moved from pgutilities into new module pgparallelopmanager.

	2017_05_30.  We added the def param b_use_gui_messaging=True, to allow
	this def to be called from a command line implentation (new module 
	pgdrivesimulation.py), and set the flag to false, without having to
	revise the call from the GUI pgguisimupop.py.

	'''
    '''	
	Running this inside a try block allows us to notify GUI
	users of exceptions propogated from anywere inside the 
	simulation setup and execution code. When we catch exceptions 
	below, we send an error message to a gui message box, then
	re-raise the exception.	
	 
	2017_08_07.  I've added the params i_output_mode and s_pop_het_filter_string,
	to allow callers to this def to set these new parameters in the PGOpSimuPop
	object.

	'''

    try:
        s_life_tables_stringified = ",".join(ls_life_table_files)

        #if we're on windows, out strings of file
        #paths may be a mangled mix of unix and
        #windows separators -- with errors resulting
        #downstream.  So we standardize:
        if pgut.is_windows_platform():
            s_life_tables_stringified= \
             pgut.fix_windows_path( s_life_tables_stringified )
            s_param_names_file= \
             pgut.fix_windows_path( s_param_names_file )
            s_output_basename= \
             pgut.fix_windows_path( s_output_basename )
        #end if windows, fix file path strings

        i_total_replicates_requested = i_input_reps

        i_max_processes_to_use = i_total_processes_for_sims
        '''
		we use a python command for a -c arg in the Popen command (see below)
		and these will be the same args for each replicate (we add the rep-number
		arg below).  We stringify so that they can be Popen command args.  Some
		are de-stringified by the pgparallelopmanager (formerly in pgutilities)
		def before sending to pgop-creator.
		'''
        seq_first_four_args_to_sim_call = (
            s_temp_config_file_for_running_replicates,
            s_life_tables_stringified, s_param_names_file, s_output_basename)

        i_total_replicates_started = 0

        o_subprocess_group = IndependantSubprocessGroup()

        while i_total_replicates_started < i_total_replicates_requested:
            #see if we need to cancel:
            if o_multiprocessing_event.is_set():

                if VERBOSE:
                    print("received event in setup loop")
                #end if VERBOSE

                o_subprocess_group.terminateAllSubprocesses()

                remove_simulation_replicate_output_files(s_output_basename)

                break

            else:

                i_number_subprocesses_alive = o_subprocess_group.getTotalAlive(
                )

                i_number_subprocesses_available= \
                  i_max_processes_to_use-i_number_subprocesses_alive

                i_number_replicates_to_go = i_total_replicates_requested - i_total_replicates_started

                i_number_subprocesses_to_start = i_number_subprocesses_available

                #reduce the number to start if we have fewer reps to go than avail procs:
                if i_number_subprocesses_available > i_number_replicates_to_go:
                    i_number_subprocesses_to_start = i_number_replicates_to_go
                #end if fewer needed than available

                for idx in range(i_number_subprocesses_to_start):

                    i_total_replicates_started += 1
                    '''
					In the Popen call, rather than rely on a driver python script 
					that would need to be in PATH, we'll simply
					invoke python with a "-c" argument that imports the 
					pgparallelopmanager (formerly code was in pgutilities)
					module and executes the correct def:
			
					complete the set of args used in the command by adding the
					replicate number (recall need comma in sequence with single item,
					to delineate sequence versus simple expression):
					'''

                    seq_complete_arg_set = seq_first_four_args_to_sim_call + (
                        str(i_total_replicates_started), )
                    '''
					2017_05_30.  We added this argument to def prep_and_call_do_pgopsimupop_replicate, to propgate
					to its call to def do_pgopsimupop_replicate_from_files.
					
					'''
                    seq_complete_arg_set = seq_complete_arg_set + (
                        str(b_use_gui_messaging), )
                    '''
					2017_08_07.  We added args to allow caller to use diffeent output modes, 
					and, if using the filter output mode, to pass a string with parameters,
					for filtering pops by mean heterozygosity.  (See new additions to PGOpSimuPop code.)

					2017_09_04. We remove the s_pop_het_filter_string argument.  It has been removed from
					the arglist for initializing PGOpSimuPop instances, and instead those instances
					will access it directly from the PGInputSimuPop object.
					'''
                    seq_complete_arg_set = seq_complete_arg_set + (
                        str(i_output_mode), )
                    '''
					in case the negui mods are not in the default python 
					install dirs, then we need to add them to the sys.paths in
					any  spawned invocation of python exe -- seems that 
					the PYTHONPATH env var known to this parent process 
					is unknown to the "python" invocation via Popen.  
					We can get for and then add to our new python invocation
					the path to all negui modules by getting the
					path to this module:
					'''
                    s_curr_mod_path = os.path.abspath(__file__)

                    #path only (stripped off "/utilities.py" )
                    #-- gives path to all negui mods:
                    s_mod_dir = os.path.dirname(s_curr_mod_path)

                    #need to fix the path if we're on windows:
                    if pgut.is_windows_platform():
                        s_mod_dir = pgut.fix_windows_path(s_mod_dir)
                    #end if windows, fix path

                    s_path_append_statements="import sys; sys.path.append( \"" \
                      + s_mod_dir + "\" );"
                    '''
					2017_11_12. The path statements used import pgutilities, but now we
					are using this new module pgparallelopmanager.
					'''
                    s_python_command=s_path_append_statements + "import pgparallelopmanager as pgpar;" \
                         "pgpar.prep_and_call_do_pgopsimupop_replicate" \
                         + "( \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\" )" %  seq_complete_arg_set

                    o_new_subprocess = subprocess.Popen(
                        [pgut.PYEXE_FOR_POPEN, "-c", s_python_command])
                    o_subprocess_group.addSubprocess(o_new_subprocess)
                #end for each idx of new procs
            #end if event is set else not
        #end while preplicates need to be started

        #we don't want to return until all processes are done.
        #meantime test for cancel-request
        i_total_still_alive_after_creating_all = o_subprocess_group.getTotalAlive(
        )

        while i_total_still_alive_after_creating_all > 0:
            if o_multiprocessing_event.is_set():

                if VERBOSE:
                    print("received event in final loop")
                #end if verbose

                o_subprocess_group.terminateAllSubprocesses()
                remove_simulation_replicate_output_files(s_output_basename)
            #end if we are to cancel
            i_total_still_alive_after_creating_all = o_subprocess_group.getTotalAlive(
            )
        #end while

    except Exception as oex:

        o_traceback = sys.exc_info()[2]
        s_err_info = pgut.get_traceback_info_about_offending_code(o_traceback)
        s_prefix_msg_with_trace="Error caught by pgparallelopmanager, " \
              + "def __do_simulation_reps_in_subprocesses." \
              + "\\nError origin info:\\n" \
              + s_err_info

        if b_use_gui_messaging:
            pgut.show_error_in_messagebox_in_new_process(
                oex, s_msg_prefix=s_prefix_msg_with_trace)
        #end if use gui messaging

        s_msg = s_prefix_msg_with_trace + str(oex)
        raise Exception(oex)
    #end try...except...
    return
	def __make_dict_interface_param_values( self ):
		ls_interface_member_names=dir( self.__interface )
	
		#GUI interface members for viz all begin
		#with this prefix--we need the trailing delimiter
		#because a generel attribute "viztype" is used only 
		#by the GUI (not a plotting param)
		s_viz_prefix=self.__mangled_attribute_prefix + "viz" \
					+ PGLineRegressConfigFileMaker.GUI_ATTRIBUTE_DELIMIT
		for s_member_name in ls_interface_member_names:

			if s_member_name.startswith( s_viz_prefix ):
			
				#strip off the mangling:
				s_member_name_unmangled=s_member_name.replace( self.__mangled_attribute_prefix, "" )

				#Extract the param name (used by the viz program):
				ls_member_name_parts=s_member_name_unmangled.split( \
						PGLineRegressConfigFileMaker.GUI_ATTRIBUTE_DELIMIT )
				s_viz_section_name=ls_member_name_parts[ \
						PGLineRegressConfigFileMaker.IDX_GUI_ATTRIB_CONFIG_FILE_SECTION ]
				s_viz_param_name=ls_member_name_parts[ \
						PGLineRegressConfigFileMaker.IDX_GUI_ATTRIB_CONFIG_FILE_PARAM ] 
				v_value_this_param = getattr( self.__interface, s_member_name )

				if s_viz_section_name not in self.__ds_interface_param_values_by_param_names_by_section:
					self.__ds_interface_param_values_by_param_names_by_section[ s_viz_section_name ] = {}
				#end if section name new to dict, add it
				
				#If its an output file (either one of the plot file names in the "destination" section
				#or the stats out file, whose param name is "outputFileName" (different section in the
				#Vis config file -- the "confidence" section).

				if s_viz_section_name == "destination" or s_viz_param_name == "outputFilename":
					'''
					2017_05_17. We skip writing the outputFilename param if its plot_type
					attribute is not the one current in the gui (see comments in __init__).
					'''
					if s_viz_param_name == "outputFilename":
						s_this_attr_plot_type=ls_member_name_parts[ \
								PGLineRegressConfigFileMaker.IDX_GUI_ATTRIB_VIZ_TYPE ]
						if s_this_attr_plot_type != self.__plot_type:
							continue
						#end if wrong type for outputFilename, don't write it into dict
					#end if this is the outputFilename

					if v_value_this_param not in [ "show", "none" ]:
						#returns a StrVal tkinter object

						v_outdir=getattr( self.__interface, self.__mangled_attribute_prefix + "output_directory" )
						s_outdir=v_outdir.get()
						v_value_this_param = s_outdir + "/" + v_value_this_param
						if pgut.is_windows_platform():
							v_value_this_param=pgut.fix_windows_path( v_value_this_param )
						#end if using Windows, fix the path

					if s_viz_section_name == "destination":
						if not ( v_value_this_param in [ "show", "none" ] \
												or v_value_this_param.endswith( ".png" ) \
												or v_value_this_param.endswith( ".pdf" ) ) :
							
							v_value_this_param = v_value_this_param + ".png"
						#end if not show, or already has png or pdf extension
					#end if this is a plotted file without a known image file ext, default to png
				#end if this is a destination, or stats out "outputFileName" option
			
				if not self.__omit_x_range \
							or s_viz_param_name  not in [ "xMin", "xMax" ]:
						self.__ds_interface_param_values_by_param_names_by_section[ s_viz_section_name ] [ \
															s_viz_param_name ] = v_value_this_param
				#end if we're not omitting x range options, or if the option is not an x range option

			#end if the member is a viz param

		#end for each member of the interface
		return
Ejemplo n.º 7
0
def negui_main():

	'''
	Note, 2016_12_29: I removed all optional arguments for negui.py, by now
	unnecessary.  The optional args were and int giving total processes (now
	defaulting to 1 process, and settable in the indivudual interfaces), and
	a default life table file, which I've discarded in favor of always loading
	all life tables.
	'''

	WINDOW_MARGIN=0.20
	CONTAINER_PADDING=10
	
	s_my_mod_path=os.path.abspath( __file__ )
	
	s_my_mod_dir=os.path.dirname( s_my_mod_path )

	i_total_simultaneous_processes=1

	s_default_life_tables = s_my_mod_dir + "/resources/*life.table.info"
	s_menu_config=s_my_mod_dir + "/resources/menu_main_interface.txt" 
	s_param_name_file_dir=s_my_mod_dir + "/resources"
	s_startup_info_file=s_my_mod_dir + "/resources/startup.info"

	db_found_files=confirm_resources( s_default_life_tables, 
												s_menu_config, 
												s_param_name_file_dir )

	#The program can't run without these files:
	if not ( db_found_files[ "menu_file" ] and db_found_files[ "param_name_files" ] ):
		s_msg="In negui, def negui_main, " \
				+ "there were resource files not found: " \
				+ "\n".join( db_found_files[ "msgs" ] )
		
		PGGUIErrorMessage( None, s_msg )
		raise Exception( s_msg )
	#end if required file not found

	'''
	The program can run without life table files loaded,
	but we'll send a warning to the console that all
	needed params need to be supplied by the config file.
	'''
	if not db_found_files[ "life_tables" ]:
		s_msg="In negui, def negui_main, " \
						+ "warning: " \
						+ "\n".join( db_found_files[ "msgs" ]  )

		PGGUIWarningMessage( None, s_msg )
		sys.stderr.write( s_msg + "\n" )

		s_default_life_tables=None
	#end if param names

	ds_param_file_names=get_param_file_names( s_param_name_file_dir )

	if pgut.is_windows_platform():
		if s_default_life_tables is not None:
			s_default_life_tables=pgut.fix_windows_path( s_default_life_tables )
		#end if life table files exist
		s_menu_config=pgut.fix_windows_path( s_menu_config )

		for s_filekey in ds_param_file_names:
			ds_param_file_names[ s_filekey ] = \
					pgut.fix_windows_path( \
							ds_param_file_names[ s_filekey ] )
		#end for each param file
	#end if windows, fix paths

	o_master=Tk()

	i_width=o_master.winfo_screenwidth()
	i_height=o_master.winfo_screenheight()

	i_geo_width=int( ( old_div(i_width,2) ) * ( 1 - WINDOW_MARGIN ) )
	i_geo_height=int( ( old_div(i_height,2) ) * ( 1 - WINDOW_MARGIN ) )

	o_host=pgn.PGHostNotebook( o_master, 
			s_menu_config, 
			ds_param_file_names[ "sim" ], 
			ds_param_file_names[ "ne" ], 
			ds_param_file_names[ "viz" ], 
			s_glob_life_tables=s_default_life_tables,
			i_max_process_total=i_total_simultaneous_processes )

	o_host.grid( row=0 )
	o_host.grid_rowconfigure( 0, weight=1 )
	o_host.grid_columnconfigure( 0, weight=1 )
	o_host.grid( row=0, column=0, sticky=( N,W,S,E ))

	o_master.geometry( str(  i_geo_width ) + "x" + str( i_geo_height ) )
	s_title=get_title( s_startup_info_file )
	o_master.title( s_title )	
	o_master.grid_rowconfigure( 0, weight=1 )
	o_master.grid_columnconfigure( 0, weight=1 )

	atexit.register( cleanup_gui, o_host )

	def ask_before_exit():
		s_msg="Exiting will kill any unfinished analyses " \
				+ "and remove their output files.  Exit anyway?"

		o_mbox=PGGUIYesNoMessage( None, s_msg )

		s_answer=o_mbox.value

		if s_answer == True:
			o_master.destroy()
		#end if do exit
	#end ask_before_exit
	
	o_master.protocol( "WM_DELETE_WINDOW", ask_before_exit )

	o_master.mainloop()

	return