I realize now that it would probably be best to define the problem I'm having according to the constraints imposed by other requirements, and not by describing the basic functionality. That way, since there are so many possible ways to get something like what I want, there will probably be only one (or none) solutions to the problem that matches the criteria completely.

So, to restate the original problem: I want to be able to tag the methods of a class so that they only can be called if some external global says it's okay. Think of it as a security device for what can or cannot be called from a particular class instance. So if "restrict" is True, attempts to call methods on class A: foo() and bar(), will be disallowed, and raise an exception.

Now, here are the constraints:

Whatever implements this security should be something that class A is a subclass of, or is in some other way external to the class definition itself, since multiple classes will want to use this ability.

It can't be a metaclass, because for other reasons, class A already has a special metaclass, and you can't have two metaclasses on one class without having one metaclass inherit from the other.

You should not be able to "foil" the security by overriding the secured methods in a subclass of A. So if A.foo() is "secured" and you make class B a subclass of A and define b.foo(), b.foo() should also be secured.

The exception that gets raised when calling a restricted method when it isn't allowed should be able to indicate what method was called on what class.

I'd prefer not to override __getattribute__ to look at every attempt to access any attribute of the class instance to see if it's restricted.
It'd also be nice if the ability to restrict some method was done via a decorator-like syntax:

class X:
    def foo():
        ...
    restrict(foo)

So there's the problem and constraints. I've painted myself into a corner, and I realize that, but I have faith that someone out there who is far better at python than me, will know some way to do this, or something close to it.

Thanks again,
-David


Bengt Richter wrote:
On Mon, 16 Jan 2006 18:55:43 -0800, David Hirschfield <[EMAIL PROTECTED]> wrote:

  
Thanks for this, it's a great list of the ways it can be done. Here's a 
    
Actually, your way is yet another ;-)

  
bit more insight into the arrangement I'm trying to get:

restrict = True
    
Why a global value? If it is to affect class instantiation, why not pass it
or a value to the constructor, e.g., C(True) or C(some_bool)?

  
class A(object):
    
       ^--should that be R?
  
   _restrict = ["test"]
  
   def _null(self, *args, **kws):
       raise Exception,"not allowed to access"
      
   def test(self):
       print "test restricted"
  
   def __init__(self):
       if restrict:
           for f in self._restrict:
               setattr(self,f,self._null)
    
I assume you know that you are using a bound method attribute
on the instance to shadow the method of the class, for a per-instance
effect as opposed to an all-instances shared effect.

  
      
class C(R):
   def __init__(self):
       super(C,self).__init__()
      
   def test(self):
       print "test from c"


In this design, calling c.test() where c is an instance of C will raise 
an exception. Now, the only thing I'd like is to not have to fill out 
that _restrict list like that, but to have some function or something 
that let's me say which methods are restricted in the same way you 
define class methods or properties, i.e.:

class A(object):
   _restrict = []
  
   def _null(self, *args, **kws):
       raise Exception,"not allowed to access"
      
   def test(self):
       print "test restricted"
   restrict(test)
   #### this does some magic to insert "test" into the _restrict list


I can't really find a way to make that work with descriptors, and it 
can't just be a function call, because I won't know what object to get 
the _restrict list from. Is there a way to refer to the class that "is 
being defined" when calling a function or classmethod?
So, ideas on how to accomplish that...again, greatly appreciated.
    

You can do it with a decorator, though it doesn't really do decoration,
just adding the decoratee to the associated _restrict list. You don't
have to factor out mkrdeco if you'r'e only defining the restrict decorator
in one class.

I changed A to R, and made the global restriction flag a constructor argument,
but you can easily change that back, either by using the global restricted
in R.__init__ as a global, or by passing it explicitly like c = C(restricted).

 >>> def mkrdeco(rlist):
 ...     def restrict(f):
 ...         rlist.append(f.func_name)
 ...         return f
 ...     return restrict
 ...
 >>> class R(object):
 ...     _restrict = []
 ...     restrict = mkrdeco(_restrict)
 ...     def _null(self, *args, **kws):
 ...         raise Exception,"not allowed to access"
 ...     def __init__(self, restricted):
 ...         if restricted:
 ...             for f in self._restrict:
 ...                 setattr(self,f,self._null)
 ...     @restrict
 ...     def test(self):
 ...         print "test restricted"
 ...
 >>> class C(R):
 ...    def __init__(self, restricted=False):
 ...        super(C,self).__init__(restricted)
 ...
 ...    def test(self):
 ...        print "test from c"
 ...
 >>> c = C(True)
 >>> c.test()
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "<stdin>", line 5, in _null
 Exception: not allowed to access
 >>> c2 = C(False)
 >>> c2.test()
 test from c
 >>> vars(c)
 {'test': <bound method C._null of <__main__.C object at 0x02EF3C4C>>}
 >>> vars(c2)
 {}
 >>> R._restrict
 ['test']
 
Still don't know what real application problem this is solving, but that's ok ;-)

Regards,
Bengt Richter
  

-- 
Presenting:
mediocre nebula.
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to