views:

56

answers:

1

I understand that repr()'s purpose is to return a string, that can be used to be evaluated as a python command and return the same object. Unfortunately, pytz does not seem to be very friendly with this function, although it should be quite easy, since pytz instances are created with a single call:

import datetime, pytz
now = datetime.datetime.now(pytz.timezone('Europe/Berlin'))
repr(now)

returns:

datetime.datetime(2010, 10, 1, 13, 2, 17, 659333, tzinfo=<DstTzInfo 'Europe/Berlin' CEST+2:00:00 DST>)

which cannot be simply copied to another ipython windows and evaluated, because it returns a Syntax Error on the tzinfo attribute.

Is there any simple way to let it print:

datetime.datetime(2010, 10, 1, 13, 2, 17, 659333, tzinfo=pytz.timezone('Europe/Berlin'))

when the 'Europe/Berlin' string is already clearly visible in the original output of repr()?

+1  A: 
import datetime
import pytz
import pytz.tzinfo

def tzinfo_repr(self):
    return 'pytz.timezone({z})'.format(z=self.zone)
pytz.tzinfo.DstTzInfo.__repr__=tzinfo_repr

berlin=pytz.timezone('Europe/Berlin')
now = datetime.datetime.now(berlin)
print(repr(now))
# datetime.datetime(2010, 10, 1, 14, 39, 4, 456039, tzinfo=pytz.timezone("Europe/Berlin"))

Note that pytz.timezone("Europe/Berlin") in the summer can mean something different than pytz.timezone("Europe/Berlin")) in the winter, due to daylight savings time. So the monkeypatched __repr__ is not a correct representation of self for all time. But it should work (except for extreme corner cases) during the time it takes to copy and paste into IPython.


An alternative approach would be to subclass datetime.tzinfo:

class MyTimezone(datetime.tzinfo):
    def __init__(self,zone):
        self.timezone=pytz.timezone(zone)
    def __repr__(self):
        return 'MyTimezone("{z}")'.format(z=self.timezone.zone)
    def utcoffset(self, dt):
        return self.timezone._utcoffset
    def tzname(self, dt):
        return self.timezone._tzname
    def dst(self, dt):
        return self.timezone._dst

berlin=MyTimezone('Europe/Berlin')
now = datetime.datetime.now(berlin)
print(repr(now))
# datetime.datetime(2010, 10, 1, 19, 2, 58, 702758, tzinfo=MyTimezone("Europe/Berlin"))
unutbu
Looks like what I wanted, although doesn't seem very elegant.
eumiro
Subclassing isn't really portable (to send someone quickly a datetime(...) constructor call line per email), but it is probably the easiest solution for local usage in ipython. Thank you!
eumiro
It looks horrible, but have you considered sending pickled objects, e.g. `import cPickle; cPickle.loads("cdatetime\ndatetime\np1\n(S'\\x07\\xda\\n\\x01\\x151+\\x0c\\x13\\xd0'\ncpytz\n_p\np2\n(S'Europe/Berlin'\np3\nI7200\nI3600\nS'CEST'\np4\ntRp5\ntRp6\n.")`
unutbu
No, because it looks horrible and I want to be able to read the line too. I am thinking about contacting pytz developpers and asking them whether their __repr__ could be changed...
eumiro
Please note the `__repr__` is supposed to give enough information to re-generate the object. Setting `__repr__` to return `"pytz.timezone(...)"` fails because it ignores the day-light savings time issue.
unutbu