--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/thirdparty/google_appengine/google/appengine/api/lib_config.py Fri Oct 23 13:54:11 2009 -0500
@@ -0,0 +1,322 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""A mechanism for library configuration.
+
+Whenever App Engine library code has the need for a user-configurable
+value, it should use the following protocol:
+
+1. Pick a prefix unique to the library module, e.g. 'mylib'.
+
+2. Call lib_config.register(prefix, mapping) with that prefix as
+ the first argument and a dict mapping suffixes to default functions
+ as the second.
+
+3. The register() function returns a config handle unique to this
+ prefix. The config handle object has attributes corresponding to
+ each of the suffixes given in the mapping. Call these functions
+ (they're not really methods even though they look like methods) to
+ access the user's configuration value. If the user didn't
+ configure a function, the default function from the mapping is
+ called instead.
+
+4. Document the function name and its signature and semantics.
+
+Users wanting to provide configuration values should create a module
+named appengine_config.py in the top-level directory of their
+application, and define functions as documented by various App Engine
+library components in that module. To change the configuration, edit
+the file and re-deploy the application. (When using the SDK, no
+redeployment is required: the development server will pick up the
+changes the next time it handles a request.)
+
+Third party libraries can also use this mechanism. For casual use,
+just calling the register() method with a unique prefix is okay. For
+carefull libraries, however, it is recommended to instantiate a new
+LibConfigRegistry instance using a different module name.
+
+Example appengine_config.py file:
+
+ from somewhere import MyMiddleWareClass
+
+ def mylib_add_middleware(app):
+ app = MyMiddleWareClass(app)
+ return app
+
+Example library use:
+
+ from google.appengine.api import lib_config
+
+ config_handle = lib_config.register(
+ 'mylib',
+ {'add_middleware': lambda app: app})
+
+ def add_middleware(app):
+ return config_handle.add_middleware(app)
+"""
+
+
+
+import logging
+import os
+import sys
+
+
+DEFAULT_MODNAME = 'appengine_config'
+
+
+class LibConfigRegistry(object):
+ """A registry for library configuration values."""
+
+ def __init__(self, modname):
+ """Constructor.
+
+ Args:
+ modname: The module name to be imported.
+
+ Note: the actual import of this module is deferred until the first
+ time a configuration value is requested through attribute access
+ on a ConfigHandle instance.
+ """
+ self._modname = modname
+ self._registrations = {}
+ self._module = None
+
+ def register(self, prefix, mapping):
+ """Register a set of configuration names.
+
+ Args:
+ prefix: A shared prefix for the configuration names being registered.
+ If the prefix doesn't end in '_', that character is appended.
+ mapping: A dict mapping suffix strings to default values.
+
+ Returns:
+ A ConfigHandle instance.
+
+ It's okay to re-register the same prefix: the mappings are merged,
+ and for duplicate suffixes the most recent registration wins.
+ """
+ if not prefix.endswith('_'):
+ prefix += '_'
+ handle = self._registrations.get(prefix)
+ if handle is None:
+ handle = ConfigHandle(prefix, self)
+ self._registrations[prefix] = handle
+ handle._update_defaults(mapping)
+ return handle
+
+ def initialize(self):
+ """Attempt to import the config module, if not already imported.
+
+ This function always sets self._module to a value unequal
+ to None: either the imported module (if imported successfully), or
+ a dummy object() instance (if an ImportError was raised). Other
+ exceptions are *not* caught.
+ """
+ if self._module is not None:
+ return
+ try:
+ __import__(self._modname)
+ except ImportError, err:
+ self._module = object()
+ else:
+ self._module = sys.modules[self._modname]
+
+ def _pairs(self, prefix):
+ """Generate (key, value) pairs from the config module matching prefix.
+
+ Args:
+ prefix: A prefix string ending in '_', e.g. 'mylib_'.
+
+ Yields:
+ (key, value) pairs where key is the configuration name with
+ prefix removed, and value is the corresponding value.
+ """
+ mapping = getattr(self._module, '__dict__', None)
+ if not mapping:
+ return
+ nskip = len(prefix)
+ for key, value in mapping.iteritems():
+ if key.startswith(prefix):
+ yield key[nskip:], value
+
+ def _dump(self):
+ """Print info about all registrations to stdout."""
+ self.initialize()
+ if not hasattr(self._module, '__dict__'):
+ print 'Module %s.py does not exist.' % self._modname
+ elif not self._registrations:
+ print 'No registrations for %s.py.' % self._modname
+ else:
+ print 'Registrations in %s.py:' % self._modname
+ print '-'*40
+ for prefix in sorted(self._registrations):
+ self._registrations[prefix]._dump()
+
+
+class ConfigHandle(object):
+ """A set of configuration for a single library module or package.
+
+ Public attributes of instances of this class are configuration
+ values. Attributes are dynamically computed (in __getattr__()) and
+ cached as regular instance attributes.
+ """
+
+ _initialized = False
+
+ def __init__(self, prefix, registry):
+ """Constructor.
+
+ Args:
+ prefix: A shared prefix for the configuration names being registered.
+ It *must* end in '_'. (This is enforced by LibConfigRegistry.)
+ registry: A LibConfigRegistry instance.
+ """
+ assert prefix.endswith('_')
+ self._prefix = prefix
+ self._defaults = {}
+ self._overrides = {}
+ self._registry = registry
+
+ def _update_defaults(self, mapping):
+ """Update the default mappings.
+
+ Args:
+ mapping: A dict mapping suffix strings to default values.
+ """
+ for key, value in mapping.iteritems():
+ if key.startswith('__') and key.endswith('__'):
+ continue
+ self._defaults[key] = value
+ if self._initialized:
+ self._update_configs()
+
+ def _update_configs(self):
+ """Update the configuration values.
+
+ This clears the cached values, initializes the registry, and loads
+ the configuration values from the config module.
+ """
+ if self._initialized:
+ self._clear_cache()
+ self._registry.initialize()
+ for key, value in self._registry._pairs(self._prefix):
+ if key not in self._defaults:
+ logging.warn('Configuration "%s" not recognized', self._prefix + key)
+ else:
+ self._overrides[key] = value
+ self._initialized = True
+
+ def _clear_cache(self):
+ """Clear the cached values."""
+ for key in self._defaults:
+ try:
+ delattr(self, key)
+ except AttributeError:
+ pass
+
+ def _dump(self):
+ """Print info about this set of registrations to stdout."""
+ print 'Prefix %s:' % self._prefix
+ if self._overrides:
+ print ' Overrides:'
+ for key in sorted(self._overrides):
+ print ' %s = %r' % (key, self._overrides[key])
+ else:
+ print ' No overrides'
+ if self._defaults:
+ print ' Defaults:'
+ for key in sorted(self._defaults):
+ print ' %s = %r' % (key, self._defaults[key])
+ else:
+ print ' No defaults'
+ print '-'*40
+
+ def __getattr__(self, suffix):
+ """Dynamic attribute access.
+
+ Args:
+ suffix: The attribute name.
+
+ Returns:
+ A configuration values.
+
+ Raises:
+ AttributeError if the suffix is not a registered suffix.
+
+ The first time an attribute is referenced, this method is invoked.
+ The value returned taken either from the config module or from the
+ registered default.
+ """
+ if not self._initialized:
+ self._update_configs()
+ if suffix in self._overrides:
+ value = self._overrides[suffix]
+ elif suffix in self._defaults:
+ value = self._defaults[suffix]
+ else:
+ raise AttributeError(suffix)
+ setattr(self, suffix, value)
+ return value
+
+
+_default_registry = LibConfigRegistry(DEFAULT_MODNAME)
+
+
+def register(prefix, mapping):
+ """Register a set of configurations with the default config module.
+
+ Args:
+ prefix: A shared prefix for the configuration names being registered.
+ If the prefix doesn't end in '_', that character is appended.
+ mapping: A dict mapping suffix strings to default values.
+
+ Returns:
+ A ConfigHandle instance.
+ """
+ return _default_registry.register(prefix, mapping)
+
+
+def main():
+ """CGI-style request handler to dump the configuration.
+
+ Put this in your app.yaml to enable (you can pick any URL):
+
+ - url: /lib_config
+ script: $PYTHON_LIB/google/appengine/api/lib_config.py
+
+ Note: unless you are using the SDK, you must be admin.
+ """
+ if not os.getenv('SERVER_SOFTWARE', '').startswith('Dev'):
+ from google.appengine.api import users
+ if not users.is_current_user_admin():
+ if users.get_current_user() is None:
+ print 'Status: 302'
+ print 'Location:', users.create_login_url(os.getenv('PATH_INFO', ''))
+ else:
+ print 'Status: 403'
+ print
+ print 'Forbidden'
+ return
+
+ print 'Content-type: text/plain'
+ print
+ _default_registry._dump()
+
+
+if __name__ == '__main__':
+ main()