[py-svn] r33965 - in py/dist/py/apigen: rest tracer tracer/testing

guido at codespeak.net guido at codespeak.net
Tue Oct 31 17:09:38 CET 2006


Author: guido
Date: Tue Oct 31 17:09:35 2006
New Revision: 33965

Modified:
   py/dist/py/apigen/rest/genrest.py
   py/dist/py/apigen/tracer/description.py
   py/dist/py/apigen/tracer/docstorage.py
   py/dist/py/apigen/tracer/testing/test_docgen.py
   py/dist/py/apigen/tracer/testing/test_package.py
   py/dist/py/apigen/tracer/tracer.py
Log:
Improved (and actually got it to work :) displaying of changes in self.__dict__
after method calls. Also some whitespace and reformatting.


Modified: py/dist/py/apigen/rest/genrest.py
==============================================================================
--- py/dist/py/apigen/rest/genrest.py	(original)
+++ py/dist/py/apigen/rest/genrest.py	Tue Oct 31 17:09:35 2006
@@ -330,6 +330,17 @@
                 items.append(Text(next))
             lst.append(ListItem(*items))
         
+        local_changes = self.dsa.get_function_local_changes(functionname)
+        lst.append(Paragraph('Changes in __dict__:'))
+        from py.__.apigen.tracer.description import NoValue
+        for k, (oldvalue, newvalue) in local_changes.iteritems():
+            description = 'value changed'
+            if oldvalue is NoValue:
+                description = 'newly added'
+            elif newvalue is NoValue:
+                description = 'deleted'
+            lst.append(ListItem('%s: %s' % (k, description)))
+        
         # XXX missing implementation of dsa.get_function_location()
         #filename, lineno = self.dsa.get_function_location(functionname)
         #linkname, linktarget = self.linkgen.getlink(filename, lineno)

Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py	(original)
+++ py/dist/py/apigen/tracer/description.py	Tue Oct 31 17:09:35 2006
@@ -42,6 +42,9 @@
     def __cmp__(self, other):
         return cmp(self._getval(), other._getval())
 
+class NoValue(object):
+    """used in MethodDesc.get_local_changes() when there is no value"""
+
 def cut_stack(stack, frame, upward_frame=None):
     if hasattr(frame, 'raw'):
         frame = frame.raw
@@ -121,7 +124,6 @@
         self.keep_frames = kwargs.get('keep_frames', False)
         self.frame_copier = kwargs.get('frame_copier', lambda x:x)
         self.retval = model.s_ImpossibleValue
-        self.local_changes = {}
     
     def consider_call(self, inputcells):
         for cell_num, cell in enumerate(inputcells):
@@ -148,13 +150,19 @@
     def consider_return(self, arg):
         self.retval = model.unionof(arg, self.retval)
 
-    def handle_local_changes(self, changeset):
-        self.local_changes = changeset
+    def consider_start_locals(self, frame):
+        pass
 
+    def consider_end_locals(self, frame):
+        pass
+    
     def getcode(self):
         return self.pyobj.func_code
     code = property(getcode)
     
+    def get_local_changes(self):
+        return {}
+    
 class ClassDesc(Desc):
     def __init__(self, *args, **kwargs):
         super(ClassDesc, self).__init__(*args, **kwargs)
@@ -196,6 +204,12 @@
     
     def consider_return(self, arg):
         pass # we *know* what return value we do have
+
+    def consider_start_locals(self, frame):
+        pass
+
+    def consider_end_locals(self, frame):
+        pass
     
     def consider_call_site(self, frame, cut_frame):
         self.fields['__init__'].consider_call_site(frame, cut_frame)
@@ -217,9 +231,42 @@
 ##        
 ##
 class MethodDesc(FunctionDesc):
+    def __init__(self, *args, **kwargs):
+        super(MethodDesc, self).__init__(*args, **kwargs)
+        self.old_dict = {}
+        self.new_dict = {}
+
     # right now it's not different than method desc, only code is different
     def getcode(self):
         return self.pyobj.im_func.func_code
     code = property(getcode)
 ##    def has_code(self, code):
 ##        return self.pyobj.im_func.func_code is code
+
+    def consider_start_locals(self, frame):
+        # XXX recursion issues?
+        obj = frame.f_locals.get('self')
+        if not obj:
+            # static method
+            return
+        self.old_dict = obj.__dict__.copy()
+
+    def consider_end_locals(self, frame):
+        obj = frame.f_locals.get('self')
+        if not obj:
+            # static method
+            return
+        self.new_dict = obj.__dict__.copy()
+
+    def get_local_changes(self):
+        changeset = {}
+        for k, v in self.old_dict.iteritems():
+            if k not in self.new_dict:
+                changeset[k] = (v, NoValue)
+            elif self.new_dict[k] != v:
+                changeset[k] = (v, self.new_dict[k])
+        for k, v in self.new_dict.iteritems():
+            if k not in self.old_dict:
+                changeset[k] = (NoValue, v)
+        return changeset
+

Modified: py/dist/py/apigen/tracer/docstorage.py
==============================================================================
--- py/dist/py/apigen/tracer/docstorage.py	(original)
+++ py/dist/py/apigen/tracer/docstorage.py	Tue Oct 31 17:09:35 2006
@@ -21,13 +21,8 @@
         if desc:
             self.generalize_args(desc, frame)
             desc.consider_call_site(caller_frame, upward_cut_frame)
+            desc.consider_start_locals(frame)
 
-    def handle_local_changes(self, frame, changes):
-        assert isinstance(frame, py.code.Frame)
-        desc = self.find_desc(frame.code)
-        if desc:
-            desc.handle_local_changes(changes)
-    
     def generalize_args(self, desc, frame):
         args = [arg for key, arg in frame.getargs()]
         #self.call_stack.append((desc, args))
@@ -41,6 +36,7 @@
         desc = self.find_desc(frame.code)
         if desc:
             self.generalize_retval(desc, arg)
+            desc.consider_end_locals(frame)
 
     def find_desc(self, code):
         return self.desc_cache.get(code.raw, None)
@@ -208,7 +204,7 @@
         return self.ds.descs[name].get_call_sites()
 
     def get_function_local_changes(self, name):
-        return self.ds.descs[name].local_changes
+        return self.ds.descs[name].get_local_changes()
     
     def get_module_name(self):
         if hasattr(self.ds, 'module'):

Modified: py/dist/py/apigen/tracer/testing/test_docgen.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_docgen.py	(original)
+++ py/dist/py/apigen/tracer/testing/test_docgen.py	Tue Oct 31 17:09:35 2006
@@ -145,3 +145,36 @@
     t.end_tracing()
     assert isinstance(ds.descs['A'].fields['method'].inputcells[1], model.SomeInt)
     assert isinstance(ds.descs['B'].fields['method'].inputcells[1], model.SomeInt)
+
+def test_local_changes():
+    class testclass(object):
+        def __init__(self):
+            self.foo = 0
+        def bar(self, x):
+            self.foo = x
+    ds = DocStorage().from_dict({'testclass': testclass})
+    t = Tracer(ds)
+    t.start_tracing()
+    c = testclass()
+    c.bar(1)
+    t.end_tracing()
+    desc = ds.descs['testclass']
+    methdesc = desc.fields['bar']
+    assert methdesc.old_dict != methdesc.new_dict
+    assert methdesc.get_local_changes() == {'foo': (0, 1)}
+
+def test_local_changes_nochange():
+    class testclass(object):
+        def __init__(self):
+            self.foo = 0
+        def bar(self, x):
+            self.foo = x
+    ds = DocStorage().from_dict({'testclass': testclass})
+    t = Tracer(ds)
+    t.start_tracing()
+    c = testclass()
+    t.end_tracing()
+    desc = ds.descs['testclass']
+    methdesc = desc.fields['bar']
+    assert methdesc.get_local_changes() == {}
+

Modified: py/dist/py/apigen/tracer/testing/test_package.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_package.py	(original)
+++ py/dist/py/apigen/tracer/testing/test_package.py	Tue Oct 31 17:09:35 2006
@@ -45,3 +45,4 @@
         methdesc = desc.fields['__init__']
         assert isinstance(methdesc.inputcells[0], model.SomeInstance)
         assert isinstance(methdesc.inputcells[1], model.SomeInt)
+

Modified: py/dist/py/apigen/tracer/tracer.py
==============================================================================
--- py/dist/py/apigen/tracer/tracer.py	(original)
+++ py/dist/py/apigen/tracer/tracer.py	Tue Oct 31 17:09:35 2006
@@ -28,31 +28,13 @@
         
         # perform actuall tracing
         frame = py.code.Frame(frame)
-        frameid = '%s:%s' % (frame.code.filename, frame.code.firstlineno)
         if event == 'call':
             assert arg is None
             self.docstorage.consider_call(frame,
                                           py.code.Frame(sys._getframe(2)),
                                           self.frame)
-            self._locals[frameid] = frame.f_locals.copy()
         elif event == 'return':
             self.docstorage.consider_return(frame, arg)
-            changeset = {}
-            if frameid in self._locals:
-                oldlocals = self._locals[frameid]
-                newlocals = frame.f_locals
-                __marker__ = []
-                for k, v in newlocals.items():
-                    oldvalue = oldlocals.get(k, __marker__)
-                    if oldvalue is not v:
-                        if oldvalue is __marker__:
-                            changeset[k] = (NoValue, v)
-                        else:
-                            changeset[k] = (oldvalue, v)
-                    for k, v in oldlocals.items():
-                        if k not in newlocals:
-                            changeset[k] = (oldvalue, NoValue)
-            self.docstorage.handle_local_changes(frame, changeset)
         return self._tracer
     
     def start_tracing(self):



More information about the pytest-commit mailing list