These files are a subset of the python-2.7.2.tgz distribution from python.org. Changed files from PyMod-2.7.2 have been copied into the corresponding directories of this tree, replacing the original files in the distribution. Signed-off-by: daryl.mcdaniel@intel.com git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13197 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			181 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Bastionification utility.
 | |
| 
 | |
| A bastion (for another object -- the 'original') is an object that has
 | |
| the same methods as the original but does not give access to its
 | |
| instance variables.  Bastions have a number of uses, but the most
 | |
| obvious one is to provide code executing in restricted mode with a
 | |
| safe interface to an object implemented in unrestricted mode.
 | |
| 
 | |
| The bastionification routine has an optional second argument which is
 | |
| a filter function.  Only those methods for which the filter method
 | |
| (called with the method name as argument) returns true are accessible.
 | |
| The default filter method returns true unless the method name begins
 | |
| with an underscore.
 | |
| 
 | |
| There are a number of possible implementations of bastions.  We use a
 | |
| 'lazy' approach where the bastion's __getattr__() discipline does all
 | |
| the work for a particular method the first time it is used.  This is
 | |
| usually fastest, especially if the user doesn't call all available
 | |
| methods.  The retrieved methods are stored as instance variables of
 | |
| the bastion, so the overhead is only occurred on the first use of each
 | |
| method.
 | |
| 
 | |
| Detail: the bastion class has a __repr__() discipline which includes
 | |
| the repr() of the original object.  This is precomputed when the
 | |
| bastion is created.
 | |
| 
 | |
| """
 | |
| from warnings import warnpy3k
 | |
| warnpy3k("the Bastion module has been removed in Python 3.0", stacklevel=2)
 | |
| del warnpy3k
 | |
| 
 | |
| __all__ = ["BastionClass", "Bastion"]
 | |
| 
 | |
| from types import MethodType
 | |
| 
 | |
| 
 | |
| class BastionClass:
 | |
| 
 | |
|     """Helper class used by the Bastion() function.
 | |
| 
 | |
|     You could subclass this and pass the subclass as the bastionclass
 | |
|     argument to the Bastion() function, as long as the constructor has
 | |
|     the same signature (a get() function and a name for the object).
 | |
| 
 | |
|     """
 | |
| 
 | |
|     def __init__(self, get, name):
 | |
|         """Constructor.
 | |
| 
 | |
|         Arguments:
 | |
| 
 | |
|         get - a function that gets the attribute value (by name)
 | |
|         name - a human-readable name for the original object
 | |
|                (suggestion: use repr(object))
 | |
| 
 | |
|         """
 | |
|         self._get_ = get
 | |
|         self._name_ = name
 | |
| 
 | |
|     def __repr__(self):
 | |
|         """Return a representation string.
 | |
| 
 | |
|         This includes the name passed in to the constructor, so that
 | |
|         if you print the bastion during debugging, at least you have
 | |
|         some idea of what it is.
 | |
| 
 | |
|         """
 | |
|         return "<Bastion for %s>" % self._name_
 | |
| 
 | |
|     def __getattr__(self, name):
 | |
|         """Get an as-yet undefined attribute value.
 | |
| 
 | |
|         This calls the get() function that was passed to the
 | |
|         constructor.  The result is stored as an instance variable so
 | |
|         that the next time the same attribute is requested,
 | |
|         __getattr__() won't be invoked.
 | |
| 
 | |
|         If the get() function raises an exception, this is simply
 | |
|         passed on -- exceptions are not cached.
 | |
| 
 | |
|         """
 | |
|         attribute = self._get_(name)
 | |
|         self.__dict__[name] = attribute
 | |
|         return attribute
 | |
| 
 | |
| 
 | |
| def Bastion(object, filter = lambda name: name[:1] != '_',
 | |
|             name=None, bastionclass=BastionClass):
 | |
|     """Create a bastion for an object, using an optional filter.
 | |
| 
 | |
|     See the Bastion module's documentation for background.
 | |
| 
 | |
|     Arguments:
 | |
| 
 | |
|     object - the original object
 | |
|     filter - a predicate that decides whether a function name is OK;
 | |
|              by default all names are OK that don't start with '_'
 | |
|     name - the name of the object; default repr(object)
 | |
|     bastionclass - class used to create the bastion; default BastionClass
 | |
| 
 | |
|     """
 | |
| 
 | |
|     raise RuntimeError, "This code is not secure in Python 2.2 and later"
 | |
| 
 | |
|     # Note: we define *two* ad-hoc functions here, get1 and get2.
 | |
|     # Both are intended to be called in the same way: get(name).
 | |
|     # It is clear that the real work (getting the attribute
 | |
|     # from the object and calling the filter) is done in get1.
 | |
|     # Why can't we pass get1 to the bastion?  Because the user
 | |
|     # would be able to override the filter argument!  With get2,
 | |
|     # overriding the default argument is no security loophole:
 | |
|     # all it does is call it.
 | |
|     # Also notice that we can't place the object and filter as
 | |
|     # instance variables on the bastion object itself, since
 | |
|     # the user has full access to all instance variables!
 | |
| 
 | |
|     def get1(name, object=object, filter=filter):
 | |
|         """Internal function for Bastion().  See source comments."""
 | |
|         if filter(name):
 | |
|             attribute = getattr(object, name)
 | |
|             if type(attribute) == MethodType:
 | |
|                 return attribute
 | |
|         raise AttributeError, name
 | |
| 
 | |
|     def get2(name, get1=get1):
 | |
|         """Internal function for Bastion().  See source comments."""
 | |
|         return get1(name)
 | |
| 
 | |
|     if name is None:
 | |
|         name = repr(object)
 | |
|     return bastionclass(get2, name)
 | |
| 
 | |
| 
 | |
| def _test():
 | |
|     """Test the Bastion() function."""
 | |
|     class Original:
 | |
|         def __init__(self):
 | |
|             self.sum = 0
 | |
|         def add(self, n):
 | |
|             self._add(n)
 | |
|         def _add(self, n):
 | |
|             self.sum = self.sum + n
 | |
|         def total(self):
 | |
|             return self.sum
 | |
|     o = Original()
 | |
|     b = Bastion(o)
 | |
|     testcode = """if 1:
 | |
|     b.add(81)
 | |
|     b.add(18)
 | |
|     print "b.total() =", b.total()
 | |
|     try:
 | |
|         print "b.sum =", b.sum,
 | |
|     except:
 | |
|         print "inaccessible"
 | |
|     else:
 | |
|         print "accessible"
 | |
|     try:
 | |
|         print "b._add =", b._add,
 | |
|     except:
 | |
|         print "inaccessible"
 | |
|     else:
 | |
|         print "accessible"
 | |
|     try:
 | |
|         print "b._get_.func_defaults =", map(type, b._get_.func_defaults),
 | |
|     except:
 | |
|         print "inaccessible"
 | |
|     else:
 | |
|         print "accessible"
 | |
|     \n"""
 | |
|     exec testcode
 | |
|     print '='*20, "Using rexec:", '='*20
 | |
|     import rexec
 | |
|     r = rexec.RExec()
 | |
|     m = r.add_module('__main__')
 | |
|     m.b = b
 | |
|     r.r_exec(testcode)
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     _test()
 |