Imported from SVN by Bitbucket

This commit is contained in:
2015-03-31 20:26:20 +00:00
committed by bitbucket
commit ceb7984dec
212 changed files with 49537 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
# don't prevent use of paste if pkg_resources isn't installed
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
try:
import modulefinder
except ImportError:
pass
else:
for p in __path__:
modulefinder.AddPackagePath(__name__, p)

View File

@@ -0,0 +1,3 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
from paste.deploy.loadwsgi import *

View File

@@ -0,0 +1,30 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
"""Python 2<->3 compatibility module"""
import sys
def print_(template, *args, **kwargs):
template = str(template)
if args:
template = template % args
elif kwargs:
template = template % kwargs
sys.stdout.writelines(template)
if sys.version_info < (3, 0):
basestring = basestring
from ConfigParser import ConfigParser
from urllib import unquote
iteritems = lambda d: d.iteritems()
def reraise(t, e, tb):
exec('raise t, e, tb', dict(t=t, e=e, tb=tb))
else:
basestring = str
from configparser import ConfigParser
from urllib.parse import unquote
iteritems = lambda d: d.items()
def reraise(t, e, tb):
exec('raise e from tb', dict(e=e, tb=tb))

View File

@@ -0,0 +1,305 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
"""Paste Configuration Middleware and Objects"""
import threading
import re
# Loaded lazily
wsgilib = None
local = None
__all__ = ['DispatchingConfig', 'CONFIG', 'ConfigMiddleware', 'PrefixMiddleware']
def local_dict():
global config_local, local
try:
return config_local.wsgi_dict
except NameError:
config_local = threading.local()
config_local.wsgi_dict = result = {}
return result
except AttributeError:
config_local.wsgi_dict = result = {}
return result
class DispatchingConfig(object):
"""
This is a configuration object that can be used globally,
imported, have references held onto. The configuration may differ
by thread (or may not).
Specific configurations are registered (and deregistered) either
for the process or for threads.
"""
# @@: What should happen when someone tries to add this
# configuration to itself? Probably the conf should become
# resolved, and get rid of this delegation wrapper
_constructor_lock = threading.Lock()
def __init__(self):
self._constructor_lock.acquire()
try:
self.dispatching_id = 0
while 1:
self._local_key = 'paste.processconfig_%i' % self.dispatching_id
if not self._local_key in local_dict():
break
self.dispatching_id += 1
finally:
self._constructor_lock.release()
self._process_configs = []
def push_thread_config(self, conf):
"""
Make ``conf`` the active configuration for this thread.
Thread-local configuration always overrides process-wide
configuration.
This should be used like::
conf = make_conf()
dispatching_config.push_thread_config(conf)
try:
... do stuff ...
finally:
dispatching_config.pop_thread_config(conf)
"""
local_dict().setdefault(self._local_key, []).append(conf)
def pop_thread_config(self, conf=None):
"""
Remove a thread-local configuration. If ``conf`` is given,
it is checked against the popped configuration and an error
is emitted if they don't match.
"""
self._pop_from(local_dict()[self._local_key], conf)
def _pop_from(self, lst, conf):
popped = lst.pop()
if conf is not None and popped is not conf:
raise AssertionError(
"The config popped (%s) is not the same as the config "
"expected (%s)"
% (popped, conf))
def push_process_config(self, conf):
"""
Like push_thread_config, but applies the configuration to
the entire process.
"""
self._process_configs.append(conf)
def pop_process_config(self, conf=None):
self._pop_from(self._process_configs, conf)
def __getattr__(self, attr):
conf = self.current_conf()
if conf is None:
raise AttributeError(
"No configuration has been registered for this process "
"or thread")
return getattr(conf, attr)
def current_conf(self):
thread_configs = local_dict().get(self._local_key)
if thread_configs:
return thread_configs[-1]
elif self._process_configs:
return self._process_configs[-1]
else:
return None
def __getitem__(self, key):
# I thought __getattr__ would catch this, but apparently not
conf = self.current_conf()
if conf is None:
raise TypeError(
"No configuration has been registered for this process "
"or thread")
return conf[key]
def __contains__(self, key):
# I thought __getattr__ would catch this, but apparently not
return key in self
def __setitem__(self, key, value):
# I thought __getattr__ would catch this, but apparently not
conf = self.current_conf()
conf[key] = value
CONFIG = DispatchingConfig()
class ConfigMiddleware(object):
"""
A WSGI middleware that adds a ``paste.config`` key to the request
environment, as well as registering the configuration temporarily
(for the length of the request) with ``paste.CONFIG``.
"""
def __init__(self, application, config):
"""
This delegates all requests to `application`, adding a *copy*
of the configuration `config`.
"""
self.application = application
self.config = config
def __call__(self, environ, start_response):
global wsgilib
if wsgilib is None:
import pkg_resources
pkg_resources.require('Paste')
from paste import wsgilib
popped_config = None
if 'paste.config' in environ:
popped_config = environ['paste.config']
conf = environ['paste.config'] = self.config.copy()
app_iter = None
CONFIG.push_thread_config(conf)
try:
app_iter = self.application(environ, start_response)
finally:
if app_iter is None:
# An error occurred...
CONFIG.pop_thread_config(conf)
if popped_config is not None:
environ['paste.config'] = popped_config
if type(app_iter) in (list, tuple):
# Because it is a concrete iterator (not a generator) we
# know the configuration for this thread is no longer
# needed:
CONFIG.pop_thread_config(conf)
if popped_config is not None:
environ['paste.config'] = popped_config
return app_iter
else:
def close_config():
CONFIG.pop_thread_config(conf)
new_app_iter = wsgilib.add_close(app_iter, close_config)
return new_app_iter
def make_config_filter(app, global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
return ConfigMiddleware(app, conf)
make_config_middleware = ConfigMiddleware.__doc__
class PrefixMiddleware(object):
"""Translate a given prefix into a SCRIPT_NAME for the filtered
application.
PrefixMiddleware provides a way to manually override the root prefix
(SCRIPT_NAME) of your application for certain, rare situations.
When running an application under a prefix (such as '/james') in
FastCGI/apache, the SCRIPT_NAME environment variable is automatically
set to to the appropriate value: '/james'. Pylons' URL generating
functions, such as url_for, always take the SCRIPT_NAME value into account.
One situation where PrefixMiddleware is required is when an application
is accessed via a reverse proxy with a prefix. The application is accessed
through the reverse proxy via the the URL prefix '/james', whereas the
reverse proxy forwards those requests to the application at the prefix '/'.
The reverse proxy, being an entirely separate web server, has no way of
specifying the SCRIPT_NAME variable; it must be manually set by a
PrefixMiddleware instance. Without setting SCRIPT_NAME, url_for will
generate URLs such as: '/purchase_orders/1', when it should be
generating: '/james/purchase_orders/1'.
To filter your application through a PrefixMiddleware instance, add the
following to the '[app:main]' section of your .ini file:
.. code-block:: ini
filter-with = proxy-prefix
[filter:proxy-prefix]
use = egg:PasteDeploy#prefix
prefix = /james
The name ``proxy-prefix`` simply acts as an identifier of the filter
section; feel free to rename it.
Also, unless disabled, the ``X-Forwarded-Server`` header will be
translated to the ``Host`` header, for cases when that header is
lost in the proxying. Also ``X-Forwarded-Host``,
``X-Forwarded-Scheme``, and ``X-Forwarded-Proto`` are translated.
If ``force_port`` is set, SERVER_PORT and HTTP_HOST will be
rewritten with the given port. You can use a number, string (like
'80') or the empty string (whatever is the default port for the
scheme). This is useful in situations where there is port
forwarding going on, and the server believes itself to be on a
different port than what the outside world sees.
You can also use ``scheme`` to explicitly set the scheme (like
``scheme = https``).
"""
def __init__(self, app, global_conf=None, prefix='/',
translate_forwarded_server=True,
force_port=None, scheme=None):
self.app = app
self.prefix = prefix.rstrip('/')
self.translate_forwarded_server = translate_forwarded_server
self.regprefix = re.compile("^%s(.*)$" % self.prefix)
self.force_port = force_port
self.scheme = scheme
def __call__(self, environ, start_response):
url = environ['PATH_INFO']
url = re.sub(self.regprefix, r'\1', url)
if not url:
url = '/'
environ['PATH_INFO'] = url
environ['SCRIPT_NAME'] = self.prefix
if self.translate_forwarded_server:
if 'HTTP_X_FORWARDED_SERVER' in environ:
environ['SERVER_NAME'] = environ['HTTP_HOST'] = environ.pop('HTTP_X_FORWARDED_SERVER').split(',')[0]
if 'HTTP_X_FORWARDED_HOST' in environ:
environ['HTTP_HOST'] = environ.pop('HTTP_X_FORWARDED_HOST').split(',')[0]
if 'HTTP_X_FORWARDED_FOR' in environ:
environ['REMOTE_ADDR'] = environ.pop('HTTP_X_FORWARDED_FOR')
if 'HTTP_X_FORWARDED_SCHEME' in environ:
environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_SCHEME')
elif 'HTTP_X_FORWARDED_PROTO' in environ:
environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_PROTO')
if self.force_port is not None:
host = environ.get('HTTP_HOST', '').split(':', 1)[0]
if self.force_port:
host = '%s:%s' % (host, self.force_port)
environ['SERVER_PORT'] = str(self.force_port)
else:
if environ['wsgi.url_scheme'] == 'http':
port = '80'
else:
port = '443'
environ['SERVER_PORT'] = port
environ['HTTP_HOST'] = host
if self.scheme is not None:
environ['wsgi.url_scheme'] = self.scheme
return self.app(environ, start_response)
def make_prefix_middleware(
app, global_conf, prefix='/',
translate_forwarded_server=True,
force_port=None, scheme=None):
from paste.deploy.converters import asbool
translate_forwarded_server = asbool(translate_forwarded_server)
return PrefixMiddleware(
app, prefix=prefix,
translate_forwarded_server=translate_forwarded_server,
force_port=force_port, scheme=scheme)
make_prefix_middleware.__doc__ = PrefixMiddleware.__doc__

View File

@@ -0,0 +1,36 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
from paste.deploy.compat import basestring
def asbool(obj):
if isinstance(obj, basestring):
obj = obj.strip().lower()
if obj in ['true', 'yes', 'on', 'y', 't', '1']:
return True
elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
return False
else:
raise ValueError("String is not true/false: %r" % obj)
return bool(obj)
def asint(obj):
try:
return int(obj)
except (TypeError, ValueError):
raise ValueError("Bad integer value: %r" % obj)
def aslist(obj, sep=None, strip=True):
if isinstance(obj, basestring):
lst = obj.split(sep)
if strip:
lst = [v.strip() for v in lst]
return lst
elif isinstance(obj, (list, tuple)):
return obj
elif obj is None:
return []
else:
return [obj]

View File

@@ -0,0 +1,725 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
from __future__ import with_statement
import os
import sys
import re
import pkg_resources
from paste.deploy.compat import ConfigParser, unquote, iteritems
from paste.deploy.util import fix_call, lookup_object
__all__ = ['loadapp', 'loadserver', 'loadfilter', 'appconfig']
############################################################
## Utility functions
############################################################
def import_string(s):
return pkg_resources.EntryPoint.parse("x=" + s).load(False)
def _aslist(obj):
"""
Turn object into a list; lists and tuples are left as-is, None
becomes [], and everything else turns into a one-element list.
"""
if obj is None:
return []
elif isinstance(obj, (list, tuple)):
return obj
else:
return [obj]
def _flatten(lst):
"""
Flatten a nested list.
"""
if not isinstance(lst, (list, tuple)):
return [lst]
result = []
for item in lst:
result.extend(_flatten(item))
return result
class NicerConfigParser(ConfigParser):
def __init__(self, filename, *args, **kw):
ConfigParser.__init__(self, *args, **kw)
self.filename = filename
if hasattr(self, '_interpolation'):
self._interpolation = self.InterpolateWrapper(self._interpolation)
read_file = getattr(ConfigParser, 'read_file', ConfigParser.readfp)
def defaults(self):
"""Return the defaults, with their values interpolated (with the
defaults dict itself)
Mainly to support defaults using values such as %(here)s
"""
defaults = ConfigParser.defaults(self).copy()
for key, val in iteritems(defaults):
defaults[key] = self.get('DEFAULT', key) or val
return defaults
def _interpolate(self, section, option, rawval, vars):
# Python < 3.2
try:
return ConfigParser._interpolate(
self, section, option, rawval, vars)
except Exception:
e = sys.exc_info()[1]
args = list(e.args)
args[0] = 'Error in file %s: %s' % (self.filename, e)
e.args = tuple(args)
e.message = args[0]
raise
class InterpolateWrapper(object):
# Python >= 3.2
def __init__(self, original):
self._original = original
def __getattr__(self, name):
return getattr(self._original, name)
def before_get(self, parser, section, option, value, defaults):
try:
return self._original.before_get(parser, section, option,
value, defaults)
except Exception:
e = sys.exc_info()[1]
args = list(e.args)
args[0] = 'Error in file %s: %s' % (parser.filename, e)
e.args = tuple(args)
e.message = args[0]
raise
############################################################
## Object types
############################################################
class _ObjectType(object):
name = None
egg_protocols = None
config_prefixes = None
def __init__(self):
# Normalize these variables:
self.egg_protocols = [_aslist(p) for p in _aslist(self.egg_protocols)]
self.config_prefixes = [_aslist(p) for p in _aslist(self.config_prefixes)]
def __repr__(self):
return '<%s protocols=%r prefixes=%r>' % (
self.name, self.egg_protocols, self.config_prefixes)
def invoke(self, context):
assert context.protocol in _flatten(self.egg_protocols)
return fix_call(context.object,
context.global_conf, **context.local_conf)
class _App(_ObjectType):
name = 'application'
egg_protocols = ['paste.app_factory', 'paste.composite_factory',
'paste.composit_factory']
config_prefixes = [['app', 'application'], ['composite', 'composit'],
'pipeline', 'filter-app']
def invoke(self, context):
if context.protocol in ('paste.composit_factory',
'paste.composite_factory'):
return fix_call(context.object,
context.loader, context.global_conf,
**context.local_conf)
elif context.protocol == 'paste.app_factory':
return fix_call(context.object, context.global_conf, **context.local_conf)
else:
assert 0, "Protocol %r unknown" % context.protocol
APP = _App()
class _Filter(_ObjectType):
name = 'filter'
egg_protocols = [['paste.filter_factory', 'paste.filter_app_factory']]
config_prefixes = ['filter']
def invoke(self, context):
if context.protocol == 'paste.filter_factory':
return fix_call(context.object,
context.global_conf, **context.local_conf)
elif context.protocol == 'paste.filter_app_factory':
def filter_wrapper(wsgi_app):
# This should be an object, so it has a nicer __repr__
return fix_call(context.object,
wsgi_app, context.global_conf,
**context.local_conf)
return filter_wrapper
else:
assert 0, "Protocol %r unknown" % context.protocol
FILTER = _Filter()
class _Server(_ObjectType):
name = 'server'
egg_protocols = [['paste.server_factory', 'paste.server_runner']]
config_prefixes = ['server']
def invoke(self, context):
if context.protocol == 'paste.server_factory':
return fix_call(context.object,
context.global_conf, **context.local_conf)
elif context.protocol == 'paste.server_runner':
def server_wrapper(wsgi_app):
# This should be an object, so it has a nicer __repr__
return fix_call(context.object,
wsgi_app, context.global_conf,
**context.local_conf)
return server_wrapper
else:
assert 0, "Protocol %r unknown" % context.protocol
SERVER = _Server()
# Virtual type: (@@: There's clearly something crufty here;
# this probably could be more elegant)
class _PipeLine(_ObjectType):
name = 'pipeline'
def invoke(self, context):
app = context.app_context.create()
filters = [c.create() for c in context.filter_contexts]
filters.reverse()
for filter in filters:
app = filter(app)
return app
PIPELINE = _PipeLine()
class _FilterApp(_ObjectType):
name = 'filter_app'
def invoke(self, context):
next_app = context.next_context.create()
filter = context.filter_context.create()
return filter(next_app)
FILTER_APP = _FilterApp()
class _FilterWith(_App):
name = 'filtered_with'
def invoke(self, context):
filter = context.filter_context.create()
filtered = context.next_context.create()
if context.next_context.object_type is APP:
return filter(filtered)
else:
# filtering a filter
def composed(app):
return filter(filtered(app))
return composed
FILTER_WITH = _FilterWith()
############################################################
## Loaders
############################################################
def loadapp(uri, name=None, **kw):
return loadobj(APP, uri, name=name, **kw)
def loadfilter(uri, name=None, **kw):
return loadobj(FILTER, uri, name=name, **kw)
def loadserver(uri, name=None, **kw):
return loadobj(SERVER, uri, name=name, **kw)
def appconfig(uri, name=None, relative_to=None, global_conf=None):
context = loadcontext(APP, uri, name=name,
relative_to=relative_to,
global_conf=global_conf)
return context.config()
_loaders = {}
def loadobj(object_type, uri, name=None, relative_to=None,
global_conf=None):
context = loadcontext(
object_type, uri, name=name, relative_to=relative_to,
global_conf=global_conf)
return context.create()
def loadcontext(object_type, uri, name=None, relative_to=None,
global_conf=None):
if '#' in uri:
if name is None:
uri, name = uri.split('#', 1)
else:
# @@: Ignore fragment or error?
uri = uri.split('#', 1)[0]
if name is None:
name = 'main'
if ':' not in uri:
raise LookupError("URI has no scheme: %r" % uri)
scheme, path = uri.split(':', 1)
scheme = scheme.lower()
if scheme not in _loaders:
raise LookupError(
"URI scheme not known: %r (from %s)"
% (scheme, ', '.join(_loaders.keys())))
return _loaders[scheme](
object_type,
uri, path, name=name, relative_to=relative_to,
global_conf=global_conf)
def _loadconfig(object_type, uri, path, name, relative_to,
global_conf):
isabs = os.path.isabs(path)
# De-Windowsify the paths:
path = path.replace('\\', '/')
if not isabs:
if not relative_to:
raise ValueError(
"Cannot resolve relative uri %r; no relative_to keyword "
"argument given" % uri)
relative_to = relative_to.replace('\\', '/')
if relative_to.endswith('/'):
path = relative_to + path
else:
path = relative_to + '/' + path
if path.startswith('///'):
path = path[2:]
path = unquote(path)
loader = ConfigLoader(path)
if global_conf:
loader.update_defaults(global_conf, overwrite=False)
return loader.get_context(object_type, name, global_conf)
_loaders['config'] = _loadconfig
def _loadegg(object_type, uri, spec, name, relative_to,
global_conf):
loader = EggLoader(spec)
return loader.get_context(object_type, name, global_conf)
_loaders['egg'] = _loadegg
def _loadfunc(object_type, uri, spec, name, relative_to,
global_conf):
loader = FuncLoader(spec)
return loader.get_context(object_type, name, global_conf)
_loaders['call'] = _loadfunc
############################################################
## Loaders
############################################################
class _Loader(object):
def get_app(self, name=None, global_conf=None):
return self.app_context(
name=name, global_conf=global_conf).create()
def get_filter(self, name=None, global_conf=None):
return self.filter_context(
name=name, global_conf=global_conf).create()
def get_server(self, name=None, global_conf=None):
return self.server_context(
name=name, global_conf=global_conf).create()
def app_context(self, name=None, global_conf=None):
return self.get_context(
APP, name=name, global_conf=global_conf)
def filter_context(self, name=None, global_conf=None):
return self.get_context(
FILTER, name=name, global_conf=global_conf)
def server_context(self, name=None, global_conf=None):
return self.get_context(
SERVER, name=name, global_conf=global_conf)
_absolute_re = re.compile(r'^[a-zA-Z]+:')
def absolute_name(self, name):
"""
Returns true if the name includes a scheme
"""
if name is None:
return False
return self._absolute_re.search(name)
class ConfigLoader(_Loader):
def __init__(self, filename):
self.filename = filename = filename.strip()
defaults = {
'here': os.path.dirname(os.path.abspath(filename)),
'__file__': os.path.abspath(filename)
}
self.parser = NicerConfigParser(filename, defaults=defaults)
self.parser.optionxform = str # Don't lower-case keys
with open(filename) as f:
self.parser.read_file(f)
def update_defaults(self, new_defaults, overwrite=True):
for key, value in iteritems(new_defaults):
if not overwrite and key in self.parser._defaults:
continue
self.parser._defaults[key] = value
def get_context(self, object_type, name=None, global_conf=None):
if self.absolute_name(name):
return loadcontext(object_type, name,
relative_to=os.path.dirname(self.filename),
global_conf=global_conf)
section = self.find_config_section(
object_type, name=name)
if global_conf is None:
global_conf = {}
else:
global_conf = global_conf.copy()
defaults = self.parser.defaults()
global_conf.update(defaults)
local_conf = {}
global_additions = {}
get_from_globals = {}
for option in self.parser.options(section):
if option.startswith('set '):
name = option[4:].strip()
global_additions[name] = global_conf[name] = (
self.parser.get(section, option))
elif option.startswith('get '):
name = option[4:].strip()
get_from_globals[name] = self.parser.get(section, option)
else:
if option in defaults:
# @@: It's a global option (?), so skip it
continue
local_conf[option] = self.parser.get(section, option)
for local_var, glob_var in get_from_globals.items():
local_conf[local_var] = global_conf[glob_var]
if object_type in (APP, FILTER) and 'filter-with' in local_conf:
filter_with = local_conf.pop('filter-with')
else:
filter_with = None
if 'require' in local_conf:
for spec in local_conf['require'].split():
pkg_resources.require(spec)
del local_conf['require']
if section.startswith('filter-app:'):
context = self._filter_app_context(
object_type, section, name=name,
global_conf=global_conf, local_conf=local_conf,
global_additions=global_additions)
elif section.startswith('pipeline:'):
context = self._pipeline_app_context(
object_type, section, name=name,
global_conf=global_conf, local_conf=local_conf,
global_additions=global_additions)
elif 'use' in local_conf:
context = self._context_from_use(
object_type, local_conf, global_conf, global_additions,
section)
else:
context = self._context_from_explicit(
object_type, local_conf, global_conf, global_additions,
section)
if filter_with is not None:
filter_with_context = LoaderContext(
obj=None,
object_type=FILTER_WITH,
protocol=None,
global_conf=global_conf, local_conf=local_conf,
loader=self)
filter_with_context.filter_context = self.filter_context(
name=filter_with, global_conf=global_conf)
filter_with_context.next_context = context
return filter_with_context
return context
def _context_from_use(self, object_type, local_conf, global_conf,
global_additions, section):
use = local_conf.pop('use')
context = self.get_context(
object_type, name=use, global_conf=global_conf)
context.global_conf.update(global_additions)
context.local_conf.update(local_conf)
if '__file__' in global_conf:
# use sections shouldn't overwrite the original __file__
context.global_conf['__file__'] = global_conf['__file__']
# @@: Should loader be overwritten?
context.loader = self
if context.protocol is None:
# Determine protocol from section type
section_protocol = section.split(':', 1)[0]
if section_protocol in ('application', 'app'):
context.protocol = 'paste.app_factory'
elif section_protocol in ('composit', 'composite'):
context.protocol = 'paste.composit_factory'
else:
# This will work with 'server' and 'filter', otherwise it
# could fail but there is an error message already for
# bad protocols
context.protocol = 'paste.%s_factory' % context_protocol
return context
def _context_from_explicit(self, object_type, local_conf, global_conf,
global_addition, section):
possible = []
for protocol_options in object_type.egg_protocols:
for protocol in protocol_options:
if protocol in local_conf:
possible.append((protocol, local_conf[protocol]))
break
if len(possible) > 1:
raise LookupError(
"Multiple protocols given in section %r: %s"
% (section, possible))
if not possible:
raise LookupError(
"No loader given in section %r" % section)
found_protocol, found_expr = possible[0]
del local_conf[found_protocol]
value = import_string(found_expr)
context = LoaderContext(
value, object_type, found_protocol,
global_conf, local_conf, self)
return context
def _filter_app_context(self, object_type, section, name,
global_conf, local_conf, global_additions):
if 'next' not in local_conf:
raise LookupError(
"The [%s] section in %s is missing a 'next' setting"
% (section, self.filename))
next_name = local_conf.pop('next')
context = LoaderContext(None, FILTER_APP, None, global_conf,
local_conf, self)
context.next_context = self.get_context(
APP, next_name, global_conf)
if 'use' in local_conf:
context.filter_context = self._context_from_use(
FILTER, local_conf, global_conf, global_additions,
section)
else:
context.filter_context = self._context_from_explicit(
FILTER, local_conf, global_conf, global_additions,
section)
return context
def _pipeline_app_context(self, object_type, section, name,
global_conf, local_conf, global_additions):
if 'pipeline' not in local_conf:
raise LookupError(
"The [%s] section in %s is missing a 'pipeline' setting"
% (section, self.filename))
pipeline = local_conf.pop('pipeline').split()
if local_conf:
raise LookupError(
"The [%s] pipeline section in %s has extra "
"(disallowed) settings: %s"
% (', '.join(local_conf.keys())))
context = LoaderContext(None, PIPELINE, None, global_conf,
local_conf, self)
context.app_context = self.get_context(
APP, pipeline[-1], global_conf)
context.filter_contexts = [
self.get_context(FILTER, name, global_conf)
for name in pipeline[:-1]]
return context
def find_config_section(self, object_type, name=None):
"""
Return the section name with the given name prefix (following the
same pattern as ``protocol_desc`` in ``config``. It must have the
given name, or for ``'main'`` an empty name is allowed. The
prefix must be followed by a ``:``.
Case is *not* ignored.
"""
possible = []
for name_options in object_type.config_prefixes:
for name_prefix in name_options:
found = self._find_sections(
self.parser.sections(), name_prefix, name)
if found:
possible.extend(found)
break
if not possible:
raise LookupError(
"No section %r (prefixed by %s) found in config %s"
% (name,
' or '.join(map(repr, _flatten(object_type.config_prefixes))),
self.filename))
if len(possible) > 1:
raise LookupError(
"Ambiguous section names %r for section %r (prefixed by %s) "
"found in config %s"
% (possible, name,
' or '.join(map(repr, _flatten(object_type.config_prefixes))),
self.filename))
return possible[0]
def _find_sections(self, sections, name_prefix, name):
found = []
if name is None:
if name_prefix in sections:
found.append(name_prefix)
name = 'main'
for section in sections:
if section.startswith(name_prefix + ':'):
if section[len(name_prefix) + 1:].strip() == name:
found.append(section)
return found
class EggLoader(_Loader):
def __init__(self, spec):
self.spec = spec
def get_context(self, object_type, name=None, global_conf=None):
if self.absolute_name(name):
return loadcontext(object_type, name,
global_conf=global_conf)
entry_point, protocol, ep_name = self.find_egg_entry_point(
object_type, name=name)
return LoaderContext(
entry_point,
object_type,
protocol,
global_conf or {}, {},
self,
distribution=pkg_resources.get_distribution(self.spec),
entry_point_name=ep_name)
def find_egg_entry_point(self, object_type, name=None):
"""
Returns the (entry_point, protocol) for the with the given
``name``.
"""
if name is None:
name = 'main'
possible = []
for protocol_options in object_type.egg_protocols:
for protocol in protocol_options:
pkg_resources.require(self.spec)
entry = pkg_resources.get_entry_info(
self.spec,
protocol,
name)
if entry is not None:
possible.append((entry.load(), protocol, entry.name))
break
if not possible:
# Better exception
dist = pkg_resources.get_distribution(self.spec)
raise LookupError(
"Entry point %r not found in egg %r (dir: %s; protocols: %s; "
"entry_points: %s)"
% (name, self.spec,
dist.location,
', '.join(_flatten(object_type.egg_protocols)),
', '.join(_flatten([
(pkg_resources.get_entry_info(self.spec, prot, name) or {}).keys()
for prot in protocol_options] or '(no entry points)'))))
if len(possible) > 1:
raise LookupError(
"Ambiguous entry points for %r in egg %r (protocols: %s)"
% (name, self.spec, ', '.join(_flatten(protocol_options))))
return possible[0]
class FuncLoader(_Loader):
""" Loader that supports specifying functions inside modules, without
using eggs at all. Configuration should be in the format:
use = call:my.module.path:function_name
Dot notation is supported in both the module and function name, e.g.:
use = call:my.module.path:object.method
"""
def __init__(self, spec):
self.spec = spec
if not ':' in spec:
raise LookupError("Configuration not in format module:function")
def get_context(self, object_type, name=None, global_conf=None):
obj = lookup_object(self.spec)
return LoaderContext(
obj,
object_type,
None, # determine protocol from section type
global_conf or {},
{},
self,
)
class LoaderContext(object):
def __init__(self, obj, object_type, protocol,
global_conf, local_conf, loader,
distribution=None, entry_point_name=None):
self.object = obj
self.object_type = object_type
self.protocol = protocol
#assert protocol in _flatten(object_type.egg_protocols), (
# "Bad protocol %r; should be one of %s"
# % (protocol, ', '.join(map(repr, _flatten(object_type.egg_protocols)))))
self.global_conf = global_conf
self.local_conf = local_conf
self.loader = loader
self.distribution = distribution
self.entry_point_name = entry_point_name
def create(self):
return self.object_type.invoke(self)
def config(self):
conf = AttrDict(self.global_conf)
conf.update(self.local_conf)
conf.local_conf = self.local_conf
conf.global_conf = self.global_conf
conf.context = self
return conf
class AttrDict(dict):
"""
A dictionary that can be assigned to.
"""
pass

View File

@@ -0,0 +1,36 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
import os
from paste.script.templates import Template
from paste.deploy.compat import print_
class PasteDeploy(Template):
_template_dir = 'paster_templates/paste_deploy'
summary = "A web application deployed through paste.deploy"
egg_plugins = ['PasteDeploy']
required_templates = ['PasteScript#basic_package']
def post(self, command, output_dir, vars):
for prereq in ['PasteDeploy']:
command.insert_into_file(
os.path.join(output_dir, 'setup.py'),
'Extra requirements',
'%r,\n' % prereq,
indent=True)
command.insert_into_file(
os.path.join(output_dir, 'setup.py'),
'Entry points',
(' [paste.app_factory]\n'
' main = %(package)s.wsgiapp:make_app\n') % vars,
indent=False)
if command.verbose:
print_('*' * 72)
print_('* Run "paster serve docs/devel_config.ini" to run the sample application')
print_('* on http://localhost:8080')
print_('*' * 72)

View File

@@ -0,0 +1,24 @@
import cgi
from paste.deploy import CONFIG
def application(environ, start_response):
# Note that usually you wouldn't be writing a pure WSGI
# application, you might be using some framework or
# environment. But as an example...
start_response('200 OK', [('Content-type', 'text/html')])
greeting = CONFIG['greeting']
content = [
'<html><head><title>%s</title></head>\n' % greeting,
'<body><h1>%s!</h1>\n' % greeting,
'<table border=1>\n',
]
items = environ.items()
items.sort()
for key, value in items:
content.append('<tr><td>%s</td><td>%s</td></tr>\n'
% (key, cgi.escape(repr(value))))
content.append('</table></body></html>')
return content

View File

@@ -0,0 +1,24 @@
from paste.deploy.config import ConfigMiddleware
import sampleapp
def make_app(
global_conf,
# Optional and required configuration parameters
# can go here, or just **kw; greeting is required:
greeting,
**kw):
# This is a WSGI application:
app = sampleapp.application
# Here we merge all the keys into one configuration
# dictionary; you don't have to do this, but this
# can be convenient later to add ad hoc configuration:
conf = global_conf.copy()
conf.update(kw)
conf['greeting'] = greeting
# ConfigMiddleware means that paste.deploy.CONFIG will,
# during this request (threadsafe) represent the
# configuration dictionary we set up:
app = ConfigMiddleware(app, conf)
return app

View File

@@ -0,0 +1,22 @@
[filter-app:main]
# This puts the interactive debugger in place:
use = egg:Paste#evalerror
next = devel
[app:devel]
# This application is meant for interactive development
use = egg:${project}
debug = true
# You can add other configuration values:
greeting = Aloha!
[app:test]
# While this version of the configuration is for non-iteractive
# tests (unit tests)
use = devel
[server:main]
use = egg:Paste#http
# Change to 0.0.0.0 to make public:
host = 127.0.0.1
port = 8080

View File

@@ -0,0 +1,74 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
import inspect
import sys
from paste.deploy.compat import reraise
def fix_type_error(exc_info, callable, varargs, kwargs):
"""
Given an exception, this will test if the exception was due to a
signature error, and annotate the error with better information if
so.
Usage::
try:
val = callable(*args, **kw)
except TypeError:
exc_info = fix_type_error(None, callable, args, kw)
raise exc_info[0], exc_info[1], exc_info[2]
"""
if exc_info is None:
exc_info = sys.exc_info()
if (exc_info[0] != TypeError
or str(exc_info[1]).find('arguments') == -1
or getattr(exc_info[1], '_type_error_fixed', False)):
return exc_info
exc_info[1]._type_error_fixed = True
argspec = inspect.formatargspec(*inspect.getargspec(callable))
args = ', '.join(map(_short_repr, varargs))
if kwargs and args:
args += ', '
if kwargs:
kwargs = kwargs.items()
kwargs.sort()
args += ', '.join(['%s=...' % n for n, v in kwargs])
gotspec = '(%s)' % args
msg = '%s; got %s, wanted %s' % (exc_info[1], gotspec, argspec)
exc_info[1].args = (msg,)
return exc_info
def _short_repr(v):
v = repr(v)
if len(v) > 12:
v = v[:8] + '...' + v[-4:]
return v
def fix_call(callable, *args, **kw):
"""
Call ``callable(*args, **kw)`` fixing any type errors that come out.
"""
try:
val = callable(*args, **kw)
except TypeError:
exc_info = fix_type_error(None, callable, args, kw)
reraise(*exc_info)
return val
def lookup_object(spec):
"""
Looks up a module or object from a some.module:func_name specification.
To just look up a module, omit the colon and everything after it.
"""
parts, target = spec.split(':') if ':' in spec else (spec, None)
module = __import__(parts)
for part in parts.split('.')[1:] + ([target] if target else []):
module = getattr(module, part)
return module