creates all the dynamic classes in the script and the class of the script itself
        and updates the script info with these new classes

        Args:
            script_information: A dictionary describing the ScriptIterator, or an existing object
            script_iterators: dictionary with the scriptiterators (optional)

        Returns:
            script_information:  The updated dictionary describing the newly created ScriptIterator class
            script_iterators: updated dictionary with the scriptiterators
        Poststate: Dynamically created classes inheriting from ScriptIterator are added to pylabcontrol.scripts

def create_dynamic_script_class(script_information, script_iterators={},verbose=False):
        '''
        creates all the dynamic classes in the script and the class of the script itself
        and updates the script info with these new classes

        Args:
            script_information: A dictionary describing the ScriptIterator, or an existing object
            script_iterators: dictionary with the scriptiterators (optional)

        Returns:
            script_information:  The updated dictionary describing the newly created ScriptIterator class
            script_iterators: updated dictionary with the scriptiterators
        Poststate: Dynamically created classes inheriting from ScriptIterator are added to pylabcontrol.scripts

        '''

        def set_up_dynamic_script(script_information, script_iterators, verbose=verbose):
            '''

            Args:
                script_information: information about the script as required by Script.get_script_information()

            Returns:
                script_default_settings: the default settings of the dynamically created script as a list of parameters
                sub_scripts

                script_iterators: dictionary of the script_iterator classes of the form {'package_name': <script_iterator_classe>}
                package: name of the package of the script_iterator

            '''

            if verbose:
                print(('script_information', script_information))
            sub_scripts = {}  # dictonary of script classes that are to be subscripts of the dynamic class. Should be in the dictionary form {'class_name': <class_object>} (btw. class_object is not the instance)
            script_order = []  # A list of parameters giving the order that the scripts in the ScriptIterator should be executed. Must be in the form {'script_name': int}. Scripts are executed from lowest number to highest
            script_execution_freq = [] # A list of parameters giving the frequency with which each script should be executed
            _, script_class_name, script_settings, _, script_sub_scripts, _, package = Script.get_script_information(script_information)

            if package not in script_iterators:
                script_iterators.update(ScriptIterator.get_script_iterator(package))

            assert package in script_iterators

            iterator_type = getattr(script_iterators[package], 'get_iterator_type')(script_settings, script_sub_scripts)
            if verbose:
                print(('iterator_type  JG', iterator_type))

            if isinstance(script_information, dict):

                for sub_script_name, sub_script_class in script_sub_scripts.items():
                    if isinstance(sub_script_class, Script):
                        # script already exists

                        # To implement: add a function to scripts that outputs a script_information dict corresponding
                        # to the current settings. This can then be fed into Script.get_script_information and things
                        # can proceed as below. We may also need to add an additional tracker to the dialogue window
                        # to differentiate between the case of wanting a new script from scratch when there is an
                        # identically named one already loaded, vs using that loaded script

                        raise NotImplementedError
                    elif script_sub_scripts[sub_script_name]['class'] == 'ScriptIterator':
                        # raise NotImplementedError # has to be dynamic maybe???
                        script_information_subclass,  script_iterators = ScriptIterator.create_dynamic_script_class(script_sub_scripts[sub_script_name], script_iterators)
                        subscript_class_name = script_information_subclass['class']
                        #previously in python 2 had used: import pylabcontrol.core.script_iterator
                        #however, this shouldn't have worked, as this was already imported as part of pylabcontrol, so nothing
                        #happens and the old version without the dynamic script is used. Here, we force import the new
                        #version of the module which now contains the script_iterator and everything works as expected
                        script_iterator_module = __import__('pylabcontrol.core.script_iterator')
                        sub_scripts.update({sub_script_name: getattr(script_iterator_module, subscript_class_name)})
                    else:
                        if verbose:
                            print(('script_sub_scripts[sub_script_name]', sub_script_class))

                        module = Script.get_script_module(sub_script_class, verbose=verbose)

                        if verbose:
                            print(('module', module))
                        new_subscript = getattr(module, script_sub_scripts[sub_script_name]['class'])
                        sub_scripts.update({sub_script_name: new_subscript})

                # for some iterators have default scripts, e.g. point iteration has select points
                default_sub_scripts, default_script_settings = getattr(script_iterators[package], 'get_iterator_default_script')(iterator_type)


                sub_scripts.update(default_sub_scripts)

                for k, v in default_script_settings.items():
                    if k in script_settings:
                        script_settings[k].update(v)



            elif isinstance(script_information, Script):

                print('old code - DOUBLE CHECK')
                raise NotImplementedError
                # if the script already exists, just update the script order parameter
                sub_scripts.update({script_class_name: script_information})
            else:
                raise TypeError('create_dynamic_script_class: unknown type of script_information')



            script_order, script_execution_freq = getattr(script_iterators[package], 'get_script_order')(script_settings['script_order'])
            script_default_settings = getattr(script_iterators[package], 'get_default_settings')(sub_scripts, script_order, script_execution_freq, iterator_type)
            return script_default_settings, sub_scripts, script_iterators, package

        def create_script_iterator_class(sub_scripts, script_settings, script_iterator_base_class, verbose=verbose):
            """
            A 'factory' to create a ScriptIterator class at runtime with the given inputs.

            Args:
                sub_scripts: dictonary of script classes that are to be subscripts of the dynamic class. Should be in the dictionary
                         form {'class_name': <class_object>} (btw. class_object is not the instance)
                script_default_settings: the default settings of the dynamically created object. Should be a list of Parameter objects.

            Returns: A newly created class inheriting from ScriptIterator, with the given subscripts and default settings

            """


            # dynamically import the module, i.e. the namespace for the scriptiterator
            script_iterator_module = __import__(script_iterator_base_class.__module__)

            if verbose:
                print('\n\n======== create_script_iterator_class ========\n')
                print(('sub_scripts', sub_scripts))
                print(('script_settings', script_settings))
                print(('script_iterator_base_class', script_iterator_base_class))

                print((script_iterator_base_class.__module__.split('.')[0]))


            class_name = script_iterator_base_class.__module__.split('.')[0] + '.dynamic_script_iterator' + str(script_iterator_base_class._number_of_classes)

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

            # If three parameters are passed to type(), it returns a new type object.
            # Three parameters to the type() function are:
            #
            #     name - class name which becomes __name__ attribute
            #     bases - a tuple that itemizes the base class, becomes __bases__ attribute
            #     dict - a dictionary which is the namespace containing definitions for class body; becomes __dict__ attribute
            dynamic_class = type(class_name, (script_iterator_base_class,), {'_SCRIPTS': sub_scripts, '_DEFAULT_SETTINGS': script_settings, '_INSTRUMENTS': {}})

            if verbose:
                print(('dynamic_class', dynamic_class))
                print(('__bases__', dynamic_class.__bases__))

                print(('dynamic_class.__name__', dynamic_class.__name__))
                print(('dynamic_class.__bases__', dynamic_class.__bases__))
                print(('dynamic_class.__dict__', dynamic_class.__dict__))

            # Now we place the dynamic script into the scope of pylabcontrol.
            setattr(script_iterator_module, class_name, dynamic_class)

            if verbose:
                print(('dynamic_class', dynamic_class))
                print(('__bases__', dynamic_class.__bases__))

                print(('dynamic_class.__name__', dynamic_class.__name__))
                print(('dynamic_class.__bases__', dynamic_class.__bases__))
                print(('dynamic_class.__dict__', dynamic_class.__dict__))

            script_iterator_base_class._class_list.append(dynamic_class)
            script_iterator_base_class._number_of_classes += 1


            return class_name, dynamic_class

            # todo: prevent multiple importation of the same script with different names
            # for someclass in cls._class_list:
            #     if (vars(ss)['_SCRIPTS'] == vars(someclass)['_SCRIPTS']):
            #         print('CLASSNAME', vars(someclass)['_CLASS'])
            #         return vars(someclass)['_CLASS']

         # get default setting, load subscripts, load the script_iterators and identify the package
        script_default_settings, sub_scripts, script_iterators, package = set_up_dynamic_script(script_information, script_iterators, verbose=verbose)

        # now actually create the classs
        class_name, dynamic_class = create_script_iterator_class(sub_scripts, script_default_settings, script_iterators[package], verbose = verbose)

        # update the generic name (e.g. ScriptIterator) to a unique name  (e.g. ScriptIterator_01)
        script_information['class'] = class_name

        if 'iterator_type' in script_information['settings']:

            if verbose:
                print('WONDER IF WE EVER HAVE THIS CASE: iterator_type in script_information[setting]')
            script_settings = {}
            for elem in script_default_settings:
                script_settings.update(elem)
            script_information['settings'] = script_settings

            if verbose:
                print('\n\n======== create_dynamic_script_class ========\n')

                print(('dynamic_class', dynamic_class))
                print(('sub_scripts', sub_scripts))
                print(('script_settings', script_settings))

        if verbose:
            print('\n======== end create_dynamic_script_class ========\n')

        return script_information, script_iterators