Mercurial > hg > WSGraph
view wsgraph/model.py @ 34:16673636dcb6
wow, testing is fun!
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Thu, 13 Dec 2012 19:06:00 -0800 |
parents | 943a4b7097af |
children | f17a6577cc0d |
line wrap: on
line source
import sys from abc import abstractmethod from copy import deepcopy from utils import isiterable class Graph(object): """ abstract base class for WSGraph model of a graph WSGraph is interacted with by implementing wsgraph.model.Graph object for a desired interface """ @abstractmethod def node(self, name, value=None): """ get or set a node When setting a node, a value of `None` will pop the value from the nodal values """ # TODO: values should not be **kwargs as you could conceivably want # to set a node or edge to an empty dict # Instead, should be (self, name, values=None) @abstractmethod def nodes(self): """returns a list of all nodes""" @abstractmethod def edge(self, node1, node2, value=None): """ get or set edge from node1 to node2 """ @abstractmethod def edges(self): """returns a list of all edges""" def __call__(self): """ returns JSGN format of graph: {'nodes': {'node1': {}, 'node2': {}, ...}, 'edges': {'node1': {'node2': {}, 'node3': {}, ...}, 'node2': {'node1': {}, ...}} } """ retval = {'nodes': {}, 'edges': {}} for node in self.nodes(): retval['nodes'][node] = self.node(node) for node1, node2 in self.edges(): retval['edges'].setdefault(node1, {})[node2] = self.edge(node1, node2) return retval def __getitem__(self, key): """ if key is a basestring, return the node of that name; if key is a 2-tuple/list, return the edge of that name """ if isinstance(key, basestring) or (not isiterable(key)): return self.node(key) else: return self.edge(*key) def __setitem__(self, key, value): if isinstance(key, basestring) or (not isiterable(key)): self.node(key, value) else: key1, key2 = key self.edge(key1, key2, value) def __contains__(self, key): """ if key is ..., returns if that node is in the graph if key is a 2-tuple/list, returns if the edge is in the graph """ # XXX not necessarily the best implementation! if isinstance(key, basestring) or (not isiterable(key)): return key in self.nodes() else: return tuple(key) in self.edges() class MemoryCache(Graph): """volatile in-memory representation of a graph""" def __init__(self): self._edges = {} self._nodes = {} def node(self, name, value=None): if value is not None: # setter self._nodes[name] = deepcopy(value) else: # getter # TODO: deepcopy return deepcopy(self._nodes.get(name, None)) def nodes(self): return self._nodes.keys() def edge(self, node1, node2, value=None): if value is not None: # setter self._edges[(node1, node2)] = deepcopy(value) for node in node1, node2: self._nodes.setdefault(node, {}) else: # getter # TODO: deepcopy return deepcopy(self._edges.get((node1, node2), None)) def edges(self): return self._edges.keys() class FileCache(MemoryCache): """on-disk JSON file cache""" def __init__(self, filename): self.filename = filename raise NotImplementedError # TODO: CLI entry point to convert from one model to another # def main(args=sys.argv[1:]):