views:

42

answers:

3

Hello people in the know,

I'm trying to replace two methods in calendar module:

import calendar


c = calendar.HTMLCalendar(calendar.MONDAY)
def ext_formatday(self, day, weekday, *notes):
    if day == 0:
        return '<td class="noday">&nbsp;</td>'
    if len(notes) == 0:
        return '<td class="%s">%d<br /></td>' % (self.cssclasses[weekday], day)
    else:
        return '<td class="%s">%d<br />%s</td>' % (self.cssclasses[weekday], day, notes)

def ext_formatweek(self, theweek, *notes):
    if len(notes) == 0:
        s = ''.join(self.formatday(d, wd) for (d, wd) in theweek)
    else:
        s = ''.join(self.formatday(d, wd, notes) for (d, wd) in theweek)
    return '<tr>%s</tr>' % s 

c.formatday = ext_formatday
c.formatweek = ext_formatweek

print c.formatmonth(2012,1,"foobar")

This won't work - could somebody point me to relevant literature or point out what I'm doing wrong? I'm trying to implement Alan Hynes suggestion from the following thread: thread It way too late for me to think straight and I've been dancing around that problem for over an hour.

Thanks in advance,
Jakub

+1  A: 

Try replacing the method at the class instead of the instance.

Like this:

import calendar                                                                                                 


def ext_formatday(self, day, weekday, *notes):                                                                  
    if day == 0:                                                                                                
        return '<td class="noday">&nbsp;</td>'                                                                  
    if len(notes) == 0:                                                                                         
        return '<td class="%s">%d<br /></td>' % (self.cssclasses[weekday], day)                                 
    else:                                                                                                       
        return '<td class="%s">%d<br />%s</td>' % (self.cssclasses[weekday], day, notes)                        

def ext_formatweek(self, theweek, *notes):                                                                      
    if len(notes) == 0:                                                                                         
        s = ''.join(self.formatday(d, wd) for (d, wd) in theweek)                                               
    else:                                                                                                       
        s = ''.join(self.formatday(d, wd, notes) for (d, wd) in theweek)                                        
    return '<tr>%s</tr>' % s                                                                                    

calendar.HTMLCalendar.formatday = ext_formatday                                                                 
calendar.HTMLCalendar.formatweek = ext_formatweek                                                               

c = calendar.HTMLCalendar(calendar.MONDAY)                                                                      
print c.formatmonth(2012,1,"foobar")                                                                            
WoLpH
A: 

Updated to use types.MethodType as suggested by Aaron in the comments.

Try:

import types
c.formatday = types.MethodType(ext_formatday, c, calendar.HTMLCalendar)

See the types module docs. To see why it was failing:

In [53]: class A(object):
   ....:     def foo(self): pass

In [54]: def bar(self): pass

In [55]: a = A()

In [56]: a.foo
Out[56]: <bound method A.foo of <__main__.A object at 0x030D4770>>

In [57]: a.foo = bar

In [58]: a.foo
Out[58]: <function bar at 0x030C3EB0>

In [59]: aa = A()

In [60]: aa.foo.im_class, aa.foo.im_func, aa.foo.im_self
Out[60]:
(<class '__main__.A'>,
 <function foo at 0x030EE6F0>,
 <__main__.A object at 0x030D4910>)

In [61]: a.foo.im_class
AttributeError: 'function' object has no attribute 'im_class'
ars
the new module is deprecated. use `types.MethodType` instead. It's constructor takes the same arguments and `new.instancemethod`.
aaronasterling
@AaronMcSmooth: updated, thanks.
ars
A: 

You don't want to replace the methods; what Alan Hynes suggested was to subclass HTMLCalendar:

class MyCustomCalendar(calendar.HTMLCalendar):

    def formatday(self, day, weekday, *notes):
        ...

    def formatweek(self, theweek, *notes):
        ...

c = MyCustomCalendar(calendar.MONDAY)

This will create a new derived class (MyCustomCalendar), which inherits all HTMLCalendar's methods and attributes, but defines its own versions of formatday and formatweek.

You can read more about Inheritance in the Python tutorial, or elsewhere on the web. It's an important tool in Python (and object-oriented programming in general), and many libraries are designed around it.

Piet Delport
Now I know why my first version didn't work - i forget about 'calendar.' before HTMLCalendar. Thank Piet you for that example and thanks everybody for the interest in my noob question!good wknd to you all
Jakub M