[shpy-commit] r2840 - in shpy/trunk/dist/shpy: . net net/test

arigo@codespeak.net arigo@codespeak.net
Mon, 19 Jan 2004 20:02:10 +0100 (MET)


Author: arigo
Date: Mon Jan 19 20:02:07 2004
New Revision: 2840

Added:
   shpy/trunk/dist/shpy/net/structure.py
   shpy/trunk/dist/shpy/net/test/test_structure.py
Modified:
   shpy/trunk/dist/shpy/net/gateway.py
   shpy/trunk/dist/shpy/net/register.py
   shpy/trunk/dist/shpy/net/shared.py
   shpy/trunk/dist/shpy/net/test/test_basic.py
   shpy/trunk/dist/shpy/ui_pygame.py
Log:
Intermediate check-in.  The basic object distribution is working nicely.
The next thing to do is use it in ui_pygame to exchange the cursor(s)
position(s) among clients.

Note that we finally dropped the idea of using pickle or marshal for
exchanging structures: just like with source code, which we send around
in text format and execute remotely, we send data representations in a
text format that you can just execute to rebuild the objects in the
other process.


Modified: shpy/trunk/dist/shpy/net/gateway.py
==============================================================================
--- shpy/trunk/dist/shpy/net/gateway.py	(original)
+++ shpy/trunk/dist/shpy/net/gateway.py	Mon Jan 19 20:02:07 2004
@@ -1,12 +1,12 @@
 import autopath
 
-import threading, pickle, Queue, select
+import threading, pickle, Queue, select, StringIO
 
 from unittest2.tool import dyncode
 from shpy.net import common 
 
 class SocketGateway:
-    def __init__(self, sock, ns = None):  
+    def __init__(self, sock, ns = None):
         if ns is None:
             ns = {}
         ns['gateway'] = self

Modified: shpy/trunk/dist/shpy/net/register.py
==============================================================================
--- shpy/trunk/dist/shpy/net/register.py	(original)
+++ shpy/trunk/dist/shpy/net/register.py	Mon Jan 19 20:02:07 2004
@@ -1,7 +1,7 @@
 
 import autopath, os
-import inspect, socket, pickle
-from shpy.net import gateway
+import inspect, socket, pickle, thread
+from shpy.net import gateway, structure
 
 
 class ServerGateway(gateway.SocketGateway):
@@ -45,6 +45,25 @@
         """)
         self.exec_remote("".join(l) % locals())
 
-    def registerclient(self):
-        self.import_remote('shared.py', 'shared')
+    def registerclient(self, reload=False):
+        self.import_remote('shared.py', 'shared', reload)
         self.exec_remote("shared.registerclient(gateway)")
+        # import the root
+        self.waiting_for_root = thread.allocate_lock()
+        self.waiting_for_root.acquire()
+        self.exec_remote(inspect.getsource(structure))
+        self.exec_remote('''
+            lines = representeverything(shared.root)
+            lines.append('root = getstructure(%r)' % getstructureid(shared.root))
+            gateway.exec_remote('gateway.setstructure(%r)' % (lines,))
+        ''')
+        self.waiting_for_root.acquire()
+        del self.waiting_for_root
+        return self.root
+
+    def setstructure(self, lines):
+        l = {}
+        exec '\n'.join(lines) in vars(structure), l
+        if 'root' in l:
+            self.root = l['root']
+            self.waiting_for_root.release()

Modified: shpy/trunk/dist/shpy/net/shared.py
==============================================================================
--- shpy/trunk/dist/shpy/net/shared.py	(original)
+++ shpy/trunk/dist/shpy/net/shared.py	Mon Jan 19 20:02:07 2004
@@ -1,6 +1,8 @@
 # This module is sent by the first connecting client to the server.
 # It is not reloaded if it changes later!
 
+import pickle
+
 clientlist = []
 
 def getclientlist():
@@ -9,3 +11,16 @@
 
 def registerclient(gw):
     clientlist.append(gw)
+
+
+class Structure:
+    def __init__(self, **attributes):
+        self.__dict__.update(attributes)
+
+root = Structure()
+
+root.cells = Structure()
+cell = Structure(lines=open('/etc/passwd', 'r').read().split('\n'))
+root.cells.list = [cell]
+
+root.users = Structure()

Added: shpy/trunk/dist/shpy/net/structure.py
==============================================================================
--- (empty file)
+++ shpy/trunk/dist/shpy/net/structure.py	Mon Jan 19 20:02:07 2004
@@ -0,0 +1,83 @@
+import socket, thread, time
+
+class Structure:
+
+    def __init__(self, **attributes):
+        self.__dict__.update(attributes)
+
+
+
+def represent(obj, ref):
+    if isinstance(obj, (int, float, str, unicode)):
+        return repr(obj)
+    elif isinstance(obj, dict):
+        items = ['%s: %s' % (represent(key,ref), represent(value,ref))
+                 for key, value in obj.items()]
+        return '{%s}' % (', '.join(items))
+    elif isinstance(obj, tuple):
+        items = [represent(item,ref)+',' for item in obj]
+        return '(%s)' % (''.join(items))
+    elif isinstance(obj, list):
+        items = [represent(item,ref) for item in obj]
+        return '[%s]' % (','.join(items))
+    elif obj.__class__.__name__ == 'Structure':  # ahem
+        ref[obj] = True
+        return 'getstructure(%r)' % getstructureid(obj)
+    else:
+        raise TypeError, 'cannot represent %r' % (obj,)
+
+
+structure2id = {}
+id2structure = {}
+maplock = thread.allocate_lock()
+hostname = socket.getfqdn()
+
+def getstructureid(structure):
+    maplock.acquire()
+    try:
+        try:
+            return structure2id[structure]
+        except KeyError:
+            structid = '%d@%s@%s' % (len(structure2id), hostname, time.time())
+            structure2id[structure] = structid
+            id2structure[structid] = structure
+            return structid
+    finally:
+        maplock.release()
+
+def getstructure(structid):
+    print "hello, i'm getstructure changing the dict id", id(id2structure)
+    maplock.acquire()
+    try:
+        try:
+            return id2structure[structid]
+        except KeyError:
+            structure = Structure()
+            structure2id[structure] = structid
+            id2structure[structid] = structure
+            return structure
+    finally:
+        maplock.release()
+
+def representstructure(structure, ref=None):
+    data = {}
+    for key, value in structure.__dict__.items():
+        if not key.startswith('_'):
+            data[key] = value
+    if ref is None:
+        ref = {}
+    return 'getstructure(%r).__dict__ = %s' % (
+        getstructureid(structure), represent(data, ref))
+
+def representeverything(root):
+    lines = []
+    pending = [root]
+    seen = {root: True}
+    for structure in pending:
+        ref = {}
+        lines.append(representstructure(structure, ref))
+        for referenced in ref:
+            if referenced not in seen:
+                pending.append(referenced)
+                seen[referenced] = True
+    return lines

Modified: shpy/trunk/dist/shpy/net/test/test_basic.py
==============================================================================
--- shpy/trunk/dist/shpy/net/test/test_basic.py	(original)
+++ shpy/trunk/dist/shpy/net/test/test_basic.py	Mon Jan 19 20:02:07 2004
@@ -30,7 +30,9 @@
 def test_1_server_initialization():
     gw = getservergateway()
 
-    gw.exec_remote('fromgateway.exec_remote( ')
+    gw.exec_remote('gateway.exec_remote("test_1_back = 42")')
+    time.sleep(1)
+    check.equal(gw.ns['test_1_back'], 42)
     #res = gw.call_synchronous(functest.f)
     #check.equal(res, 42)
 

Added: shpy/trunk/dist/shpy/net/test/test_structure.py
==============================================================================
--- (empty file)
+++ shpy/trunk/dist/shpy/net/test/test_structure.py	Mon Jan 19 20:02:07 2004
@@ -0,0 +1,17 @@
+import autopath, os, time, sys
+
+from unittest2 import check, main
+
+
+from shpy.net import shared
+from shpy.net.structure import representeverything, getstructure
+
+def test_everything():
+    lines = representeverything(shared.root)
+    shared.root.funnythings = 42
+    exec '\n'.join(lines)
+    check.false(hasattr(shared.root, 'funnythings'))
+
+
+if __name__=='__main__':
+    main()

Modified: shpy/trunk/dist/shpy/ui_pygame.py
==============================================================================
--- shpy/trunk/dist/shpy/ui_pygame.py	(original)
+++ shpy/trunk/dist/shpy/ui_pygame.py	Mon Jan 19 20:02:07 2004
@@ -111,7 +111,8 @@
         self.cell = InputCell()
         self.cursor = Cursor()
         self.cursor.entercell(self.cell, (10, 10))
-        self.servergateway.registerclient()
+        self.root = self.servergateway.registerclient()
+        import pdb; pdb.set_trace()
 
     def repaint(self):
         self.screen.fill((255,255,255))