dfunckt / django-rules

Awesome Django authorization, without the database

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error: 'function' object has no attribute 'context' when using Predicate

perezzini opened this issue · comments

Hello,

I got an AttributeError when wrapping a function into a predicate like the following:

def f(a):
    f.context["v"] = 3
    return True

pred_f = Predicate(f)

pred_f.test(5)  # AttributeError: 'function' object has no attribute 'context'

Using a the predicate decorator, works correctly:

@predicate
def f(a):
    f.context["v"] = 3
    return True

f.test(5)  # works fine, returns True

This behaviour is considered by design, or am I doing something wrong?

Thanks for your time.

Regards.

This can be confusing but is normal Python behaviour. f is indeed the undecorated function, so it obviously has no context attribute. On the other hand, pred_f should have the context attribute.

So, if I'd like to use Predicate to wrap a function definition, I'd have to define f like the following?:

def f(self, a):
    self.context["v"] = 3
    return True

pred_f = Predicate(f, bind=True)

pred_f.test(5)  # works correctly, returns True

The latter is the approach I must take in this case, right? Or is it another work-around (I'd like to not use the predicate decorator to wrap arbitrary functions into rules's predicates)?

Thanks in advance for the help!

It's totally fine to use the Predicate class directly instead of the decorator. This snippet looks good to me.

On the other hand, if the function tries to access self.context it's not really just an "arbitrary function" -- it has explicit knowledge of rules and predicates. I don't know what you're trying to do, but my point is maybe wrapping the original function f as a predicate is the best course of action -- plain invocations of it will throw an exception, as you found out -- so it can't be used for much else than a predicate.

Yes, you're right: it's not an "arbitrary function". The problem is that I'm currently in an scenario where we consume function definitons on-the-fly, and them could try to access context. So the better approach, I think, is wrapping them using Predicate(f, bind=True) class (obviously, each function definition must have a signature like def f(self, ...) and access context like self.context).

Btw, I'm using rules as a generic framework for a rule-based system.

Thanks for your quick response @dfunckt !