Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/galaxy/util/pastescript/loadwsgi.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 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 | |
| 3 | |
| 4 # Mostly taken from PasteDeploy and stripped down for Galaxy | |
| 5 | |
| 6 import inspect | |
| 7 import os | |
| 8 import re | |
| 9 import sys | |
| 10 | |
| 11 import pkg_resources | |
| 12 from six import iteritems | |
| 13 from six.moves.urllib.parse import unquote | |
| 14 | |
| 15 from galaxy.util.getargspec import getfullargspec | |
| 16 from galaxy.util.properties import NicerConfigParser | |
| 17 | |
| 18 | |
| 19 __all__ = ('loadapp', 'loadserver', 'loadfilter', 'appconfig') | |
| 20 | |
| 21 # ---- from paste.deploy.compat -------------------------------------- | |
| 22 | |
| 23 """Python 2<->3 compatibility module""" | |
| 24 | |
| 25 | |
| 26 def print_(template, *args, **kwargs): | |
| 27 template = str(template) | |
| 28 if args: | |
| 29 template = template % args | |
| 30 elif kwargs: | |
| 31 template = template % kwargs | |
| 32 sys.stdout.writelines(template) | |
| 33 | |
| 34 | |
| 35 if sys.version_info < (3, 0): | |
| 36 def reraise(t, e, tb): | |
| 37 exec('raise t, e, tb', dict(t=t, e=e, tb=tb)) | |
| 38 else: | |
| 39 def reraise(t, e, tb): | |
| 40 exec('raise e from tb', dict(e=e, tb=tb)) | |
| 41 | |
| 42 # ---- from paste.deploy.util ---------------------------------------- | |
| 43 | |
| 44 | |
| 45 def fix_type_error(exc_info, callable, varargs, kwargs): | |
| 46 """ | |
| 47 Given an exception, this will test if the exception was due to a | |
| 48 signature error, and annotate the error with better information if | |
| 49 so. | |
| 50 | |
| 51 Usage:: | |
| 52 | |
| 53 try: | |
| 54 val = callable(*args, **kw) | |
| 55 except TypeError: | |
| 56 exc_info = fix_type_error(None, callable, args, kw) | |
| 57 raise exc_info[0], exc_info[1], exc_info[2] | |
| 58 """ | |
| 59 if exc_info is None: | |
| 60 exc_info = sys.exc_info() | |
| 61 if (exc_info[0] != TypeError or | |
| 62 str(exc_info[1]).find('argument') == -1 or | |
| 63 getattr(exc_info[1], '_type_error_fixed', False)): | |
| 64 return exc_info | |
| 65 exc_info[1]._type_error_fixed = True | |
| 66 argspec = inspect.formatargspec(*getfullargspec(callable)) | |
| 67 args = ', '.join(map(_short_repr, varargs)) | |
| 68 if kwargs and args: | |
| 69 args += ', ' | |
| 70 if kwargs: | |
| 71 kwargs = sorted(kwargs.keys()) | |
| 72 args += ', '.join('%s=...' % n for n in kwargs) | |
| 73 gotspec = '(%s)' % args | |
| 74 msg = '%s; got %s, wanted %s' % (exc_info[1], gotspec, argspec) | |
| 75 exc_info[1].args = (msg,) | |
| 76 return exc_info | |
| 77 | |
| 78 | |
| 79 def _short_repr(v): | |
| 80 v = repr(v) | |
| 81 if len(v) > 12: | |
| 82 v = v[:8] + '...' + v[-4:] | |
| 83 return v | |
| 84 | |
| 85 | |
| 86 def fix_call(callable, *args, **kw): | |
| 87 """ | |
| 88 Call ``callable(*args, **kw)`` fixing any type errors that come out. | |
| 89 """ | |
| 90 try: | |
| 91 val = callable(*args, **kw) | |
| 92 except TypeError: | |
| 93 exc_info = fix_type_error(None, callable, args, kw) | |
| 94 reraise(*exc_info) | |
| 95 return val | |
| 96 | |
| 97 | |
| 98 def lookup_object(spec): | |
| 99 """ | |
| 100 Looks up a module or object from a some.module:func_name specification. | |
| 101 To just look up a module, omit the colon and everything after it. | |
| 102 """ | |
| 103 parts, target = spec.split(':') if ':' in spec else (spec, None) | |
| 104 module = __import__(parts) | |
| 105 | |
| 106 for part in parts.split('.')[1:] + ([target] if target else []): | |
| 107 module = getattr(module, part) | |
| 108 | |
| 109 return module | |
| 110 | |
| 111 # ---- from paste.deploy.loadwsgi ------------------------------------ | |
| 112 | |
| 113 ############################################################ | |
| 114 # Utility functions | |
| 115 ############################################################ | |
| 116 | |
| 117 | |
| 118 def import_string(s): | |
| 119 return pkg_resources.EntryPoint.parse("x=" + s).load(False) | |
| 120 | |
| 121 | |
| 122 def _aslist(obj): | |
| 123 """ | |
| 124 Turn object into a list; lists and tuples are left as-is, None | |
| 125 becomes [], and everything else turns into a one-element list. | |
| 126 """ | |
| 127 if obj is None: | |
| 128 return [] | |
| 129 elif isinstance(obj, (list, tuple)): | |
| 130 return obj | |
| 131 else: | |
| 132 return [obj] | |
| 133 | |
| 134 | |
| 135 def _flatten(lst): | |
| 136 """ | |
| 137 Flatten a nested list. | |
| 138 """ | |
| 139 if not isinstance(lst, (list, tuple)): | |
| 140 return [lst] | |
| 141 result = [] | |
| 142 for item in lst: | |
| 143 result.extend(_flatten(item)) | |
| 144 return result | |
| 145 | |
| 146 | |
| 147 ############################################################ | |
| 148 # Object types | |
| 149 ############################################################ | |
| 150 | |
| 151 | |
| 152 class _ObjectType(object): | |
| 153 | |
| 154 name = None | |
| 155 egg_protocols = None | |
| 156 config_prefixes = None | |
| 157 | |
| 158 def __init__(self): | |
| 159 # Normalize these variables: | |
| 160 self.egg_protocols = [_aslist(p) for p in _aslist(self.egg_protocols)] | |
| 161 self.config_prefixes = [_aslist(p) for p in _aslist(self.config_prefixes)] | |
| 162 | |
| 163 def __repr__(self): | |
| 164 return '<%s protocols=%r prefixes=%r>' % ( | |
| 165 self.name, self.egg_protocols, self.config_prefixes) | |
| 166 | |
| 167 def invoke(self, context): | |
| 168 assert context.protocol in _flatten(self.egg_protocols) | |
| 169 return fix_call(context.object, | |
| 170 context.global_conf, **context.local_conf) | |
| 171 | |
| 172 | |
| 173 class _App(_ObjectType): | |
| 174 | |
| 175 name = 'application' | |
| 176 egg_protocols = ['paste.app_factory', 'paste.composite_factory', | |
| 177 'paste.composit_factory'] | |
| 178 config_prefixes = [['app', 'application'], ['composite', 'composit'], | |
| 179 'pipeline', 'filter-app'] | |
| 180 | |
| 181 def invoke(self, context): | |
| 182 if context.protocol in ('paste.composit_factory', | |
| 183 'paste.composite_factory'): | |
| 184 return fix_call(context.object, | |
| 185 context.loader, context.global_conf, | |
| 186 **context.local_conf) | |
| 187 elif context.protocol == 'paste.app_factory': | |
| 188 return fix_call(context.object, context.global_conf, **context.local_conf) | |
| 189 else: | |
| 190 assert 0, "Protocol %r unknown" % context.protocol | |
| 191 | |
| 192 | |
| 193 APP = _App() | |
| 194 | |
| 195 | |
| 196 class _Filter(_ObjectType): | |
| 197 name = 'filter' | |
| 198 egg_protocols = [['paste.filter_factory', 'paste.filter_app_factory']] | |
| 199 config_prefixes = ['filter'] | |
| 200 | |
| 201 def invoke(self, context): | |
| 202 if context.protocol == 'paste.filter_factory': | |
| 203 return fix_call(context.object, | |
| 204 context.global_conf, **context.local_conf) | |
| 205 elif context.protocol == 'paste.filter_app_factory': | |
| 206 def filter_wrapper(wsgi_app): | |
| 207 # This should be an object, so it has a nicer __repr__ | |
| 208 return fix_call(context.object, | |
| 209 wsgi_app, context.global_conf, | |
| 210 **context.local_conf) | |
| 211 return filter_wrapper | |
| 212 else: | |
| 213 assert 0, "Protocol %r unknown" % context.protocol | |
| 214 | |
| 215 | |
| 216 FILTER = _Filter() | |
| 217 | |
| 218 | |
| 219 class _Server(_ObjectType): | |
| 220 name = 'server' | |
| 221 egg_protocols = [['paste.server_factory', 'paste.server_runner']] | |
| 222 config_prefixes = ['server'] | |
| 223 | |
| 224 def invoke(self, context): | |
| 225 if context.protocol == 'paste.server_factory': | |
| 226 return fix_call(context.object, | |
| 227 context.global_conf, **context.local_conf) | |
| 228 elif context.protocol == 'paste.server_runner': | |
| 229 def server_wrapper(wsgi_app): | |
| 230 # This should be an object, so it has a nicer __repr__ | |
| 231 return fix_call(context.object, | |
| 232 wsgi_app, context.global_conf, | |
| 233 **context.local_conf) | |
| 234 return server_wrapper | |
| 235 else: | |
| 236 assert 0, "Protocol %r unknown" % context.protocol | |
| 237 | |
| 238 | |
| 239 SERVER = _Server() | |
| 240 | |
| 241 | |
| 242 # Virtual type: (@@: There's clearly something crufty here; | |
| 243 # this probably could be more elegant) | |
| 244 class _PipeLine(_ObjectType): | |
| 245 name = 'pipeline' | |
| 246 | |
| 247 def invoke(self, context): | |
| 248 app = context.app_context.create() | |
| 249 filters = [c.create() for c in context.filter_contexts] | |
| 250 filters.reverse() | |
| 251 for filter_ in filters: | |
| 252 app = filter_(app) | |
| 253 return app | |
| 254 | |
| 255 | |
| 256 PIPELINE = _PipeLine() | |
| 257 | |
| 258 | |
| 259 class _FilterApp(_ObjectType): | |
| 260 name = 'filter_app' | |
| 261 | |
| 262 def invoke(self, context): | |
| 263 next_app = context.next_context.create() | |
| 264 filter_ = context.filter_context.create() | |
| 265 return filter_(next_app) | |
| 266 | |
| 267 | |
| 268 FILTER_APP = _FilterApp() | |
| 269 | |
| 270 | |
| 271 class _FilterWith(_App): | |
| 272 name = 'filtered_with' | |
| 273 | |
| 274 def invoke(self, context): | |
| 275 filter_ = context.filter_context.create() | |
| 276 filtered = context.next_context.create() | |
| 277 if context.next_context.object_type is APP: | |
| 278 return filter_(filtered) | |
| 279 else: | |
| 280 # filtering a filter | |
| 281 def composed(app): | |
| 282 return filter_(filtered(app)) | |
| 283 return composed | |
| 284 | |
| 285 | |
| 286 FILTER_WITH = _FilterWith() | |
| 287 | |
| 288 ############################################################ | |
| 289 # Loaders | |
| 290 ############################################################ | |
| 291 | |
| 292 | |
| 293 def loadapp(uri, name=None, **kw): | |
| 294 return loadobj(APP, uri, name=name, **kw) | |
| 295 | |
| 296 | |
| 297 def loadfilter(uri, name=None, **kw): | |
| 298 return loadobj(FILTER, uri, name=name, **kw) | |
| 299 | |
| 300 | |
| 301 def loadserver(uri, name=None, **kw): | |
| 302 return loadobj(SERVER, uri, name=name, **kw) | |
| 303 | |
| 304 | |
| 305 def appconfig(uri, name=None, relative_to=None, global_conf=None): | |
| 306 context = loadcontext(APP, uri, name=name, | |
| 307 relative_to=relative_to, | |
| 308 global_conf=global_conf) | |
| 309 return context.config() | |
| 310 | |
| 311 | |
| 312 _loaders = {} | |
| 313 | |
| 314 | |
| 315 def loadobj(object_type, uri, name=None, relative_to=None, | |
| 316 global_conf=None): | |
| 317 context = loadcontext( | |
| 318 object_type, uri, name=name, relative_to=relative_to, | |
| 319 global_conf=global_conf) | |
| 320 return context.create() | |
| 321 | |
| 322 | |
| 323 def loadcontext(object_type, uri, name=None, relative_to=None, | |
| 324 global_conf=None): | |
| 325 if '#' in uri: | |
| 326 if name is None: | |
| 327 uri, name = uri.split('#', 1) | |
| 328 else: | |
| 329 # @@: Ignore fragment or error? | |
| 330 uri = uri.split('#', 1)[0] | |
| 331 if name is None: | |
| 332 name = 'main' | |
| 333 if ':' not in uri: | |
| 334 raise LookupError("URI has no scheme: %r" % uri) | |
| 335 scheme, path = uri.split(':', 1) | |
| 336 scheme = scheme.lower() | |
| 337 if scheme not in _loaders: | |
| 338 raise LookupError( | |
| 339 "URI scheme not known: %r (from %s)" | |
| 340 % (scheme, ', '.join(_loaders.keys()))) | |
| 341 return _loaders[scheme]( | |
| 342 object_type, | |
| 343 uri, path, name=name, relative_to=relative_to, | |
| 344 global_conf=global_conf) | |
| 345 | |
| 346 | |
| 347 def _loadconfig(object_type, uri, path, name, relative_to, | |
| 348 global_conf): | |
| 349 isabs = os.path.isabs(path) | |
| 350 # De-Windowsify the paths: | |
| 351 path = path.replace('\\', '/') | |
| 352 if not isabs: | |
| 353 if not relative_to: | |
| 354 raise ValueError( | |
| 355 "Cannot resolve relative uri %r; no relative_to keyword " | |
| 356 "argument given" % uri) | |
| 357 relative_to = relative_to.replace('\\', '/') | |
| 358 if relative_to.endswith('/'): | |
| 359 path = relative_to + path | |
| 360 else: | |
| 361 path = relative_to + '/' + path | |
| 362 if path.startswith('///'): | |
| 363 path = path[2:] | |
| 364 path = unquote(path) | |
| 365 loader = ConfigLoader(path) | |
| 366 if global_conf: | |
| 367 loader.update_defaults(global_conf, overwrite=False) | |
| 368 return loader.get_context(object_type, name, global_conf) | |
| 369 | |
| 370 | |
| 371 _loaders['config'] = _loadconfig | |
| 372 | |
| 373 | |
| 374 def _loadegg(object_type, uri, spec, name, relative_to, | |
| 375 global_conf): | |
| 376 loader = EggLoader(spec) | |
| 377 return loader.get_context(object_type, name, global_conf) | |
| 378 | |
| 379 | |
| 380 _loaders['egg'] = _loadegg | |
| 381 | |
| 382 | |
| 383 def _loadfunc(object_type, uri, spec, name, relative_to, | |
| 384 global_conf): | |
| 385 | |
| 386 loader = FuncLoader(spec) | |
| 387 return loader.get_context(object_type, name, global_conf) | |
| 388 | |
| 389 | |
| 390 _loaders['call'] = _loadfunc | |
| 391 | |
| 392 ############################################################ | |
| 393 # Loaders | |
| 394 ############################################################ | |
| 395 | |
| 396 | |
| 397 class _Loader(object): | |
| 398 | |
| 399 def get_app(self, name=None, global_conf=None): | |
| 400 return self.app_context( | |
| 401 name=name, global_conf=global_conf).create() | |
| 402 | |
| 403 def get_filter(self, name=None, global_conf=None): | |
| 404 return self.filter_context( | |
| 405 name=name, global_conf=global_conf).create() | |
| 406 | |
| 407 def get_server(self, name=None, global_conf=None): | |
| 408 return self.server_context( | |
| 409 name=name, global_conf=global_conf).create() | |
| 410 | |
| 411 def app_context(self, name=None, global_conf=None): | |
| 412 return self.get_context( | |
| 413 APP, name=name, global_conf=global_conf) | |
| 414 | |
| 415 def filter_context(self, name=None, global_conf=None): | |
| 416 return self.get_context( | |
| 417 FILTER, name=name, global_conf=global_conf) | |
| 418 | |
| 419 def server_context(self, name=None, global_conf=None): | |
| 420 return self.get_context( | |
| 421 SERVER, name=name, global_conf=global_conf) | |
| 422 | |
| 423 _absolute_re = re.compile(r'^[a-zA-Z]+:') | |
| 424 | |
| 425 def absolute_name(self, name): | |
| 426 """ | |
| 427 Returns true if the name includes a scheme | |
| 428 """ | |
| 429 if name is None: | |
| 430 return False | |
| 431 return self._absolute_re.search(name) | |
| 432 | |
| 433 | |
| 434 class ConfigLoader(_Loader): | |
| 435 | |
| 436 def __init__(self, filename): | |
| 437 self.filename = filename = filename.strip() | |
| 438 defaults = { | |
| 439 'here': os.path.dirname(os.path.abspath(filename)), | |
| 440 '__file__': os.path.abspath(filename) | |
| 441 } | |
| 442 self.parser = NicerConfigParser(filename, defaults=defaults) | |
| 443 self.parser.optionxform = str # Don't lower-case keys | |
| 444 with open(filename) as f: | |
| 445 self.parser.read_file(f) | |
| 446 | |
| 447 def update_defaults(self, new_defaults, overwrite=True): | |
| 448 for key, value in iteritems(new_defaults): | |
| 449 if not overwrite and key in self.parser._defaults: | |
| 450 continue | |
| 451 self.parser._defaults[key] = value | |
| 452 | |
| 453 def get_context(self, object_type, name=None, global_conf=None): | |
| 454 if self.absolute_name(name): | |
| 455 return loadcontext(object_type, name, | |
| 456 relative_to=os.path.dirname(self.filename), | |
| 457 global_conf=global_conf) | |
| 458 section = self.find_config_section( | |
| 459 object_type, name=name) | |
| 460 if global_conf is None: | |
| 461 global_conf = {} | |
| 462 else: | |
| 463 global_conf = global_conf.copy() | |
| 464 defaults = self.parser.defaults() | |
| 465 global_conf.update(defaults) | |
| 466 local_conf = {} | |
| 467 global_additions = {} | |
| 468 get_from_globals = {} | |
| 469 for option in self.parser.options(section): | |
| 470 if option.startswith('set '): | |
| 471 name = option[4:].strip() | |
| 472 global_additions[name] = global_conf[name] = ( | |
| 473 self.parser.get(section, option)) | |
| 474 elif option.startswith('get '): | |
| 475 name = option[4:].strip() | |
| 476 get_from_globals[name] = self.parser.get(section, option) | |
| 477 else: | |
| 478 if option in defaults: | |
| 479 # @@: It's a global option (?), so skip it | |
| 480 continue | |
| 481 local_conf[option] = self.parser.get(section, option) | |
| 482 for local_var, glob_var in get_from_globals.items(): | |
| 483 local_conf[local_var] = global_conf[glob_var] | |
| 484 if object_type in (APP, FILTER) and 'filter-with' in local_conf: | |
| 485 filter_with = local_conf.pop('filter-with') | |
| 486 else: | |
| 487 filter_with = None | |
| 488 if 'require' in local_conf: | |
| 489 for spec in local_conf['require'].split(): | |
| 490 pkg_resources.require(spec) | |
| 491 del local_conf['require'] | |
| 492 if section.startswith('filter-app:'): | |
| 493 context = self._filter_app_context( | |
| 494 object_type, section, name=name, | |
| 495 global_conf=global_conf, local_conf=local_conf, | |
| 496 global_additions=global_additions) | |
| 497 elif section.startswith('pipeline:'): | |
| 498 context = self._pipeline_app_context( | |
| 499 object_type, section, name=name, | |
| 500 global_conf=global_conf, local_conf=local_conf, | |
| 501 global_additions=global_additions) | |
| 502 elif 'use' in local_conf: | |
| 503 context = self._context_from_use( | |
| 504 object_type, local_conf, global_conf, global_additions, | |
| 505 section) | |
| 506 else: | |
| 507 context = self._context_from_explicit( | |
| 508 object_type, local_conf, global_conf, global_additions, | |
| 509 section) | |
| 510 if filter_with is not None: | |
| 511 filter_with_context = LoaderContext( | |
| 512 obj=None, | |
| 513 object_type=FILTER_WITH, | |
| 514 protocol=None, | |
| 515 global_conf=global_conf, local_conf=local_conf, | |
| 516 loader=self) | |
| 517 filter_with_context.filter_context = self.filter_context( | |
| 518 name=filter_with, global_conf=global_conf) | |
| 519 filter_with_context.next_context = context | |
| 520 return filter_with_context | |
| 521 return context | |
| 522 | |
| 523 def _context_from_use(self, object_type, local_conf, global_conf, | |
| 524 global_additions, section): | |
| 525 use = local_conf.pop('use') | |
| 526 context = self.get_context( | |
| 527 object_type, name=use, global_conf=global_conf) | |
| 528 context.global_conf.update(global_additions) | |
| 529 context.local_conf.update(local_conf) | |
| 530 if '__file__' in global_conf: | |
| 531 # use sections shouldn't overwrite the original __file__ | |
| 532 context.global_conf['__file__'] = global_conf['__file__'] | |
| 533 # @@: Should loader be overwritten? | |
| 534 context.loader = self | |
| 535 | |
| 536 if context.protocol is None: | |
| 537 # Determine protocol from section type | |
| 538 section_protocol = section.split(':', 1)[0] | |
| 539 if section_protocol in ('application', 'app'): | |
| 540 context.protocol = 'paste.app_factory' | |
| 541 elif section_protocol in ('composit', 'composite'): | |
| 542 context.protocol = 'paste.composit_factory' | |
| 543 else: | |
| 544 # This will work with 'server' and 'filter', otherwise it | |
| 545 # could fail but there is an error message already for | |
| 546 # bad protocols | |
| 547 context.protocol = 'paste.%s_factory' % section_protocol | |
| 548 | |
| 549 return context | |
| 550 | |
| 551 def _context_from_explicit(self, object_type, local_conf, global_conf, | |
| 552 global_addition, section): | |
| 553 possible = [] | |
| 554 for protocol_options in object_type.egg_protocols: | |
| 555 for protocol in protocol_options: | |
| 556 if protocol in local_conf: | |
| 557 possible.append((protocol, local_conf[protocol])) | |
| 558 break | |
| 559 if len(possible) > 1: | |
| 560 raise LookupError( | |
| 561 "Multiple protocols given in section %r: %s" | |
| 562 % (section, possible)) | |
| 563 if not possible: | |
| 564 raise LookupError( | |
| 565 "No loader given in section %r" % section) | |
| 566 found_protocol, found_expr = possible[0] | |
| 567 del local_conf[found_protocol] | |
| 568 value = import_string(found_expr) | |
| 569 context = LoaderContext( | |
| 570 value, object_type, found_protocol, | |
| 571 global_conf, local_conf, self) | |
| 572 return context | |
| 573 | |
| 574 def _filter_app_context(self, object_type, section, name, | |
| 575 global_conf, local_conf, global_additions): | |
| 576 if 'next' not in local_conf: | |
| 577 raise LookupError( | |
| 578 "The [%s] section in %s is missing a 'next' setting" | |
| 579 % (section, self.filename)) | |
| 580 next_name = local_conf.pop('next') | |
| 581 context = LoaderContext(None, FILTER_APP, None, global_conf, | |
| 582 local_conf, self) | |
| 583 context.next_context = self.get_context( | |
| 584 APP, next_name, global_conf) | |
| 585 if 'use' in local_conf: | |
| 586 context.filter_context = self._context_from_use( | |
| 587 FILTER, local_conf, global_conf, global_additions, | |
| 588 section) | |
| 589 else: | |
| 590 context.filter_context = self._context_from_explicit( | |
| 591 FILTER, local_conf, global_conf, global_additions, | |
| 592 section) | |
| 593 return context | |
| 594 | |
| 595 def _pipeline_app_context(self, object_type, section, name, | |
| 596 global_conf, local_conf, global_additions): | |
| 597 if 'pipeline' not in local_conf: | |
| 598 raise LookupError( | |
| 599 "The [%s] section in %s is missing a 'pipeline' setting" | |
| 600 % (section, self.filename)) | |
| 601 pipeline = local_conf.pop('pipeline').split() | |
| 602 if local_conf: | |
| 603 raise LookupError( | |
| 604 "The [%s] pipeline section in %s has extra " | |
| 605 "(disallowed) settings: %s" | |
| 606 % (', '.join(local_conf.keys()))) | |
| 607 context = LoaderContext(None, PIPELINE, None, global_conf, | |
| 608 local_conf, self) | |
| 609 context.app_context = self.get_context( | |
| 610 APP, pipeline[-1], global_conf) | |
| 611 context.filter_contexts = [ | |
| 612 self.get_context(FILTER, pname, global_conf) | |
| 613 for pname in pipeline[:-1]] | |
| 614 return context | |
| 615 | |
| 616 def find_config_section(self, object_type, name=None): | |
| 617 """ | |
| 618 Return the section name with the given name prefix (following the | |
| 619 same pattern as ``protocol_desc`` in ``config``. It must have the | |
| 620 given name, or for ``'main'`` an empty name is allowed. The | |
| 621 prefix must be followed by a ``:``. | |
| 622 | |
| 623 Case is *not* ignored. | |
| 624 """ | |
| 625 possible = [] | |
| 626 for name_options in object_type.config_prefixes: | |
| 627 for name_prefix in name_options: | |
| 628 found = self._find_sections( | |
| 629 self.parser.sections(), name_prefix, name) | |
| 630 if found: | |
| 631 possible.extend(found) | |
| 632 break | |
| 633 if not possible: | |
| 634 raise LookupError( | |
| 635 "No section %r (prefixed by %s) found in config %s" | |
| 636 % (name, | |
| 637 ' or '.join(map(repr, _flatten(object_type.config_prefixes))), | |
| 638 self.filename)) | |
| 639 if len(possible) > 1: | |
| 640 raise LookupError( | |
| 641 "Ambiguous section names %r for section %r (prefixed by %s) " | |
| 642 "found in config %s" | |
| 643 % (possible, name, | |
| 644 ' or '.join(map(repr, _flatten(object_type.config_prefixes))), | |
| 645 self.filename)) | |
| 646 return possible[0] | |
| 647 | |
| 648 def _find_sections(self, sections, name_prefix, name): | |
| 649 found = [] | |
| 650 if name is None: | |
| 651 if name_prefix in sections: | |
| 652 found.append(name_prefix) | |
| 653 name = 'main' | |
| 654 for section in sections: | |
| 655 if section.startswith(name_prefix + ':'): | |
| 656 if section[len(name_prefix) + 1:].strip() == name: | |
| 657 found.append(section) | |
| 658 return found | |
| 659 | |
| 660 | |
| 661 class EggLoader(_Loader): | |
| 662 | |
| 663 def __init__(self, spec): | |
| 664 self.spec = spec | |
| 665 | |
| 666 def get_context(self, object_type, name=None, global_conf=None): | |
| 667 if self.absolute_name(name): | |
| 668 return loadcontext(object_type, name, | |
| 669 global_conf=global_conf) | |
| 670 entry_point, protocol, ep_name = self.find_egg_entry_point( | |
| 671 object_type, name=name) | |
| 672 return LoaderContext( | |
| 673 entry_point, | |
| 674 object_type, | |
| 675 protocol, | |
| 676 global_conf or {}, {}, | |
| 677 self, | |
| 678 distribution=pkg_resources.get_distribution(self.spec), | |
| 679 entry_point_name=ep_name) | |
| 680 | |
| 681 def find_egg_entry_point(self, object_type, name=None): | |
| 682 """ | |
| 683 Returns the (entry_point, protocol) for the with the given | |
| 684 ``name``. | |
| 685 """ | |
| 686 if name is None: | |
| 687 name = 'main' | |
| 688 possible = [] | |
| 689 for protocol_options in object_type.egg_protocols: | |
| 690 for protocol in protocol_options: | |
| 691 pkg_resources.require(self.spec) | |
| 692 entry = pkg_resources.get_entry_info( | |
| 693 self.spec, | |
| 694 protocol, | |
| 695 name) | |
| 696 if entry is not None: | |
| 697 possible.append((entry.load(), protocol, entry.name)) | |
| 698 break | |
| 699 if not possible: | |
| 700 # Better exception | |
| 701 dist = pkg_resources.get_distribution(self.spec) | |
| 702 raise LookupError( | |
| 703 "Entry point %r not found in egg %r (dir: %s; protocols: %s; " | |
| 704 "entry_points: %s)" | |
| 705 % (name, self.spec, | |
| 706 dist.location, | |
| 707 ', '.join(_flatten(object_type.egg_protocols)), | |
| 708 ', '.join(_flatten([ | |
| 709 list((pkg_resources.get_entry_info(self.spec, prot, name) or {}).keys()) | |
| 710 for prot in protocol_options] or '(no entry points)')))) | |
| 711 if len(possible) > 1: | |
| 712 raise LookupError( | |
| 713 "Ambiguous entry points for %r in egg %r (protocols: %s)" | |
| 714 % (name, self.spec, ', '.join(_flatten(protocol_options)))) | |
| 715 return possible[0] | |
| 716 | |
| 717 | |
| 718 class FuncLoader(_Loader): | |
| 719 """ Loader that supports specifying functions inside modules, without | |
| 720 using eggs at all. Configuration should be in the format: | |
| 721 use = call:my.module.path:function_name | |
| 722 | |
| 723 Dot notation is supported in both the module and function name, e.g.: | |
| 724 use = call:my.module.path:object.method | |
| 725 """ | |
| 726 | |
| 727 def __init__(self, spec): | |
| 728 self.spec = spec | |
| 729 if ':' not in spec: | |
| 730 raise LookupError("Configuration not in format module:function") | |
| 731 | |
| 732 def get_context(self, object_type, name=None, global_conf=None): | |
| 733 obj = lookup_object(self.spec) | |
| 734 return LoaderContext( | |
| 735 obj, | |
| 736 object_type, | |
| 737 None, # determine protocol from section type | |
| 738 global_conf or {}, | |
| 739 {}, | |
| 740 self, | |
| 741 ) | |
| 742 | |
| 743 | |
| 744 class LoaderContext(object): | |
| 745 | |
| 746 def __init__(self, obj, object_type, protocol, | |
| 747 global_conf, local_conf, loader, | |
| 748 distribution=None, entry_point_name=None): | |
| 749 self.object = obj | |
| 750 self.object_type = object_type | |
| 751 self.protocol = protocol | |
| 752 # assert protocol in _flatten(object_type.egg_protocols), ( | |
| 753 # "Bad protocol %r; should be one of %s" | |
| 754 # % (protocol, ', '.join(map(repr, _flatten(object_type.egg_protocols))))) | |
| 755 self.global_conf = global_conf | |
| 756 self.local_conf = local_conf | |
| 757 self.loader = loader | |
| 758 self.distribution = distribution | |
| 759 self.entry_point_name = entry_point_name | |
| 760 | |
| 761 def create(self): | |
| 762 return self.object_type.invoke(self) | |
| 763 | |
| 764 def config(self): | |
| 765 conf = AttrDict(self.global_conf) | |
| 766 conf.update(self.local_conf) | |
| 767 conf.local_conf = self.local_conf | |
| 768 conf.global_conf = self.global_conf | |
| 769 conf.context = self | |
| 770 return conf | |
| 771 | |
| 772 | |
| 773 class AttrDict(dict): | |
| 774 """ | |
| 775 A dictionary that can be assigned to. | |
| 776 """ | |
| 777 pass |
