Removed depreciated code in ipalib.plugable that has been moving into ipalib.base

This commit is contained in:
Jason Gerard DeRose
2009-01-02 00:46:45 -07:00
parent ea7f9594df
commit b4dc333ee2
2 changed files with 2 additions and 440 deletions

View File

@@ -36,104 +36,9 @@ import subprocess
import errors
from errors import check_type, check_isinstance
from config import Env
from constants import DEFAULT_CONFIG
import util
class ReadOnly(object):
"""
Base class for classes with read-only attributes.
Be forewarned that Python does not offer true read-only user defined
classes. In particular, do not rely upon the read-only-ness of this
class for security purposes.
The point of this class is not to make it impossible to set or delete
attributes, but to make it impossible to accidentally do so. The plugins
are not thread-safe: in the server, they are loaded once and the same
instances will be used to process many requests. Therefore, it is
imperative that they not set any instance attributes after they have
been initialized. This base class enforces that policy.
For example:
>>> ro = ReadOnly() # Initially unlocked, can setattr, delattr
>>> ro.name = 'John Doe'
>>> ro.message = 'Hello, world!'
>>> del ro.message
>>> ro.__lock__() # Now locked, cannot setattr, delattr
>>> ro.message = 'How are you?'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../ipalib/plugable.py", line 93, in __setattr__
(self.__class__.__name__, name)
AttributeError: read-only: cannot set ReadOnly.message
>>> del ro.name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jderose/projects/freeipa2/ipalib/plugable.py", line 104, in __delattr__
(self.__class__.__name__, name)
AttributeError: read-only: cannot del ReadOnly.name
"""
__locked = False
def __lock__(self):
"""
Put this instance into a read-only state.
After the instance has been locked, attempting to set or delete an
attribute will raise AttributeError.
"""
assert self.__locked is False, '__lock__() can only be called once'
self.__locked = True
def __islocked__(self):
"""
Return True if instance is locked, otherwise False.
"""
return self.__locked
def __setattr__(self, name, value):
"""
If unlocked, set attribute named ``name`` to ``value``.
If this instance is locked, AttributeError will be raised.
"""
if self.__locked:
raise AttributeError('read-only: cannot set %s.%s' %
(self.__class__.__name__, name)
)
return object.__setattr__(self, name, value)
def __delattr__(self, name):
"""
If unlocked, delete attribute named ``name``.
If this instance is locked, AttributeError will be raised.
"""
if self.__locked:
raise AttributeError('read-only: cannot del %s.%s' %
(self.__class__.__name__, name)
)
return object.__delattr__(self, name)
def lock(readonly):
"""
Lock a `ReadOnly` instance.
This is mostly a convenience function to call `ReadOnly.__lock__()`. It
also verifies that the locking worked using `ReadOnly.__islocked__()`
:param readonly: An instance of the `ReadOnly` class.
"""
if not isinstance(readonly, ReadOnly):
raise ValueError('not a ReadOnly instance: %r' % readonly)
readonly.__lock__()
assert readonly.__islocked__(), 'Ouch! The locking failed?'
return readonly
from base import ReadOnly, NameSpace, lock, islocked, check_name
from constants import DEFAULT_CONFIG
class SetProxy(ReadOnly):
@@ -512,158 +417,6 @@ class PluginProxy(SetProxy):
)
def check_name(name):
"""
Verify that ``name`` is suitable for a `NameSpace` member name.
Raises `errors.NameSpaceError` if ``name`` is not a valid Python
identifier suitable for use as the name of `NameSpace` member.
:param name: Identifier to test.
"""
check_type(name, str, 'name')
regex = r'^[a-z][_a-z0-9]*[a-z0-9]$'
if re.match(regex, name) is None:
raise errors.NameSpaceError(name, regex)
return name
class NameSpace(ReadOnly):
"""
A read-only namespace with handy container behaviours.
Each member of a NameSpace instance must have a ``name`` attribute whose
value:
1. Is unique among the members
2. Passes the `check_name()` function
Beyond that, no restrictions are placed on the members: they can be
classes or instances, and of any type.
The members can be accessed as attributes on the NameSpace instance or
through a dictionary interface. For example:
>>> class obj(object):
... name = 'my_obj'
...
>>> namespace = NameSpace([obj])
>>> obj is getattr(namespace, 'my_obj') # As attribute
True
>>> obj is namespace['my_obj'] # As dictionary item
True
Here is a more detailed example:
>>> class Member(object):
... def __init__(self, i):
... self.i = i
... self.name = 'member_%d' % i
... def __repr__(self):
... return 'Member(%d)' % self.i
...
>>> namespace = NameSpace(Member(i) for i in xrange(3))
>>> namespace.member_0 is namespace['member_0']
True
>>> len(namespace) # Returns the number of members in namespace
3
>>> list(namespace) # As iterable, iterates through the member names
['member_0', 'member_1', 'member_2']
>>> list(namespace()) # Calling a NameSpace iterates through the members
[Member(0), Member(1), Member(2)]
>>> 'member_1' in namespace # Does namespace contain 'member_1'?
True
"""
def __init__(self, members, sort=True):
"""
:param members: An iterable providing the members.
:param sort: Whether to sort the members by member name.
"""
self.__sort = check_type(sort, bool, 'sort')
if self.__sort:
self.__members = tuple(sorted(members, key=lambda m: m.name))
else:
self.__members = tuple(members)
self.__names = tuple(m.name for m in self.__members)
self.__map = dict()
for member in self.__members:
name = check_name(member.name)
assert name not in self.__map, 'already has key %r' % name
self.__map[name] = member
assert not hasattr(self, name), 'already has attribute %r' % name
setattr(self, name, member)
lock(self)
def __len__(self):
"""
Return the number of members.
"""
return len(self.__members)
def __iter__(self):
"""
Iterate through the member names.
If this instance was created with ``sort=True``, the names will be in
alphabetical order; otherwise the names will be in the same order as
the members were passed to the constructor.
This method is like an ordered version of dict.iterkeys().
"""
for name in self.__names:
yield name
def __call__(self):
"""
Iterate through the members.
If this instance was created with ``sort=True``, the members will be
in alphabetical order by name; otherwise the members will be in the
same order as they were passed to the constructor.
This method is like an ordered version of dict.itervalues().
"""
for member in self.__members:
yield member
def __contains__(self, name):
"""
Return True if namespace has a member named ``name``.
"""
return name in self.__map
def __getitem__(self, spec):
"""
Return a member by name or index, or returns a slice of members.
:param spec: The name or index of a member, or a slice object.
"""
if type(spec) is str:
return self.__map[spec]
if type(spec) in (int, slice):
return self.__members[spec]
raise TypeError(
'spec: must be %r, %r, or %r; got %r' % (str, int, slice, spec)
)
def __repr__(self):
"""
Return a pseudo-valid expression that could create this instance.
"""
return '%s(<%d members>, sort=%r)' % (
self.__class__.__name__,
len(self),
self.__sort,
)
def __todict__(self):
"""
Return a copy of the private dict mapping name to member.
"""
return dict(self.__map)
class Registrar(DictProxy):
"""
Collects plugin classes as they are registered.