/usr/share/pyshared/epsilon/expose.py is in python-epsilon 0.7.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | # Copright 2008 Divmod, Inc. See LICENSE file for details.
# -*- test-case-name: epsilon.test.test_expose -*-
"""
This module provides L{Exposer}, a utility for creating decorators that expose
methods on types for a particular purpose.
The typical usage of this module is for an infrastructure layer (usually one
that allows methods to be invoked from the network, directly or indirectly) to
provide an explicit API for exposing those methods securely.
For example, a sketch of a finger protocol implementation which could use this
to expose the results of certain methods as finger results::
# tx_finger.py
fingermethod = Exposer("This object exposes finger methods.")
...
class FingerProtocol(Protocol):
def __init__(self, fingerModel):
self.model = fingerModel
...
def fingerQuestionReceived(self, whichUser):
try:
method = fingermethod.get(self.model, whichUser)
except MethodNotExposed:
method = lambda : "Unknown user"
return method()
# myfingerserver.py
from tx_finger import fingermethod
...
class MyFingerModel(object):
@fingermethod.expose("bob")
def someMethod(self):
return "Bob is great."
Assuming lots of protocol code to hook everything together, this would then
allow you to use MyFingerModel and 'finger bob' to get the message 'Bob is
great.'
"""
import inspect
from types import FunctionType
class MethodNotExposed(Exception):
"""
The requested method was not exposed for the purpose requested. More
specifically, L{Exposer.get} was used to retrieve a key from an object
which does not expose that key with that exposer.
"""
class NameRequired(Exception):
"""
L{Exposer.expose} was used to decorate a non-function object without having
a key explicitly specified.
"""
class Exposer(object):
"""
This is an object that can expose and retrieve methods on classes.
@ivar _exposed: a dict mapping exposed keys to exposed function objects.
"""
def __init__(self, doc):
"""
Create an exposer.
"""
self.__doc__ = doc
self._exposed = {}
def expose(self, key=None):
"""
Expose the decorated method for this L{Exposer} with the given key. A
method which is exposed will be able to be retrieved by this
L{Exposer}'s C{get} method with that key. If no key is provided, the
key is the method name of the exposed method.
Use like so::
class MyClass:
@someExposer.expose()
def foo(): ...
or::
class MyClass:
@someExposer.expose('foo')
def unrelatedMethodName(): ...
@param key: a hashable object, used by L{Exposer.get} to look up the
decorated method later. If None, the key is the exposed method's name.
@return: a 1-argument callable which records its input as exposed, then
returns it.
"""
def decorator(function):
rkey = key
if rkey is None:
if isinstance(function, FunctionType):
rkey = function.__name__
else:
raise NameRequired()
if rkey not in self._exposed:
self._exposed[rkey] = []
self._exposed[rkey].append(function)
return function
return decorator
def get(self, obj, key):
"""
Retrieve 'key' from an instance of a class which previously exposed it.
@param key: a hashable object, previously passed to L{Exposer.expose}.
@return: the object which was exposed with the given name on obj's key.
@raise MethodNotExposed: when the key in question was not exposed with
this exposer.
"""
if key not in self._exposed:
raise MethodNotExposed()
rightFuncs = self._exposed[key]
T = obj.__class__
seen = {}
for subT in inspect.getmro(T):
for name, value in subT.__dict__.items():
for rightFunc in rightFuncs:
if value is rightFunc:
if name in seen:
raise MethodNotExposed()
return value.__get__(obj, T)
seen[name] = True
raise MethodNotExposed()
|