[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