Esempio n. 1
0
    def test_import_examples(self):

        for examples_path, category_name in example_categories_names():

            info("Opening Dir named: %s", category_name)

            examples_set = examples_path / category_name
            for listed_path in examples_set.iterdir():

                # cast from Path class to dumb string.
                path = str(listed_path)

                # assuming these are all jsons for now.
                name = basename(path)

                if name in UNITTEST_SKIPLIST:
                    info(f"Skipping test import of: {name} - to permit unit-tests to continue")
                    continue

                with self.subTest(file=name):
                    # info("Importing: %s", name)
                    with self.temporary_node_tree("ImportedTree") as new_tree:
                        # Do not try to process imported tree,
                        # that will just take time anyway
                        new_tree.sv_process = False
                        importer = JSONImporter.init_from_path(path)
                        importer.import_into_tree(new_tree, print_log=False)
                        for node in new_tree.nodes:
                            if is_old(node):
                                error_format = "This example contains deprecated node `{}' ({}). Please upgrade the example file."
                                self.fail(error_format.format(node.name, node.bl_idname))
                            if is_dependent(node.bl_idname):
                                self.skipTest("Some dependencies was not installed")
                        if importer.has_fails:
                            raise ImportError(importer.fail_massage)
Esempio n. 2
0
def add_node_to_tree(nodes, n, nodes_to_import, name_remap, create_texts):
    node_ref = nodes_to_import[n]
    bl_idname = node_ref['bl_idname']

    try:
        if old_nodes.is_old(bl_idname):
            old_nodes.register_old(bl_idname)

        if bl_idname == 'SvMonadGenericNode':
            node = unpack_monad(nodes, node_ref)
            if not node:
                raise Exception("It seems no valid node was created for this Monad {0}".format(node_ref))
        else:
            node = nodes.new(bl_idname)

    except Exception as err:
        print(traceback.format_exc())
        print(bl_idname, 'not currently registered, skipping')
        return

    if create_texts:
        add_texts(node, node_ref)
    
    if bl_idname in {'SvObjInLite', 'SvExecNodeMod', 'SvMeshEvalNode'}:
        node.storage_set_data(node_ref)

    if bl_idname == 'SvObjectsNodeMK3':
        for named_object in node_ref.get('object_names', []):
            node.object_names.add().name = named_object

    gather_remapped_names(node, n, name_remap)
    apply_core_props(node, node_ref)
    apply_superficial_props(node, node_ref)
    apply_post_processing(node, node_ref)
Esempio n. 3
0
    def _build_nodes(self, tree, factories, imported_structs):
        """Build nodes of the main tree, other dependencies should be already initialized"""
        with tree.init_tree():
            # first all nodes should be created without applying their inner data
            # because some nodes can have `parent` property which points into another node
            node_structs = []
            for node_name, raw_structure in self._struct["main_tree"]["nodes"].items():
                with self.logger.add_fail("Init node (main tree)", f"Name: {node_name}"):
                    node_struct = factories.node(node_name, self.logger, raw_structure)

                    # register optional node classes
                    if old_nodes.is_old(node_struct.read_bl_type()):
                        old_nodes.register_old(node_struct.read_bl_type())
                    if dummy_nodes.is_dependent(node_struct.read_bl_type()):
                        dummy_nodes.register_dummy(node_struct.read_bl_type())

                    # add node an save its new name
                    node = tree.nodes.new(node_struct.read_bl_type())
                    node.name = node_name
                    imported_structs[(StrTypes.NODE, tree.name, node_name)] = node.name
                    node_structs.append(node_struct)

            for node_struct in node_structs:
                with self.logger.add_fail("Build node (main tree)", f"Name {node_struct.name}"):
                    new_name = imported_structs[(StrTypes.NODE, tree.name, node_struct.name)]
                    node = tree.nodes[new_name]
                    node_struct.build(node, factories, imported_structs)

            for raw_struct in self._struct["main_tree"]["links"]:
                with self.logger.add_fail("Build link (main tree)", f"Struct: {raw_struct}"):
                    factories.link(None, self.logger, raw_struct).build(tree, factories, imported_structs)
Esempio n. 4
0
    def test_import_examples(self):

        for cat in examples_paths:

            if not examples_paths.get(cat):
                info("Dir named: %s is empty", cat)
                continue

            info("Opening Dir named: %s", cat)

            examples_set = Path(examples_paths.get(cat))
            for listed_path in examples_set.iterdir():

                # cast from Path class to dumb string.
                path = str(listed_path)

                # assuming these are all jsons for now.
                name = basename(path)

                if name in UNITTEST_BLACKLIST:
                    info("Skipping (blacklisted) : %s to permit unit tests to continue", name)
                    continue

                with self.subTest(file=name):
                    # info("Importing: %s", name)
                    with self.temporary_node_tree("ImportedTree") as new_tree:
                        with self.assert_logs_no_errors():
                            # Do not try to process imported tree,
                            # that will just take time anyway
                            new_tree.sv_process = False
                            import_tree(new_tree, path)
                        for node in new_tree.nodes:
                            if is_old(node):
                                error_format = "This example contains deprecated node `{}' ({}). Please upgrade the example file." 
                                self.fail(error_format.format(node.name, node.bl_idname))
Esempio n. 5
0
    def build(self, tree, factories: StructFactory, imported_structs: OldNewNames):
        """Reads and generates nodes, links, dependent data blocks"""
        with tree.init_tree():
            # first all nodes should be created without applying their inner data
            # because some nodes can have `parent` property which points into another node
            node_structs = []
            for node_name, raw_structure in self._struct["nodes"].items():
                with self.logger.add_fail("Init node", f"Tree: {tree.name}, Node: {node_name}"):
                    node_struct = factories.node(node_name, self.logger, raw_structure)

                    # register optional node classes
                    if old_nodes.is_old(node_struct.read_bl_type()):
                        old_nodes.register_old(node_struct.read_bl_type())
                    if dummy_nodes.is_dependent(node_struct.read_bl_type()):
                        dummy_nodes.register_dummy(node_struct.read_bl_type())

                    # add node an save its new name
                    node = tree.nodes.new(node_struct.read_bl_type())
                    node.name = node_name
                    imported_structs[(StrTypes.NODE, tree.name, node_name)] = node.name
                    node_structs.append(node_struct)

            for node_struct in node_structs:
                with self.logger.add_fail("Build node", f"Tree: {tree.name}, Node: {node_struct.name}"):
                    new_name = imported_structs[(StrTypes.NODE, tree.name, node_struct.name)]
                    node = tree.nodes[new_name]
                    node_struct.build(node, factories, imported_structs)

            for raw_struct in self._struct["links"]:
                with self.logger.add_fail("Build link", f"Tree: {tree.name}, Struct: {raw_struct}"):
                    factories.link(None, self.logger, raw_struct).build(tree, factories, imported_structs)

            for prop_name, prop_value in self._struct.get("properties", dict()).items():
                with self.logger.add_fail("Setting tree property", f'Tree: {node.id_data.name}, prop: {prop_name}'):
                    factories.prop(prop_name, self.logger, prop_value).build(tree, factories, imported_structs)
def add_node_to_tree(nodes, n, nodes_to_import, name_remap, create_texts):
    node_ref = nodes_to_import[n]
    bl_idname = node_ref['bl_idname']

    try:
        if old_nodes.is_old(bl_idname):
            old_nodes.register_old(bl_idname)

        if bl_idname == 'SvMonadGenericNode':
            node = nodes.new(bl_idname)
            params = node_ref.get('params')
            cls_dict = params.get('cls_dict')
            monad_name = params.get('monad')
            monad = bpy.data.node_groups[monad_name]
            node.input_template = cls_dict['input_template']
            node.output_template = cls_dict['output_template']
            setattr(node, 'cls_bl_idname', cls_dict['cls_bl_idname'])
            setattr(monad, 'cls_bl_idname', cls_dict['cls_bl_idname'])

            # node.bl_idname = node.cls_bl_idname
        else:
            node = nodes.new(bl_idname)
    except Exception as err:
        print(traceback.format_exc())
        print(bl_idname, 'not currently registered, skipping')
        return

    if create_texts:
        add_texts(node, node_ref)

    gather_remapped_names(node, n, name_remap)
    apply_core_props(node, node_ref)
    apply_superficial_props(node, node_ref)
    apply_post_processing(node, node_ref)
def add_node_to_tree(nodes, n, nodes_to_import, name_remap, create_texts):
    node_ref = nodes_to_import[n]
    bl_idname = node_ref['bl_idname']

    try:
        if old_nodes.is_old(bl_idname):
            old_nodes.register_old(bl_idname)

        if bl_idname == 'SvMonadGenericNode':
            node = unpack_monad(nodes, node_ref)
            if not node:
                raise Exception("It seems no valid node was created for this Monad {0}".format(node_ref))
        else:
            node = nodes.new(bl_idname)

    except Exception as err:
        exception(err)
        error('%s not currently registered, skipping', bl_idname)
        return

    if create_texts:
        add_texts(node, node_ref)

    if hasattr(node, 'storage_set_data'):
        node.storage_set_data(node_ref)

    if bl_idname == 'SvObjectsNodeMK3':
        for named_object in node_ref.get('object_names', []):
            node.object_names.add().name = named_object

    gather_remapped_names(node, n, name_remap)
    apply_core_props(node, node_ref)
    apply_superficial_props(node, node_ref)
    apply_post_processing(node, node_ref)
    apply_custom_socket_props(node, node_ref)
Esempio n. 8
0
    def test_import_examples(self):

        for cat in examples_paths:

            if not examples_paths.get(cat):
                info("Dir named: %s is empty", cat)
                continue

            info("Opening Dir named: %s", cat)

            examples_set = Path(examples_paths.get(cat))
            for listed_path in examples_set.iterdir():

                # cast from Path class to dumb string.
                path = str(listed_path)

                # assuming these are all jsons for now.
                name = basename(path)

                if name in UNITTEST_BLACKLIST:
                    info("Skipping (blacklisted) : %s to permit unit tests to continue", name)
                    continue

                with self.subTest(file=name):
                    info("Importing: %s", name)
                    with self.temporary_node_tree("ImportedTree") as new_tree:
                        with self.assert_logs_no_errors():
                            # Do not try to process imported tree,
                            # that will just take time anyway
                            new_tree.sv_process = False
                            import_tree(new_tree, path)
                        for node in new_tree.nodes:
                            if is_old(node):
                                error_format = "This example contains deprecated node `{}' ({}). Please upgrade the example file." 
                                self.fail(error_format.format(node.name, node.bl_idname))
Esempio n. 9
0
def add_node_to_tree(nodes, n, nodes_to_import, name_remap, create_texts):
    node_ref = nodes_to_import[n]
    bl_idname = node_ref['bl_idname']

    try:
        if old_nodes.is_old(bl_idname):
            old_nodes.register_old(bl_idname)

        if bl_idname == 'SvMonadGenericNode':
            node = unpack_monad(nodes, node_ref)
            if not node:
                raise Exception("It seems no valid node was created for this Monad {0}".format(node_ref))
        else:
            node = nodes.new(bl_idname)

    except Exception as err:
        exception(err)
        error('%s not currently registered, skipping', bl_idname)
        return

    if create_texts:
        add_texts(node, node_ref)

    if hasattr(node, 'storage_set_data'):
        node.storage_set_data(node_ref)

    if bl_idname == 'SvObjectsNodeMK3':
        for named_object in node_ref.get('object_names', []):
            node.object_names.add().name = named_object

    gather_remapped_names(node, n, name_remap)
    apply_core_props(node, node_ref)
    apply_superficial_props(node, node_ref)
    apply_post_processing(node, node_ref)
    apply_custom_socket_props(node, node_ref)
Esempio n. 10
0
    def execute(self, context):
        ntree = context.space_data.node_tree

        for node in ntree.nodes:
            if old_nodes.is_old(node):
                info("Deprecated node: `%s' (%s)", node.name, node.bl_idname)

        self.report({'INFO'}, "See logs")
        return {'FINISHED'}
Esempio n. 11
0
    def execute(self, context):
        ntree = context.space_data.node_tree

        for node in ntree.nodes:
            if is_old(node):
                info("Deprecated node: `%s' (%s)", node.name, node.bl_idname)

        self.report({'INFO'}, "See logs")
        return {'FINISHED'}
Esempio n. 12
0
 def add_node(self, bl_type: str, node_name: str) -> Union[SverchCustomTreeNode, None]:
     """
     Trying to add node with given bl_idname into given tree
     Also it can register dummy and old nodes and register fails
     """
     with self._fails_log.add_fail("Creating node", f'Tree: {self._tree_name}, Node: {node_name}'):
         if old_nodes.is_old(bl_type):  # old node classes are registered only by request
             old_nodes.register_old(bl_type)
         if dummy_nodes.is_dependent(bl_type):
             # some node types are not registered if dependencies are not installed
             # in this case such nodes are registered as dummies
             dummy_nodes.register_dummy(bl_type)
         node = self._tree.nodes.new(bl_type)
         node.name = node_name
         return node
Esempio n. 13
0
def add_node_to_tree(nodes, n, nodes_to_import, name_remap, create_texts):
    node_ref = nodes_to_import[n]
    bl_idname = node_ref['bl_idname']

    try:
        if old_nodes.is_old(bl_idname):
            old_nodes.register_old(bl_idname)

        if bl_idname == 'SvMonadGenericNode':
            node = unpack_monad(nodes, node_ref)
            if not node:
                raise Exception(
                    "It seems no valid node was created for this Monad {0}".
                    format(node_ref))
        else:
            if dummy_nodes.is_dependent(bl_idname):
                try:
                    node = nodes.new(bl_idname)
                except RuntimeError:
                    dummy_nodes.register_dummy(bl_idname)
                    node = nodes.new(bl_idname)
            else:
                node = nodes.new(bl_idname)

    except Exception as err:
        exception(err)
        error('%s not currently registered, skipping', bl_idname)
        return

    # fix_enum_identifier_spaces_if_needed(node, node_ref)

    if create_texts:
        add_texts(node, node_ref)

    if hasattr(node, 'storage_set_data'):
        node.storage_set_data(node_ref)

    if bl_idname == 'SvObjectsNodeMK3':
        for named_object in node_ref.get('object_names', []):
            node.object_names.add().name = named_object

    gather_remapped_names(node, n, name_remap)
    import_node_settings(node, node_ref)
Esempio n. 14
0
def add_node_to_tree(nodes, n, nodes_to_import, name_remap, create_texts):
    node_ref = nodes_to_import[n]
    bl_idname = node_ref["bl_idname"]

    try:
        if old_nodes.is_old(bl_idname):
            old_nodes.register_old(bl_idname)

        if bl_idname == "SvMonadGenericNode":
            node = nodes.new(bl_idname)
            params = node_ref.get("params")
            cls_dict = params.get("cls_dict")
            monad_name = params.get("monad")
            monad = bpy.data.node_groups[monad_name]
            node.input_template = cls_dict["input_template"]
            node.output_template = cls_dict["output_template"]
            setattr(node, "cls_bl_idname", cls_dict["cls_bl_idname"])
            setattr(monad, "cls_bl_idname", cls_dict["cls_bl_idname"])

            # node.bl_idname = node.cls_bl_idname
        else:
            node = nodes.new(bl_idname)
    except Exception as err:
        print(traceback.format_exc())
        print(bl_idname, "not currently registered, skipping")
        return

    if create_texts:
        add_texts(node, node_ref)

    if bl_idname in {"SvObjInLite", "SvExecNodeMod"}:
        node.storage_set_data(node_ref)

    if bl_idname == "SvObjectsNodeMK3":
        print(node_ref)
        obj_names = node_ref.get("object_names", [])
        for n in obj_names:
            node.object_names.add().name = n

    gather_remapped_names(node, n, name_remap)
    apply_core_props(node, node_ref)
    apply_superficial_props(node, node_ref)
    apply_post_processing(node, node_ref)
Esempio n. 15
0
    def generate_layout(fullpath, nodes_json):
        print('#' * 12, nodes_json['export_version'])
        ''' first create all nodes. '''
        nodes_to_import = nodes_json['nodes']
        groups_to_import = nodes_json.get('groups', {})

        group_name_remap = {}
        for name in groups_to_import:
            group_ng = bpy.data.node_groups.new(name, 'SverchGroupTreeType')
            if group_ng.name != name:
                group_name_remap[name] = ng.name
            import_tree(group_ng, '', groups_to_import[name])

        name_remap = {}
        texts = bpy.data.texts

        for n in sorted(nodes_to_import):
            node_ref = nodes_to_import[n]
            bl_idname = node_ref['bl_idname']

            try:
                if old_nodes.is_old(bl_idname):
                    old_nodes.register_old(bl_idname)
                node = nodes.new(bl_idname)
            except Exception as err:
                print(traceback.format_exc())
                print(bl_idname, 'not currently registered, skipping')
                continue

            if create_texts:
                if node.bl_idname in SCRIPTED_NODES:
                    '''
                    Scripted Node will no longer create alternative versions of a file.
                    If a scripted node wants to make a file called 'inverse.py' and the
                    current .blend already contains such a file, then for simplicity the
                    importer will not try to create 'inverse.001.py' and reference that.
                    It will instead do nothing and assume the existing python file is
                    functionally the same.

                    If you have files that work differently but have the same name, stop.

                    '''
                    params = node_ref.get('params')
                    if params:

                        script_name = params.get('script_name')
                        script_content = params.get('script_str')

                        if script_name and not (script_name in texts):
                            new_text = texts.new(script_name)
                            new_text.from_string(script_content)

                        node.script_name = script_name
                        node.script_str = script_content

                    if node.bl_idname == 'SvScriptNode':
                        node.user_name = "templates"  # best would be in the node.
                        node.files_popup = "sv_lang_template.sn"  # import to reset easy fix
                        node.load()
                    else:
                        node.files_popup = node.avail_templates(None)[0][0]
                        node.load()

                elif node.bl_idname == 'SvProfileNode':
                    new_text = texts.new(node_ref['params']['filename'])
                    new_text.from_string(node_ref['path_file'])
                    node.update()

                # as it's a beta service, old IO json may not be compatible - in this interest
                # of neat code we assume it finds everything.
                elif node.bl_idname == 'SvTextInNode':
                    params = node_ref.get('params')
                    current_text = params['current_text']
                    node.textmode = params['textmode']

                    if not current_text:
                        print(node.name,
                              "doesn't store a current_text in params")

                    elif not (current_text in texts):
                        new_text = texts.new(current_text)
                        if node.textmode == 'JSON':
                            json_str = json.dumps(
                                node_ref['text_lines']['stored_as_json'])
                            new_text.from_string(json_str)
                        else:
                            new_text.from_string(node_ref['text_lines'])

                    else:
                        texts[current_text].from_string(node_ref['text_lines'])
            '''
            When n is assigned to node.name, blender will decide whether or
            not it can do that, if there exists already a node with that name,
            then the assignment to node.name is not n, but n.00x. Hence on the
            following line we check if the assignment was accepted, and store a
            remapped name if it wasn't.
            '''
            node.name = n
            if not (node.name == n):
                name_remap[n] = node.name

            params = node_ref['params']
            # print(node.name, params)
            for p in params:
                val = params[p]
                setattr(node, p, val)

            node.location = node_ref['location']
            node.height = node_ref['height']
            node.width = node_ref['width']
            node.label = node_ref['label']
            node.hide = node_ref['hide']
            node.color = node_ref['color']
            '''
            Nodes that require post processing to work properly
            '''
            if node.bl_idname in {'SvGroupInputsNode', 'SvGroupOutputsNode'}:
                node.load()
            elif node.bl_idname in {'SvGroupNode'}:
                node.load()
                group_name = node.group_name
                node.group_name = group_name_remap.get(group_name, group_name)
            elif node.bl_idname == 'SvTextInNode':
                # node.reload()
                # node.reset()
                # node.reload()
                node.load()

        update_lists = nodes_json['update_lists']
        print('update lists:')
        for ulist in update_lists:
            print(ulist)
        ''' now connect them '''

        # naive
        # freeze updates while connecting the tree, otherwise
        # each connection will cause an update event
        ng.freeze(hard=True)

        failed_connections = []

        for link in update_lists:
            try:
                ng.links.new(*resolve_socket(*link, name_dict=name_remap))
            except Exception as err:
                print(traceback.format_exc())
                failed_connections.append(link)
                continue

        if failed_connections:
            print('failed total {0}'.format(len(failed_connections)))
            print(failed_connections)
        else:
            print('no failed connections! awesome.')
        ''' set frame parents '''
        finalize = lambda name: name_remap.get(name, name)
        framed_nodes = nodes_json['framed_nodes']
        for node_name, parent in framed_nodes.items():
            ng.nodes[finalize(node_name)].parent = ng.nodes[finalize(parent)]

        old_nodes.scan_for_old(ng)
        ng.unfreeze(hard=True)
        ng.update()
    def generate_layout(fullpath, nodes_json):
        print('#' * 12, nodes_json['export_version'])
        ''' first create all nodes. '''
        nodes_to_import = nodes_json['nodes']
        groups_to_import = nodes_json.get('groups', {})

        group_name_remap = {}
        for name in groups_to_import:
            group_ng = bpy.data.node_groups.new(name, 'SverchGroupTreeType')
            if group_ng.name != name:
                group_name_remap[name] = ng.name
            import_tree(group_ng, '', groups_to_import[name])

        name_remap = {}
        texts = bpy.data.texts

        for n in sorted(nodes_to_import):
            node_ref = nodes_to_import[n]
            bl_idname = node_ref['bl_idname']
            try:
                if old_nodes.is_old(bl_idname):
                    old_nodes.register_old(bl_idname)
                node = nodes.new(bl_idname)
            except Exception as err:
                print(traceback.format_exc())
                print(bl_idname, 'not currently registered, skipping')
                continue
            '''
            When n is assigned to node.name, blender will decide whether or
            not it can do that, if there exists already a node with that name,
            then the assignment to node.name is not n, but n.00x. Hence on the
            following line we check if the assignment was accepted, and store a
            remapped name if it wasn't.
            '''
            node.name = n
            if not (node.name == n):
                name_remap[n] = node.name

            params = node_ref['params']
            print(node.name, params)
            for p in params:
                val = params[p]
                setattr(node, p, val)

            node.location = node_ref['location']
            node.height = node_ref['height']
            node.width = node_ref['width']
            node.label = node_ref['label']
            node.hide = node_ref['hide']
            node.color = node_ref['color']
            ''' maintenance warning:
            for the creation of new text files. If this script is run in a
            file which contains these Text names already, then the script/file
            names stored in the node must be updated to reflect this.

            Also is a script/profile is used for more than one node it will lead
            to duplication. All names have to collected and then fixed at end
            '''
            if create_texts:
                if node.bl_idname in ('SvScriptNode', 'SvScriptNodeMK2'):
                    new_text = texts.new(node.script_name)
                    #  there is no gurantee that we get the name we request
                    if new_text.name != node.script_name:
                        node.script_name = new_text.name
                    new_text.from_string(node.script_str)
                    node.user_name = "templates"  # best would be in the node.
                    node.files_popup = "sv_lang_template.sn"  # import to reset easy fix
                    node.load()

                elif node.bl_idname == 'SvProfileNode':
                    new_text = texts.new(node.filename)
                    new_text.from_string(node_ref['path_file'])
                    #  needed!
                    node.update()
            '''
            Nodes that require post processing to work properly
            '''
            if node.bl_idname in {'SvGroupInputsNode', 'SvGroupOutputsNode'}:
                node.load()
            elif node.bl_idname in {'SvGroupNode'}:
                node.load()
                group_name = node.group_name
                node.group_name = group_name_remap.get(group_name, group_name)

        update_lists = nodes_json['update_lists']
        print('update lists:')
        for ulist in update_lists:
            print(ulist)
        ''' now connect them '''

        # naive
        # freeze updates while connecting the tree, otherwise
        # each connection will cause an update event
        ng.freeze(hard=True)

        failed_connections = []

        for link in update_lists:
            try:
                ng.links.new(*resolve_socket(*link, name_dict=name_remap))
            except Exception as err:
                print(traceback.format_exc())
                failed_connections.append(link)
                continue

        if failed_connections:
            print('failed total {0}'.format(len(failed_connections)))
            print(failed_connections)
        else:
            print('no failed connections! awesome.')
        ''' set frame parents '''
        finalize = lambda name: name_remap.get(name, name)
        framed_nodes = nodes_json['framed_nodes']
        for node_name, parent in framed_nodes.items():
            ng.nodes[finalize(node_name)].parent = ng.nodes[finalize(parent)]

        old_nodes.scan_for_old(ng)
        ng.unfreeze(hard=True)
        ng.update()
Esempio n. 17
0
    def generate_layout(fullpath, nodes_json):
        print('#' * 12, nodes_json['export_version'])

        ''' first create all nodes. '''
        nodes_to_import = nodes_json['nodes']
        groups_to_import = nodes_json.get('groups', {})

        group_name_remap = {}
        for name in groups_to_import:
            group_ng = bpy.data.node_groups.new(name, 'SverchGroupTreeType')
            if group_ng.name != name:
                group_name_remap[name] = ng.name
            import_tree(group_ng, '', groups_to_import[name])

        name_remap = {}
        texts = bpy.data.texts

        for n in sorted(nodes_to_import):
            node_ref = nodes_to_import[n]
            bl_idname = node_ref['bl_idname']
            try:
                if old_nodes.is_old(bl_idname):
                    old_nodes.register_old(bl_idname)
                node = nodes.new(bl_idname)
            except Exception as err:
                print(traceback.format_exc())
                print(bl_idname, 'not currently registered, skipping')
                continue



            ''' maintenance warning:
            for the creation of new text files. If this script is run in a
            file which contains these Text names already, then the script/file
            names stored in the node must be updated to reflect this.

            Also is a script/profile is used for more than one node it will lead
            to duplication. All names have to collected and then fixed at end
            '''
            if create_texts:
                if node.bl_idname in ('SvScriptNode', 'SvScriptNodeMK2'):
                    new_text = texts.new(node.script_name)
                    #  there is no gurantee that we get the name we request
                    if new_text.name != node.script_name:
                        node.script_name = new_text.name
                    new_text.from_string(node.script_str)
                    node.user_name = "templates"               # best would be in the node.
                    node.files_popup = "sv_lang_template.sn"   # import to reset easy fix
                    node.load()

                elif node.bl_idname == 'SvProfileNode':
                    new_text = texts.new(node.filename)
                    new_text.from_string(node_ref['path_file'])
                    #  needed!
                    node.update()
                elif node.bl_idname == 'SvTextInNode':
                    if node_ref['current_text'] not in [a.name for a in texts]:
                        new_text = texts.new(node.current_text)
                        new_text.name = node_ref['current_text']
                        new_text.from_string(node_ref['text_lines'])
                    else:
                        texts[node_ref['current_text']].from_string(node_ref['text_lines'])

            '''
            When n is assigned to node.name, blender will decide whether or
            not it can do that, if there exists already a node with that name,
            then the assignment to node.name is not n, but n.00x. Hence on the
            following line we check if the assignment was accepted, and store a
            remapped name if it wasn't.
            '''
            node.name = n
            if not (node.name == n):
                name_remap[n] = node.name

            params = node_ref['params']
            print(node.name, params)
            for p in params:
                val = params[p]
                setattr(node, p, val)

            node.location = node_ref['location']
            node.height = node_ref['height']
            node.width = node_ref['width']
            node.label = node_ref['label']
            node.hide = node_ref['hide']
            node.color = node_ref['color']

            '''
            Nodes that require post processing to work properly
            '''
            if node.bl_idname in {'SvGroupInputsNode', 'SvGroupOutputsNode'}:
                node.load()
            elif node.bl_idname in {'SvGroupNode'}:
                node.load()
                group_name = node.group_name
                node.group_name = group_name_remap.get(group_name, group_name)
            elif node.bl_idname == 'SvTextInNode':
                node.reload()
                #node.reset()
                #node.load()

        update_lists = nodes_json['update_lists']
        print('update lists:')
        for ulist in update_lists:
            print(ulist)

        ''' now connect them '''

        # naive
        # freeze updates while connecting the tree, otherwise
        # each connection will cause an update event
        ng.freeze(hard=True)

        failed_connections = []

        for link in update_lists:
            try:
                ng.links.new(*resolve_socket(*link, name_dict=name_remap))
            except Exception as err:
                print(traceback.format_exc())
                failed_connections.append(link)
                continue

        if failed_connections:
            print('failed total {0}'.format(len(failed_connections)))
            print(failed_connections)
        else:
            print('no failed connections! awesome.')

        ''' set frame parents '''
        finalize = lambda name: name_remap.get(name, name)
        framed_nodes = nodes_json['framed_nodes']
        for node_name, parent in framed_nodes.items():
            ng.nodes[finalize(node_name)].parent = ng.nodes[finalize(parent)]

        old_nodes.scan_for_old(ng)
        ng.unfreeze(hard=True)
        ng.update()
    def generate_layout(fullpath, nodes_json):
        print('#' * 12, nodes_json['export_version'])

        ''' first create all nodes. '''
        nodes_to_import = nodes_json['nodes']
        groups_to_import = nodes_json.get('groups', {})

        group_name_remap = {}
        for name in groups_to_import:
            group_ng = bpy.data.node_groups.new(name, 'SverchGroupTreeType')
            if group_ng.name != name:
                group_name_remap[name] = ng.name
            import_tree(group_ng, '', groups_to_import[name])

        name_remap = {}
        texts = bpy.data.texts

        for n in sorted(nodes_to_import):
            node_ref = nodes_to_import[n]
            bl_idname = node_ref['bl_idname']

            try:
                if old_nodes.is_old(bl_idname):
                    old_nodes.register_old(bl_idname)
                node = nodes.new(bl_idname)
            except Exception as err:
                print(traceback.format_exc())
                print(bl_idname, 'not currently registered, skipping')
                continue

            if create_texts:
                if node.bl_idname in SCRIPTED_NODES:

                    '''
                    Scripted Node will no longer create alternative versions of a file.
                    If a scripted node wants to make a file called 'inverse.py' and the
                    current .blend already contains such a file, then for simplicity the
                    importer will not try to create 'inverse.001.py' and reference that.
                    It will instead do nothing and assume the existing python file is
                    functionally the same.

                    If you have files that work differently but have the same name, stop.

                    '''
                    params = node_ref.get('params')
                    if params:

                        script_name = params.get('script_name')
                        script_content = params.get('script_str')

                        if script_name and not (script_name in texts):
                            new_text = texts.new(script_name)
                            new_text.from_string(script_content)

                        node.script_name = script_name
                        node.script_str = script_content

                    if node.bl_idname == 'SvScriptNode':
                        node.user_name = "templates"               # best would be in the node.
                        node.files_popup = "sv_lang_template.sn"   # import to reset easy fix
                        node.load()
                    else:
                        node.files_popup = node.avail_templates(None)[0][0]
                        node.load()

                elif node.bl_idname == 'SvProfileNode':
                    new_text = texts.new(node_ref['params']['filename'])
                    new_text.from_string(node_ref['path_file'])
                    node.update()

                # as it's a beta service, old IO json may not be compatible - in this interest
                # of neat code we assume it finds everything.
                elif node.bl_idname == 'SvTextInNode':
                    params = node_ref.get('params')
                    current_text = params['current_text']
                    node.textmode = params['textmode']

                    if not current_text:
                        print(node.name, "doesn't store a current_text in params")

                    elif not (current_text in texts):
                        new_text = texts.new(current_text)
                        if node.textmode == 'JSON':
                            json_str = json.dumps(node_ref['text_lines']['stored_as_json'])
                            new_text.from_string(json_str)
                        else:
                            new_text.from_string(node_ref['text_lines'])

                    else:
                        texts[current_text].from_string(node_ref['text_lines'])

            '''
            When n is assigned to node.name, blender will decide whether or
            not it can do that, if there exists already a node with that name,
            then the assignment to node.name is not n, but n.00x. Hence on the
            following line we check if the assignment was accepted, and store a
            remapped name if it wasn't.
            '''
            node.name = n
            if not (node.name == n):
                name_remap[n] = node.name

            params = node_ref['params']
            # print(node.name, params)
            for p in params:
                val = params[p]
                setattr(node, p, val)

            node.location = node_ref['location']
            node.height = node_ref['height']
            node.width = node_ref['width']
            node.label = node_ref['label']
            node.hide = node_ref['hide']
            node.color = node_ref['color']

            '''
            Nodes that require post processing to work properly
            '''
            if node.bl_idname in {'SvGroupInputsNode', 'SvGroupOutputsNode'}:
                node.load()
            elif node.bl_idname in {'SvGroupNode'}:
                node.load()
                group_name = node.group_name
                node.group_name = group_name_remap.get(group_name, group_name)
            elif node.bl_idname == 'SvTextInNode':
                # node.reload()
                # node.reset()
                # node.reload()
                node.load()

        update_lists = nodes_json['update_lists']
        print('update lists:')
        for ulist in update_lists:
            print(ulist)

        ''' now connect them '''

        # naive
        # freeze updates while connecting the tree, otherwise
        # each connection will cause an update event
        ng.freeze(hard=True)

        failed_connections = []

        for link in update_lists:
            try:
                ng.links.new(*resolve_socket(*link, name_dict=name_remap))
            except Exception as err:
                print(traceback.format_exc())
                failed_connections.append(link)
                continue

        if failed_connections:
            print('failed total {0}'.format(len(failed_connections)))
            print(failed_connections)
        else:
            print('no failed connections! awesome.')

        ''' set frame parents '''
        finalize = lambda name: name_remap.get(name, name)
        framed_nodes = nodes_json['framed_nodes']
        for node_name, parent in framed_nodes.items():
            ng.nodes[finalize(node_name)].parent = ng.nodes[finalize(parent)]

        old_nodes.scan_for_old(ng)
        ng.unfreeze(hard=True)
        ng.update()