##  FileDefaults.py Version 1.10 (module 'FileDefaults')

##  Copyright (c) 2006 Bruce Vaughan, BV Detailing & Design, Inc.

##  All rights reserved.

############################################################################

"""

/// Function definitions for exporting/importing default values to/from disk

/// 'file_name' must be a valid path/file name.

/// If 'file_name' is not valid, both functions return None.

/// 'check_Defaults_dir' can create the directory if it does not exist (added in v_1.03)

/// 'dd' can be anything supported by 'Pickler', but must be a dictionary or

/// list of dictionaries for 'import_data'. 'import_data' returns one dictionary or

/// None (version 1.07).

///

/// Revision History:

///     Version 1.01 (10/25/06) -   Restored 'try-except-except' in import_data

///     Version 1.02 (11/6/06) -    Added break in loop 'for item in dd:'

///                                 Modified Warning message text

///                                 Add test function

///     Version 1.03 (11/7/06) -    Return 'None' instead of '0'

///                                 Add function check_Defaults_dir

///                                 Move 'excepts' after f = open() in import_data

///                                 Move imports inside 'def's

///                                 Add functions 'job_Defaults_path' and 'data_Defaults_path'

///     Version 1.04 (11/08/06) -   Optimized code

///                                 Return True or False in check_Defaults_dir() and export_data()

///                                 Moved 'return dd' in import_data

///     Version 1.05 (11/27/06) -   Eliminate 'types' import.

///                                 Revise object type argument in isinstance calls.

///     Version 1.06 (11/27/06) -   Consolidate import os and pickle

///     Version 1.07 (12/17/06) -   Incorporate 'enumerate' into import_data()

///                                 import_data() now returns one dictionary or None

///     Version 1.08 (2/17/07) -    Add function job_Defaults_path1() which uses an alternate

///                                 way of determining the job path for job depositories not

///                                 under SDS/2 root data directory.

///     Version 1.09 (4/7/07) -     Add functions import_user_data and export_user_data

///     Version 1.10 (5/8/07) -     Import function dim__ to convert fractions and feet-inches-16ths dimensions

///     Version 1.11 (8/3/07) -     Change to user import and export file functions from functions using pickle

///                                 Modify function fdim to correctly convert lists

 

Support for saving integers, floats, and lists. Fractions written as "1/2" to the default file will convert to float (0.5).

"""

 

###############################################################################

# Create the 'Defaults' directory if it does not exist

# Example:

# 'C:\SDS2_7.0\jobs\607_Great_Wolf\macro' is an existing path

# Make directory 'C:\SDS2_7.0\jobs\607_Great_Wolf\macro\Defaults'

# To create a directory only one level deep, use 'os.mkdir'

# Return 1 if directory exists or directory creation is successful

 

import os

import macrolib.pickle

from param import Warning, yes_or_no, dim

from job import JobName

import sys, re

from macrolib.fifDim import dim__

 

def check_Defaults_dir(file_path):

    if not os.path.isdir(file_path):

        if yes_or_no("The directory path does not exist. Do you want to create directory '%s'?" % (file_path)):

            try:

                os.makedirs(file_path)

                return True

            except OSError, e:

                Warning("Could not create directory %s: %s" % (file_path, e))

                return False

        else:

            return False

    return True

   

###############################################################################

# return the path to the job default values directory

# format - 'SDS/2 root data'\jobs\'name of job'\macro\Defaults

def job_Defaults_path():

    return os.path.join(os.getcwd(), "jobs", JobName(), "macro", "Defaults")

 

###############################################################################

# return the path to the job default values directory

# format - 'job directory'\macro\Defaults

def job_Defaults_path1():

    return os.path.join(sys.path[0], "Defaults")

 

###############################################################################

# return the path to the data default values directory

# format - 'SDS/2 root data'\macro\Defaults

def data_Defaults_path():

    return os.path.join(os.getcwd(), "macro", "Defaults")

 

###############################################################################

def OLD_import_data(file_name):

    try:

        f = open(file_name, "r")

    except IOError, e:

        # unable to open file

        Warning("Default file import error. Reverting to original defaults...")

        return None

   

    # file open is successful

    try:

       

        dd = macrolib.pickle.Unpickler(f).load()

        f.close()

        # test for a dictionary or list of dictionaries

        if isinstance(dd, dict):

            return dd

        elif isinstance(dd, list):

            for i, item in enumerate(dd):

                if not isinstance(item, dict):

                    Warning("**INVALID** List item %s is not a dictionary." % (i))

                    return None

            # always return one dictionary

            ddr = {}

            for d in dd: ddr.update(d)

            return ddr

        else:

            # dd is not a dictionary or list of dictionaries

            Warning("Invalid imported data type.\nData must be a dictionary or list of dictionaries.")

            return None

   

    except:

        # file is not compatible with Unpickler - close file and warn user

        f.close()

        Warning("Invalid defaults file. Reverting to original defaults...")

        return None

   

###############################################################################

def OLD_export_data(file_name, dd):

    if check_Defaults_dir(os.path.dirname(file_name)):

        # directory exists or was created

        try:

            f = open(file_name, "w")

            macrolib.pickle.Pickler(f).dump(dd)

            f.close()

            return True

        except:

            Warning("Default values file export error.")

            return False

       

    else:

        # directory did not exist and the user chose 'no' to create directory

        Warning("The default values file export was aborted")

        return False

 

###############################################################################

def fdim(s):

    ss = s.split('/')

    return float(ss[0])/float(ss[1])

       

def convertType(s):

        for func in (int, float, fdim, eval):

            try:

                n = func(s)

                return n

            except:

                pass

        return s

   

def import_data(file_name):

    patt = r'.+=.+'

    try:

        data = [item.strip().split('=') for item in re.findall(patt, open(file_name).read()) if not item.startswith('#')]

        return dict(zip([j[0].strip() for j in data], [convertType(i[1].strip()) for i in data]))

    except:

        Warning("User default file import error. Reverting to auto or initial defaults...")

        return None

   

###############################################################################

   

# valid joined path and file name, dictionary, descriptive header text

def export_data(file_name, dd, name="Python Script Default File"):

    if check_Defaults_dir(os.path.dirname(file_name)):

        # directory exists or was created

        keys = dd.keys()

        keys.sort()

        try:

            f = open(file_name, "w")

            f.write('\n'.join(['#'+name, ]+['%s=%s' % (key, dd[key]) for key in keys]))

            f.close()

            return True

        except:

            Warning("User Default values file export error.")

            return False

       

    else:

        # directory did not exist and the user chose 'no' to create directory

        Warning("The default values file export was aborted")

        return False

 

#########################################################

# dLoc is locals() of the calling object

def export_locals(file_name, name, dLoc=globals()):

    if check_Defaults_dir(os.path.dirname(file_name)):

        # directory exists or was created

        dKey, dValue = zip(*[[key,dLoc[key]] for key in dLoc.keys() if type(dLoc[key]) in (int, str, float, list)])

        dd = dict(zip(dKey, dValue))

        keys = dd.keys()

        keys.sort()

        try:

            f = open(file_name, "w")

            f.write('\n'.join(['#'+name, ]+['%s=%s' % (key, dd[key]) for key in keys]))

            f.close()

            return True

        except:

            Warning("User Default values file export error.")

            return False

       

    else:

        # directory did not exist and the user chose 'no' to create directory

        Warning("The default values file export was aborted")

        return False

###############################################################################

def test_import_export():

    from macrolib.PrintDict import formatDict

 

    dd_list = [{'stf_thk':0.375, 'stf_width':2.5, 'foo':'Python is fun!'}, \

               {'stf_thk1':0.75, 'stf_width1':6.5, 'foobar':'Work is not fun.'}, \

               {'s1':12, 's2':15, 's3':22.5}]

 

    #dd_list = {'stf_thk':0.375, 'stf_width':2.5, 'foo':'Python is fun!'}

    export_data("C:/SDS2_7.0/macro/Defaults/tem.txt", dd_list)

    dd_list = import_data("C:/SDS2_7.0/macro/Defaults/tem.txt")

    if dd_list and isinstance(dd_list, list):

        for dd in dd_list:

            print formatDict("Imported dictionary listing:", dd)

    elif dd_list:

        print formatDict("Imported dictionary listing:", dd_list)

       

###############################################################################

def test_user_export():

 

    dd_list = [{'stf_thk':0.375, 'stf_width':2.5, 'foo':'Python is fun!'}, \

               {'stf_thk1':0.75, 'stf_width1':6.5, 'foobar':'Work is not fun.'}, \

               {'s1':12, 's2':15, 's3':22.5, 'weld_size': '1/4', 'lst': [1,2,3,4,5,6], 'afraction': '1/2'}]

    dd = {}

    for d in dd_list:

      dd.update(d)

 

    print 'Data Exported:'

    for key in dd:

        print key, dd[key]

    print

    

    export_user_data("C:/SDS2_7.0/macro/Defaults/tem1.txt", dd, 'This is a test')

 

###############################################################################

def test_user_import():

    dd = import_user_data("C:/SDS2_7.0/macro/Defaults/tem1.txt")

    #dd = import_user_data(r'C:\SDS2_7.0\jobs\612_Toringdon_VI\macro\Defaults\Col_Outrigger\Col_Outrigger.txt')

    print 'Imported Data:'

    for key in dd:

        print '%s=%s' % (key, dd[key])

    print

    stf_thk = 1.375

    stf_width = 14.375

    print 'Set Values:'

    print 'stf_thk =', stf_thk

    print 'stf_width =', stf_width

    print

    # Use globals().update(dd) if script is not encapsulated in a function

    for key, value in dd.items():

        exec "%s = %s" % (key, repr(value)) in None

        print key, repr(value)

    print

    print 'Updated values:'

    print 'stf_thk =', stf_thk

    print 'stf_width =', stf_width

    export_user_data(r'C:\SDS2_7.0\jobs\612_Toringdon_VI\macro\Defaults\Col_Outrigger\Col_OutriggerTest.txt', dd, 'This is a test')

    return dd

###############################################################################

def test_export_locals(dd):

    stf_thk=0.375

    export_locals("C:/SDS2_7.0/macro/Defaults/locals1.txt", 'This is a test', dd)

 

###############################################################################

           

def test_check_Defaults_dir():

    import os

    #file_name = os.path.join(os.getcwd(), "tem1", "tem2", "tem3")

    #file_path = os.path.dirname(file_name)

    file_path = job_Defaults_path1()

    if not os.path.isdir(file_path):

        if not check_Defaults_dir(file_path):

            print "User elected NOT to make directory '%s'\n" % (file_path)

        else:

            print "User created directory '%s'\n" % (file_path)

    else:

        print "Directory already exists.\n"

       

###############################################################################

if __name__ == '__main__':

    try:

        # test_check_Defaults_dir()

        # test_import_export()

        test_user_export()

        test_user_import()

        #test_export_locals(locals())

    finally:

        del test_import_export

        del test_check_Defaults_dir

        del test_user_export

        del test_user_import

        del test_export_locals