def remove_edge(self, *args): """ Removes an edge from the graph. :param str UUID: edge UUID :param str conn: connection string (ie "node1.output,node2.input") :returns: edge removal was successful. :rtype: bool """ edges = self.get_edge(*args) if not edges: log.warning('cannot find edge.') return for edge in edges: edge_id = (edge[0], edge[1]) if edge_id in self.network.edges(): log.debug('Removing edge: "%s"' % self.edge_nice_name(*edge_id)) self.network.remove_edge(*edge_id) self.remove_node_edge(*edge_id) # update the scene self.graphUpdated(edge_id) return True return False
def remove_edge(self, *args): """ Removes an edge from the graph. :param str UUID: edge UUID :param str conn: connection string (ie "node1.output,node2.input") :returns: edge removal was successful. :rtype: bool """ edges = self.get_edge(*args) if not edges: log.warning('cannot find edge.') return for edge in edges: edge_id = (edge[0], edge[1]) if edge_id in self.network.edges(): log.debug('Removing edge: "%s"' % self.edge_nice_name(*edge_id)) self.network.remove_edge(*edge_id) self.remove_node_edge(*edge_id) # update the scene self.graphUpdated(edge_id) return True return False
def _get_qss_files(self, paths=[]): """ Get qss files. :param list path: ist of paths to add to the scan. :returns: dictionary of stylesheet names/filenames. :rtype: dict """ qss_files = dict() if not paths: return [] for path in paths: for fn in os.listdir(path): bn, fext = os.path.splitext(fn) if fext.lower() in ['.qss', '.css']: qss_file = os.path.join(path, fn) if qss_file not in qss_files.values(): style_name = self._parse_stylesheet_name(qss_file) if style_name is None: log.warning('cannot parse style name from "%s".' % qss_file) style_name = 'no-style' log.debug('adding stylesheet "%s" from "%s".' % (style_name, qss_file)) if style_name not in qss_files: qss_files[style_name] = qss_file return qss_files
def updateDagNodes(self, dagnodes, debug=False): """ Update the networkx nodes and links attributes from scene values. :param dagnodes: list of dag node objects. :type dagnodes: list """ if type(dagnodes) not in [list, tuple]: dagnodes = [ dagnodes, ] for dag in dagnodes: log.debug('Graph: updating dag node "%s"' % dag.name) nid = dag.id if nid in self.network.nodes(): #self.network.node[nid].update(dag.data) dag_data = json.loads(str(dag), object_pairs_hook=dict) nx_data = self.network.node[nid] nx_data.update(dag_data) if debug: # write temp file filename = os.path.join( os.path.dirname(self.autosave_path), '%s.json' % dag.name) fn = open(filename, 'w') json.dump(dag_data, fn, indent=4) fn.close()
def _get_qss_files(self, paths=[]): """ Get qss files. :param list path: ist of paths to add to the scan. :returns: dictionary of stylesheet names/filenames. :rtype: dict """ qss_files = dict() if not paths: return [] for path in paths: for fn in os.listdir(path): bn, fext = os.path.splitext(fn) if fext.lower() in ['.qss', '.css']: qss_file = os.path.join(path, fn) if qss_file not in qss_files.values(): style_name = self._parse_stylesheet_name(qss_file) if style_name is None: log.warning('cannot parse style name from "%s".' % qss_file) style_name = 'no-style' log.debug('adding stylesheet "%s" from "%s".' % (style_name, qss_file)) if style_name not in qss_files: qss_files[style_name] = qss_file return qss_files
def updateDagNodes(self, dagnodes, debug=False): """ Update the networkx nodes and links attributes from scene values. :param dagnodes: list of dag node objects. :type dagnodes: list """ if type(dagnodes) not in [list, tuple]: dagnodes=[dagnodes,] for dag in dagnodes: log.debug('Graph: updating dag node "%s"' % dag.name) nid = dag.id if nid in self.network.nodes(): #self.network.node[nid].update(dag.data) dag_data = json.loads(str(dag), object_pairs_hook=dict) nx_data = self.network.node[nid] nx_data.update(dag_data) if debug: # write temp file filename = os.path.join(os.path.dirname(self.autosave_path), '%s.json' % dag.name) fn = open(filename, 'w') json.dump(dag_data, fn, indent=4) fn.close()
def _get_config_files(self, paths=[]): """ Get config files. :param list path: ist of paths to add to the scan. :returns: dictionary of config names/filenames. :rtype: dict """ cfg_files = dict() if not paths: return [] for path in paths: for fn in os.listdir(path): bn, fext = os.path.splitext(fn) if fext.lower() in ['.ini', '.cfg']: cfg_file = os.path.join(path, fn) names = bn.split('-') if len(names) < 2: log.warning('improperly named config file: "%s"' % cfg_file) continue style_name, cfg_type = names if style_name not in cfg_files: cfg_files[style_name] = dict(fonts=None, palette=None) log.debug('adding %s config "%s" from "%s".' % (cfg_type, style_name, cfg_file)) cfg_files[style_name][cfg_type] = cfg_file return cfg_files
def _get_qss_paths(self, paths=[]): """ Read stylesheets from config paths. :param list paths: list of paths to add to the scan. :returns: array of search paths. :rtype: tuple """ if paths and type(paths) in [str, unicode]: paths = [paths,] qss_paths = () qss_paths = qss_paths + (options.SCENEGRAPH_STYLESHEET_PATH,) # read external paths if 'SCENEGRAPH_STYLESHEET_PATH' in os.environ: qpaths = os.getenv('SCENEGRAPH_STYLESHEET_PATH').split(':') if paths: for p in paths: if p not in qpaths: qpaths.append(p) for path in qpaths: if path not in qss_paths: if not os.path.exists(path): log.warning('stylesheet path "%s" does not exist, skipping.' % path) continue log.debug('reading external stylesheet path: "%s".' % path) qss_paths = qss_paths + (path,) return qss_paths
def _get_config_paths(self, paths=[]): """ Read configs from config paths. :param list paths: list of paths to add to the scan. :returns: array of search paths. :rtype: tuple """ if paths and type(paths) in [str, unicode]: paths = [paths,] cfg_paths = () cfg_paths = cfg_paths + (options.SCENEGRAPH_CONFIG_PATH,) # read external paths if 'SCENEGRAPH_CONFIG_PATH' in os.environ: spaths = os.getenv('SCENEGRAPH_CONFIG_PATH').split(':') if paths: for p in paths: if p not in spaths: spaths.append(p) for path in spaths: if path not in cfg_paths: if not os.path.exists(path): log.warning('config path "%s" does not exist, skipping.' % path) continue log.debug('reading config external path: "%s".' % path) cfg_paths = cfg_paths + (path,) return cfg_paths
def _get_config_files(self, paths=[]): """ Get config files. :param list path: ist of paths to add to the scan. :returns: dictionary of config names/filenames. :rtype: dict """ cfg_files = dict() if not paths: return [] for path in paths: for fn in os.listdir(path): bn, fext = os.path.splitext(fn) if fext.lower() in ['.ini', '.cfg']: cfg_file = os.path.join(path, fn) names = bn.split('-') if len(names) < 2: log.warning('improperly named config file: "%s"' % cfg_file) continue style_name, cfg_type = names if style_name not in cfg_files: cfg_files[style_name] = dict(fonts=None, palette=None) log.debug('adding %s config "%s" from "%s".' % (cfg_type, style_name, cfg_file)) cfg_files[style_name][cfg_type] = cfg_file return cfg_files
def get_modules(path): """ Returns all sub-modules of this package. :returns: list of module names in the current package. :rtype: list """ mod_names = [] modules = pkgutil.iter_modules(path=[path]) for loader, mod_name, ispkg in modules: mod_names.append(mod_name) log.debug('reading module: "%s"' % mod_name) return sorted(mod_names)
def get_modules(path): """ Returns all sub-modules of this package. :returns: list of module names in the current package. :rtype: list """ mod_names = [] modules = pkgutil.iter_modules(path=[path]) for loader, mod_name, ispkg in modules: mod_names.append(mod_name) log.debug('reading module: "%s"' % mod_name) return sorted(mod_names)
def _get_qss_paths(self, paths=[]): """ Read stylesheets from config paths. :param list paths: list of paths to add to the scan. :returns: array of search paths. :rtype: tuple """ if paths and type(paths) in [str, unicode]: paths = [ paths, ] qss_paths = () qss_paths = qss_paths + (options.SCENEGRAPH_STYLESHEET_PATH, ) # read external paths if 'SCENEGRAPH_STYLESHEET_PATH' in os.environ: qpaths = os.getenv('SCENEGRAPH_STYLESHEET_PATH').split(':') if paths: for p in paths: if p not in qpaths: qpaths.append(p) for path in qpaths: if path not in qss_paths: if not os.path.exists(path): log.warning( 'stylesheet path "%s" does not exist, skipping.' % path) continue log.debug('reading external stylesheet path: "%s".' % path) qss_paths = qss_paths + (path, ) return qss_paths
def _get_config_paths(self, paths=[]): """ Read configs from config paths. :param list paths: list of paths to add to the scan. :returns: array of search paths. :rtype: tuple """ if paths and type(paths) in [str, unicode]: paths = [ paths, ] cfg_paths = () cfg_paths = cfg_paths + (options.SCENEGRAPH_CONFIG_PATH, ) # read external paths if 'SCENEGRAPH_CONFIG_PATH' in os.environ: spaths = os.getenv('SCENEGRAPH_CONFIG_PATH').split(':') if paths: for p in paths: if p not in spaths: spaths.append(p) for path in spaths: if path not in cfg_paths: if not os.path.exists(path): log.warning( 'config path "%s" does not exist, skipping.' % path) continue log.debug('reading config external path: "%s".' % path) cfg_paths = cfg_paths + (path, ) return cfg_paths
def parse(self, filename): """ Parses a single template file. Data is structured into groups of attributes (ie: 'Transform', 'Attributes') :param str filename: file on disk to read. :returns: dictionary of metadata parameters. :rtype: dict """ if self._initialized: self.initialize() log.debug('reading metadata file: "%s"' % filename) data = dict() if filename is not None: if os.path.exists(filename): parent = data attr_name = None for line in open(filename,'r'): #remove newlines line = line.rstrip('\n') rline = line.lstrip(' ') rline = rline.rstrip() if not rline.startswith("#") and not rline.startswith(';') and rline.strip() != "": # parse sections # remove leading spaces # section/attribute header match if re.match(regex.get("section"), rline): section_obj = re.search(regex.get("section_value"), rline) if section_obj: section_type = section_obj.group('attr') section_value = section_obj.group('value') # parse groups if section_type == 'group': if section_value not in parent: parent = data group_data = dict() # set the current parent parent[section_value] = group_data parent = parent[section_value] #print '\nGroup: "%s"' % section_value if section_type == 'attr': attr_data = dict() # connection attributes #attr_data.update(connectable=False) #attr_data.update(connection_type=None) parent[section_value] = attr_data attr_name = section_value #print ' Attribute: "%s"' % attr_name if section_type in ['input', 'output']: conn_data = dict() conn_data.update(connectable=True) conn_data.update(connection_type=section_type) parent[section_value] = conn_data attr_name = section_value #print ' Connection: "%s"' % attr_name else: prop_obj = re.search(regex.get("properties"), rline) if prop_obj: pname = prop_obj.group('name') ptype = prop_obj.group('type') pvalu = prop_obj.group('value') #print 'property: "%s" (%s)' % (pname, rline) value = pvalu if ptype in ['BOOL', 'INPUT', 'OUTPUT']: if ptype == 'BOOL': value = True if pvalu == 'true' else False # return connection types if ptype in ['INPUT', 'OUTPUT']: # data type: pvalu = FILE, DIRECTORY, ETC. value = pvalu.lower() # try and get the actual value else: try: value = eval(pvalu) except: log.warning('cannot parse default value of "%s.%s": "%s" (%s)' % (attr_name, pname, pvalu, filename)) #print ' property: %s (%s)' % (prop_obj.group('name'), attr_name) properties = {pname: {'type':ptype, 'value':value}} parent[attr_name].update(properties) else: if rline: log.debug('skipping: "%s"' % rline) return data
def restore(self, data, nodes=True, graph=True): """ Restore current DAG state from data. Also used for restoring graph state for the undo stack. :param dict data: dictionary of scene graph data. :param bool nodes: restore nodes/edges. :param bool graph: restore scene attributes/preferences. """ self.reset() graph_data = data.get('graph', []) node_data = data.get('nodes', []) edge_data = data.get('links', []) self.updateConsole(msg='restoring %d nodes' % len(node_data)) # update graph attributes for gdata in graph_data: if len(gdata): if graph or gdata[0] in ['scene', 'api_version']: if len(gdata) > 1: self.network.graph[gdata[0]] = gdata[1] # build nodes from data if nodes: for node_attrs in node_data: # get the node type node_type = node_attrs.pop('node_type', 'default') # add the dag node/widget dag_node = self.add_node(node_type, **node_attrs) log.debug('building node "%s"' % node_attrs.get('name')) # edge : ['src_attr', 'target', 'weight', 'dest_id', 'source', 'dest_attr', 'key', 'src_id'] for edge in edge_data: src_id = edge.get('src_id') dest_id = edge.get('dest_id') src_attr = edge.get('src_attr') dest_attr = edge.get('dest_attr') weight = edge.get('weight', 1.0) src_dag_nodes = self.get_node(src_id) dest_dag_nodes = self.get_node(dest_id) if not src_dag_nodes or not dest_dag_nodes: log.warning('cannot parse nodes.') return src_dag_node = src_dag_nodes[0] dest_dag_node = dest_dag_nodes[0] src_string = '%s.%s' % (src_dag_node.name, src_attr) dest_string = '%s.%s' % (dest_dag_node.name, dest_attr) # TODO: need to get connection node here log.info('connecting nodes: "%s" "%s"' % (src_string, dest_string)) dag_edge = self.add_edge(src_dag_node, dest_dag_node, src_attr=src_attr, dest_attr=dest_attr, weight=weight) #self.handler.scene.clear() scene_pos = self.network.graph.get('view_center', (0, 0)) view_scale = self.network.graph.get('view_scale', (1.0, 1.0)) # update the UI. if self.mode == 'ui': if graph: self.handler.restoreGeometry(pos=scene_pos, scale=view_scale) self._initialized = 1
def restore(self, data, nodes=True, graph=True): """ Restore current DAG state from data. Also used for restoring graph state for the undo stack. :param dict data: dictionary of scene graph data. :param bool nodes: restore nodes/edges. :param bool graph: restore scene attributes/preferences. """ self.reset() graph_data = data.get('graph', []) node_data = data.get('nodes', []) edge_data = data.get('links', []) self.updateConsole(msg='restoring %d nodes' % len(node_data)) # update graph attributes for gdata in graph_data: if len(gdata): if graph or gdata[0] in ['scene', 'api_version']: if len(gdata) > 1: self.network.graph[gdata[0]]=gdata[1] # build nodes from data if nodes: for node_attrs in node_data: # get the node type node_type = node_attrs.pop('node_type', 'default') # add the dag node/widget dag_node = self.add_node(node_type, **node_attrs) log.debug('building node "%s"' % node_attrs.get('name')) # edge : ['src_attr', 'target', 'weight', 'dest_id', 'source', 'dest_attr', 'key', 'src_id'] for edge in edge_data: src_id = edge.get('src_id') dest_id = edge.get('dest_id') src_attr = edge.get('src_attr') dest_attr = edge.get('dest_attr') weight = edge.get('weight', 1.0) src_dag_nodes = self.get_node(src_id) dest_dag_nodes = self.get_node(dest_id) if not src_dag_nodes or not dest_dag_nodes: log.warning('cannot parse nodes.') return src_dag_node = src_dag_nodes[0] dest_dag_node = dest_dag_nodes[0] src_string = '%s.%s' % (src_dag_node.name, src_attr) dest_string = '%s.%s' % (dest_dag_node.name, dest_attr) # TODO: need to get connection node here log.info('connecting nodes: "%s" "%s"' % (src_string, dest_string)) dag_edge = self.add_edge(src_dag_node, dest_dag_node, src_attr=src_attr, dest_attr=dest_attr, weight=weight) #self.handler.scene.clear() scene_pos = self.network.graph.get('view_center', (0,0)) view_scale = self.network.graph.get('view_scale', (1.0, 1.0)) # update the UI. if self.mode == 'ui': if graph: self.handler.restoreGeometry(pos=scene_pos, scale=view_scale) self._initialized = 1
def parse(self, filename): """ Parses a single template file. Data is structured into groups of attributes (ie: 'Transform', 'Attributes') :param str filename: file on disk to read. :returns: dictionary of metadata parameters. :rtype: dict """ if self._initialized: self.initialize() log.debug('reading metadata file: "%s"' % filename) data = dict() if filename is not None: if os.path.exists(filename): parent = data attr_name = None for line in open(filename, 'r'): #remove newlines line = line.rstrip('\n') rline = line.lstrip(' ') rline = rline.rstrip() if not rline.startswith("#") and not rline.startswith( ';') and rline.strip() != "": # parse sections # remove leading spaces # section/attribute header match if re.match(regex.get("section"), rline): section_obj = re.search(regex.get("section_value"), rline) if section_obj: section_type = section_obj.group('attr') section_value = section_obj.group('value') # parse groups if section_type == 'group': if section_value not in parent: parent = data group_data = dict() # set the current parent parent[section_value] = group_data parent = parent[section_value] #print '\nGroup: "%s"' % section_value if section_type == 'attr': attr_data = dict() # connection attributes #attr_data.update(connectable=False) #attr_data.update(connection_type=None) parent[section_value] = attr_data attr_name = section_value #print ' Attribute: "%s"' % attr_name if section_type in ['input', 'output']: conn_data = dict() conn_data.update(connectable=True) conn_data.update( connection_type=section_type) parent[section_value] = conn_data attr_name = section_value #print ' Connection: "%s"' % attr_name else: prop_obj = re.search(regex.get("properties"), rline) if prop_obj: pname = prop_obj.group('name') ptype = prop_obj.group('type') pvalu = prop_obj.group('value') #print 'property: "%s" (%s)' % (pname, rline) value = pvalu if ptype in ['BOOL', 'INPUT', 'OUTPUT']: if ptype == 'BOOL': value = True if pvalu == 'true' else False # return connection types if ptype in ['INPUT', 'OUTPUT']: # data type: pvalu = FILE, DIRECTORY, ETC. value = pvalu.lower() # try and get the actual value else: try: value = eval(pvalu) except: log.warning( 'cannot parse default value of "%s.%s": "%s" (%s)' % (attr_name, pname, pvalu, filename)) #print ' property: %s (%s)' % (prop_obj.group('name'), attr_name) properties = { pname: { 'type': ptype, 'value': value } } parent[attr_name].update(properties) else: if rline: log.debug('skipping: "%s"' % rline) return data
def read_metadata(self, verbose=False): """ Initialize node metadata from metadata files on disk. Metadata is parsed by looking at the __bases__ of each node class (ie: all DagNode subclasses will inherit all of the default DagNode attributes). """ import inspect parser = MetadataParser() node_metadata = dict() if verbose: print '\n# DEBUG: building metadata for: "%s" ' % self.Class() # query the base classes result = [ self.__class__, ] for pc in self.ParentClasses(): if pc.__name__ != 'Node': result.append(pc) sg_core_path = os.path.join(SCENEGRAPH_CORE, 'nodes.py') for cls in reversed(result): cname = cls.__name__ src_file = inspect.getfile(cls) node_type = None if hasattr(cls, 'node_type'): node_type = cls.node_type py_src = src_file.rstrip('c') if verbose: print ' - base class "%s" source file: "%s"' % (cname, py_src) dirname = os.path.dirname(src_file) basename = os.path.splitext(os.path.basename(src_file))[0] # return the source .py file if it exists if os.path.exists(py_src): src_file = py_src metadata_filename = os.path.join(dirname, '%s.mtd' % basename) # look for code node metadata in ../mtd if py_src == sg_core_path: if node_type: metadata_filename = os.path.join(SCENEGRAPH_METADATA_PATH, '%s.mtd' % node_type) if verbose: print ' - metadata file for "%s": "%s"' % ( cname, metadata_filename) if not os.path.exists(metadata_filename): if not verbose: log.warning( 'plugin description file "%s" does not exist.' % metadata_filename) else: print ' WARNING: metadata file for "%s": "%s" not found' % ( cname, metadata_filename) continue log.debug('reading plugin metadata file: "%s".' % metadata_filename) # parse the metadata parsed = parser.parse(metadata_filename) for section in parsed: if section not in node_metadata: node_metadata[section] = dict() attributes = parsed.get(section) # parse out input/output here? for attr in attributes: if attr not in node_metadata[section]: node_metadata.get(section)[attr] = dict() attr_properties = attributes.get(attr) node_metadata.get(section).get(attr).update( attr_properties) return node_metadata
def read_metadata(self, verbose=False): """ Initialize node metadata from metadata files on disk. Metadata is parsed by looking at the __bases__ of each node class (ie: all DagNode subclasses will inherit all of the default DagNode attributes). """ import inspect parser = MetadataParser() node_metadata = dict() if verbose: print '\n# DEBUG: building metadata for: "%s" ' % self.Class() # query the base classes result = [self.__class__,] for pc in self.ParentClasses(): if pc.__name__ != 'Node': result.append(pc) sg_core_path = os.path.join(SCENEGRAPH_CORE, 'nodes.py') for cls in reversed(result): cname = cls.__name__ src_file = inspect.getfile(cls) node_type = None if hasattr(cls, 'node_type'): node_type = cls.node_type py_src = src_file.rstrip('c') if verbose: print ' - base class "%s" source file: "%s"' % (cname, py_src) dirname = os.path.dirname(src_file) basename = os.path.splitext(os.path.basename(src_file))[0] # return the source .py file if it exists if os.path.exists(py_src): src_file = py_src metadata_filename = os.path.join(dirname, '%s.mtd' % basename) # look for code node metadata in ../mtd if py_src == sg_core_path: if node_type: metadata_filename = os.path.join(SCENEGRAPH_METADATA_PATH, '%s.mtd' % node_type) if verbose: print ' - metadata file for "%s": "%s"' % (cname, metadata_filename) if not os.path.exists(metadata_filename): if not verbose: log.warning('plugin description file "%s" does not exist.' % metadata_filename) else: print ' WARNING: metadata file for "%s": "%s" not found' % (cname, metadata_filename) continue log.debug('reading plugin metadata file: "%s".' % metadata_filename) # parse the metadata parsed = parser.parse(metadata_filename) for section in parsed: if section not in node_metadata: node_metadata[section] = dict() attributes = parsed.get(section) # parse out input/output here? for attr in attributes: if attr not in node_metadata[section]: node_metadata.get(section)[attr] = dict() attr_properties = attributes.get(attr) node_metadata.get(section).get(attr).update(attr_properties) return node_metadata