def getDate(self): '''Method to return datetime object and formatted date string''' try: date = datetime(int(self.year.text()), int(self.month.text()), int(self.day.text()), int(self.hour.text())) except: self.log.error('Must set the date!') # Log an error criticalMessage("Must set the date!!!").exec_() # Generate error message dialog return None, None # Return None for the date and date string # Dialog to remind user to make sure date is entered correctly dial = confirmMessage( "Are you sure you entered to date correctly?\n\n" + \ "It MUST be in UTC time!" ) # Initialize confirmation dialog dial.exec_() # Execute the dialog; make it appear if not dial.check(): # If the user clicked no self.log.warning('Canceled because incorrect date') # Log a warning return None, None return date, date.strftime(settings.date_fmt)
def ftp_upload(self, *args): if self.ranFTP: self.log.info( 'You already ran this step!' ); criticalMessage( "You already tried to upload to FTP" ).exec_(); # Initialize confirmation for quitting return; self.ranFTP = True; # Set ran FTP to True for key in self.ftpInfo: # Iterate over all keys in the ftpInfo dictionary self.log.info( 'Uploading data to: {}'.format(self.ftpInfo[key]['url']) );# Log some info try: # Try to... ftp = ftpUpload( self.ftpInfo[key]['url'] ); # Set up and FTP instance except: # On exception... self.log.critical( 'Error initializing the FTP upload: {}'.format( self.ftpInfo[key]['url'] ) ); # Log a critical error else: # Else... self.ftpInfo[key]['upload'] = ftp.uploadFiles( self.ftpInfo[key]['dir'], self.ftpInfo[key]['files'], user = self.ftpInfo[key]['user'], passwd = self.ftpInfo[key]['passwd'], ); # Attempt to upload the files if not self.ftpInfo[key]['upload']: # If one or more files failed to upload msg = 'FAILED!!! Upload to {} NOT successful'; # Formatter for error message self.log.critical( msg.format( self.ftpInfo[key]['url'] ) ); # Log a critical error criticalMessage( "Something went wrong!\n\n" + \ "There was an error uploading one or more files to the FTP.\n\n" + \ "FTP Address: {}\n\n".format( self.ftpInfo[key]['url'] ) + \ "Check the logs to determine which file(s) failed to upload.\n\n" + \ "YOU MUST MANUALLY UPLOAD ANY FILES THAT FAILED!!!" ).exec_(); else: self.log.info( 'Data upload successful!' ); if self.ftpInfo['ucar']['upload']: # If the upload to UCAR was a success self.uploadSucces.show(); # Show green light next to the 'FTP Upload' button to indicate that step is complete self.checkButton.setEnabled(True)
def gen_sounding(self, *args): ''' Method for generating the SPC-like sounding using the SPCWindow class of SHARPpy. ''' self.log.info( 'Generating Skew-T diagram' ); # Log some information sndDataPNG = settings.skewT_fmt.format( self.date_str ); # Set the name for the skewT file using the settings.skew_T_fmt string self.sndDataPNG = os.path.join( self.dst_dirFull, sndDataPNG ); # Set the sndDataPNG attribute using the dst_dirFull attribute and sndDataFile variable save_msg = "Check that the image looks okay.\n " + \ "If ok, click save, else click cancel"; # Confirmation message for the save dialog for Skew-T; will update if cannot save Skew-T due to issue in SHARPpy sharppy_bug = False; # Flag for if sharppy bug encountered try: # Try to... decoder = SPCDecoder( self.sndDataFile ); # Decode the sounding file using the SPCDecoder profile = decoder.getProfiles(); # Get the profiles from the file stn_id = decoder.getStnId(); # Get the station id from the file except: # On exception criticalMessage( "There was an error loading the sounding data\n\n" ).exec_(); # Initialize and display critical error dialog return; # Return from method model = "Archive"; # Set model to 'Archive'; not sure why but was in the SHARPpy full_gui.py disp_name = stn_id; # Set the display name to the station ID from the sounding data file run = profile.getCurrentDate(); # Set the run to the current date from the sounding data profile.setMeta('model', model); # Set the model in the sounding data profile.setMeta('loc', disp_name); # Set the display name in the sounding data profile.setMeta('run', run); # Set the run in the sounding data if not profile.getMeta('observed'): # If it's not an observed profile profile.setAsync( AsyncThreads(2, debug) ); # Generate profile objects in background. Not sure why works but in SHARPpy full_gui.py self.log.debug('Generating SHARPpy window') if self.skew is None: # If there is no skew window setup; there should never be... self.skew = SPCWindow(cfg=self.config); # Initialize a new SPCWindow object self.skew.closed.connect(self.__skewAppClosed); # Connect the closed method to the __skewAppClosed private method self.skew.addProfileCollection(profile); # Add the profile data to the SPCWindow object try: self.skew.show(); # Show the window except: sharppy_bug = True; self.log.warning("SHARPpy didn't like that sounding very much!") save_msg = "Congradulations!\n\n" + \ "You just found a bug in SHARPpy.\n" + \ "There is nothing we can about this. No Skew-T can be created.\n" + \ "Just click 'Save' and continue with the uploading"; dial = saveMessage( save_msg ); # Set up save message pop-up dial.exec_(); # Display the save message pop-up if dial.check(): # If clicked save if not sharppy_bug: # If the SHARPpy bug did NOT occur self.ftpInfo['ucar']['files'].append( self.sndDataPNG ); # Append the SHARPpy image file name to the ftpInfo['ucar']['files'] list self.log.info('Saving the Skew-T to: {}'.format( self.sndDataPNG ) ); # Log some information pixmap = QPixmap.grabWidget( self.skew ); # Grab the image from the skew T window pixmap.save( self.sndDataPNG, 'PNG', 100); # Save the image self.config.set('paths', 'save_img', os.path.dirname(self.sndDataPNG)); # Add image path to the config object self.log.debug( 'Files to upload to UCAR: {}'.format( ', '.join(self.ftpInfo['ucar']['files']) ) ) self.genSucces.show(); # Show green light next to the 'Generate Sounding' button to indicate that step is complete self.uploadButton.setEnabled( True ); # Enable the upload button else: # Else self.log.critical('Skew-T save aborted! Not allowed to upload!'); # Log an error try: self.skew.close(); # Close the skew T window except: pass;
def proc_files(self, *args): ''' Method for processing sounding files; i.e., renaming and removing values where ballon is descending in sounding ''' failed = False; # Initialize failed to False self.log.info( 'Processing files' ); files = os.listdir( self.dst_dirFull ); # Get list of all files in the directory rename_status = dict.fromkeys( settings.rename.keys(), False); # Status of file renaming process_status = dict.fromkeys( settings.convert.keys(), False); # Status of file processing for file in files: # Iterate over the list of files for key in settings.rename: # Loop over the keys in the settings.rename dictionary if key in file: # If the key is in the source file name rename_status[key] = True; # Add rname status as True dst_file = settings.rename[key].format( self.date_str ); # Set a destination file name dst = os.path.join( self.dst_dirFull, dst_file ); # Build the destination file path src = os.path.join( self.dst_dirFull, file ); # Set source file path # self.uploadFiles.append( dst ); # Append the file to the uploadFile list self.log.info( 'Moving file: {} -> {}'.format(src, dst) ); # Log some information os.rename( src, dst ); # Move the file if not os.path.isfile( dst ): # If the renamed file does NOT exist self.log.error( 'There was an error renaming the file!' ); # Log an error failed = True; # Set failed to True file_found = False; # Flag for in the file to process is found! for key in settings.convert: # Loop over the keys in the settings.rename dictionary if key in file: # If the key is in the source file name process_status[key] = True; # Set to true if the file is found dst_file = settings.convert[key].format( self.date_str ); # Set a destination file name self.sndDataFile = os.path.join( self.dst_dirFull, dst_file ); # Build the destination file path src = os.path.join( self.dst_dirFull, file ); # Set source file path # self.uploadFiles.append( dst ); # Append the file to the uploadFile list self.log.info( 'Converting sounding data to SHARPpy format...' ); # Log some information res = iMet2SHARPpy( src, self.stationName.text().upper(), datetime = self.date, output = self.sndDataFile); # Run function to convert data to SHARPpy format if res and os.path.isfile( self.sndDataFile ): # If function returned True and the output file exists for key in self.ftpInfo: # Iterate over keys in ftpInfo attribute self.ftpInfo[key]['files'].append( self.sndDataFile ); # Append sounding data file path to files key in ftpInfo dictionary else: failed = True; # Set failed to True self.sndDataFile = None; # if the function failed to run OR the output file does NOT exist self.log.error( 'There was an error creating SHARPpy file!' ); # Log an error criticalMessage( 'Problem converting the sounding data to SHARPpy format!' ).exec_(); # Generate critical error message box if not all( rename_status.values() ): failed = True; self.log.error( 'There was an error renaming one or more files!' ); # Log an error criticalMessage( 'Problem renaming one or more files!' ).exec_(); # Generate critical error message box if not all( process_status.values() ): failed = True; self.log.error( 'There was an error converting one or more files to SHARPpy format!' ); # Log an error criticalMessage( 'Problem converting one or more files to SHARPpy format!' ).exec_(); # Generate critical error message box if not failed: # If failed is False self.procSucces.show(); # Show green light next to the 'Process Files' button to indicate that step is complete if self.date <= datetime.utcnow(): # If the date for the sound is NOT in the future self.timeCheck.emit(); # Emit signal to activate the 'Generate Sounding' button else: # Else, date for sounding IS in the future dt = self.date - datetime.utcnow(); # Compute the current time difference between the sounding and utcnow msg = ['Date requested is in the future!', 'Sounding generation disabled until requested sounding time', 'Wait time remaining {}'.format( str(dt) ) ]; # List that contains message for the logger self.log.warning( '\n'.join(msg) ); # Log the message as a warning criticalMessage( 'The data processing has completed!\n\n' + \ 'However, the requested date/time for the\n' + \ 'sounding is in the future!\n\n' +\ 'The \'Generate Sounding\' button will activate\n' + \ 'when the current time is after the requested time!' ).exec_(); # Generate critical error message box dt = (int( dt.total_seconds() ) + 2) * 1000; # Get total time between now and future time, add 2 seconds, convert to integer, then conver to milliseconds QTimer.singleShot( dt, self._timeCheck ); # Run single shot timer thread for the _timeCheck method, waiting dt milliseconds before running
def copy_files(self, *args): ''' Method for copying files from source to destination, renaming files along the way ''' if self.dst_dir is None: self.log.error( 'Destination directory NOT set!' ); return; if self.src_dir is None: self.log.error( 'Source directory NOT set!' ); return; if self.iopName.text() == '': self.log.error( 'IOP Number NOT set!!!' ) criticalMessage( "Must set the IOP Number!!!" ).exec_(); return if self.stationName.text() == '': self.log.error( 'Station Name NOT set!!!' ) criticalMessage( "Must set the Station Name!!!" ).exec_(); return # Main copying code failed = False; # Initialize failed to False self.__init_ftpInfo(); # Initialize ftpInfo attribute using method self.date, self.date_str = self.dateFrame.getDate( ); # Get datetime object and date string as entered in the gui if self.date is None: return; # If the date variable is set to None self.dst_dirFull = os.path.join( self.dst_dir, 'IOP'+self.iopName.text(), self.date_str ); # Build destination directory using the dst_dir, iopName, and date string if not os.path.isdir( self.dst_dirFull ): # If the output directory does NOT exist self.log.info( 'Creating directory: ' + self.dst_dirFull ); # Log some information os.makedirs( self.dst_dirFull ); # IF the dst_dir does NOT exist, then create it else: # Else, the directory exists, so check to over write dial = confirmMessage( "The destination directory exists!\n" + \ "Do you want to overwrite it?\n\n" + \ "YOU CANNOT UNDO THIS ACTION!!!" ); dial.exec_(); # Generate the message window if dial.check(): self.log.info( 'Removing directory: ' + self.dst_dirFull ); # Log some information shutil.rmtree( self.dst_dirFull ); # Delete the directory self.log.info( 'Creating directory: ' + self.dst_dirFull ); # Log some information os.makedirs( self.dst_dirFull ); # IF the dst_dir does NOT exist, then create it else: # Else, don't do anything self.log.warning('Cannot over write data!'); # Log a warning return; # Return from function self.log.info( 'Source directory: {}'.format(self.src_dir) ); # Log some information self.log.info( 'Destination directory: {}'.format(self.dst_dirFull) ); # Log some information self.log.info( 'Copying directory' ); # Log some information for root, dirs, files in os.walk( self.src_dir ): # Walk over the source directory for file in files: # Loop over all files src = os.path.join( root, file ); # Set the source file path dst = os.path.join( self.dst_dirFull, file ); # Set the destination path shutil.copy2( src, dst ); # Copy all data from the source directory to the dst_dir if not os.path.isfile( dst ): # If the destination file does NOT exist self.log.error( 'There was an error copying file: {}'.format(file) ); # Log a warning failed = True; # Set failed to True break; # Break the for loop if not failed: self.log.info( 'Finished copying' ); # log some information self.log.info( 'Ready to process data files!' ); # Log some info self.copySucces.show(); # Show green light next to the 'Copy Files' button to indicate that step is complete self.procButton.setEnabled( True ); # Enable the 'Process Files' button else: # Else, something went wrong criticalMessage( "Something went wrong!\n\n" + \ "There was an error copying a data file.\n" + \ "Please check the logs and directories to see what happened." ).exec_();