4

When you print an object in Python, and __repr__ and __str__ are not defined by the user, Python converts the objects to string representations, delimited with angle brackets...

<bound method Shell.clear of <Shell object at 0x112f6f350>>

The problem is rendering this in a web browser in strings that also contain HTML that must be rendered normally. The browser obviously gets confused by the angle brackets.

I'm struggling to find any information about how these representations are formed, if there's a name for them even.

Is it possible to change the way that Python represents objects as strings, for all objects that don't have a __repr__ method defined, by overriding __repr__ for the object class?

So, if Python would normally return "<Foo object at 0x112f6f350>", what hook could make it return "{Foo object at {0x112f6f350}}" instead, or whatever else, without having to modify the Foo and every other class directly?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Carl Smith
  • 3,025
  • 24
  • 36
  • How about escaping the characters that have XML meaning? –  Nov 03 '13 at 16:07
  • It needs to render something like `""` as the `Shell` repr, in italics. – Carl Smith Nov 03 '13 at 18:45
  • I guess escaping everything that's not in a list of actual HTML elements might work. I'd still rather avoid parsing the strings though. It's messy. There must be some way in Python to hook into the `__repr__` method or something. It'd be nice to be able to override the way `__repr__` works by default, based on `self`, to syntax highlight object representations and pull out docstrings etc. – Carl Smith Dec 29 '13 at 18:28
  • 1
    There is no way to override the default representation of Python classes short of injecting a meta class into each and every class or providing a base class that provides a `__repr__` implementation (including providing an alternative built-in `object`). A far better solution is to use a decent templating library that auto-escapes anglebrackets when generating HTML. – Martijn Pieters Dec 29 '13 at 22:40
  • @CarlSmith: [`cgi.escape()`](http://hg.python.org/cpython/file/2.7/Lib/cgi.py#l1036) that makes html-safe strings would be trivial to implement. – jfs Dec 29 '13 at 23:03
  • 1
    @CarlSmith: At some point your objects are objects, call `escape(repr(obj))` instead of `repr(obj)` at this point. Or just use an HTML template library as Marijin suggested – jfs Dec 31 '13 at 07:50
  • They're not *my* objects chap. It's for a shell, so the user will be able to print any stuff they like. If they print a list of 3 `Foo`s, in a browser based client, they should not get a list of three broken [invisible] HTML elements. I'm after a way to tweak Python so that all objects that are represented after the tweaks are made, are rendered differently to the default. – Carl Smith Jan 01 '14 at 23:10

2 Answers2

7

You can play with the __builtin__s (before importing anything). I found that replacing __builtin__.repr does not work, but replacing __builtin__.object does.

Here's how it can be done. Say you have a module defining classes:

# foo.py
class Foo(object):
    pass

In your main script, do:

# main.py
import __builtin__

class newobject(object):
    def __repr__(self):
        return '{%s object at {%s}}' % (self.__class__.__name__, hex(id(self)))

__builtin__.object = newobject

from foo import Foo

foo = Foo()
print '%r' % foo

Prints:

{Foo object at {0x100400010}}

NOTE you have given bound method as an example you'd like to handle, but bound methods do have __repr__ defined, and therefor I'm guessing you don't really want a solution which affects them. (check out object().__repr__.__repr__)

shx2
  • 61,779
  • 13
  • 130
  • 153
  • 1
    This answers the bounty part of the question, but I would strongly advise against such a solution. There is no way of knowing what side effects this will have (e.g. some code may rely on the `__repr__` values for logic). – Krumelur Dec 29 '13 at 19:50
  • 1
    @Krumelur I agree. As I see it, your comment is more about the question than the answer. The question asks how it can be done. I agree with all the comments which say it probably *should not* be done. – shx2 Dec 29 '13 at 19:53
  • 1
    I know it's dangerous, but that's ok for the purpose. It's all about finding the hooks. This is a good answer the question posed, though Krumelur's comment is perfectly valid (+1). – Carl Smith Dec 31 '13 at 04:11
2

They're not my objects chap. It's for a shell, so the user will be able to print any stuff they like. If they print a list of 3 Foos, in a browser based client, they should not get a list of three broken [invisible] HTML elements. I'm after a way to tweak Python so that all objects that are represented after the tweaks are made, are rendered differently to the default.

In that case, you could change sys.displayhook():

import sys
from cgi import escape
try:
    import __builtin__ as builtins
except ImportError: # Python 3
    import builtins

def html_displayhook(value):
    if value is None:
        return
    text = escape(repr(value)) # <-- make html-safe text
    sys.stdout.write(text)
    sys.stdout.write("\n")
    builtins._ = value   

sys.displayhook = html_displayhook

It prints html-safe object representations by default and it doesn't prevent users from printing a raw html if they like it.

jfs
  • 399,953
  • 195
  • 994
  • 1,670