Back to index

moin  1.9.0~rc2
__init__.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003 MoinMoin - base classes for datastructs.
00004 
00005 @copyright: 2009 MoinMoin:DmitrijsMilajevs
00006 @license: GPL, see COPYING for details
00007 """
00008 
00009 from UserDict import DictMixin
00010 
00011 
00012 class GroupDoesNotExistError(Exception):
00013     """
00014     Raised when a group name is not found in the backend.
00015     """
00016 
00017 
00018 class DictDoesNotExistError(Exception):
00019     """
00020     Raised when a dict name is not found in the backend.
00021     """
00022 
00023 
00024 class BaseGroup(object):
00025     """
00026     Group is something which stores members. Groups are immutable. A
00027     member is some arbitrary entity name (Unicode object).
00028     """
00029 
00030     def __init__(self, request, name, backend):
00031         """
00032         Initialize a group.
00033 
00034         @param request
00035         @param name: moin group name
00036         @backend: backend object which created this object
00037         """
00038         self.request = request
00039         self.name = name
00040         self._backend = backend
00041 
00042     def __contains__(self, member, processed_groups=None):
00043         raise NotImplementedError()
00044 
00045     def __iter__(self, yielded_members=None, processed_groups=None):
00046         raise NotImplementedError()
00047 
00048 
00049 class BaseGroupsBackend(object):
00050     """
00051     Backend provides access to the group definitions for the other
00052     MoinMoin code.
00053     """
00054 
00055     def __init__(self, request):
00056         self.request = request
00057         self.page_group_regex = request.cfg.cache.page_group_regexact
00058 
00059     def is_group_name(self, member):
00060         return self.page_group_regex.match(member)
00061 
00062     def __contains__(self, group_name):
00063         """
00064         Check if a group called <group_name> is available in this backend.
00065         """
00066         raise NotImplementedError()
00067 
00068     def __iter__(self):
00069         """
00070         Iterate over moin group names of the groups defined in this backend.
00071 
00072         @return: moin group names
00073         """
00074         raise NotImplementedError()
00075 
00076     def __getitem__(self, group_name):
00077         """
00078         Get a group by its moin group name.
00079         """
00080         raise NotImplementedError()
00081 
00082     def __repr__(self):
00083         return "<%s groups=%s>" % (self.__class__, list(self))
00084 
00085     def _retrieve_members(self, group_name):
00086         raise NotImplementedError()
00087 
00088     def groups_with_member(self, member):
00089         """
00090         List all group names of groups containing <member>.
00091 
00092         @param member: member name [unicode]
00093         @return: list of group names [unicode]
00094         """
00095         for group_name in self:
00096             try:
00097                 if member in self[group_name]:
00098                     yield group_name
00099             except GroupDoesNotExistError:
00100                 pass
00101 
00102     def get(self, key, default=None):
00103         """
00104         Return the group named <key> if key is in the backend, else
00105         default. If default is not given, it defaults to None, so that
00106         this method never raises a GroupDoesNotExistError.
00107         """
00108         try:
00109             return self[key]
00110         except GroupDoesNotExistError:
00111             return default
00112 
00113 
00114 class LazyGroup(BaseGroup):
00115     """
00116     A lazy group does not store members internally, but gets them from
00117     a backend when needed.
00118 
00119     Lazy group is made only of members. It can not consist of other groups.
00120 
00121     For instance, this is a possible LazyGroup:
00122 
00123      PossibleGroup
00124       * OneMember
00125       * OtherMember
00126 
00127     This is a group which cannot be LazyGroup:
00128 
00129      NotPossibleGroup
00130       * OneMember
00131       * OtherMember
00132       * OtherGroup
00133     """
00134 
00135     def __init__(self, request, name, backend):
00136         super(LazyGroup, self).__init__(request, name, backend)
00137 
00138         if name not in backend:
00139             raise GroupDoesNotExistError(name)
00140 
00141     def __contains__(self, member, processed_groups=None):
00142         # processed_groups are not used here but other group classes
00143         # may expect this parameter.
00144         return self._backend._group_has_member(self.name, member)
00145 
00146     def __iter__(self, yielded_members=None, processed_groups=None):
00147         # processed_groups are not used here but other group classes
00148         # may expect this parameter.
00149         if yielded_members is None:
00150             yielded_members = set()
00151 
00152         for member in self._backend._iter_group_members(self.name):
00153             if member not in yielded_members:
00154                 yielded_members.add(member)
00155                 yield member
00156 
00157 
00158 class LazyGroupsBackend(BaseGroupsBackend):
00159 
00160     def _iter_group_members(self, group_name):
00161         raise NotImplementedError()
00162 
00163     def _group_has_member(self, group_name, member):
00164         raise NotImplementedError()
00165 
00166 
00167 class GreedyGroup(BaseGroup):
00168     """
00169     GreedyGroup gets all members during initialization and stores them internally.
00170 
00171     Members of a group may be names of other groups.
00172     """
00173 
00174     def __init__(self, request, name, backend):
00175 
00176         super(GreedyGroup, self).__init__(request, name, backend)
00177         self.members, self.member_groups = self._load_group()
00178 
00179     def _load_group(self):
00180         """
00181         Retrieve group data from the backend and filter it to members and group_members.
00182         """
00183         members_retrieved = set(self._backend._retrieve_members(self.name))
00184 
00185         member_groups = set(member for member in members_retrieved if self._backend.is_group_name(member))
00186         members = members_retrieved - member_groups
00187 
00188         return members, member_groups
00189 
00190     def __contains__(self, member, processed_groups=None):
00191         """
00192         First check if <member> is part of this group and then check
00193         for every subgroup in this group.
00194 
00195         <processed_groups> is needed to avoid infinite recursion, if
00196         groups are defined recursively.
00197 
00198         @param member: member name [unicode]
00199         @param processed_groups: groups which were checked for containment before [set]
00200         """
00201 
00202         if processed_groups is None:
00203             processed_groups = set()
00204 
00205         processed_groups.add(self.name)
00206 
00207         if member in self.members or member in self.member_groups:
00208             return True
00209         else:
00210             groups = self.request.groups
00211             for group_name in self.member_groups:
00212                 if group_name not in processed_groups and group_name in groups and groups[group_name].__contains__(member, processed_groups):
00213                     return True
00214 
00215         return False
00216 
00217     def __iter__(self, yielded_members=None, processed_groups=None):
00218         """
00219         Iterate first over members of this group, then over subgroups of this group.
00220 
00221         <yielded_members> and <processed_groups> are needed to avoid infinite recursion.
00222         This can happen if there are two groups like these:
00223            OneGroup: Something, OtherGroup
00224            OtherGroup: OneGroup, SomethingOther
00225 
00226         @param yielded_members: members which have been already yielded before [set]
00227         @param processed_groups: group names which have been iterated before [set]
00228         """
00229 
00230         if processed_groups is None:
00231             processed_groups = set()
00232 
00233         if yielded_members is None:
00234             yielded_members = set()
00235 
00236         processed_groups.add(self.name)
00237 
00238         for member in self.members:
00239             if member not in yielded_members:
00240                 yielded_members.add(member)
00241                 yield member
00242 
00243         groups = self.request.groups
00244         for group_name in self.member_groups:
00245             if group_name not in processed_groups:
00246                 if group_name in groups:
00247                     for member in groups[group_name].__iter__(yielded_members, processed_groups):
00248                         yield member
00249                 else:
00250                     yield group_name
00251 
00252     def __repr__(self):
00253         return "<%s name=%s members=%s member_groups=%s>" % (self.__class__,
00254                                                              self.name,
00255                                                              self.members,
00256                                                              self.member_groups)
00257 
00258 
00259 class BaseDict(object, DictMixin):
00260 
00261     def __init__(self, request, name, backend):
00262         """
00263         Initialize a dict. Dicts are greedy, it stores all keys and
00264         items internally.
00265 
00266         @param request
00267         @param name: moin dict name
00268         @backend: backend object which created this object
00269         """
00270         self.request = request
00271         self.name = name
00272         self._backend = backend
00273         self._dict = self._load_dict()
00274 
00275     def __iter__(self):
00276         return self._dict.__iter__()
00277 
00278     def keys(self):
00279         return list(self)
00280 
00281     def __len__(self):
00282         return self._dict.__len__()
00283 
00284     def __getitem__(self, key):
00285         return self._dict[key]
00286 
00287     def get(self, key, default=None):
00288         """
00289         Return the value if key is in the dictionary, else default. If
00290         default is not given, it defaults to None, so that this method
00291         never raises a KeyError.
00292         """
00293         return self._dict.get(key, default)
00294 
00295     def _load_dict(self):
00296         """
00297         Retrieve dict data from the backend.
00298         """
00299         return self._backend._retrieve_items(self.name)
00300 
00301     def __repr__(self):
00302         return "<%r name=%r items=%r>" % (self.__class__, self.name, self._dict.items())
00303 
00304 
00305 class BaseDictsBackend(object):
00306 
00307     def __init__(self, request):
00308         self.request = request
00309         self.page_dict_regex = request.cfg.cache.page_dict_regexact
00310 
00311     def is_dict_name(self, name):
00312         return self.page_dict_regex.match(name)
00313 
00314     def __contains__(self, dict_name):
00315         """
00316         Check if a dict called <dict_name> is available in this backend.
00317         """
00318         raise NotImplementedError()
00319 
00320     def __getitem__(self, dict_name):
00321         """
00322         Get a dict by its moin dict name.
00323         """
00324         raise NotImplementedError()
00325 
00326     def _retrieve_items(self, dict_name):
00327         raise NotImplementedError()
00328 
00329     def get(self, key, default=None):
00330         """
00331         Return the dictionary named <key> if key is in the backend,
00332         else default. If default is not given, it defaults to None, so
00333         that this method never raises a DictDoesNotExistError.
00334         """
00335         try:
00336             return self[key]
00337         except DictDoesNotExistError:
00338             return default
00339