""" Allows for the construction of source from objects -- i.e., serializing into Python expressions. Examples:: >>> src = SourceRepr() >>> src.addObject(10) >>> print src.source() 10 >>> class Holder: ... def __init__(self, *args, **kw): ... self.args = args ... self.kw = kw ... def __repr__(self): ... args = map(repr, self.args) ... args.extend(['%s=%r' % v for v in self.kw.items()]) ... return 'Holder(%s)' % ', '.join(args) >>> print Holder(1, 2, x=10) Holder(1, 2, x=10) >>> src.addObject(Holder(1, 2, x=10)) >>> print src.source() 10 Holder(1, 2, x=10) >>> import declarative >>> class Me(declarative.Declarative): ... \"\"\" ... A simple class. ... \"\"\" ... __unpackargs__ = ('name',) ... name = None >>> src.addObject(Me, binding='Me') >>> print src.source() 10 Holder(1, 2, x=10) class Me(Declarative): \"\"\" A simple class. \"\"\" __unpackargs__ = ('name',) name = None >>> src = SourceRepr() >>> src.addObject(Me(name='Something')) >>> print src.source() Me('Something') >>> src.addObject(Me(name='nothing', other=1, val=(1, 2)), binding='obj') >>> print src.source() Me('Something') class obj(Me): name = 'nothing' other = 1 val = (1, 2) """ try: from cStringIO import StringIO except ImportError: from StringIO import StringIO class SourceRepr(object): def __init__(self): self.modules = [] self.out = StringIO() def addObject(self, obj, binding=None): self.out.write(self.makeRepr(obj, binding=binding)) self.out.write('\n') def makeRepr(self, obj, binding=None): if not isinstance(obj, type) and hasattr(obj, '__sourcerepr__'): return self.awareObject(obj, binding=binding) elif isinstance(obj, type) and hasattr(obj, '__classsourcerepr__'): return self.awareClass(obj, binding=binding) elif isinstance(obj, type): return self.unawareClass(obj, binding=binding) else: return self.unawareObject(obj, binding=binding) def awareObject(self, obj, binding=None): source = obj.__sourcerepr__(self, binding=binding) return source def awareClass(self, obj, binding=None): source = obj.__classsourcerepr__(self, binding=binding) return source def unawareObject(self, obj, binding=None): source = self.reprObject(obj) if binding: return '%s = %s' % (binding, source) else: return source def unawareClass(self, obj, binding=None): if binding == obj.__name__: binding = None text = self.makeClass(obj, obj.__name__, obj.__dict__, obj.__bases__) if binding: text = '%s = %s\n' % (text, binding, obj.__name__) return text def makeClass(self, cls, clsName, d, bases): source = StringIO() source.write('class %s(%s):\n' % (clsName, ', '.join([c.__name__ for c in bases]))) vals = d.copy() if vals.has_key('__doc__'): if vals['__doc__']: source.write(' %s\n' % _tripleQuoteRepr(vals['__doc__'])) del vals['__doc__'] if vals.has_key('__module__'): del vals['__module__'] vals = vals.items() vals.sort() for name, value in vals: source.write(self.redent( self.makeRepr(value, binding=name), 4)) source.write('\n') source.write('\n') return source.getvalue() def reprObject(self, obj): if isinstance(obj, dict): source = self.reprDict(obj) elif isinstance(obj, tuple): source = self.reprTuple(obj) elif isinstance(obj, list): source = self.reprList(obj) else: source = repr(obj) if source.startswith('<'): # Sure sign we got a broken repr... raise TypeError, "Object %r is not producing an acceptable source representation from repr()" % obj return source def reprDict(self, obj): items = [] for name, value in obj.items(): items.append((self.reprObject(name), self.reprObject(value))) try: items.sort() except TypeError: pass if len(items) > 2: return '{%s}' % ''.join(['%s: %s,\n ' % i for i in items]) else: return '{%s}' % ', '.join(['%s: %s' % i for i in items]) def reprTuple(self, obj): if len(obj) == 1: return '(%s,)' % self.reprObject(obj[0]) if len(obj) == 2: return '(%s, %s)' % (self.reprObject(obj[0]), self.reprObject(obj[1])) else: return '(%s)' % ''.join(['%s,\n ' % self.reprObject(i) for i in obj]) def reprList(self, obj): if len(obj) <= 2: return '[%s]' % ', '.join([self.reprObject(i) for i in obj]) else: return '[%s]' % ''.join(['%s,\n ' % self.reprObject(i) for i in obj]) def source(self): text = [] for module in self.modules: text.append('import %s' % module) text.append('') text.append(self.out.getvalue()) return '\n'.join(text) def redent(self, text, indent): if isinstance(indent, (int, long)): indent = ' '*indent lines = text.split('\n') joiner = '\n' + indent return indent + joiner.join(lines) + '\n' def _tripleQuoteRepr(v): v = repr(v)[1:-1] v = v.replace('\\n', '\n') v = v.replace('\\"', '"') v = v.replace("\\'", "'") v = v.replace('\\t', '\t') v = v.replace('"""', '\\"\\"\\"') return '"""%s"""' % v