Created
March 26, 2017 19:53
-
-
Save juriad/937ded801a8c43283ece45aff1e9339b to your computer and use it in GitHub Desktop.
Graph with Meta
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from enum import Enum | |
class MetaItem(type): | |
def __new__(cls, name, bases, namespace, **kwds): | |
def named_adder(k): | |
def adder(self, val): | |
getattr(self, k).append(val) | |
val.set_parent(self) | |
return adder | |
def named_setter(k): | |
def setter(self, val): | |
setattr(self, k, val) | |
val.set_parent(self) | |
return setter | |
def setting_init(mod, old): | |
def init(self, *args, **kwargs): | |
old(self, *args, **kwargs) | |
for k, (v, _mn, _mf) in mod.items(): | |
setattr(self, k, v) | |
return init | |
mod = {} | |
for k, v in namespace.items(): | |
if isinstance(v, list): | |
mod[k] = (v, 'add' + k.title()[:-1], named_adder(k)) | |
if v == None: | |
mod[k] = (v, 'set' + k.title(), named_setter(k)) | |
for k, (_v, mn, mf) in mod.items(): | |
namespace[mn] = mf | |
del namespace[k] | |
namespace['__init__'] = setting_init(mod, namespace['__init__']) | |
result = type.__new__(cls, name, bases, namespace, **kwds) | |
return result | |
class Item(object, metaclass=MetaItem): | |
def __init__(self, type, id_attr='id', add_parent=False): | |
self._type = type | |
self._id_attr = id_attr | |
self._add_parent = add_parent | |
self._gen = {} | |
self._id = None | |
self._parent = None | |
def _next_id(self, type): | |
i = self._gen.get(type, 0) | |
self._gen[type] = i + 1 | |
return self.type + str(i + 1) | |
def set_parent(self, parent): | |
self._parent = parent | |
def get_id(self): | |
i = getattr(self, self._id_attr) | |
if i != None: | |
if self._add_parent: | |
return "%s::%s" % (self._parent.get_id(), i) | |
else: | |
return i | |
if self._id != None: | |
self._id = self._parent._next_id(self.item_type) | |
return '%s::%s' % (self._parent.get_id(), self._id) | |
class KeyForEnum(Enum): | |
ALL = 'all' | |
GRAPHML = 'graphml' | |
GRAPH = 'graph' | |
NODE = 'node' | |
EDGE = 'edge' | |
HYPEREDGE = 'hyperedge' | |
PORT = 'port' | |
ENDPOINT = 'endpoint' | |
class AttrTypeEnum(Enum): | |
BOOLEAN = 'boolean' | |
INT = 'int' | |
LONG = 'long' | |
FLOAT = 'float' | |
DOUBLE = 'double' | |
STRING = 'string' | |
class Key(Item): | |
def __init__(self, id, for_=KeyForEnum.ALL, desc=None, default=None, attr_name=None, attr_type=None): | |
super().__init__('k') | |
self.id = id | |
self.for_ = for_ | |
self.desc = desc | |
self.default = default | |
class Data(Item): | |
def __init__(self, key, value, id=None): | |
super().__init__('d') | |
self.key = key | |
self.value = value | |
self.id = id | |
class Port(Item): | |
datas = [] | |
ports = [] | |
def __init__(self, name, desc=None): | |
super().__init__('p', 'name', True) | |
self.name = name | |
self.desc = desc | |
def get_node(self): | |
p = self._parent | |
while p != None and p._type != 'n': | |
p = p._parent | |
if p == None: | |
raise RuntimeError('Port is not part of any node') | |
return p | |
class Node(Item): | |
datas = [] | |
ports = [] | |
graph = None | |
def __init__(self, id=None, desc=None): | |
super().__init__('n') | |
self.id = id | |
self.desc = desc | |
class Edge(Item): | |
datas = [] | |
graph = None | |
def __init__(self, source=None, target=None, id=None, desc=None, directed=None, source_port=None, target_port=None): | |
super().__init__('e') | |
self.source = source | |
self.target = target | |
self.id = id | |
self.desc = desc | |
self.directed = directed | |
self.source_port = source_port | |
self.target_port = target_port | |
if source == None and source_port == None: | |
raise RuntimeError('At least one of source and source_port must be set') | |
if source_port != None: | |
source = source_port.getNode() | |
if target == None and target_port == None: | |
raise RuntimeError('At least one of target and target_port must be set') | |
if target_port != None: | |
target = target_port.getNode() | |
def is_directed(self): | |
if self.directed != None: | |
return self.directed | |
return self._parent.edgedefault != EdgeDefaultEnum.UNDIRECTED | |
class EndpointTypeEnum(Enum): | |
IN = 'in' | |
OUT = 'out' | |
UNDIR = 'undir' | |
class Endpoint(Item): | |
def __init__(self, node=None, id=None, desc=None, port=None, type=EndpointTypeEnum.UNDIR): | |
super().__init__('d') | |
self.node = node | |
self.id = id | |
self.desc = desc | |
self.port = port | |
self.type = type | |
if node == None and port == None: | |
raise RuntimeError('At least one of node and port must be set') | |
if port != None: | |
node = port.getNode() | |
class Hyperedge(Item): | |
datas = [] | |
endpoints = [] | |
graph = None | |
def __init__(self, id=None, desc=None): | |
super().__init__('h') | |
self.id = id | |
self.desc = desc | |
class EdgeDefaultEnum(Enum): | |
DIRECTED = 'directed' | |
UNDIRECTED = 'undirected' | |
class Graph(Item): | |
datas = [] | |
nodes = [] | |
edges = [] | |
hyperedges = [] | |
def __init__(self, id=None, desc=None, edgedefault=EdgeDefaultEnum.DIRECTED): | |
super().__init__('g') | |
self.id = id | |
self.desc = desc | |
self.edgedefault = edgedefault | |
class GraphML (Item): | |
keys = [] | |
graphs = [] | |
datas = [] | |
def __init__(self, desc=None): | |
super().__init__('_') | |
self.desc = desc | |
def get_id(self): | |
return '' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment