コード例 #1
0
ファイル: gui01.py プロジェクト: iruletheworld/SVG2EMF
    def save_setting(self):
        """
        This function saves the user setting to an INI file.

        Parameter
        ----------
        self
        
        Return
        -------
        None
        
        Example
        --------
        .. code:: python
        
            self.save_setting()
        """

        print(gsyIO.date_time_now() + 'Saving settings...')

        # form INI file content
        str_setting = '[User settings]\n'

        str_setting += 'ledt_inkscape_dir=' + self.ledt_inkscape_dir.text() + '\n'

        str_setting += 'ledt_svg_dir=' + self.ledt_svg_dir.text() + '\n'

        str_setting += 'ledt_emf_dir=' + self.ledt_emf_dir.text() + '\n'

        str_setting += 'checkBox=' + str(self.checkBox.isChecked())

        # form INI file path
        str_ini_file_path = os.path.join(os.getcwd(), CONST_INI_FILENAME)

        # save INI file
        gsyINI.write_ini(str_ini_file_path, str_setting)
コード例 #2
0
ファイル: gui01.py プロジェクト: iruletheworld/SVG2EMF
    def read_setting(self):
        """
        This function reads the user setting from an INI file and
        then assigns them to the objects.

        Parameter
        ----------
        self
        
        Return
        -------
        None
        
        Example
        --------
        .. code:: python
        
            self.read_setting()
        """
        
        # get INI file path
        str_ini_file_path = os.path.join(os.getcwd(), CONST_INI_FILENAME)

        # read INI file
        bool_ini_exist, str_setting = gsyINI.read_ini(str_ini_file_path)

        # if INI file not found, return False
        if bool_ini_exist == False:

            print(gsyIO.date_time_now() + 'Read user setting failed.')

            return False

        else:

            pass

        try:

            # get rid of the line breaks
            str_setting = [item.strip('\n') for item in str_setting]

            str_setting = [item.strip('\r') for item in str_setting]

            # list for QLineEdit
            list_widget = [self.ledt_inkscape_dir, self.ledt_svg_dir,
                           self.ledt_emf_dir]

            # assign values
            for item in str_setting:
                
                # keep the left of "="
                index = item.find('=')

                str_temp_setting = item[:index]

                # assign the checkbox
                if str_temp_setting == 'checkBox':

                    str_temp = item[(index + 1):]

                    if str_temp == 'True':

                        self.checkBox.setChecked(True)

                    else:

                        self.checkBox.setChecked(False)

                # assign the QLineEdit
                for j in list_widget:

                    if str_temp_setting == j.objectName():

                        j.setText(item[(index + 1):])

                        # if found, remove from list
                        list_widget.pop(list_widget.index(j))

                        break

                    else:

                        pass

            print(gsyIO.date_time_now() + 'Read user setting complete')

            return True

        except:

            print(gsyIO.date_time_now() + 'Read user setting failed.')

            return False
    def save_data(self):
        '''
        Save the generated data in CSV.
        '''

        print(gsyIO.date_time_now() + 'Updating data before save')

        self.print_info('Saving data as CSV...')

        bool_temp = self.update_data()

        if bool_temp == False:

            root = tk.Tk()

            root.withdraw()

            msgbox.showerror(
                'Error', 'Error when making phase data. Time cannot be zero.')

            root.destroy()

            return False

        header = [
            'time', 'Phase-A Mag', 'Phase-A Omega', 'Phase-A Phi',
            'Phase-A DC', 'Phase-A Real', 'Phase-A Imag', 'Phase-A Radius',
            'Phase-A Angle', 'Phase-B Mag', 'Phase-B Omega', 'Phase-B Phi',
            'Phase-B DC', 'Phase-B Real', 'Phase-B Imag', 'Phase-B Radius',
            'Phase-B Angle', 'Phase-C Mag', 'Phase-C Omega', 'Phase-C Phi',
            'Phase-C DC', 'Phase-C Real', 'Phase-C Imag', 'Phase-C Radius',
            'Phase-C Angle', 'Phase-A + Real', 'Phase-A + Imag',
            'Phase-A + Radius', 'Phase-A + Angle', 'Phase-B + Real',
            'Phase-B + Imag', 'Phase-B + Radius', 'Phase-B + Angle',
            'Phase-C + Real', 'Phase-C + Imag', 'Phase-C + Radius',
            'Phase-C + Angle', 'Phase-A - Real', 'Phase-A - Imag',
            'Phase-A - Radius', 'Phase-A - Angle', 'Phase-B - Real',
            'Phase-B - Imag', 'Phase-B - Radius', 'Phase-B - Angle',
            'Phase-C - Real', 'Phase-C - Imag', 'Phase-C - Radius',
            'Phase-C - Angle', 'Zero Real', 'Zero Imag', 'Zero Radius',
            'Zero Angle', 'Alpha Real', 'Alpha Imag', 'Alpha Radius',
            'Alpha Angle', 'Beta Real', 'Beta Imag', 'Beta Radius',
            'Beta Angle', 'Alpha + Real', 'Alpha + Image', 'Alpha + Radius',
            'Alpha + Angle', 'Beta + Real', 'Beta + Image', 'Beta + Radius',
            'Beta + Angle', 'Alpha - Real', 'Alpha - Imag', 'Alpha - Radius',
            'Alpha - Angle', 'Beta - Real', 'Beta - Imag', 'Beta - Radius',
            'Beta - Angle', 'd Real', 'd Imag', 'd Radius', 'd Angle',
            'q Real', 'q Imag', 'q Radius', 'q Angle', 'd + Real', 'd + Imag',
            'd + Radius', 'd + Angle', 'q + Real', 'q + Imag', 'q + Radius',
            'q + Angle', 'd - Real', 'd - Imag', 'd - Radius', 'd - Angle',
            'q - Real', 'q - Imag', 'q - Radius', 'q - Angle', 'PLL Omega',
            'PLL Phi', 'PLL theta'
        ]

        # data length needs to be the same
        phase_a_mag = [self.phaseAMag] * len(self.time_samples)
        phase_a_omega = [self.phaseAOmega] * len(self.time_samples)
        phase_a_phi = [self.phaseAPhi] * len(self.time_samples)
        phase_a_dc = [self.phaseADC] * len(self.time_samples)

        phase_b_mag = [self.phaseBMag] * len(self.time_samples)
        phase_b_omega = [self.phaseBOmega] * len(self.time_samples)
        phase_b_phi = [self.phaseBPhi] * len(self.time_samples)
        phase_b_dc = [self.phaseBDC] * len(self.time_samples)

        phase_c_mag = [self.phaseCMag] * len(self.time_samples)
        phase_c_omega = [self.phaseCOmega] * len(self.time_samples)
        phase_c_phi = [self.phaseCPhi] * len(self.time_samples)
        phase_c_dc = [self.phaseCDC] * len(self.time_samples)

        pll_omega = [self.pllOmega] * len(self.time_samples)
        pll_phi = [self.pllPhi] * len(self.time_samples)

        data_sets = [
            self.time_samples, phase_a_mag, phase_a_omega, phase_a_phi,
            phase_a_dc, self.phaseAdata.real, self.phaseAdata.imag,
            abs(self.phaseAdata),
            np.angle(self.phaseAdata), phase_b_mag, phase_b_omega, phase_b_phi,
            phase_b_dc, self.phaseBdata.real, self.phaseBdata.imag,
            abs(self.phaseBdata),
            np.angle(self.phaseBdata), phase_c_mag, phase_c_omega, phase_c_phi,
            phase_c_dc, self.phaseCdata.real, self.phaseCdata.imag,
            abs(self.phaseCdata),
            np.angle(self.phaseCdata), self.phaseA_pos.real,
            self.phaseA_pos.imag,
            abs(self.phaseA_pos),
            np.angle(self.phaseA_pos), self.phaseB_pos.real,
            self.phaseB_pos.imag,
            abs(self.phaseB_pos),
            np.angle(self.phaseB_pos), self.phaseC_pos.real,
            self.phaseC_pos.imag,
            abs(self.phaseC_pos),
            np.angle(self.phaseC_pos), self.phaseA_neg.real,
            self.phaseA_neg.imag,
            abs(self.phaseA_neg),
            np.angle(self.phaseA_neg), self.phaseB_neg.real,
            self.phaseB_neg.imag,
            abs(self.phaseB_neg),
            np.angle(self.phaseB_neg), self.phaseC_neg.real,
            self.phaseC_neg.imag,
            abs(self.phaseC_neg),
            np.angle(self.phaseC_neg), self.phaseZero.real,
            self.phaseZero.imag,
            abs(self.phaseZero),
            np.angle(self.phaseZero), self.alpha.real, self.alpha.imag,
            abs(self.alpha),
            np.angle(self.alpha), self.beta.real, self.beta.imag,
            abs(self.beta),
            np.angle(self.beta), self.alpha_pos.real, self.alpha_pos.imag,
            abs(self.alpha_pos),
            np.angle(self.alpha_pos), self.beta_pos.real, self.beta_pos.imag,
            abs(self.beta_pos),
            np.angle(self.beta_pos), self.alpha_neg.real, self.alpha_neg.imag,
            abs(self.alpha_neg),
            np.angle(self.alpha_neg), self.beta_neg.real, self.beta_neg.imag,
            abs(self.beta_neg),
            np.angle(self.beta_neg), self.d.real, self.d.imag,
            abs(self.d),
            np.angle(self.d), self.q.real, self.q.imag,
            abs(self.q),
            np.angle(self.q), self.d_pos.real, self.d_pos.imag,
            abs(self.d_pos),
            np.angle(self.d_pos), self.q_pos.real, self.q_pos.imag,
            abs(self.q_pos),
            np.angle(self.q_pos), self.d_neg.real, self.d_neg.imag,
            abs(self.d_neg),
            np.angle(self.d_neg), self.q_neg.real, self.q_neg.imag,
            abs(self.q_neg),
            np.angle(self.q_neg), pll_omega, pll_phi, self.thetaPLL
        ]

        gsyIO.save_csv_gui(header, data_sets)

        self.save_setting()

        self.print_info('Data saved as CSV')

        return True
コード例 #4
0
ファイル: gui01.py プロジェクト: iruletheworld/SVG2EMF
    def convert(self):
        """
        This function converts the SVG files found to EMF files.

        The filenames of the SVG files would be kept.

        Overwirte files with the same filenames without notice.

        Conversion is achieved via Inkscape. 
        
        The command is in the form of:

        .. code::

            inkscape foo.svg --export-emf=bar.emf

        Parameter
        ----------
        self
        
        Return
        -------
        bool
            Returns True if conversion successful.
            Returns False if conversion unsuccessful or on exception.
        
        Example
        --------
        .. code:: python
        
            self.btn_go.clicked.connect(self.convert)
        """

        print(gsyIO.date_time_now() + 'Converting...')

        # progress bar control
        int_count = 0

        dbl_progress = 0

        self.progressBar.setValue(dbl_progress)

        # check if all folders exist
        bool_dir_exist = self.check_dir_exist()

        try:

            # if not all folders exist, prompt error message and return False
            if bool_dir_exist == False:

                gsyIO.prompt_msg(str_title='Folder not found',
                                str_msg='At least one folder not found',
                                str_type='err')

                print(gsyIO.date_time_now() + 'At least one folder not found')
                print(gsyIO.date_time_now() + 'Conversion failed')

                return False

            else:
                
                # first part of the shell command
                str_inkscape = '"' + self.str_inkscape_dir + os.sep + 'inkscape' + '"'

                # search for SVG files
                list_svg_file_path = self.search_svg()

                # if the list is empty
                if not list_svg_file_path:

                    gsyIO.prompt_msg(str_title='SVG not found',
                                    str_msg='No SVG file found',
                                    str_type='err')

                    print(gsyIO.date_time_now() + 'No SVG file found')
                    print(gsyIO.date_time_now() + 'Conversion failed')

                    return False

                else:
                    
                    # save user settings
                    self.save_setting()

                    # get the total number of SVG files in the list
                    int_svg_file_count = len(list_svg_file_path)

                    # For-Loop through the SVG files and convert to EMF
                    for item in list_svg_file_path:

                        str_svg_file_path = item

                        # reverse find first path separator
                        index = str_svg_file_path.rfind(os.sep)

                        # get the filename (only) of the SVG file
                        str_svg_filename = str_svg_file_path[(index + 1):]

                        # find the "." of the SVG extension
                        index = str_svg_filename.rfind('.')

                        # replace the "svg" for "emf"
                        str_emf_filename = str_svg_filename[:(index + 1)] + 'emf'

                        # form the full path for the EMF file
                        str_emf_file_path = os.path.join(self.str_emf_dir, str_emf_filename)

                        # form the shell command
                        str_cmd = (str_inkscape + ' ' 
                                + '"' + str_svg_file_path + '"' + ' ' 
                                + '"' + CONST_EXPT_EMF + str_emf_file_path + '"')

                        # run the shell command, timeout is 10 minutes
                        obj = subprocess.run(str_cmd, shell=True, timeout=600)

                        # progress bar control
                        int_count += 1

                        dbl_progress = float(int_count) / float(int_svg_file_count) * 100.0

                        str_info = ('Converting ' + str(int_count) + ' of ' + str(int_svg_file_count)
                                    + ', ' + '{:.2f}'.format(dbl_progress) + r'%')

                        print(str_info)

                        self.progressBar.setValue(dbl_progress)

                    # open EMF folder on end
                    if self.checkBox.isChecked() == True:

                        self.open_emf_folder()

                    else:

                        pass

                    print(gsyIO.date_time_now() + 'Conversion complete')

                    return True

        except:

            print(gsyIO.date_time_now() + 'Conversion failed')

            return False
    def update_data(self):
        '''
        Update the user inputs.
        '''

        print(gsyIO.date_time_now() + 'Updating')

        self.print_info('Updating data...')

        list_temp = []

        # convert user inputs to numerics
        self.phaseAMag = self.to_numeric(self.ledt_phaseAMag.text())
        self.phaseAOmega = self.to_numeric(self.ledt_phaseAOmega.text())
        self.phaseAPhi = self.to_numeric(self.ledt_phaseAPhi.text())
        self.phaseADC = self.to_numeric(self.ledt_phaseADC.text())

        list_temp.append(['Phase-A Mag = ', self.phaseAMag])
        list_temp.append(['Phase-A Omega = ', self.phaseAOmega])
        list_temp.append(['Phase-A Phi = ', self.phaseAPhi])
        list_temp.append(['Phase-A DC = ', self.phaseADC])

        self.phaseBMag = self.to_numeric(self.ledt_phaseBMag.text())
        self.phaseBOmega = self.to_numeric(self.ledt_phaseBOmega.text())
        self.phaseBPhi = self.to_numeric(self.ledt_phaseBPhi.text())
        self.phaseBDC = self.to_numeric(self.ledt_phaseBDC.text())

        list_temp.append(['Phase-B Mag = ', self.phaseBMag])
        list_temp.append(['Phase-B Omega = ', self.phaseBOmega])
        list_temp.append(['Phase-B Phi = ', self.phaseBPhi])
        list_temp.append(['Phase-B DC = ', self.phaseBDC])

        self.phaseCMag = self.to_numeric(self.ledt_phaseCMag.text())
        self.phaseCOmega = self.to_numeric(self.ledt_phaseCOmega.text())
        self.phaseCPhi = self.to_numeric(self.ledt_phaseCPhi.text())
        self.phaseCDC = self.to_numeric(self.ledt_phaseCDC.text())

        list_temp.append(['Phase-C Mag = ', self.phaseCMag])
        list_temp.append(['Phase-C Omega = ', self.phaseCOmega])
        list_temp.append(['Phase-C Phi = ', self.phaseCPhi])
        list_temp.append(['Phase-C DC = ', self.phaseCDC])

        self.pllOmega = self.to_numeric(self.ledt_pllOmega.text())
        self.pllPhi = self.to_numeric(self.ledt_pllPhi.text())

        list_temp.append(['PLL Omega = ', self.pllOmega])
        list_temp.append(['PLL Phi = ', self.pllPhi])

        self.timeEnd = self.to_numeric(self.ledt_time.text())
        self.timeEnd = abs(self.timeEnd)

        list_temp.append(['Time = ', self.timeEnd])

        # print to console
        for item in list_temp:

            print(gsyIO.date_time_now() + str(item[0]) + str(item[1]))

        if self.timeEnd == 0:

            root = tk.Tk()

            root.withdraw()

            msgbox.showerror(
                'Error', 'Error when making phase data. Time cannot be zero.')

            root.destroy()

            return False

        # make three-phase data
        self.phaseAdata, self.time_samples = self.make_phase(
            self.phaseAMag, self.phaseAOmega, self.phaseAPhi, self.phaseADC)

        self.phaseBdata, _ = self.make_phase(self.phaseBMag, self.phaseBOmega,
                                             self.phaseBPhi, self.phaseBDC)
        # print(self.phaseBdata)

        self.phaseCdata, _ = self.make_phase(self.phaseCMag, self.phaseCOmega,
                                             self.phaseCPhi, self.phaseCDC)

        # calculations for Fortescue, Clarke and Park
        # Fortescue
        (self.phaseA_pos, self.phaseB_pos, self.phaseC_pos, self.phaseA_neg,
         self.phaseB_neg, self.phaseC_neg,
         self.phaseZero) = trf.cal_symm(self.phaseAdata, self.phaseBdata,
                                        self.phaseCdata)

        # Clarke
        self.alpha, self.beta, _ = trf.cal_clarke(self.phaseAdata,
                                                  self.phaseBdata,
                                                  self.phaseCdata)

        # Clarke symm
        (self.alpha_pos, self.beta_pos, self.alpha_neg, self.beta_neg,
         _) = trf.cal_clarke_dsogi(self.phaseAdata, self.phaseBdata,
                                   self.phaseCdata)

        # Park
        self.thetaPLL = self.pllOmega * self.time_samples + self.pllPhi

        self.d, self.q, _ = trf.cal_park(self.thetaPLL, self.alpha, self.beta)

        # Park symm
        self.d_pos, self.q_pos, _ = trf.cal_park(self.thetaPLL, self.alpha_pos,
                                                 self.beta_pos)

        self.d_neg, self.q_neg, _ = trf.cal_park(self.thetaPLL, self.alpha_neg,
                                                 self.beta_neg)

        # axes limits
        self.xlim_max = self.timeEnd
        self.xlim_min = 0

        # print('before limits')

        self.ylim_max = max(max(abs(self.phaseAdata)),
                            max(abs(self.phaseBdata)),
                            max(abs(self.phaseCdata)), max(abs(self.alpha)),
                            max(abs(self.beta)), max(abs(self.d)),
                            max(abs(self.q)), max(abs(self.phaseZero)))

        self.ylim_max *= 1.08

        self.ylim_min = -1 * self.ylim_max

        self.print_info('Data updated')

        return True
    def read_setting(self):

        # print('I am reading settings')

        self.print_info('Reading user settings...')

        str_cwd = os.getcwd()

        str_ini_file_path = os.path.join(str_cwd, CONST_INI_FILENAME)

        bool_ini_exist, str_setting = gsyINI.read_ini(str_ini_file_path)

        if bool_ini_exist == False:

            print(gsyIO.date_time_now() + 'Read user setting failed.')

            return False

        else:

            pass

        try:

            str_setting = [item.strip('\n') for item in str_setting]

            str_setting = [item.strip('\r') for item in str_setting]

            # print(str_setting)

            widget_count = self.gridLayout.count()

            # list for QLineEdit widgets
            ledt_list = []

            for item in range(widget_count):

                temp_widget = self.gridLayout.itemAt(item).widget()

                if temp_widget.objectName().startswith('ledt'):

                    ledt_list.append(temp_widget)

            # keep the left of the '='
            for item in str_setting:

                index = item.find('=')

                str_temp_setting = item[:index]

                for j in ledt_list:

                    if str_temp_setting == j.objectName():

                        j.setText(item[(index + 1):])

                        # if found, remove from list
                        ledt_list.pop(ledt_list.index(j))

                        break

                    else:

                        pass

            print(gsyIO.date_time_now() + 'Read user setting complete')

            self.print_info('Read user settings complete')

            return True

        except:

            print(gsyIO.date_time_now() + 'Read user setting failed.')

            self.print_info('Read user setting failed')

            return False
コード例 #7
0
ファイル: gsyINI.py プロジェクト: iruletheworld/GSY
def read_ini_to_tb(locStr_ini_file_path, locList_textbox):
    """
    .. _read_ini_to_tb : 
    
    Read a INI file and assign the corresponding elements to the matplotlib
    textboxes.

    This function would assign the INI element value (right of the "=" sign in 
    the INI file) to the textbox if the label string of the textbox is the same
    as the INI element name (left of the "=" sign in the INI file). 
    
    The input list for textbox would be copied by value into a new list object
    first to prevent modification of the original list.
    
    .. code:: python
    
        locTemp_textbox = list(locList_textbox)
    
    If the INI element is found, the corresponding textbox is removed from 
    locTemp_textbox to make the search faster.

    Parameters
    ------------
    
    locStr_ini_file_path : string
        The path for the INI file.
        
    locList_textbox : list (containing all the matplotlib textboxes)
        The list of textboxes to be filled.

    Returns
    -------
    
    bool
        Returns True if deemed successful (no exception). Returns False if deemed
        unsuccessful (on exception).
        
    locConfig : list or int
        Each element in the list is a line of content read from the given INI 
        file if read successful.
        
        Returns 0 when read fail.
    
    Examples
    --------
    >>> read_ini_to_tb(r'C:\some.ini', list_textbox)
    2017-11-23, 10:33:29:Reading INI file...
    2017-11-23, 10:33:29:Read INI file complete
    2017-11-23, 10:33:29:Setting config : InputHarmonicOrder=2
    2017-11-23, 10:33:29:Setting config : InputPLLOrder=1
    2017-11-23, 10:33:29:Setting config : Samples=300
    2017-11-23, 10:33:29:Setting config : FPS=30
    2017-11-23, 10:33:29:Setting config : BaseFreq=50
    2017-11-23, 10:33:29:Setting config : FFmpegpath=
    """

    try:

        # call function to read INI file
        bool_ini, locConfig = read_ini(locStr_ini_file_path)

        # if read INI fale, exit this function
        if bool_ini == False:

            return (False, locConfig)

        # get of the line break for each line
        locConfig = [item.strip('\n') for item in locConfig]

        locConfig = [item.strip('\r') for item in locConfig]

        # copy the values of the list, otherwise the original list object would be modified
        locTemp_textbox = list(locList_textbox)

        # double for-loop start
        for i in locConfig:

            locIndex = i.find('=')

            # keep the left of the '='
            locStr_temp_config = i[:locIndex]

            for j in locTemp_textbox:

                # strip chars from the labels
                locStr_temp_label = (j.label.get_text().replace(
                    ' ', '').replace('\n', '').replace('\r',
                                                       '').replace(':', ''))

                if locStr_temp_config == locStr_temp_label:

                    # get the right part of the '=' and assgin it to the text boxes
                    j.set_val(i[(locIndex + 1):])

                    print(date_time_now() + 'Setting config : ' + i)

                    # if found, remove from list
                    locTemp_textbox.pop(locTemp_textbox.index(j))

                    break

                else:

                    pass
        # double for-loop end

        return (True, locConfig)

    except:

        print(date_time_now() + 'INI file read failed')

        locConfig = 0

        return (False, locConfig)
コード例 #8
0
ファイル: gsyINI.py プロジェクト: iruletheworld/GSY
def read_ini(locStr_ini_file_path):
    """
    .. _read_ini :     
        
    This funciton reads the given INI file by line and return the read line
    as a list object. This does NOT manipulate the read contents.


    Parameters
    ----------
    locStr_ini_file_path : str
        The INI file full path.

    Returns
    -------
    
    bool
        Returns True if read successful (no exception). Returns False on exception.

    locConfig : list or int
        Returns the INI read by line contents if read successful.
        
        Returns 0 when read fail.
    
    Examples
    --------
    
    >>> read_ini(r'C:\some.ini')
    2017-11-23, 11:13:38:Reading INI file...
    2017-11-23, 11:13:38:Read INI file complete
    (True,
     ['[User configurations]\\n',
      'InputHarmonicOrder=1.7\\n',
      'InputPLLOrder=1\\n',
      'Samples=200\\n',
      'FPS=30\\n',
      'BaseFreq=50\\n',
      'FFmpegpath=\\n'])
    """

    print(date_time_now() + 'Reading INI file...')

    try:

        # open ini file
        locIni_file = open(locStr_ini_file_path, 'r')

        # read by lines
        locConfig = locIni_file.readlines()

        print(date_time_now() + 'Read INI file complete')

        return (True, locConfig)

    except:

        print(date_time_now() + 'Fail to read INI file.')

        locConfig = 0

        return (False, locConfig)
コード例 #9
0
ファイル: gsyINI.py プロジェクト: iruletheworld/GSY
def write_ini(locStr_ini_file_path, locStr_ini):
    """
    .. _write_ini :
    
    Write the given string into the given INI file path.

    Parameters
    ----------
    
    locStr_ini_file_path : str
        The file full path of the INI file. If the extension ".ini" is not included,
        it would be added to the path.
        
    locStr_ini : str
        The string to be written into the INI file.

    Returns
    -------
    
    bool
        Returns True if deemed successful (no exception). Returns False if deemed
        unsuccessful (on exception).

    Examples
    --------
    >>> write_ini('C:\\Temp\\testini', '[User configurations]\\nsome string')
    2017-11-21, 16:24:40:INI file save start
    2017-11-21, 16:24:40:INI file save complete
    Out[51]: True
    
    Content of the INI file would be:
        |  '[User configurations]
        |  some string'
    """

    print(date_time_now() + 'INI file save start')

    try:

        # check whether the INI file path ends with '.ini' (case insensitive)
        if locStr_ini_file_path[-4:].lower() == '.ini':

            # if yes, pass
            pass

        else:

            # if no, append
            locStr_ini_file_path = locStr_ini_file_path + '.ini'

        # open the INI for write
        locIni_file = open(locStr_ini_file_path, 'w')

        # write the string into the INI
        locIni_file.write(locStr_ini)

        # close the INI file
        locIni_file.close()

        print(date_time_now() + 'INI file save complete')

        return True

    except:

        print(date_time_now() + 'INI file save failed')

        return False


# =============================================================================
# </Function: write ini file>
# =============================================================================