From 2b2baf924cadcc6268477a7c350a76d5e774c595 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Sat, 17 Mar 2012 17:23:39 +0000 Subject: [PATCH] Improve tracediff2's dumping. --- scripts/tracediff2.py | 16 ++++--- scripts/unpickle.py | 103 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 106 insertions(+), 13 deletions(-) diff --git a/scripts/tracediff2.py b/scripts/tracediff2.py index 13fcbd1..3f14d36 100755 --- a/scripts/tracediff2.py +++ b/scripts/tracediff2.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ########################################################################## # -# Copyright 2011 Jose Fonseca +# Copyright 2011-2012 Jose Fonseca # All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,12 +26,13 @@ import difflib +import itertools import optparse import os.path import subprocess import sys -from unpickle import Unpickler +from unpickle import Unpickler, Dumper from highlight import ColorHighlighter, LessHighlighter @@ -86,6 +87,7 @@ class SDiffer: self.callNos = callNos self.aSpace = 0 self.bSpace = 0 + self.dumper = Dumper() def diff(self): matcher = difflib.SequenceMatcher(self.isjunk, self.a, self.b) @@ -167,15 +169,15 @@ class SDiffer: def replace_value(self, a, b): if b == a: - self.highlighter.write(str(b)) + self.highlighter.write(self.dumper.visit(b)) else: self.highlighter.strike() self.highlighter.color(self.delete_color) - self.highlighter.write(str(a)) + self.highlighter.write(self.dumper.visit(a)) self.highlighter.normal() self.highlighter.write(" ") self.highlighter.color(self.insert_color) - self.highlighter.write(str(b)) + self.highlighter.write(self.dumper.visit(b)) self.highlighter.normal() escape = "\33[" @@ -235,9 +237,9 @@ class SDiffer: self.highlighter.bold(True) self.highlighter.write(call.functionName) self.highlighter.bold(False) - self.highlighter.write('(' + ', '.join(map(repr, call.args)) + ')') + self.highlighter.write('(' + ', '.join(itertools.imap(self.dumper.visit, call.args)) + ')') if call.ret is not None: - self.highlighter.write(' = ' + repr(call.ret)) + self.highlighter.write(' = ' + self.dumper.visit(call.ret)) self.highlighter.normal() self.highlighter.write('\n') diff --git a/scripts/unpickle.py b/scripts/unpickle.py index 98e2c30..3f0bc42 100755 --- a/scripts/unpickle.py +++ b/scripts/unpickle.py @@ -33,10 +33,100 @@ Run as: ''' +import itertools import optparse -import cPickle as pickle import sys import time +import re +import cPickle as pickle + + +class Visitor: + + def __init__(self): + self.dispatch = {} + self.dispatch[type(None)] = self.visitNone + self.dispatch[bool] = self.visitBool + self.dispatch[int] = self.visitInt + self.dispatch[long] = self.visitInt + self.dispatch[float] = self.visitFloat + self.dispatch[str] = self.visitStr + self.dispatch[tuple] = self.visitTuple + self.dispatch[list] = self.visitList + self.dispatch[dict] = self.visitDict + self.dispatch[bytearray] = self.visitByteArray + + def visit(self, obj, *args, **kwargs): + return self.dispatch[type(obj)](obj, *args, **kwargs) + + def visitAtom(self, obj, *args, **kwargs): + raise NotImplementedError + + def visitNone(self, obj, *args, **kwargs): + return self.visitAtom(obj, *args, **kwargs) + + def visitBool(self, obj, *args, **kwargs): + return self.visitAtom(obj, *args, **kwargs) + + def visitInt(self, obj, *args, **kwargs): + return self.visitAtom(obj, *args, **kwargs) + + def visitFloat(self, obj, *args, **kwargs): + return self.visitAtom(obj, *args, **kwargs) + + def visitStr(self, obj, *args, **kwargs): + return self.visitAtom(obj, *args, **kwargs) + + def visitIterable(self, obj, *args, **kwargs): + raise NotImplementedError + + def visitTuple(self, obj, *args, **kwargs): + return self.visitIterable(obj, *args, **kwargs) + + def visitList(self, obj, *args, **kwargs): + return self.visitIterable(obj, *args, **kwargs) + + def visitDict(self, obj, *args, **kwargs): + raise NotImplementedError + + def visitByteArray(self, obj, *args, **kwargs): + raise NotImplementedError + + +class Dumper(Visitor): + + id_re = re.compile('^[_A-Za-z][_A-Za-z0-9]*$') + + def visitAtom(self, obj, *args, **kwargs): + return repr(obj) + + def visitStr(self, obj, *args, **kwargs): + if self.id_re.match(obj): + return obj + else: + return repr(obj) + + def visitTuple(self, obj, *args, **kwargs): + return '[' + ', '.join(itertools.imap(self.visit, obj)) + ']' + + def visitList(self, obj, *args, **kwargs): + return '(' + ', '.join(itertools.imap(self.visit, obj)) + ')' + + def visitByteArray(self, obj, *args, **kwargs): + return 'blob(%u)' % len(obj) + + +class Hasher(Visitor): + '''Returns a hashable version of the objtree.''' + + def visitAtom(self, obj, *args, **kwargs): + return obj + + def visitIterable(self, obj, *args, **kwargs): + return tuple(itertools.imap(self.visit, obj)) + + def visitByteArray(self, obj, *args, **kwargs): + return str(obj) class Call: @@ -49,10 +139,11 @@ class Call: s = self.functionName if self.no is not None: s = str(self.no) + ' ' + s - s += '(' + ', '.join(map(repr, self.args)) + ')' + dumper = Dumper() + s += '(' + ', '.join(itertools.imap(dumper.visit, self.args)) + ')' if self.ret is not None: s += ' = ' - s += repr(self.ret) + s += dumper.visit(self.ret) return s def __eq__(self, other): @@ -63,9 +154,9 @@ class Call: def __hash__(self): if self._hash is None: - # XXX: hack due to unhashable types - #self._hash = hash(self.functionName) ^ hash(tuple(self.args)) ^ hash(self.ret) - self._hash = hash(self.functionName) ^ hash(repr(self.args)) ^ hash(repr(self.ret)) + hasher = Hasher() + hashable = hasher.visit(self.functionName), hasher.visit(self.args), hasher.visit(self.ret) + self._hash = hash(hashable) return self._hash -- 2.43.0