Exemple #1
0
def state_not(inv, msg=None):
	"""
	Decorates an object method to throw StateError if its state is listed in
	the given invalid states

	The object is assumed to have a "state" attribute; it is up to the caller
	to ensure that this holds.

	@param inv: either the invalid state or an iterable of invalid states
	@param msg: either an error message, or a callable or map that returns one
	"""
	msg_cb = callable_wrap(msg)
	def decorate(method):
		if hasattr(inv, "__iter__"):
			def wrap(self, *args, **kwargs):
				if self.state in inv:
					raise StateError(msg_cb(self.state), self.state)
				return method(self, *args, **kwargs)
		else:
			def wrap(self, *args, **kwargs):
				if self.state == inv:
					raise StateError(msg_cb(self.state), self.state)
				return method(self, *args, **kwargs)
		return wrap
	return decorate
Exemple #2
0
	def build(self, keep_dangle=False, bipartite=False, node_attr=None, inverse=False, complete=True):
		"""
		Build a graph out of the sample.

		Definitions: an "explicit" node is one which has been explicited added
		to the sample with add_node(). A "dangling" node is one referenced by
		the out-dicts of other nodes, but not explicitly added to the sample
		(and implicitly has no out-dict of its own).

		The total number of explicit nodes will be stored in self.order, and
		if kept (see <keep_dangle>), the total number of dangling nodes will be
		stored in self.extra.

		@param keep_dangle: whether to keep dangling nodes; if so, these nodes
		       will have vertex ids greater than explicit nodes. <bipartite>
		       and <node_attr> will only have an effect if this is True.
		@param bipartite: whether to raise an error if an explicit node points
		       to another explicit node
		@param node_attr: this is passed through callable_wrap() to give a
		       mapping from dangling nodes to node attributes
		@param inverse: whether to invert edge directions
		@param complete: whether to store the built graph in self.graph and
		       discard the cache. it will then be impossible to add new nodes,
		       and future calls to this method will always return self.graph
		@return: The built graph
		"""
		if self.graph is not None: return self.graph

		if keep_dangle:
			attr_cb = callable_wrap(node_attr)

		# init nodes
		v_id = [node.id for node in self._list]
		v_attr = [node.attr for node in self._list]
		id_v = dict((node.id, i) for i, node in enumerate(self._list))
		self.order = j = len(self._list)

		# init edges
		arc_s, arc_t, edges, e_attr = edge_array(0x10001 if keep_dangle else j, 'd', inverse)

		for (i, node) in enumerate(self._list):
			for (dst, attr) in node.out.iteritems():
				if dst in self._keys:
					if keep_dangle and bipartite:
						raise ValueError("non-bipartite graph: %s - %s" % (node.id, dst))
					arc_s.append(i)
					arc_t.append(id_v[dst])
					e_attr.append(attr)

				elif keep_dangle:
					if dst in id_v:
						x = id_v[dst]
					else:
						x = id_v[dst] = j
						v_id.append(dst)
						v_attr.append(attr_cb(dst))
						j += 1

					arc_s.append(i)
					arc_t.append(x)
					e_attr.append(attr)
				else:
					pass

		assert j == len(id_v) == len(v_id) == len(v_attr)
		if keep_dangle:
			self.extra = j - self.order

		# igraph can't handle utf-8 output, see launchpad bug #545663
		for (i, id) in enumerate(v_id):
			if type(id) == unicode:
				v_id[i] = id.encode("utf-8")

		# prepare attributes
		va = {NID: v_id}
		if any(a is not None for a in v_attr):
			va[NAT] = v_attr

		# build graph
		gg = Graph(n=j, directed=True, vertex_attrs=va)
		gg.add_edges(edges)
		gg.es[AAT] = e_attr

		if complete:
			self.graph = gg
			self._keys = None
			self._list = None

		return gg