Back to index

moin  1.9.0~rc2
Public Member Functions | Public Attributes | Static Public Attributes | Properties | Private Member Functions | Private Attributes | Static Private Attributes
MoinMoin.config.multiconfig.ConfigFunctionality Class Reference
Inheritance diagram for MoinMoin.config.multiconfig.ConfigFunctionality:
Inheritance graph
[legend]

List of all members.

Public Member Functions

def __init__
def calc_secrets
def load_meta_dict
def make_iwid_property
def make_event_handlers_prop
def load_IWID
def __getitem__

Public Attributes

 data_dir
 language_default
 logo_string
 chart_options
 auth_methods
 navi_bar
 xapian_search
 notification_server
 url_prefix_action
 url_prefix_local
 url_prefix_fckeditor
 secrets

Static Public Attributes

 cfg_mtime = None
 siteid = None
 cache = None
 mail_enabled = None
 jabber_enabled = None
 auth_can_logout = None
 auth_have_login = None
 auth_login_inputs = None
 xapian_searchers = None
 moinmoin_dir = None
 shared_intermap_files = None
tuple iwid = make_iwid_property("_iwid")
tuple iwid_full = make_iwid_property("_iwid_full")
tuple event_handlers = make_event_handlers_prop()

Properties

 meta_dict = property(load_meta_dict)

Private Member Functions

def _config_check
def _decode
def _check_directories
def _loadPluginModule
def _fillDicts

Private Attributes

 _plugin_modules

Static Private Attributes

 _site_plugin_lists = None
 _iwid = None
 _iwid_full = None
 _meta_dict = None
 _event_handlers = None

Detailed Description

Configuration base class with config class behaviour.

    This class contains the functionality for the DefaultConfig
    class for the benefit of the WikiConfig macro.

Definition at line 209 of file multiconfig.py.


Constructor & Destructor Documentation

Init Config instance 

Definition at line 234 of file multiconfig.py.

00234 
00235     def __init__(self, siteid):
00236         """ Init Config instance """
00237         self.siteid = siteid
00238         self.cache = CacheClass()
00239 
00240         from MoinMoin.Page import ItemCache
00241         self.cache.meta = ItemCache('meta')
00242         self.cache.pagelists = ItemCache('pagelists')
00243 
00244         if self.config_check_enabled:
00245             self._config_check()
00246 
00247         # define directories
00248         self.moinmoin_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
00249         data_dir = os.path.normpath(self.data_dir)
00250         self.data_dir = data_dir
00251         for dirname in ('user', 'cache', 'plugin'):
00252             name = dirname + '_dir'
00253             if not getattr(self, name, None):
00254                 setattr(self, name, os.path.abspath(os.path.join(data_dir, dirname)))
00255         # directories below cache_dir (using __dirname__ to avoid conflicts)
00256         for dirname in ('session', ):
00257             name = dirname + '_dir'
00258             if not getattr(self, name, None):
00259                 setattr(self, name, os.path.abspath(os.path.join(self.cache_dir, '__%s__' % dirname)))
00260 
00261         # Try to decode certain names which allow unicode
00262         self._decode()
00263 
00264         # After that, pre-compile some regexes
00265         self.cache.page_category_regex = re.compile(self.page_category_regex, re.UNICODE)
00266         self.cache.page_dict_regex = re.compile(self.page_dict_regex, re.UNICODE)
00267         self.cache.page_group_regex = re.compile(self.page_group_regex, re.UNICODE)
00268         self.cache.page_template_regex = re.compile(self.page_template_regex, re.UNICODE)
00269 
00270         # the ..._regexact versions only match if nothing is left (exact match)
00271         self.cache.page_category_regexact = re.compile(u'^%s$' % self.page_category_regex, re.UNICODE)
00272         self.cache.page_dict_regexact = re.compile(u'^%s$' % self.page_dict_regex, re.UNICODE)
00273         self.cache.page_group_regexact = re.compile(u'^%s$' % self.page_group_regex, re.UNICODE)
00274         self.cache.page_template_regexact = re.compile(u'^%s$' % self.page_template_regex, re.UNICODE)
00275 
00276         self.cache.ua_spiders = self.ua_spiders and re.compile(self.ua_spiders, re.IGNORECASE)
00277 
00278         self._check_directories()
00279 
00280         if not isinstance(self.superuser, list):
00281             msg = """The superuser setting in your wiki configuration is not a list
00282                      (e.g. ['Sample User', 'AnotherUser']).
00283                      Please change it in your wiki configuration and try again."""
00284             raise error.ConfigurationError(msg)
00285 
00286         self._loadPluginModule()
00287 
00288         # Preparse user dicts
00289         self._fillDicts()
00290 
00291         # Normalize values
00292         self.language_default = self.language_default.lower()
00293 
00294         # Use site name as default name-logo
00295         if self.logo_string is None:
00296             self.logo_string = self.sitename
00297 
00298         # Check for needed modules
00299 
00300         # FIXME: maybe we should do this check later, just before a
00301         # chart is needed, maybe in the chart module, instead doing it
00302         # for each request. But this require a large refactoring of
00303         # current code.
00304         if self.chart_options:
00305             try:
00306                 import gdchart
00307             except ImportError:
00308                 self.chart_options = None
00309 
00310         # post process
00311 
00312         # 'setuid' special auth method auth method can log out
00313         self.auth_can_logout = ['setuid']
00314         self.auth_login_inputs = []
00315         found_names = []
00316         for auth in self.auth:
00317             if not auth.name:
00318                 raise error.ConfigurationError("Auth methods must have a name.")
00319             if auth.name in found_names:
00320                 raise error.ConfigurationError("Auth method names must be unique.")
00321             found_names.append(auth.name)
00322             if auth.logout_possible and auth.name:
00323                 self.auth_can_logout.append(auth.name)
00324             for input in auth.login_inputs:
00325                 if not input in self.auth_login_inputs:
00326                     self.auth_login_inputs.append(input)
00327         self.auth_have_login = len(self.auth_login_inputs) > 0
00328         self.auth_methods = found_names
00329 
00330         # internal dict for plugin `modules' lists
00331         self._site_plugin_lists = {}
00332 
00333         # we replace any string placeholders with config values
00334         # e.g u'%(page_front_page)s' % self
00335         self.navi_bar = [elem % self for elem in self.navi_bar]
00336 
00337         # check if python-xapian is installed
00338         if self.xapian_search:
00339             try:
00340                 import xapian
00341             except ImportError, err:
00342                 self.xapian_search = False
00343                 logging.error("xapian_search was auto-disabled because python-xapian is not installed [%s]." % str(err))
00344 
00345         # list to cache xapian searcher objects
00346         self.xapian_searchers = []
00347 
00348         # check if mail is possible and set flag:
00349         self.mail_enabled = (self.mail_smarthost is not None or self.mail_sendmail is not None) and self.mail_from
00350         self.mail_enabled = self.mail_enabled and True or False
00351 
00352         # check if jabber bot is available and set flag:
00353         self.jabber_enabled = self.notification_bot_uri is not None
00354 
00355         # if we are to use the jabber bot, instantiate a server object for future use
00356         if self.jabber_enabled:
00357             from xmlrpclib import Server
00358             self.notification_server = Server(self.notification_bot_uri, )
00359 
00360         # Cache variables for the properties below
00361         self._iwid = self._iwid_full = self._meta_dict = None
00362 
00363         self.cache.acl_rights_before = AccessControlList(self, [self.acl_rights_before])
00364         self.cache.acl_rights_default = AccessControlList(self, [self.acl_rights_default])
00365         self.cache.acl_rights_after = AccessControlList(self, [self.acl_rights_after])
00366 
00367         action_prefix = self.url_prefix_action
00368         if action_prefix is not None and action_prefix.endswith('/'): # make sure there is no trailing '/'
00369             self.url_prefix_action = action_prefix[:-1]
00370 
00371         if self.url_prefix_local is None:
00372             self.url_prefix_local = self.url_prefix_static
00373 
00374         if self.url_prefix_fckeditor is None:
00375             self.url_prefix_fckeditor = self.url_prefix_local + '/applets/FCKeditor'
00376 
00377         if self.secrets is None:  # admin did not setup a real secret, so make up something
00378             self.secrets = self.calc_secrets()
00379 
00380         secret_key_names = ['action/cache', 'wikiutil/tickets', 'xmlrpc/ProcessMail', 'xmlrpc/RemoteScript', ]
00381         if self.jabber_enabled:
00382             secret_key_names.append('jabberbot')
00383 
00384         secret_min_length = 10
00385         if isinstance(self.secrets, str):
00386             if len(self.secrets) < secret_min_length:
00387                 raise error.ConfigurationError("The secrets = '...' wiki config setting is a way too short string (minimum length is %d chars)!" % (
00388                     secret_min_length))
00389             # for lazy people: set all required secrets to same value
00390             secrets = {}
00391             for key in secret_key_names:
00392                 secrets[key] = self.secrets
00393             self.secrets = secrets
00394 
00395         # we check if we have all secrets we need and that they have minimum length
00396         for secret_key_name in secret_key_names:
00397             try:
00398                 secret = self.secrets[secret_key_name]
00399                 if len(secret) < secret_min_length:
00400                     raise ValueError
00401             except (KeyError, ValueError):
00402                 raise error.ConfigurationError("You must set a (at least %d chars long) secret string for secrets['%s']!" % (
00403                     secret_min_length, secret_key_name))

Here is the call graph for this function:


Member Function Documentation

Make it possible to access a config object like a dict 

Definition at line 638 of file multiconfig.py.

00638 
00639     def __getitem__(self, item):
00640         """ Make it possible to access a config object like a dict """
00641         return getattr(self, item)
00642 

Here is the caller graph for this function:

Make sure directories are accessible

Both data and underlay should exists and allow read, write and
execute.

Definition at line 543 of file multiconfig.py.

00543 
00544     def _check_directories(self):
00545         """ Make sure directories are accessible
00546 
00547         Both data and underlay should exists and allow read, write and
00548         execute.
00549         """
00550         mode = os.F_OK | os.R_OK | os.W_OK | os.X_OK
00551         for attr in ('data_dir', 'data_underlay_dir'):
00552             path = getattr(self, attr)
00553 
00554             # allow an empty underlay path or None
00555             if attr == 'data_underlay_dir' and not path:
00556                 continue
00557 
00558             path_pages = os.path.join(path, "pages")
00559             if not (os.path.isdir(path_pages) and os.access(path_pages, mode)):
00560                 msg = """
00561 %(attr)s "%(path)s" does not exist, or has incorrect ownership or
00562 permissions.
00563 
00564 Make sure the directory and the subdirectory "pages" are owned by the web
00565 server and are readable, writable and executable by the web server user
00566 and group.
00567 
00568 It is recommended to use absolute paths and not relative paths. Check
00569 also the spelling of the directory name.
00570 """ % {'attr': attr, 'path': path, }
00571                 raise error.ConfigurationError(msg)

Check namespace and warn about unknown names

Warn about names which are not used by DefaultConfig, except
modules, classes, _private or __magic__ names.

This check is disabled by default, when enabled, it will show an
error message with unknown names.

Definition at line 469 of file multiconfig.py.

00469 
00470     def _config_check(self):
00471         """ Check namespace and warn about unknown names
00472 
00473         Warn about names which are not used by DefaultConfig, except
00474         modules, classes, _private or __magic__ names.
00475 
00476         This check is disabled by default, when enabled, it will show an
00477         error message with unknown names.
00478         """
00479         unknown = ['"%s"' % name for name in dir(self)
00480                   if not name.startswith('_') and
00481                   name not in DefaultConfig.__dict__ and
00482                   not isinstance(getattr(self, name), (type(sys), type(DefaultConfig)))]
00483         if unknown:
00484             msg = """
00485 Unknown configuration options: %s.
00486 
00487 For more information, visit HelpOnConfiguration. Please check your
00488 configuration for typos before requesting support or reporting a bug.
00489 """ % ', '.join(unknown)
00490             raise error.ConfigurationError(msg)

Here is the caller graph for this function:

Try to decode certain names, ignore unicode values

Try to decode str using utf-8. If the decode fail, raise FatalError.

Certain config variables should contain unicode values, and
should be defined with u'text' syntax. Python decode these if
the file have a 'coding' line.

This will allow utf-8 users to use simple strings using, without
using u'string'. Other users will have to use u'string' for
these names, because we don't know what is the charset of the
config files.

Definition at line 491 of file multiconfig.py.

00491 
00492     def _decode(self):
00493         """ Try to decode certain names, ignore unicode values
00494 
00495         Try to decode str using utf-8. If the decode fail, raise FatalError.
00496 
00497         Certain config variables should contain unicode values, and
00498         should be defined with u'text' syntax. Python decode these if
00499         the file have a 'coding' line.
00500 
00501         This will allow utf-8 users to use simple strings using, without
00502         using u'string'. Other users will have to use u'string' for
00503         these names, because we don't know what is the charset of the
00504         config files.
00505         """
00506         charset = 'utf-8'
00507         message = u"""
00508 "%(name)s" configuration variable is a string, but should be
00509 unicode. Use %(name)s = u"value" syntax for unicode variables.
00510 
00511 Also check your "-*- coding -*-" line at the top of your configuration
00512 file. It should match the actual charset of the configuration file.
00513 """
00514 
00515         decode_names = (
00516             'sitename', 'interwikiname', 'user_homewiki', 'logo_string', 'navi_bar',
00517             'page_front_page', 'page_category_regex', 'page_dict_regex',
00518             'page_group_regex', 'page_template_regex', 'page_license_page',
00519             'page_local_spelling_words', 'acl_rights_default',
00520             'acl_rights_before', 'acl_rights_after', 'mail_from'
00521             )
00522 
00523         for name in decode_names:
00524             attr = getattr(self, name, None)
00525             if attr:
00526                 # Try to decode strings
00527                 if isinstance(attr, str):
00528                     try:
00529                         setattr(self, name, unicode(attr, charset))
00530                     except UnicodeError:
00531                         raise error.ConfigurationError(message %
00532                                                        {'name': name})
00533                 # Look into lists and try to decode strings inside them
00534                 elif isinstance(attr, list):
00535                     for i in xrange(len(attr)):
00536                         item = attr[i]
00537                         if isinstance(item, str):
00538                             try:
00539                                 attr[i] = unicode(item, charset)
00540                             except UnicodeError:
00541                                 raise error.ConfigurationError(message %
00542                                                                {'name': name})

fill config dicts

Fills in missing dict keys of derived user config by copying
them from this base class.

Definition at line 627 of file multiconfig.py.

00627 
00628     def _fillDicts(self):
00629         """ fill config dicts
00630 
00631         Fills in missing dict keys of derived user config by copying
00632         them from this base class.
00633         """
00634         # user checkbox defaults
00635         for key, value in DefaultConfig.user_checkbox_defaults.items():
00636             if key not in self.user_checkbox_defaults:
00637                 self.user_checkbox_defaults[key] = value

import all plugin modules

To be able to import plugin from arbitrary path, we have to load
the base package once using imp.load_module. Later, we can use
standard __import__ call to load plugins in this package.

Since each configured plugin path has unique plugins, we load the
plugin packages as "moin_plugin_<sha1(path)>.plugin".

Definition at line 572 of file multiconfig.py.

00572 
00573     def _loadPluginModule(self):
00574         """
00575         import all plugin modules
00576 
00577         To be able to import plugin from arbitrary path, we have to load
00578         the base package once using imp.load_module. Later, we can use
00579         standard __import__ call to load plugins in this package.
00580 
00581         Since each configured plugin path has unique plugins, we load the
00582         plugin packages as "moin_plugin_<sha1(path)>.plugin".
00583         """
00584         import imp
00585         from MoinMoin.support.python_compatibility import hash_new
00586 
00587         plugin_dirs = [self.plugin_dir] + self.plugin_dirs
00588         self._plugin_modules = []
00589 
00590         try:
00591             # Lock other threads while we check and import
00592             imp.acquire_lock()
00593             try:
00594                 for pdir in plugin_dirs:
00595                     csum = 'p_%s' % hash_new('sha1', pdir).hexdigest()
00596                     modname = '%s.%s' % (self.siteid, csum)
00597                     # If the module is not loaded, try to load it
00598                     if not modname in sys.modules:
00599                         # Find module on disk and try to load - slow!
00600                         abspath = os.path.abspath(pdir)
00601                         parent_dir, pname = os.path.split(abspath)
00602                         fp, path, info = imp.find_module(pname, [parent_dir])
00603                         try:
00604                             # Load the module and set in sys.modules
00605                             module = imp.load_module(modname, fp, path, info)
00606                             setattr(sys.modules[self.siteid], 'csum', module)
00607                         finally:
00608                             # Make sure fp is closed properly
00609                             if fp:
00610                                 fp.close()
00611                     if modname not in self._plugin_modules:
00612                         self._plugin_modules.append(modname)
00613             finally:
00614                 imp.release_lock()
00615         except ImportError, err:
00616             msg = """
00617 Could not import plugin package "%(path)s" because of ImportError:
00618 %(err)s.
00619 
00620 Make sure your data directory path is correct, check permissions, and
00621 that the data/plugin directory has an __init__.py file.
""" % {
make up some 'secret' using some config values 

Definition at line 404 of file multiconfig.py.

00404 
00405     def calc_secrets(self):
00406         """ make up some 'secret' using some config values """
00407         varnames = ['data_dir', 'data_underlay_dir', 'language_default',
00408                     'mail_smarthost', 'mail_from', 'page_front_page',
00409                     'theme_default', 'sitename', 'logo_string',
00410                     'interwikiname', 'user_homewiki', 'acl_rights_before', ]
00411         secret = ''
00412         for varname in varnames:
00413             var = getattr(self, varname, None)
00414             if isinstance(var, (str, unicode)):
00415                 secret += repr(var)
00416         return secret

Loads the InterWikiID of this instance. It is used to identify the instance
    globally.
    The IWID is available as cfg.iwid
    The full IWID containing the interwiki name is available as cfg.iwid_full
    This method is called by the property.

Definition at line 449 of file multiconfig.py.

00449 
00450     def load_IWID(self):
00451         """ Loads the InterWikiID of this instance. It is used to identify the instance
00452             globally.
00453             The IWID is available as cfg.iwid
00454             The full IWID containing the interwiki name is available as cfg.iwid_full
00455             This method is called by the property.
00456         """
00457         try:
00458             iwid = self.meta_dict['IWID']
00459         except KeyError:
00460             iwid = util.random_string(16).encode("hex") + "-" + str(int(time.time()))
00461             self.meta_dict['IWID'] = iwid
00462             self.meta_dict.sync()
00463 
00464         self._iwid = iwid
00465         if self.interwikiname is not None:
00466             self._iwid_full = packLine([iwid, self.interwikiname])
00467         else:
00468             self._iwid_full = packLine([iwid])

Here is the call graph for this function:

Here is the caller graph for this function:

The meta_dict contains meta data about the wiki instance. 

Definition at line 418 of file multiconfig.py.

00418 
00419     def load_meta_dict(self):
00420         """ The meta_dict contains meta data about the wiki instance. """
00421         if self._meta_dict is None:
00422             self._meta_dict = wikiutil.MetaDict(os.path.join(self.data_dir, 'meta'), self.cache_dir)
        return self._meta_dict

Definition at line 437 of file multiconfig.py.

00437 
00438     def make_event_handlers_prop():
00439         def getter(self):
00440             if self._event_handlers is None:
00441                 self._event_handlers = events.get_handlers(self)
00442             return self._event_handlers
00443 
00444         def setter(self, new_handlers):
00445             self._event_handlers = new_handlers
00446 
        return property(getter, setter)

Definition at line 426 of file multiconfig.py.

00426 
00427     def make_iwid_property(attr):
00428         def getter(self):
00429             if getattr(self, attr, None) is None:
00430                 self.load_IWID()
00431             return getattr(self, attr)
        return property(getter)

Here is the call graph for this function:


Member Data Documentation

Definition at line 436 of file multiconfig.py.

Definition at line 227 of file multiconfig.py.

Definition at line 228 of file multiconfig.py.

Definition at line 417 of file multiconfig.py.

Definition at line 587 of file multiconfig.py.

Definition at line 226 of file multiconfig.py.

Definition at line 223 of file multiconfig.py.

Definition at line 224 of file multiconfig.py.

Definition at line 225 of file multiconfig.py.

Definition at line 327 of file multiconfig.py.

Definition at line 220 of file multiconfig.py.

Definition at line 218 of file multiconfig.py.

Definition at line 307 of file multiconfig.py.

Reimplemented in MoinMoin._tests.wikiconfig.Config.

Definition at line 249 of file multiconfig.py.

Definition at line 447 of file multiconfig.py.

Definition at line 432 of file multiconfig.py.

Definition at line 433 of file multiconfig.py.

Definition at line 222 of file multiconfig.py.

Definition at line 291 of file multiconfig.py.

Reimplemented in MoinMoin._tests.wikiconfig.Config.

Definition at line 295 of file multiconfig.py.

Definition at line 221 of file multiconfig.py.

Definition at line 230 of file multiconfig.py.

Definition at line 334 of file multiconfig.py.

Definition at line 357 of file multiconfig.py.

Definition at line 377 of file multiconfig.py.

Definition at line 232 of file multiconfig.py.

Definition at line 219 of file multiconfig.py.

Definition at line 368 of file multiconfig.py.

Definition at line 374 of file multiconfig.py.

Definition at line 371 of file multiconfig.py.

Definition at line 341 of file multiconfig.py.

Definition at line 229 of file multiconfig.py.


Property Documentation

Definition at line 423 of file multiconfig.py.


The documentation for this class was generated from the following file: