docs: 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