root/galaxy-central/eggs/PasteDeploy-1.3.3-py2.6.egg/paste/deploy/loadwsgi.py @ 3

リビジョン 3, 23.1 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
2# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
3import os
4import re
5import sys
6import urllib
7from ConfigParser import ConfigParser
8import pkg_resources
9from paste.deploy.util.fixtypeerror import fix_call
10
11__all__ = ['loadapp', 'loadserver', 'loadfilter', 'appconfig']
12
13############################################################
14## Utility functions
15############################################################
16
17def import_string(s):
18    return pkg_resources.EntryPoint.parse("x="+s).load(False)
19
20def _aslist(obj):
21    """
22    Turn object into a list; lists and tuples are left as-is, None
23    becomes [], and everything else turns into a one-element list.
24    """
25    if obj is None:
26        return []
27    elif isinstance(obj, (list, tuple)):
28        return obj
29    else:
30        return [obj]
31
32def _flatten(lst):
33    """
34    Flatten a nested list.
35    """
36    if not isinstance(lst, (list, tuple)):
37        return [lst]
38    result = []
39    for item in lst:
40        result.extend(_flatten(item))
41    return result
42
43class NicerConfigParser(ConfigParser):
44
45    def __init__(self, filename, *args, **kw):
46        ConfigParser.__init__(self, *args, **kw)
47        self.filename = filename
48
49    def defaults(self):
50        """Return the defaults, with their values interpolated (with the
51        defaults dict itself)
52
53        Mainly to support defaults using values such as %(here)s
54        """
55        defaults = ConfigParser.defaults(self).copy()
56        for key, val in defaults.iteritems():
57            defaults[key] = self._interpolate('DEFAULT', key, val, defaults)
58        return defaults
59
60    def _interpolate(self, section, option, rawval, vars):
61        try:
62            return ConfigParser._interpolate(
63                self, section, option, rawval, vars)
64        except Exception, e:
65            args = list(e.args)
66            args[0] = 'Error in file %s, [%s] %s=%r: %s' % (
67                self.filename, section, option, rawval, e)
68            e.args = tuple(args)
69            raise
70
71############################################################
72## Object types
73############################################################
74
75class _ObjectType(object):
76
77    name = None
78    egg_protocols = None
79    config_prefixes = None
80
81    def __init__(self):
82        # Normalize these variables:
83        self.egg_protocols = map(_aslist, _aslist(self.egg_protocols))
84        self.config_prefixes = map(_aslist, _aslist(self.config_prefixes))
85
86    def __repr__(self):
87        return '<%s protocols=%r prefixes=%r>' % (
88            self.name, self.egg_protocols, self.config_prefixes)
89
90    def invoke(self, context):
91        assert context.protocol in _flatten(self.egg_protocols)
92        return fix_call(context.object,
93                        context.global_conf, **context.local_conf)
94
95class _App(_ObjectType):
96
97    name = 'application'
98    egg_protocols = ['paste.app_factory', 'paste.composite_factory',
99                     'paste.composit_factory']
100    config_prefixes = [['app', 'application'], ['composite', 'composit'],
101                       'pipeline', 'filter-app']
102
103    def invoke(self, context):
104        if context.protocol in ('paste.composit_factory',
105                                'paste.composite_factory'):
106            return fix_call(context.object,
107                            context.loader, context.global_conf,
108                            **context.local_conf)
109        elif context.protocol == 'paste.app_factory':
110            return fix_call(context.object, context.global_conf, **context.local_conf)
111        else:
112            assert 0, "Protocol %r unknown" % context.protocol
113
114APP = _App()
115
116class _Filter(_ObjectType):
117    name = 'filter'
118    egg_protocols = [['paste.filter_factory', 'paste.filter_app_factory']]
119    config_prefixes = ['filter']
120
121    def invoke(self, context):
122        if context.protocol == 'paste.filter_factory':
123            return fix_call(context.object,
124                            context.global_conf, **context.local_conf)
125        elif context.protocol == 'paste.filter_app_factory':
126            def filter_wrapper(wsgi_app):
127                # This should be an object, so it has a nicer __repr__
128                return fix_call(context.object,
129                                wsgi_app, context.global_conf,
130                                **context.local_conf)
131            return filter_wrapper
132        else:
133            assert 0, "Protocol %r unknown" % context.protocol
134
135FILTER = _Filter()
136
137class _Server(_ObjectType):
138    name = 'server'
139    egg_protocols = [['paste.server_factory', 'paste.server_runner']]
140    config_prefixes = ['server']
141
142    def invoke(self, context):
143        if context.protocol == 'paste.server_factory':
144            return fix_call(context.object,
145                            context.global_conf, **context.local_conf)
146        elif context.protocol == 'paste.server_runner':
147            def server_wrapper(wsgi_app):
148                # This should be an object, so it has a nicer __repr__
149                return fix_call(context.object,
150                                wsgi_app, context.global_conf,
151                                **context.local_conf)
152            return server_wrapper
153        else:
154            assert 0, "Protocol %r unknown" % context.protocol
155
156SERVER = _Server()
157
158# Virtual type: (@@: There's clearly something crufty here;
159# this probably could be more elegant)
160class _PipeLine(_ObjectType):
161    name = 'pipeline'
162
163    def invoke(self, context):
164        app = context.app_context.create()
165        filters = [c.create() for c in context.filter_contexts]
166        filters.reverse()
167        for filter in filters:
168            app = filter(app)
169        return app
170
171PIPELINE = _PipeLine()
172
173class _FilterApp(_ObjectType):
174    name = 'filter_app'
175
176    def invoke(self, context):
177        next_app = context.next_context.create()
178        filter = context.filter_context.create()
179        return filter(next_app)
180
181FILTER_APP = _FilterApp()
182
183class _FilterWith(_App):
184    name = 'filtered_with'
185
186    def invoke(self, context):
187        filter = context.filter_context.create()
188        filtered = context.next_context.create()
189        if context.next_context.object_type is APP:
190            return filter(filtered)
191        else:
192            # filtering a filter
193            def composed(app):
194                return filter(filtered(app))
195            return composed
196
197FILTER_WITH = _FilterWith()
198
199############################################################
200## Loaders
201############################################################
202
203def loadapp(uri, name=None, **kw):
204    return loadobj(APP, uri, name=name, **kw)
205
206def loadfilter(uri, name=None, **kw):
207    return loadobj(FILTER, uri, name=name, **kw)
208
209def loadserver(uri, name=None, **kw):
210    return loadobj(SERVER, uri, name=name, **kw)
211
212def appconfig(uri, name=None, relative_to=None, global_conf=None):
213    context = loadcontext(APP, uri, name=name,
214                          relative_to=relative_to,
215                          global_conf=global_conf)
216    return context.config()
217
218_loaders = {}
219
220def loadobj(object_type, uri, name=None, relative_to=None,
221            global_conf=None):
222    context = loadcontext(
223        object_type, uri, name=name, relative_to=relative_to,
224        global_conf=global_conf)
225    return context.create()
226
227def loadcontext(object_type, uri, name=None, relative_to=None,
228                global_conf=None):
229    if '#' in uri:
230        if name is None:
231            uri, name = uri.split('#', 1)
232        else:
233            # @@: Ignore fragment or error?
234            uri = uri.split('#', 1)[0]
235    if name is None:
236        name = 'main'
237    if ':' not in uri:
238        raise LookupError("URI has no scheme: %r" % uri)
239    scheme, path = uri.split(':', 1)
240    scheme = scheme.lower()
241    if scheme not in _loaders:
242        raise LookupError(
243            "URI scheme not known: %r (from %s)"
244            % (scheme, ', '.join(_loaders.keys())))
245    return _loaders[scheme](
246        object_type,
247        uri, path, name=name, relative_to=relative_to,
248        global_conf=global_conf)
249
250def _loadconfig(object_type, uri, path, name, relative_to,
251                global_conf):
252    # De-Windowsify the paths:
253    path = path.replace('\\', '/')
254    absolute_path = True
255    if sys.platform == 'win32':
256        _absolute_re = re.compile(r'^[a-zA-Z]:')
257        if not _absolute_re.search(path):
258            absolute_path = False
259    else:
260        if not path.startswith('/'):
261            absolute_path = False
262    if not absolute_path:
263        if not relative_to:
264            raise ValueError(
265                "Cannot resolve relative uri %r; no context keyword "
266                "argument given" % uri)
267        relative_to = relative_to.replace('\\', '/')
268        if relative_to.endswith('/'):
269            path = relative_to + path
270        else:
271            path = relative_to + '/' + path
272    if path.startswith('///'):
273        path = path[2:]
274    path = urllib.unquote(path)
275    loader = ConfigLoader(path)
276    if global_conf:
277        loader.update_defaults(global_conf, overwrite=False)
278    return loader.get_context(object_type, name, global_conf)
279
280_loaders['config'] = _loadconfig
281
282def _loadegg(object_type, uri, spec, name, relative_to,
283             global_conf):
284    loader = EggLoader(spec)
285    return loader.get_context(object_type, name, global_conf)
286
287_loaders['egg'] = _loadegg
288
289############################################################
290## Loaders
291############################################################
292
293class _Loader(object):
294
295    def get_app(self, name=None, global_conf=None):
296        return self.app_context(
297            name=name, global_conf=global_conf).create()
298
299    def get_filter(self, name=None, global_conf=None):
300        return self.filter_context(
301            name=name, global_conf=global_conf).create()
302
303    def get_server(self, name=None, global_conf=None):
304        return self.server_context(
305            name=name, global_conf=global_conf).create()
306
307    def app_context(self, name=None, global_conf=None):
308        return self.get_context(
309            APP, name=name, global_conf=global_conf)
310
311    def filter_context(self, name=None, global_conf=None):
312        return self.get_context(
313            FILTER, name=name, global_conf=global_conf)
314
315    def server_context(self, name=None, global_conf=None):
316        return self.get_context(
317            SERVER, name=name, global_conf=global_conf)
318
319    _absolute_re = re.compile(r'^[a-zA-Z]+:')
320    def absolute_name(self, name):
321        """
322        Returns true if the name includes a scheme
323        """
324        if name is None:
325            return False
326        return self._absolute_re.search(name)       
327
328class ConfigLoader(_Loader):
329
330    def __init__(self, filename):
331        self.filename = filename = filename.strip()
332        self.parser = NicerConfigParser(self.filename)
333        # Don't lower-case keys:
334        self.parser.optionxform = str
335        # Stupid ConfigParser ignores files that aren't found, so
336        # we have to add an extra check:
337        if not os.path.exists(filename):
338            if filename.strip() != filename:
339                raise OSError(
340                    "File %r not found; trailing whitespace: "
341                    "did you try to use a # on the same line as a filename? "
342                    "(comments must be on their own line)" % filename)
343            raise OSError(
344                "File %r not found" % filename)
345        self.parser.read(filename)
346        self.parser._defaults.setdefault(
347            'here', os.path.dirname(os.path.abspath(filename)))
348        self.parser._defaults.setdefault(
349            '__file__', os.path.abspath(filename))
350
351    def update_defaults(self, new_defaults, overwrite=True):
352        for key, value in new_defaults.items():
353            if not overwrite and key in self.parser._defaults:
354                continue
355            self.parser._defaults[key] = value
356
357    def get_context(self, object_type, name=None, global_conf=None):
358        if self.absolute_name(name):
359            return loadcontext(object_type, name,
360                               relative_to=os.path.dirname(self.filename),
361                               global_conf=global_conf)
362        section = self.find_config_section(
363            object_type, name=name)
364        if global_conf is None:
365            global_conf = {}
366        else:
367            global_conf = global_conf.copy()
368        defaults = self.parser.defaults()
369        global_conf.update(defaults)
370        local_conf = {}
371        global_additions = {}
372        get_from_globals = {}
373        for option in self.parser.options(section):
374            if option.startswith('set '):
375                name = option[4:].strip()
376                global_additions[name] = global_conf[name] = (
377                    self.parser.get(section, option))
378            elif option.startswith('get '):
379                name = option[4:].strip()
380                get_from_globals[name] = self.parser.get(section, option)
381            else:
382                if option in defaults:
383                    # @@: It's a global option (?), so skip it
384                    continue
385                local_conf[option] = self.parser.get(section, option)
386        for local_var, glob_var in get_from_globals.items():
387            local_conf[local_var] = global_conf[glob_var]
388        if object_type in (APP, FILTER) and 'filter-with' in local_conf:
389            filter_with = local_conf.pop('filter-with')
390        else:
391            filter_with = None
392        if 'require' in local_conf:
393            for spec in local_conf['require'].split():
394                pkg_resources.require(spec)
395            del local_conf['require']
396        if section.startswith('filter-app:'):
397            context = self._filter_app_context(
398                object_type, section, name=name,
399                global_conf=global_conf, local_conf=local_conf,
400                global_additions=global_additions)
401        elif section.startswith('pipeline:'):
402            context = self._pipeline_app_context(
403                object_type, section, name=name,
404                global_conf=global_conf, local_conf=local_conf,
405                global_additions=global_additions)
406        elif 'use' in local_conf:
407            context = self._context_from_use(
408                object_type, local_conf, global_conf, global_additions,
409                section)
410        else:
411            context = self._context_from_explicit(
412                object_type, local_conf, global_conf, global_additions,
413                section)
414        if filter_with is not None:
415            filter_with_context = LoaderContext(
416                obj=None,
417                object_type=FILTER_WITH,
418                protocol=None,
419                global_conf=global_conf, local_conf=local_conf,
420                loader=self)
421            filter_with_context.filter_context = self.filter_context(
422                name=filter_with, global_conf=global_conf)
423            filter_with_context.next_context = context
424            return filter_with_context
425        return context
426
427    def _context_from_use(self, object_type, local_conf, global_conf,
428                          global_additions, section):
429        use = local_conf.pop('use')
430        context = self.get_context(
431            object_type, name=use, global_conf=global_conf)
432        context.global_conf.update(global_additions)
433        context.local_conf.update(local_conf)
434        if '__file__' in global_conf:
435            # use sections shouldn't overwrite the original __file__
436            context.global_conf['__file__'] = global_conf['__file__']
437        # @@: Should loader be overwritten?
438        context.loader = self
439        return context
440
441    def _context_from_explicit(self, object_type, local_conf, global_conf,
442                               global_addition, section):
443        possible = []
444        for protocol_options in object_type.egg_protocols:
445            for protocol in protocol_options:
446                if protocol in local_conf:
447                    possible.append((protocol, local_conf[protocol]))
448                    break
449        if len(possible) > 1:
450            raise LookupError(
451                "Multiple protocols given in section %r: %s"
452                % (section, possible))
453        if not possible:
454            raise LookupError(
455                "No loader given in section %r" % section)
456        found_protocol, found_expr = possible[0]
457        del local_conf[found_protocol]
458        value = import_string(found_expr)
459        context = LoaderContext(
460            value, object_type, found_protocol,
461            global_conf, local_conf, self)
462        return context
463
464    def _filter_app_context(self, object_type, section, name,
465                            global_conf, local_conf, global_additions):
466        if 'next' not in local_conf:
467            raise LookupError(
468                "The [%s] section in %s is missing a 'next' setting"
469                % (section, self.filename))
470        next_name = local_conf.pop('next')
471        context = LoaderContext(None, FILTER_APP, None, global_conf,
472                                local_conf, self)
473        context.next_context = self.get_context(
474            APP, next_name, global_conf)
475        if 'use' in local_conf:
476            context.filter_context = self._context_from_use(
477                FILTER, local_conf, global_conf, global_additions,
478                section)
479        else:
480            context.filter_context = self._context_from_explicit(
481                FILTER, local_conf, global_conf, global_additions,
482                section)
483        return context
484
485    def _pipeline_app_context(self, object_type, section, name,
486                              global_conf, local_conf, global_additions):
487        if 'pipeline' not in local_conf:
488            raise LookupError(
489                "The [%s] section in %s is missing a 'pipeline' setting"
490                % (section, self.filename))
491        pipeline = local_conf.pop('pipeline').split()
492        if local_conf:
493            raise LookupError(
494                "The [%s] pipeline section in %s has extra "
495                "(disallowed) settings: %s"
496                % (', '.join(local_conf.keys())))
497        context = LoaderContext(None, PIPELINE, None, global_conf,
498                                local_conf, self)
499        context.app_context = self.get_context(
500            APP, pipeline[-1], global_conf)
501        context.filter_contexts = [
502            self.get_context(FILTER, name, global_conf)
503            for name in pipeline[:-1]]
504        return context
505
506    def find_config_section(self, object_type, name=None):
507        """
508        Return the section name with the given name prefix (following the
509        same pattern as ``protocol_desc`` in ``config``.  It must have the
510        given name, or for ``'main'`` an empty name is allowed.  The
511        prefix must be followed by a ``:``.
512
513        Case is *not* ignored.
514        """
515        possible = []
516        for name_options in object_type.config_prefixes:
517            for name_prefix in name_options:
518                found = self._find_sections(
519                    self.parser.sections(), name_prefix, name)
520                if found:
521                    possible.extend(found)
522                    break
523        if not possible:
524            raise LookupError(
525                "No section %r (prefixed by %s) found in config %s"
526                % (name,
527                   ' or '.join(map(repr, _flatten(object_type.config_prefixes))),
528                   self.filename))
529        if len(possible) > 1:
530            raise LookupError(
531                "Ambiguous section names %r for section %r (prefixed by %s) "
532                "found in config %s"
533                % (possible, name,
534                   ' or '.join(map(repr, _flatten(object_type.config_prefixes))),
535                   self.filename))
536        return possible[0]
537
538    def _find_sections(self, sections, name_prefix, name):
539        found = []
540        if name is None:
541            if name_prefix in sections:
542                found.append(name_prefix)
543            name = 'main'
544        for section in sections:
545            if section.startswith(name_prefix+':'):
546                if section[len(name_prefix)+1:].strip() == name:
547                    found.append(section)
548        return found
549
550
551class EggLoader(_Loader):
552
553    def __init__(self, spec):
554        self.spec = spec
555
556    def get_context(self, object_type, name=None, global_conf=None):
557        if self.absolute_name(name):
558            return loadcontext(object_type, name,
559                               global_conf=global_conf)
560        entry_point, protocol, ep_name = self.find_egg_entry_point(
561            object_type, name=name)
562        return LoaderContext(
563            entry_point,
564            object_type,
565            protocol,
566            global_conf or {}, {},
567            self,
568            distribution=pkg_resources.get_distribution(self.spec),
569            entry_point_name=ep_name)
570
571    def find_egg_entry_point(self, object_type, name=None):
572        """
573        Returns the (entry_point, protocol) for the with the given
574        ``name``.
575        """
576        if name is None:
577            name = 'main'
578        possible = []
579        for protocol_options in object_type.egg_protocols:
580            for protocol in protocol_options:
581                pkg_resources.require(self.spec)
582                entry = pkg_resources.get_entry_info(
583                    self.spec,
584                    protocol,
585                    name)
586                if entry is not None:
587                    possible.append((entry.load(), protocol, entry.name))
588                    break
589        if not possible:
590            # Better exception
591            dist = pkg_resources.get_distribution(self.spec)
592            raise LookupError(
593                "Entry point %r not found in egg %r (dir: %s; protocols: %s; "
594                "entry_points: %s)"
595                % (name, self.spec,
596                   dist.location,
597                   ', '.join(_flatten(object_type.egg_protocols)),
598                   ', '.join(_flatten([
599                (pkg_resources.get_entry_info(self.spec, prot, name) or {}).keys()
600                for prot in protocol_options] or '(no entry points)'))))
601        if len(possible) > 1:
602            raise LookupError(
603                "Ambiguous entry points for %r in egg %r (protocols: %s)"
604                % (name, self.spec, ', '.join(_flatten(protocol_options))))
605        return possible[0]
606
607class LoaderContext(object):
608
609    def __init__(self, obj, object_type, protocol,
610                 global_conf, local_conf, loader,
611                 distribution=None, entry_point_name=None):
612        self.object = obj
613        self.object_type = object_type
614        self.protocol = protocol
615        #assert protocol in _flatten(object_type.egg_protocols), (
616        #    "Bad protocol %r; should be one of %s"
617        #    % (protocol, ', '.join(map(repr, _flatten(object_type.egg_protocols)))))
618        self.global_conf = global_conf
619        self.local_conf = local_conf
620        self.loader = loader
621        self.distribution = distribution
622        self.entry_point_name = entry_point_name
623
624    def create(self):
625        return self.object_type.invoke(self)
626
627    def config(self):
628        conf = AttrDict(self.global_conf)
629        conf.update(self.local_conf)
630        conf.local_conf = self.local_conf
631        conf.global_conf = self.global_conf
632        conf.context = self
633        return conf
634
635class AttrDict(dict):
636    """
637    A dictionary that can be assigned to.
638    """
639    pass
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。