def load_and_append(script_dict, scripts=None, instruments=None, log_function=None, data_path=None,
                        raise_errors=False, package='pylabcontrol', verbose=False):
        """
        load script from script_dict and append to scripts, if additional instruments are required create them and add them to instruments

        Args:
            script_dict: dictionary of form

                script_dict = {
                name_of_script_1 :
                    {"settings" : settings_dictionary, "class" : name_of_class}
                name_of_instrument_2 :
                    {"settings" : settings_dictionary, "class" : name_of_class}
                ...
                }

            or

                script_dict = {
                name_of_script_1 : name_of_class,
                name_of_script_2 : name_of_class
                ...
                }

            where name_of_class is either a class or the name of a class

            scripts: dictionary of form

                scripts = {
                name_of_script_1 : instance_of_script_1,
                name_of_script_2 : instance_of_script_2,
                ...
                }

            instruments: dictionary of form

                instruments = {
                name_of_instrument_1 : instance_of_instrument_1,
                name_of_instrument_2 : instance_of_instrument_2,
                ...
                }
            log_function: function that takes a string

            data_path: absolute path where data is saved, in case the path in the script is definded as a relative path

            raise_errors: if True errors are raised
        Returns:
                dictionary of form
                script_dict = { name_of_script_1 : script_1_instance, name_of_script_2 : script_2_instance, ...}
                load_failed = {name_of_script_1: exception_1, name_of_script_2: exception_2, ....}
                updated_instruments = {name_of_instrument_1 : instance_of_instrument_1, ..}

        """
        if scripts is None:
            scripts = {}
        if instruments is None:
            instruments = {}

        load_failed = {}
        updated_scripts = {}
        updated_scripts.update(scripts)
        updated_instruments = {}
        updated_instruments.update(instruments)

        if verbose:
            print(('script_dict', script_dict))

        def get_instruments(class_of_script, script_instruments, instruments):
            """

            creates the dictionary with the instruments needed for the script and update the instrument dictionary if new instruments are required

            Args:
                class_of_script: the class of the script
                instruments: the instruments that have been loaded already

            Returns: dictionary with the instruments that the script needs and the updated instruments dictionary

            """

            default_instruments = getattr(class_of_script, '_INSTRUMENTS')
            instrument_dict = {}
            instruments_updated = {}
            instruments_updated.update(instruments)
            # check if instruments needed by script already exist, if not create an instance
            for instrument_name, instrument_class in default_instruments.items():
                # check if instruments needed by script already exist
                instrument = [instance for name, instance in instruments_updated.items() if
                              isinstance(instance, instrument_class) and name == instrument_name]

                if len(instrument) == 0:
                    # create new instance of instrument
                    instruments_updated, __ = Instrument.load_and_append({instrument_name: instrument_class}, instruments_updated, raise_errors)

                if script_instruments is not None and instrument_name in script_instruments:
                    instrument_settings_dict = script_instruments[instrument_name]['settings']
                else:
                    instrument_settings_dict = instruments_updated[instrument_name].settings

                instrument_instance = instruments_updated[instrument_name]

                # make a deepcopy of _DEFAULT_SETTINGS to get a parameter object
                instrument_settings = deepcopy(instrument_instance._DEFAULT_SETTINGS)

                #now update parameter object with new values
                instrument_settings.update(instrument_settings_dict)

                instrument_dict.update({instrument_name: {"instance":instrument_instance, "settings":instrument_settings}})


            return instrument_dict, instruments_updated

        def get_sub_scripts(class_of_script, instruments, sub_scripts_dict, log_function = None):
            """

            creates the dictionary with the sub scripts needed by the script and updates the instrument dictionary if new instruments are required

            Args:
                class_of_script: the class of the script
                instruments: the instruments that have been loaded already
                sub_scripts_dict: settings of script in dictionary form

            Returns:dictionary with the sub scripts that the script needs

            """

            default_scripts = getattr(class_of_script, '_SCRIPTS')
            #
            # create instruments that script needs
            sub_scripts = {}
            sub_scripts, scripts_failed, instruments_updated = Script.load_and_append(default_scripts, sub_scripts,
                                                                                      instruments,
                                                                                      log_function=log_function,
                                                                                      raise_errors=raise_errors)
            try:
                if sub_scripts_dict is not None:
                    for k, v in sub_scripts_dict.items():
                        #update settings, updates instrument and settings
                        sub_scripts[k].update(v)
            except TypeError: #if actually an object, as with dynamic scripts
                pass

            if len(scripts_failed)>0:
                raise ImportError('script {:s}: failed to load subscripts'.format(class_of_script))
            return sub_scripts, instruments_updated

        for script_name, script_info in script_dict.items():

            # check if script already exists
            if script_name in list(scripts.keys()):
                print(('WARNING: script {:s} already exists. Did not load!'.format(script_name)))
                load_failed[script_name] = ValueError('script {:s} already exists. Did not load!'.format(script_name))
            else:
                module, script_class_name, script_settings, script_instruments, script_sub_scripts, script_doc, package = Script.get_script_information(script_info, package=package)
                # creates all dynamic scripts so they can be imported following the if statement
                # if script_class_name == 'ScriptIterator':
                if 'ScriptIterator' in script_class_name:
                    # creates all the dynamic classes in the script and the class of the script itself
                    # and updates the script info with these new classes
                    from pylabcontrol.core.script_iterator import ScriptIterator #CAUTION: imports ScriptIterator, which inherits from script. Local scope should avoid circular imports.

                    script_info, _ = ScriptIterator.create_dynamic_script_class(script_info)

                    # now get the info for the dynamically created class
                    module, script_class_name, script_settings, script_instruments, script_sub_scripts, script_doc, package = Script.get_script_information(script_info)
                if verbose:
                    print(('load_and_append.module', module))
                    print(('load_and_append.script_info', script_info))
                    print(('load_and_append.package', package))

                if module is None and inspect.isclass(script_info):
                    class_of_script = script_info
                else:
                    class_of_script = getattr(module, script_class_name)

                #  ========= create the instruments that are needed by the script =========
                try:
                    script_instruments, updated_instruments = get_instruments(class_of_script, script_instruments, updated_instruments)
                except Exception as err:
                    print(('loading script {:s} failed. Could not load instruments!'.format(script_name)))
                    load_failed[script_name] = err
                    if raise_errors:
                        raise err
                    continue
                #  ========= create the subscripts that are needed by the script =========
                try:
                    sub_scripts, updated_instruments = get_sub_scripts(class_of_script, updated_instruments, script_sub_scripts, log_function = log_function)
                except Exception as err:
                    print(('loading script {:s} failed. Could not load subscripts!'.format(script_name)))
                    load_failed[script_name] = err
                    if raise_errors:
                        raise err
                    continue

                #  ========= create the script if instruments and subscripts have been loaded successfully =========
                class_creation_string = ''
                if script_instruments:
                    class_creation_string += ', instruments = script_instruments'
                if sub_scripts:
                    class_creation_string += ', scripts = sub_scripts'
                if script_settings:
                    class_creation_string += ', settings = script_settings'
                if log_function:
                    class_creation_string += ', log_function = log_function'
                if data_path:
                    class_creation_string += ', data_path = data_path'
                class_creation_string = 'class_of_script(name=script_name{:s})'.format(class_creation_string)

                if verbose:
                    print(('class_creation_string', class_creation_string))
                    print(('class_of_script', class_of_script))
                    print(('scripts', sub_scripts))

                try:
                    script_instance = eval(class_creation_string)
                except Exception as err:
                    print('loading ' + script_name + ' failed:')
                    print(traceback.format_exc())
                    # print(('loading script {:s} failed. Could not create instance of script!'.format(script_name)))
                    load_failed[script_name] = err
                    if raise_errors:
                        raise err
                    continue

                if script_doc:
                    script_instance.__doc__ = script_doc

                updated_scripts.update({script_name: script_instance})


        return updated_scripts, load_failed, updated_instruments
def load_and_append ( script_dict , scripts = None , instruments = None , log_function = None , data_path = None , raise_errors = False , package = 'pylabcontrol' , verbose = False ) : if scripts is None : scripts = { } if instruments is None : instruments = { } load_failed = { } updated_scripts = { } updated_scripts . update ( scripts ) updated_instruments = { } updated_instruments . update ( instruments ) if verbose : print ( ( 'script_dict' , script_dict ) ) def get_instruments ( class_of_script , script_instruments , instruments ) : default_instruments = getattr ( class_of_script , '_INSTRUMENTS' ) instrument_dict = { } instruments_updated = { } instruments_updated . update ( instruments ) for instrument_name , instrument_class in default_instruments . items ( ) : instrument = [ instance for name , instance in instruments_updated . items ( ) if isinstance ( instance , instrument_class ) and name == instrument_name ] if len ( instrument ) == 0 : instruments_updated , __ = Instrument . load_and_append ( { instrument_name : instrument_class } , instruments_updated , raise_errors ) if script_instruments is not None and instrument_name in script_instruments : instrument_settings_dict = script_instruments [ instrument_name ] [ 'settings' ] else : instrument_settings_dict = instruments_updated [ instrument_name ] . settings instrument_instance = instruments_updated [ instrument_name ] instrument_settings = deepcopy ( instrument_instance . _DEFAULT_SETTINGS ) instrument_settings . update ( instrument_settings_dict ) instrument_dict . update ( { instrument_name : { "instance" : instrument_instance , "settings" : instrument_settings } } ) return instrument_dict , instruments_updated def get_sub_scripts ( class_of_script , instruments , sub_scripts_dict , log_function = None ) : default_scripts = getattr ( class_of_script , '_SCRIPTS' ) sub_scripts = { } sub_scripts , scripts_failed , instruments_updated = Script . load_and_append ( default_scripts , sub_scripts , instruments , log_function = log_function , raise_errors = raise_errors ) try : if sub_scripts_dict is not None : for k , v in sub_scripts_dict . items ( ) : sub_scripts [ k ] . update ( v ) except TypeError : pass if len ( scripts_failed ) > 0 : raise ImportError ( 'script {:s}: failed to load subscripts' . format ( class_of_script ) ) return sub_scripts , instruments_updated for script_name , script_info in script_dict . items ( ) : if script_name in list ( scripts . keys ( ) ) : print ( ( 'WARNING: script {:s} already exists. Did not load!' . format ( script_name ) ) ) load_failed [ script_name ] = ValueError ( 'script {:s} already exists. Did not load!' . format ( script_name ) ) else : module , script_class_name , script_settings , script_instruments , script_sub_scripts , script_doc , package = Script . get_script_information ( script_info , package = package ) if 'ScriptIterator' in script_class_name : from pylabcontrol . core . script_iterator import ScriptIterator script_info , _ = ScriptIterator . create_dynamic_script_class ( script_info ) module , script_class_name , script_settings , script_instruments , script_sub_scripts , script_doc , package = Script . get_script_information ( script_info ) if verbose : print ( ( 'load_and_append.module' , module ) ) print ( ( 'load_and_append.script_info' , script_info ) ) print ( ( 'load_and_append.package' , package ) ) if module is None and inspect . isclass ( script_info ) : class_of_script = script_info else : class_of_script = getattr ( module , script_class_name ) try : script_instruments , updated_instruments = get_instruments ( class_of_script , script_instruments , updated_instruments ) except Exception as err : print ( ( 'loading script {:s} failed. Could not load instruments!' . format ( script_name ) ) ) load_failed [ script_name ] = err if raise_errors : raise err continue try : sub_scripts , updated_instruments = get_sub_scripts ( class_of_script , updated_instruments , script_sub_scripts , log_function = log_function ) except Exception as err : print ( ( 'loading script {:s} failed. Could not load subscripts!' . format ( script_name ) ) ) load_failed [ script_name ] = err if raise_errors : raise err continue class_creation_string = '' if script_instruments : class_creation_string += ', instruments = script_instruments' if sub_scripts : class_creation_string += ', scripts = sub_scripts' if script_settings : class_creation_string += ', settings = script_settings' if log_function : class_creation_string += ', log_function = log_function' if data_path : class_creation_string += ', data_path = data_path' class_creation_string = 'class_of_script(name=script_name{:s})' . format ( class_creation_string ) if verbose : print ( ( 'class_creation_string' , class_creation_string ) ) print ( ( 'class_of_script' , class_of_script ) ) print ( ( 'scripts' , sub_scripts ) ) try : script_instance = eval ( class_creation_string ) except Exception as err : print ( 'loading ' + script_name + ' failed:' ) print ( traceback . format_exc ( ) ) load_failed [ script_name ] = err if raise_errors : raise err continue if script_doc : script_instance . __doc__ = script_doc updated_scripts . update ( { script_name : script_instance } ) return updated_scripts , load_failed , updated_instruments
load script from script_dict and append to scripts, if additional instruments are required create them and add them to instruments

        Args:
            script_dict: dictionary of form

                script_dict = {
                name_of_script_1 :
                    {"settings" : settings_dictionary, "class" : name_of_class}
                name_of_instrument_2 :
                    {"settings" : settings_dictionary, "class" : name_of_class}
                ...
                }

            or

                script_dict = {
                name_of_script_1 : name_of_class,
                name_of_script_2 : name_of_class
                ...
                }

            where name_of_class is either a class or the name of a class

            scripts: dictionary of form

                scripts = {
                name_of_script_1 : instance_of_script_1,
                name_of_script_2 : instance_of_script_2,
                ...
                }

            instruments: dictionary of form

                instruments = {
                name_of_instrument_1 : instance_of_instrument_1,
                name_of_instrument_2 : instance_of_instrument_2,
                ...
                }
            log_function: function that takes a string

            data_path: absolute path where data is saved, in case the path in the script is definded as a relative path

            raise_errors: if True errors are raised
        Returns:
                dictionary of form
                script_dict = { name_of_script_1 : script_1_instance, name_of_script_2 : script_2_instance, ...}
                load_failed = {name_of_script_1: exception_1, name_of_script_2: exception_2, ....}
                updated_instruments = {name_of_instrument_1 : instance_of_instrument_1, ..}