Why can't I use @staticmethod here?

64 views Asked by At

I'm using django-fsm to implement a state machine. The code looks like

def user_ok_to_check_me( instance, user):
    ... 

class Job( models.Model):

# ... many screenfulls of code

    @transition( field=state,  target=BOOKING, source=CHECKING, permission=user_ok_to_check_me)
    def fail_checking(self, **kwargs):
    ...

and it's working. Code readability is impaired by having that little utility function outside the class it belongs with, so I tried

class Job( models.Model):

    # ... many screenfulls of code

    @staticmethod
    def user_ok_to_check_me( instance, user):
        ... 
    @transition( field=state,  target=BOOKING, source=CHECKING, permission=user_ok_to_check_me)
    def fail_checking(self, **kwargs):

which does not work. Not sure what user_ok_to_check_me does now do, it behaves like a no-op function always returning True even when all it does is return False

Why? And is there any way to declare this little function inside the class? (It's just a little bit too long to use lambda instance, user: )

1

There are 1 answers

0
nigel222 On

Have found the answer, although I'm not sure I understand it.

class Job( models.Model):

    # ... many screenfulls of code

    # @staticmethod  #NO DECORATOR
    def user_ok_to_check_me( instance, user):
    ... 
    @transition( field=state,  target=BOOKING, source=CHECKING, permission=user_ok_to_check_me)
    def fail_checking(self, **kwargs):

The use of ok_to_check_me in @transition occurs during the execution of the code that creates the class, and not during the instantiation thereof. So it needs a reference to the actual function defined above. Application of @staticmethod to that function replaces it by something else, and whatever that is, is not acceptable to the transition decorator.

When the class is instantiated, the function gets bound to the instance. This does not, however, affect the reference to the function which @transition has already stored in its internals. In this case the binding is harmless since instance and self normally refer to the same. In other cases one might want to delete the un-intended bound function from the instance in its __init__ method (or just heavily document not to try to use it as an object method).