[Checkins] SVN: zc.zk/trunk/src/zc/zk/ Separated parsing of tree representations into a separate fuction,
Jim Fulton
jim at zope.com
Fri Dec 9 12:15:30 UTC 2011
Log message for revision 123646:
Separated parsing of tree representations into a separate fuction,
``parse_tree``, to support analysis and added a ``graphvis``
demonstration module to show how one might use tree representations
for system modeling.
Changed:
U zc.zk/trunk/src/zc/zk/README.txt
U zc.zk/trunk/src/zc/zk/__init__.py
A zc.zk/trunk/src/zc/zk/graphvis.py
-=-
Modified: zc.zk/trunk/src/zc/zk/README.txt
===================================================================
--- zc.zk/trunk/src/zc/zk/README.txt 2011-12-09 10:27:33 UTC (rev 123645)
+++ zc.zk/trunk/src/zc/zk/README.txt 2011-12-09 12:15:29 UTC (rev 123646)
@@ -581,6 +581,23 @@
logging API. ZooKeeper log messages are forwarded to the Python
``'ZooKeeper'`` logger.
+Graph analysis
+==============
+
+The textual tree representation can be used to model and analyze a
+system architecturte. You can get a parsed representation of a tree
+using ``zc.zk.parse_tree`` to parse a text tree representation
+generated by hand for import, or using the ``export_tree`` method.
+
+ >>> tree = zc.zk.parse_tree(tree_text)
+ >>> sorted(tree.children)
+ ['cms', 'lb']
+ >>> tree.children['lb'].properties
+ {'type': 'ipvs'}
+
+The demo module, ``zc.zk.graphvis`` shows how you might generate
+system diagrams from tree models.
+
Reference
=========
@@ -780,21 +797,21 @@
- Fixed bug: Ephemeral nodes weren't recreated when sessions were
reestablished.
-
- ``zc.zk.RegisteringServer`` events are generated during server
registration to allow third-party libraries to record additional
properties on new server nodes.
-
- Added a testing module that provides ZooKeeper emulation for
testing complex interactions with zc.zk without needing a running
ZooKeeper server.
-
- `zc.zk.Children`_ objects now have a __len__, which is mainly useful
for testing whether they are empty.
+- Separated parsing of tree representations into a separate fuction,
+ ``parse_tree``, to support analysis and added a ``graphvis``
+ demonstration module to show how one might use tree representations
+ for system modeling.
-
0.2.0 (2011-12-05)
-~~~~~~~~~~~~~~~~~~
+------------------
- Added tree import and export.
- Added symbolic-links.
@@ -811,7 +828,7 @@
the session.
0.1.0 (2011-11-27)
-~~~~~~~~~~~~~~~~~~
+------------------
Initial release
Modified: zc.zk/trunk/src/zc/zk/__init__.py
===================================================================
--- zc.zk/trunk/src/zc/zk/__init__.py 2011-12-09 10:27:33 UTC (rev 123645)
+++ zc.zk/trunk/src/zc/zk/__init__.py 2011-12-09 12:15:29 UTC (rev 123646)
@@ -307,76 +307,9 @@
def import_tree(self, text, path='/', trim=False, acl=OPEN_ACL_UNSAFE,
dry_run=False):
- # Step 1, build up internal tree repesentation:
- root = _Tree()
- indents = [(-1, root)] # sorted [(indent, node)]
- lineno = 0
- for line in text.split('\n'):
- lineno += 1
- line = line.rstrip()
- if not line:
- continue
- data = line.strip()
- if data[0] == '#':
- continue
- indent = len(line) - len(data)
-
- m = _text_is_property(data)
- if m:
- expr = m.group('expr')
- try:
- data = eval(expr, {})
- except Exception, v:
- raise ValueError("Error %s in expression: %r" % (v, expr))
- data = m.group('name'), data
- else:
- m = _text_is_link(data)
- if m:
- data = (m.group('name') + ' ->'), m.group('target')
- else:
- m = _text_is_node(data)
- if m:
- data = _Tree(m.group('name'))
- if m.group('type'):
- data.properties['type'] = m.group('type')
- else:
- if '->' in data:
- raise ValueError(lineno, data, "Bad link format")
- else:
- raise ValueError(lineno, data, "Unrecognized data")
-
- if indent > indents[-1][0]:
- if not isinstance(indents[-1][1], _Tree):
- raise ValueError(
- lineno, line,
- "Can't indent under properties")
- indents.append((indent, data))
- else:
- while indent < indents[-1][0]:
- indents.pop()
-
- if indent > indents[-1][0]:
- raise ValueError(lineno, data, "Invalid indentation")
-
- if isinstance(data, _Tree):
- children = indents[-2][1].children
- if data.name in children:
- raise ValueError(lineno, data, 'duplicate node')
- children[data.name] = data
- indents[-1] = indent, data
- else:
- if indents[-2][1] is root:
- raise ValueError("Can't above imported nodes.")
- properties = indents[-2][1].properties
- name, value = data
- if name in properties:
- raise ValueError(lineno, data, 'duplicate property')
- properties[name] = value
-
- # Step 2 Create The nodes
while path.endswith('/'):
path = path[:-1] # Mainly to deal w root: /
- self._import_tree(path, root, acl, trim, dry_run, True)
+ self._import_tree(path, parse_tree(text), acl, trim, dry_run, True)
def _import_tree(self, path, node, acl, trim, dry_run, top=False):
self.connected.wait(self.timeout)
@@ -729,6 +662,74 @@
# Gaaaa, collections.Mapping
return hash(id(self))
+def parse_tree(text):
+ root = _Tree()
+ indents = [(-1, root)] # sorted [(indent, node)]
+ lineno = 0
+ for line in text.split('\n'):
+ lineno += 1
+ line = line.rstrip()
+ if not line:
+ continue
+ data = line.strip()
+ if data[0] == '#':
+ continue
+ indent = len(line) - len(data)
+
+ m = _text_is_property(data)
+ if m:
+ expr = m.group('expr')
+ try:
+ data = eval(expr, {})
+ except Exception, v:
+ raise ValueError("Error %s in expression: %r" % (v, expr))
+ data = m.group('name'), data
+ else:
+ m = _text_is_link(data)
+ if m:
+ data = (m.group('name') + ' ->'), m.group('target')
+ else:
+ m = _text_is_node(data)
+ if m:
+ data = _Tree(m.group('name'))
+ if m.group('type'):
+ data.properties['type'] = m.group('type')
+ else:
+ if '->' in data:
+ raise ValueError(lineno, data, "Bad link format")
+ else:
+ raise ValueError(lineno, data, "Unrecognized data")
+
+ if indent > indents[-1][0]:
+ if not isinstance(indents[-1][1], _Tree):
+ raise ValueError(
+ lineno, line,
+ "Can't indent under properties")
+ indents.append((indent, data))
+ else:
+ while indent < indents[-1][0]:
+ indents.pop()
+
+ if indent > indents[-1][0]:
+ raise ValueError(lineno, data, "Invalid indentation")
+
+ if isinstance(data, _Tree):
+ children = indents[-2][1].children
+ if data.name in children:
+ raise ValueError(lineno, data, 'duplicate node')
+ children[data.name] = data
+ indents[-1] = indent, data
+ else:
+ if indents[-2][1] is root:
+ raise ValueError("Can't above imported nodes.")
+ properties = indents[-2][1].properties
+ name, value = data
+ if name in properties:
+ raise ValueError(lineno, data, 'duplicate property')
+ properties[name] = value
+
+ return root
+
class _Tree:
# Internal tree rep for import/export
Added: zc.zk/trunk/src/zc/zk/graphvis.py
===================================================================
--- zc.zk/trunk/src/zc/zk/graphvis.py (rev 0)
+++ zc.zk/trunk/src/zc/zk/graphvis.py 2011-12-09 12:15:29 UTC (rev 123646)
@@ -0,0 +1,68 @@
+##############################################################################
+#
+# Copyright Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""This is a doodle/demo for generating a graphvis model from a tree.
+
+It assumes the convention that nodes are "services" if they have a
+``providers`` subnode (not a link) and if they or one of their subnodes
+symbolically links to a provides node.
+"""
+
+import sys
+import zc.zk
+
+def _get_edges(tree, path, service, edges):
+
+ if 'providers' in tree.children:
+ service = path
+
+ if service:
+ for name, value in tree.properties.iteritems():
+ if name.endswith(' ->') and value.endswith('/providers'):
+ edges.append((service, value[:-10]))
+
+ for name, child in tree.children.iteritems():
+ _get_edges(child, path+'/'+name, service, edges)
+
+def get_edges(tree):
+ if isinstance(tree, basestring):
+ if '\n' not in tree:
+ if tree == '-':
+ tree = sys.stdin.read()
+ else:
+ tree = open(tree).read()
+ tree = zc.zk.parse_tree(tree)
+ edges = []
+ _get_edges(tree, '', '', edges)
+ return edges
+
+def dump_edges(edges, fname=None):
+ if not isinstance(edges, list):
+ edges = get_edges(edges)
+
+ if fname and fname != '-':
+ f = open(fname, 'w')
+ else:
+ f = sys.stdout
+
+ f.write('digraph g {\n')
+ for e in edges:
+ f.write(' "%s" -> "%s";\n' % e)
+ f.write('}\n')
+
+ if fname and fname != '-':
+ f.close()
+
+if __name__ == '__main__':
+ dump_edges(*sys.argv[1:])
+
Property changes on: zc.zk/trunk/src/zc/zk/graphvis.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: svn:eol-style
+ native
More information about the checkins
mailing list