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)
def execute(self, context): if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} path = get_preset_path(self.preset_name) gist_filename = self.preset_name + ".json" gist_description = self.preset_name with open(path, 'rb') as jsonfile: gist_body = jsonfile.read().decode('utf8') try: gist_url = sv_gist_tools.main_upload_function(gist_filename, gist_description, gist_body, show_browser=False) context.window_manager.clipboard = gist_url # full destination url info(gist_url) self.report({'WARNING'}, "Copied gist URL to clipboad") sv_gist_tools.write_or_append_datafiles(gist_url, gist_filename) except Exception as err: exception(err) self.report({'ERROR'}, "Error 222: net connection or github login failed!") return {'CANCELLED'} finally: return {'FINISHED'}
def execute(self, context): ng = context.space_data.node_tree gist_filename = ng.name gist_description = 'to do later? 2018' layout_dict = create_dict_of_tree(ng, skip_set={}, selected=self.selected_only) try: gist_body = json.dumps(layout_dict, sort_keys=True, indent=2) except Exception as err: if 'not JSON serializable' in repr(err): error(layout_dict) else: exception(err) self.report({'WARNING'}, "See terminal/Command prompt for printout of error") return {'CANCELLED'} try: gist_url = sv_gist_tools.main_upload_function(gist_filename, gist_description, gist_body, show_browser=False) context.window_manager.clipboard = gist_url # full destination url info(gist_url) self.report({'WARNING'}, "Copied gistURL to clipboad") sv_gist_tools.write_or_append_datafiles(gist_url, gist_filename) return {'FINISHED'} except Exception as err: info(err) self.report({'ERROR'}, "Error 222: net connection or github login failed!") return {'CANCELLED'}
def do_update_heat_map(node_list, nodes): """ Create a heat map for the node tree, Needs development. """ if not nodes.id_data.sv_user_colors: color_data = {node.name: (node.color[:], node.use_custom_color) for node in nodes} nodes.id_data.sv_user_colors = str(color_data) times = do_update_general(node_list, nodes) if not times: return t_max = max(times) addon_name = data_structure.SVERCHOK_NAME addon = bpy.context.user_preferences.addons.get(addon_name) if addon: # to use Vector.lerp cold = Vector(addon.preferences.heat_map_cold) hot = addon.preferences.heat_map_hot else: error("Cannot find preferences") cold = Vector((1, 1, 1)) hot = (.8, 0, 0) for name, t in zip(node_list, times): nodes[name].use_custom_color = True # linear scale. nodes[name].color = cold.lerp(hot, t / t_max)
def apply_socket_props(socket, info): debug("applying socket props") for tracked_prop_name, tracked_prop_value in info.items(): try: setattr(socket, tracked_prop_name, tracked_prop_value) except Exception as err: error("Error while setting node socket: %s | %s", node.name, socket.index) error("the following failed | %s <- %s", tracked_prop_name, tracked_prop_value) exception(err)
def apply_custom_socket_props(node, node_ref): debug("applying node props for node: %s", node.bl_idname) socket_properties = node_ref.get('custom_socket_props') if socket_properties: for idx, info in socket_properties.items(): try: socket = node.inputs[int(idx)] apply_socket_props(socket, info) except Exception as err: error("socket index: %s, trying to pass: %s, num_sockets: %s", idx, info, len(node.inputs)) exception(err)
def make_update_list(node_tree, node_set=None, dependencies=None): """ Makes a update list from a node_group if a node set is passed only the subtree defined by the node set is used. Otherwise the complete node tree is used. If dependencies are not passed they are built. """ ng = node_tree if not node_set: # if no node_set, take all node_set = set(ng.nodes.keys()) if len(node_set) == 1: return list(node_set) if node_set: # get one name name = node_set.pop() node_set.add(name) else: return [] if not dependencies: deps = make_dep_dict(ng) else: deps = dependencies tree_stack = collections.deque([name]) tree_stack_append = tree_stack.append tree_stack_pop = tree_stack.pop out = collections.OrderedDict() # travel in node graph create one sorted list of nodes based on dependencies node_count = len(node_set) while node_count > len(out): node_dependencies = True for dep_name in deps[name]: if dep_name in node_set and dep_name not in out: tree_stack_append(name) name = dep_name node_dependencies = False break if len(tree_stack) > node_count: error("Invalid node tree!") return [] # if all dependencies are in out if node_dependencies: if name not in out: out[name] = 1 if tree_stack: name = tree_stack_pop() else: if node_count == len(out): break for node_name in node_set: if node_name not in out: name = node_name break return list(out.keys())
def compile_socket(link): try: link_data = (link.from_node.name, link.from_socket.index, link.to_node.name, link.to_socket.index) except Exception as err: if "'NodeSocketColor' object has no attribute 'index'" in repr(err): debug('adding node reroute using socketname instead if index') else: error(repr(err)) link_data = (link.from_node.name, link.from_socket.name, link.to_node.name, link.to_socket.name) return link_data
def display_introspection_info(node, k, v): if not isinstance(v, (float, int, str)): debug('//') debug("%s -> property: %s: %s", node.name, k, type(v)) if k in node.bl_rna.properties: debug(type(node.bl_rna.properties[k])) elif k in node: # something like node['lp'] , ID Property directly on the node instance. debug(type(node[k])) else: error('%s is not bl_rna or IDproperty.. please report this', k) debug('\\\\')
def update_cls(self): """ create or update the corresponding class reference """ if not all((self.input_node, self.output_node)): error("Monad %s not set up correctly", self.name) return None cls_dict = {} if not self.cls_bl_idname: # the monad cls_bl_idname needs to be unique and cannot change monad_base_name = make_valid_identifier(self.name) monad_itentifier = id(self) ^ random.randint(0, 4294967296) cls_name = "SvGroupNode{}_{}".format(monad_base_name, monad_itentifier) # set the unique name for the class, depending on context this might fail # then we cannot do the setup of the class properly so abandon try: self.cls_bl_idname = cls_name except Exception: return None else: cls_name = self.cls_bl_idname self.verify_props() cls_dict["bl_idname"] = cls_name cls_dict["bl_label"] = self.name cls_dict["input_template"] = self.generate_inputs() cls_dict["output_template"] = self.generate_outputs() self.make_props(cls_dict) # done with setup old_cls_ref = get_node_class_reference(cls_name) bases = (SvGroupNodeExp, Node, SverchCustomTreeNode) cls_ref = type(cls_name, bases, cls_dict) if old_cls_ref: sverchok.utils.unregister_node_class(old_cls_ref) sverchok.utils.register_node_class(cls_ref) return cls_ref
def frame_array(self, ts): tangents, normals, binormals = self.tangent_normal_binormal_array(ts) tangents = tangents / np.linalg.norm(tangents, axis=1)[np.newaxis].T matrices_np = np.dstack((normals, binormals, tangents)) matrices_np = np.transpose(matrices_np, axes=(0,2,1)) try: matrices_np = np.linalg.inv(matrices_np) return matrices_np, normals, binormals except np.linalg.LinAlgError as e: error("Some of matrices are singular:") for i, m in enumerate(matrices_np): if abs(np.linalg.det(m) < 1e-5): error("M[%s] (t = %s):\n%s", i, ts[i], m) raise e
def execute(self, context): ng = context.space_data.node_tree is_tree_exportable, msg = self.can_be_exported(ng) if not is_tree_exportable: self.report({'ERROR'}, msg) return {'CANCELLED'} gist_filename = ng.name app_version = bpy.app.version_string.replace(" ", "") time_stamp = strftime("%Y.%m.%d | %H:%M", localtime()) gist_description = f"Sverchok.{version_and_sha} | Blender.{app_version} | {ng.name} | {time_stamp}" # layout_dict = create_dict_of_tree(ng, skip_set={}, selected=self.selected_only) if self.selected_only: layout_dict = JSONExporter.get_nodes_structure([node for node in ng.nodes if node.select]) else: layout_dict = JSONExporter.get_tree_structure(ng) try: gist_body = json.dumps(layout_dict, sort_keys=True, indent=2) except Exception as err: if 'not JSON serializable' in repr(err): error(layout_dict) exception(err) self.report({'WARNING'}, "See terminal/Command prompt for printout of error") return {'CANCELLED'} try: gist_url = sv_gist_tools.main_upload_function(gist_filename, gist_description, gist_body, show_browser=False) if not gist_url: self.report({'ERROR'}, "You have not specified GitHub API access token, which is " + "required to create gists from Sverchok. Please see " + TOKEN_HELP_URL + " for more information.") return {'CANCELLED'} context.window_manager.clipboard = gist_url # full destination url info(gist_url) self.report({'WARNING'}, "Copied gist URL to clipboad") sv_gist_tools.write_or_append_datafiles(gist_url, gist_filename) return {'FINISHED'} except Exception as err: exception(err) self.report({'ERROR'}, "Error 222: net connection or github login failed!") return {'CANCELLED'}
def execute(self, context): if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} path = get_preset_path(self.preset_name) os.remove(path) info("Removed `%s'", path) self.report({'INFO'}, "Removed `{}'".format(self.preset_name)) return {'FINISHED'}
def unpack_monad(nodes, node_ref): params = node_ref.get('params') if params: socket_prop_data = params.get('all_props') monad_name = params.get('monad') monad = bpy.data.node_groups[monad_name] if socket_prop_data: # including this to keep bw comp for trees that don't include this info. monad.set_all_props(socket_prop_data) cls_ref = monad.update_cls() node = nodes.new(cls_ref.bl_idname) # -- addition 1 --------- setting correct properties on sockets. cls_dict = params.get('cls_dict') input_template = cls_dict['input_template'] for idx, (sock_name, sock_type, sock_props) in enumerate(input_template): socket_reference = node.inputs[idx] if sock_props: for prop, val in sock_props.items(): setattr(socket_reference, prop, val) # -- addition 2 --------- force push param values # -- (this step is skipped by apply_core_props because this node has a cls_dict) for prop_data in ('float_props', 'int_props'): data_list = socket_prop_data.get(prop_data) if not data_list: continue for k, v in data_list.items(): if hasattr(node, k): if k in params: setattr(node, k, params[k]) # else: # print(k, 'not in', params) #else: # print('node name:', node, node.name, 'has no property called', k, 'yet..') # node.output_template = cls_dict['output_template'] for attr in 'vectorize', 'loop_me', 'loops_max', 'loops': if attr in params: setattr(node, attr, params[attr]) return node else: error('no parameters found! .json might be broken')
def check_dir(directory, fnames): dir_name = basename(directory) index_name = dir_name + "_index.rst" index_file_path = join(directory, index_name) bad_files = [] for fname in fnames: if fname.endswith("_index.rst"): continue if not check(index_file_path, fname): bad_files.append(fname) if bad_files: error("The following files are not mentioned in %s:\n%s", index_name, "\n".join(bad_files)) self.fail( "Not all node documentation files are mentioned in their corresponding indexes." )
def make_links(update_lists, name_remap): print_update_lists(update_lists) failed_connections = [] for link in update_lists: try: ng.links.new(*resolve_socket(*link, name_dict=name_remap)) except Exception as err: exception(err) failed_connections.append(link) continue if failed_connections: error("failed total: %s", len(failed_connections)) error(failed_connections) else: debug('no failed connections! awesome.')
def write_json(layout_dict, destination_path): try: m = json.dumps(layout_dict, sort_keys=True, indent=2) except Exception as err: error(repr(err)) info(layout_dict) # optional post processing step post_processing = False if post_processing: flatten = lambda match: r' {}'.format(match.group(1), m) m = re.sub(r'\s\s+(\d+)', flatten, m) with open(destination_path, 'w') as node_tree: node_tree.writelines(m)
def check_dir(directory): dir_name = basename(directory) bad_files = [] for doc_path in glob(join(directory, "*.rst")): if doc_path.endswith("_index.rst"): continue doc_file = basename(doc_path) doc_name, ext = splitext(doc_file) py_name = doc_name + ".py" py_path = join(nodes_dir, dir_name, py_name) if not exists(py_path): bad_files.append(doc_file) if bad_files: error("Category %s: The following documentation files do not have respective python modules:\n%s", dir_name, "\n".join(bad_files)) self.fail("There are excessive documentation files.")
def execute(self, context): if not self.category: msg = "Category name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if self.category == GENERAL or self.category in get_category_names(): msg = "Category named `{}' already exists; refusing to overwrite existing category" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} path = get_presets_directory(category=self.category, mkdir=True) info("Created new category `%s' at %s", self.category, path) self.report({'INFO'}, "Created new category {}".format(self.category)) return {'FINISHED'}
def apply_core_props(node, node_ref): params = node_ref['params'] if 'cls_dict' in params: return for p in params: val = params[p] try: setattr(node, p, val) except Exception as e: # FIXME: this is ugly, need to find better approach error_message = repr(e) # for reasons error(error_message) msg = 'failed to assign value to the node' debug("`%s': %s = %s: %s", node.name, p, val, msg) if "val: expected sequence items of type boolean, not int" in error_message: debug("going to convert a list of ints to a list of bools and assign that instead") setattr(node, p, [bool(i) for i in val])
def execute(self, context): bpy.ops.text.select_line() bpy.ops.text.copy() copied_text = bpy.data.window_managers[0].clipboard if "def sv_main(" not in copied_text: self.report({'INFO'}, "ERROR - LOOK CONSOLE") error(sv_error_message) return {'CANCELLED'} answer = converted(copied_text) if answer: info(answer) bpy.data.window_managers[0].clipboard = answer bpy.ops.text.move(type='LINE_BEGIN') bpy.ops.text.move(type='NEXT_LINE') bpy.ops.text.paste() return {'FINISHED'}
def unpack_monad(nodes, node_ref): params = node_ref.get('params') if params: socket_prop_data = params.get('all_props') monad_name = params.get('monad') monad = bpy.data.node_groups[monad_name] if socket_prop_data: # including this to keep bw comp for trees that don't include this info. monad.set_all_props(socket_prop_data) cls_ref = monad.update_cls() node = nodes.new(cls_ref.bl_idname) # -- addition 1 --------- setting correct properties on sockets. cls_dict = params.get('cls_dict') input_template = cls_dict['input_template'] for idx, (sock_name, sock_type, sock_props) in enumerate(input_template): socket_reference = node.inputs[idx] if sock_props: for prop, val in sock_props.items(): setattr(socket_reference, prop, val) # -- addition 2 --------- force push param values # -- (this step is skipped by apply_core_props because this node has a cls_dict) for prop_data in ('float_props', 'int_props'): data_list = socket_prop_data.get(prop_data) if not data_list: continue for k, v in data_list.items(): if hasattr(node, k): if k in params: setattr(node, k, params[k]) # else: # print(k, 'not in', params) #else: # print('node name:', node, node.name, 'has no property called', k, 'yet..') # node.output_template = cls_dict['output_template'] return node else: error('no parameters found! .json might be broken')
def execute(self, context): ng = context.space_data.node_tree gist_filename = ng.name gist_description = "Sverchok_" + version_and_sha + ng.name + "_Bl_" + bpy.app.version_string.replace( " ", "") + str(tl().tm_year) + str(tl().tm_mon) + str( tl().tm_mday) + str(tl().tm_hour) layout_dict = create_dict_of_tree(ng, skip_set={}, selected=self.selected_only) try: gist_body = json.dumps(layout_dict, sort_keys=True, indent=2) except Exception as err: if 'not JSON serializable' in repr(err): error(layout_dict) exception(err) self.report({'WARNING'}, "See terminal/Command prompt for printout of error") return {'CANCELLED'} try: gist_url = sv_gist_tools.main_upload_function(gist_filename, gist_description, gist_body, show_browser=False) if not gist_url: self.report( {'ERROR'}, "You have not specified GitHub API access token, which is " + "required to create gists from Sverchok. Please see " + TOKEN_HELP_URL + " for more information.") return {'CANCELLED'} context.window_manager.clipboard = gist_url # full destination url info(gist_url) self.report({'WARNING'}, "Copied gist URL to clipboad") sv_gist_tools.write_or_append_datafiles(gist_url, gist_filename) return {'FINISHED'} except Exception as err: exception(err) self.report({'ERROR'}, "Error 222: net connection or github login failed!") return {'CANCELLED'}
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)
def execute(self, context): if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.filepath: msg = "Source file path is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} target_path = get_preset_path(self.preset_name) shutil.copy(self.filepath, target_path) msg = "Imported `{}' as `{}'".format(self.filepath, self.preset_name) info(msg) self.report({'INFO'}, msg) return {'FINISHED'}
def execute(self, context): if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.filepath: msg = "Target file path is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} existing_path = get_preset_path(self.preset_name, category=self.category) shutil.copy(existing_path, self.filepath) msg = "Saved `{} / {}' as `{}'".format(self.category, self.preset_name, self.filepath) info(msg) self.report({'INFO'}, msg) return {'FINISHED'}
def frame_array(self, ts, on_zero_curvature=ASIS, tangent_delta=None): """ input: * ts - np.array of shape (n,) * on_zero_curvature - what to do if the curve has zero curvature at one of T values. The supported options are: * SvCurve.FAIL: raise ZeroCurvatureException * SvCurve.RETURN_NONE: return None * SvCurve.ASIS: do not perform special check for this case, the algorithm will raise a general LinAlgError exception if it can't calculate the matrix. output: tuple: * matrices: np.array of shape (n, 3, 3) * normals: np.array of shape (n, 3) * binormals: np.array of shape (n, 3) """ h = self.get_tangent_delta(tangent_delta) tangents, normals, binormals = self.tangent_normal_binormal_array( ts, tangent_delta=h) if on_zero_curvature != SvCurve.ASIS: zero_normal = np.linalg.norm(normals, axis=1) < 1e-6 if zero_normal.any(): if on_zero_curvature == SvCurve.FAIL: raise ZeroCurvatureException(np.unique(ts[zero_normal]), zero_normal) elif on_zero_curvature == SvCurve.RETURN_NONE: return None tangents = tangents / np.linalg.norm(tangents, axis=1)[np.newaxis].T matrices_np = np.dstack((normals, binormals, tangents)) matrices_np = np.transpose(matrices_np, axes=(0, 2, 1)) try: matrices_np = np.linalg.inv(matrices_np) return matrices_np, normals, binormals except np.linalg.LinAlgError as e: error("Some of matrices are singular:") for i, m in enumerate(matrices_np): if abs(np.linalg.det(m) < 1e-5): error("M[%s] (t = %s):\n%s", i, ts[i], m) raise e
def execute(self, context): if not self.category: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if self.category == GENERAL: msg = "General category can not be deleted" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} path = get_presets_directory(category=self.category) files = glob(join(path, "*")) if files: msg = "Category `{}' is not empty; refusing to delete non-empty category.".format( self.category) error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} os.rmdir(path) ntree = context.space_data.node_tree panel_props = ntree.preset_panel_properties panel_props.category = GENERAL return {'FINISHED'}
def execute(self, context): if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.gist_id: msg = "Gist ID is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} gist_data = sv_IO_panel_tools.load_json_from_gist(self.gist_id, self) target_path = get_preset_path(self.preset_name) if os.path.exists(target_path): msg = "Preset named `{}' already exists. Refusing to rewrite existing preset.".format(self.preset_name) error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} with open(target_path, 'wb') as jsonfile: gist_data = json.dumps(gist_data, sort_keys=True, indent=2).encode('utf8') jsonfile.write(gist_data) msg = "Imported `{}' as `{}'".format(self.gist_id, self.preset_name) info(msg) self.report({'INFO'}, msg) return {'FINISHED'}
def execute(self, context): if not self.id_tree: msg = "Node tree is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} ng = bpy.data.node_groups[self.id_tree] nodes = list(filter(lambda n: n.select, ng.nodes)) if not len(nodes): msg = "There are no selected nodes to export" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} layout_dict = JSONExporter.get_nodes_structure([n for n in ng.nodes if n.select]) preset = SvPreset(name=self.preset_name, category = self.category) preset.make_add_operator() destination_path = preset.path json.dump(layout_dict, open(destination_path, 'w'), sort_keys=True, indent=2) msg = 'exported to: ' + destination_path self.report({"INFO"}, msg) info(msg) return {'FINISHED'}
def execute(self, context): if not self.id_tree: msg = "Node tree is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} ng = bpy.data.node_groups[self.id_tree] nodes = list(filter(lambda n: n.select, ng.nodes)) if not len(nodes): msg = "There are no selected nodes to export" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} layout_dict = create_dict_of_tree(ng, selected=True) preset = SvPreset(name=self.preset_name) preset.make_add_operator() destination_path = preset.path write_json(layout_dict, destination_path) msg = 'exported to: ' + destination_path self.report({"INFO"}, msg) info(msg) return {'FINISHED'}
def register_old(bl_id): if bl_id in old_bl_idnames: mod = importlib.import_module(".{}".format(old_bl_idnames[bl_id]), __name__) res = inspect.getmembers(mod) # print('mod/res:', mod, res) for name, cls in res: if inspect.isclass(cls): if issubclass(cls, bpy.types.Node) and cls.bl_idname == bl_id: if bl_id not in imported_mods: try: mod.register() except Exception as err: print('failed mod register') exception(err) imported_mods[bl_id] = mod return mod else: return imported_mods[bl_id] error("Cannot find {} among old nodes".format(bl_id)) return None
def get_file_obj_from_zip(fullpath): ''' fullpath must point to a zip file. usage: nodes_json = get_file_obj_from_zip(fullpath) print(nodes_json['export_version']) ''' with zipfile.ZipFile(fullpath, "r") as jfile: exported_name = "" for name in jfile.namelist(): if name.endswith('.json'): exported_name = name break if not exported_name: error('zip contains no files ending with .json') return debug(exported_name + ' <') fp = jfile.open(exported_name, 'r') m = fp.read().decode() return json.loads(m)
def read_n_decode(url): try: content_at_url = urlopen(url) found_json = content_at_url.read().decode() return found_json except urllib.error.HTTPError as err: if err.code == 404: message = 'url: ' + str(url) + ' doesn\'t appear to be a valid url, copy it again from your source' error(message) if operator: operator.report({'ERROR'}, message) else: message = 'url error:' + str(err.code) error(message) if operator: operator.report({'ERROR'}, message) except Exception as err: exception(err) if operator: operator.report({'ERROR'}, 'unspecified error, check your internet connection') return
def execute(self, context): ng = context.space_data.node_tree gist_filename = ng.name gist_description = 'to do later? 2018' layout_dict = create_dict_of_tree(ng, skip_set={}, selected=self.selected_only) try: gist_body = json.dumps(layout_dict, sort_keys=True, indent=2) except Exception as err: if 'not JSON serializable' in repr(err): error(layout_dict) else: exception(err) self.report({'WARNING'}, "See terminal/Command prompt for printout of error") return {'CANCELLED'} try: gist_url = sv_gist_tools.main_upload_function(gist_filename, gist_description, gist_body, show_browser=False) context.window_manager.clipboard = gist_url # full destination url info(gist_url) self.report({'WARNING'}, "Copied gistURL to clipboad") sv_gist_tools.write_or_append_datafiles(gist_url, gist_filename) return {'FINISHED'} except Exception as err: info(err) self.report( {'ERROR'}, "Error uploading the gist, check your internet connection!") return {'CANCELLED'}
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)
def check_category(directory): dir_name = basename(directory) bad_files = [] known = [] for module_path in glob(join(directory, "*.py")): module_file = basename(module_path) if module_file == "__init__.py": continue module_name, ext = splitext(module_file) doc_name = module_name + ".rst" doc_path = join(docs_dir, dir_name, doc_name) if not exists(doc_path): if module_file in known_problems: known.append(module_file) else: bad_files.append(module_file) if known: info("Category %s: Tolerating unexistance of the documentation for the following nodes for now:\n%s", dir_name, "\n".join(known)) if bad_files: error("Category %s: The following nodes do not have corresponding documentation files:\n%s", dir_name, "\n".join(bad_files)) self.fail("Not all nodes have corresponding documentation; missing are:\n{}".format("\n".join(bad_files)))
def execute(self, context): if not self.old_name: msg = "Old preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.new_name: msg = "New preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} preset = SvPreset(name=self.old_name, category=self.old_category) preset.meta['description'] = self.description preset.meta['keywords'] = self.keywords preset.meta['author'] = self.author preset.meta['license'] = self.license preset.save() category_changed = self.allow_change_category and (self.new_category != self.old_category) if self.new_name != self.old_name or category_changed: old_path = get_preset_path(self.old_name, category=self.old_category) new_path = get_preset_path(self.new_name, category=self.new_category) if os.path.exists(new_path): msg = "Preset named `{}' already exists. Refusing to rewrite existing preset.".format( self.new_name) error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} os.rename(old_path, new_path) preset.name = self.new_name preset.category = self.new_category info("Renamed `%s' to `%s'", old_path, new_path) self.report({'INFO'}, "Renamed `{}' to `{}'".format(self.old_name, self.new_name)) bpy.utils.unregister_class(preset_add_operators[(self.old_category, self.old_name)]) del preset_add_operators[(self.old_category, self.old_name)] preset.make_add_operator() return {'FINISHED'}
def execute(self, context): if not self.old_name: msg = "Old preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.new_name: msg = "New preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} preset = SvPreset(name = self.old_name) preset.meta['description'] = self.description preset.meta['author'] = self.author preset.meta['license'] = self.license preset.save() if self.new_name != self.old_name: old_path = get_preset_path(self.old_name) new_path = get_preset_path(self.new_name) if os.path.exists(new_path): msg = "Preset named `{}' already exists. Refusing to rewrite existing preset.".format(self.new_name) error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} os.rename(old_path, new_path) preset.name = self.new_name info("Renamed `%s' to `%s'", old_path, new_path) self.report({'INFO'}, "Renamed `{}' to `{}'".format(self.old_name, self.new_name)) bpy.utils.unregister_class(preset_add_operators[self.old_name]) del preset_add_operators[self.old_name] preset.make_add_operator() return {'FINISHED'}
def execute(self, context): if not self.id_tree: msg = "Node tree is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} if not self.preset_name: msg = "Preset name is not specified" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} ng = bpy.data.node_groups[self.id_tree] nodes = list(filter(lambda n: n.select, ng.nodes)) if not len(nodes): msg = "There are no selected nodes to export" error(msg) self.report({'ERROR'}, msg) return {'CANCELLED'} # the operator can be used for both preset importing of a node and preset from a bunch of selected nodes if self.is_node_preset: layout_dict = JSONExporter.get_node_structure(nodes[0]) else: layout_dict = JSONExporter.get_tree_structure(ng, True) preset = SvPreset(name=self.preset_name, category=self.category) preset.make_add_operator() destination_path = preset.path json.dump(layout_dict, open(destination_path, 'w'), indent=2) # sort keys is not expected by the exporter msg = 'exported to: ' + destination_path self.report({"INFO"}, msg) info(msg) return {'FINISHED'}
def test_get_data_nesting_level_2(self): with self.assertRaises(TypeError): data = [dict(), 3] level = get_data_nesting_level(data) error("get_data_nesting_level() returned %s", level)
def test_ensure_nesting_level_2(self): with self.assertRaises(TypeError): data = [[[17]]] result = ensure_nesting_level(data, 1) error("ensure_nesting_level() returned %s", result)
def create_dict_of_tree(ng, skip_set={}, selected=False, identified_node=None): nodes = ng.nodes layout_dict = {} nodes_dict = {} groups_dict = {} if not skip_set: skip_set = {'Sv3DviewPropsNode'} if selected: nodes = list(filter(lambda n: n.select, nodes)) if identified_node: # this mode will import one node only. nodes = [identified_node] # get nodes and params for node in nodes: if node.bl_idname in skip_set: continue node_dict = {} node_items = {} node_enums = find_enumerators(node) IsMonadInstanceNode = (node.bl_idname.startswith('SvGroupNodeMonad')) for k, v in node.items(): display_introspection_info(node, k, v) if can_skip_property(node, k): continue elif has_state_switch_protection(node, k): continue handle_old_groupnode(node, k, v, groups_dict, create_dict_of_tree) if isinstance(v, (float, int, str)): node_items[k] = v elif node.bl_idname in {'ScalarMathNode', 'SvLogicNode'} and k == 'prop_types': node_items[k] = getattr(node, k)[:] continue else: node_items[k] = v[:] handle_enum_property(node, k, v, node_items, node_enums) if IsMonadInstanceNode and node.monad: pack_monad(node, node_items, groups_dict, create_dict_of_tree) if hasattr(node, "storage_get_data"): node.storage_get_data(node_dict) node_dict['params'] = node_items collect_custom_socket_properties(node, node_dict) # if node.bl_idname == 'NodeFrame': # frame_props = 'shrink', 'use_custom_color', 'label_size' # node_dict['params'].update({fpv: getattr(node, fpv) for fpv in frame_props}) if IsMonadInstanceNode: node_dict['bl_idname'] = 'SvMonadGenericNode' else: node_dict['bl_idname'] = node.bl_idname if node.bl_idname in {'SvGroupInputsNodeExp', 'SvGroupOutputsNodeExp'}: node_dict[node.node_kind] = node.stash() get_superficial_props(node_dict, node) nodes_dict[node.name] = node_dict # ------------------- layout_dict['nodes'] = nodes_dict layout_dict['groups'] = groups_dict # ''' get connections ''' # links = (compile_socket(l) for l in ng.links) # connections_dict = {idx: link for idx, link in enumerate(links)} # layout_dict['connections'] = connections_dict ''' get framed nodes ''' framed_nodes = {} for node in nodes: if node.bl_idname in skip_set: continue if node.parent: if selected and node.parent.select: framed_nodes[node.name] = node.parent.name elif not selected: framed_nodes[node.name] = node.parent.name layout_dict['framed_nodes'] = framed_nodes ''' get update list (cache, order to link) ''' # try/except for now, node tree links might be invalid # among other things. auto rebuild on F8 try: ng.build_update_list() links_out = [] for name in chain(*ng.get_update_lists()[0]): for socket in ng.nodes[name].inputs: if selected and not ng.nodes[name].select: continue if socket.links: link = socket.links[0] if selected and not link.from_node.select: continue links_out.append(compile_socket(link)) layout_dict['update_lists'] = links_out except Exception as err: exception(err) error('no update lists found or other error!') error(' - trigger an update and retry') return layout_dict['export_version'] = _EXPORTER_REVISION_ return layout_dict