def addRequestContainer(app, environ=None): """Add the request container with a fake request to the app object's acquisition context and return the wrapped app object. Additional request environment values can be passed as a dict ``environ``. """ from sys import stdin, stdout from ZPublisher.HTTPRequest import HTTPRequest from ZPublisher.HTTPResponse import HTTPResponse from ZPublisher.BaseRequest import RequestContainer from zope.publisher.browser import setDefaultSkin if environ is None: environ = {} environ.setdefault('SERVER_NAME', 'nohost') environ.setdefault('SERVER_PORT', 'port') environ.setdefault('REQUEST_METHOD', 'GET') resp = HTTPResponse(stdout=stdout) req = HTTPRequest(stdin, environ, resp) req._steps = ['noobject'] # Fake a published object. setDefaultSkin(req) requestcontainer = RequestContainer(REQUEST=req) return app.__of__(requestcontainer)
def wsgi_publish(environ, start_response): """ copied from publish_module in ZPublisher/Test.py, simplified, and modified to accept streaming responses """ from ZPublisher.Request import Request from ZPublisher.Publish import publish from ZServer.HTTPResponse import ZServerHTTPResponse from zope.publisher.browser import setDefaultSkin from StringIO import StringIO outstream = StringIO() must_die=0 after_list=[None] response = ZServerHTTPResponse(stdout=outstream, stderr=sys.stderr) stdout = response.stdout request = Request(environ['wsgi.input'], environ, response) try: try: setDefaultSkin(request) response = publish(request, 'Zope2', after_list, debug=0) except SystemExit, v: must_die=sys.exc_info() response.exception(must_die) except ImportError, v: if isinstance(v, tuple) and len(v)==3: must_die=v else: must_die=sys.exc_info() response.exception(1, v)
def __call__(self, input_stream, env, output_stream=None): """See `zope.app.publication.interfaces.IPublicationRequestFactory`""" # BBB: This is backward-compatibility support for the deprecated # output stream. try: env.get except AttributeError: import warnings warnings.warn( "Can't pass output streams to requests anymore. " "This will go away in Zope 3.4.", DeprecationWarning, 2) env, output_stream = output_stream, env method = env.get('REQUEST_METHOD', 'GET').upper() request_class, publication_class = chooseClasses(method, env) publication = self._publication_cache.get(publication_class) if publication is None: publication = publication_class(self._db) self._publication_cache[publication_class] = publication request = request_class(input_stream, env) request.setPublication(publication) if IBrowserRequest.providedBy(request): # only browser requests have skins setDefaultSkin(request) return request
def publish_module_standard(module_name, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, environ=os.environ, debug=0, request=None, response=None): must_die = 0 status = 200 after_list = [None] try: try: if response is None: response = Response(stdout=stdout, stderr=stderr) else: stdout = response.stdout if request is None: request = Request(stdin, environ, response) # make sure that the request we hand over has the # default layer/skin set on it; subsequent code that # wants to look up views will likely depend on it setDefaultSkin(request) response = publish(request, module_name, after_list, debug=debug) except SystemExit, v: must_die = sys.exc_info() request.response.exception(must_die) except ImportError, v: if isinstance(v, tuple) and len(v) == 3: must_die = v elif hasattr(sys, 'exc_info'): must_die = sys.exc_info() else: must_die = SystemExit, v, sys.exc_info()[2] request.response.exception(1, v)
def afterSetUp(self): # We need to fiddle the request for zope 2.9+ setDefaultSkin(self.app.REQUEST) self.folder.invokeFactory('Document', 'test', title='Test default page') self.view = Plone(self.portal, self.app.REQUEST) self.view._initializeData()
def test_browserSaveSubscriptions(self): self.login('member') sm = SubscriptionManager(self.portal) request = TestRequest() setDefaultSkin(request) view = getMultiAdapter((self.portal, request), name='subscriptions_config.html') for x in view.subscriptions(): self.failIf(x['subscribed_email']) # string values here mean nothing, the parameter just needs to # be in the request. request = TestRequest(form={'email_Advisory': 'yes', 'email_Study': 'yes'}) view = getMultiAdapter((self.portal, request), name='subscriptions_config.html') view._saveSubscriptions() for x in sm.subscriptions: if x.id in ('Advisory', 'Study'): self.failUnless(x.email) else: self.failIf(x.email) self.logout()
def _get_request_interfaces(self): request = TestRequest() setDefaultSkin(request) orig_iro = list(directlyProvidedBy(request).__iro__) directlyProvides(request, [self.additive_layer] + orig_iro) notify(BeforeTraverseEvent(self.portal, request)) iro = list(request.__provides__.__iro__) return iro
def _get_request_interfaces(self): request = self.layer['request'] setDefaultSkin(request) orig_iro = list(directlyProvidedBy(request).__iro__) directlyProvides(request, [self.additive_layer] + orig_iro) # Reset markers so that we can still register new skins and browserlayers del request._plonebrowserlayer_ del request._plonetheme_ notify(BeforeTraverseEvent(self.portal, request)) iro = list(request.__provides__.__iro__) return iro
def make_request(): """ make request suitable for browser views and Zope2 security. """ response = HTTPResponse(stdout=sys.stdout) request = HTTPRequest( sys.stdin, {"SERVER_NAME": "localhost", "SERVER_PORT": "80", "REQUEST_METHOD": "GET"}, response ) setDefaultSkin(request) alsoProvides(request, IFormLayer) # suitable for testing z3c.form views alsoProvides(request, ITeamworkProductLayer) # product layer return request
def test_request(): """ make request suitable for browser views and Zope2 security. """ response = HTTPResponse(stdout=sys.stdout) request = HTTPRequest( sys.stdin, {"SERVER_NAME": "localhost", "SERVER_PORT": "80", "REQUEST_METHOD": "GET"}, response ) request["ACTUAL_URL"] = "http://nohost/plone" setDefaultSkin(request) alsoProvides(request, IFormLayer) # suitable for testing z3c.form views return request
def test_browserAddTheme(self): request = TestRequest() setDefaultSkin(request) view = getMultiAdapter((self.portal, request), name='minaraad_config.html') lastId = max([x[0] for x in view.themeManager.themes]) request.form['theme_name'] = 'blah' view._addTheme() self.failUnless(view.themeManager.themes[-1] == (lastId + 1, 'blah'))
def test_request(): """ make request suitable for browser views and Zope2 security. """ response = HTTPResponse(stdout=sys.stdout) request = HTTPRequest(sys.stdin, { 'SERVER_NAME': 'localhost', 'SERVER_PORT': '80', 'REQUEST_METHOD': 'GET', }, response) request['ACTUAL_URL'] = 'http://nohost/plone/myform' setDefaultSkin(request) alsoProvides(request, IFormLayer) # suitable for testing z3c.form views return request
def test_browserSaveThemes(self): request = TestRequest() setDefaultSkin(request) view = getMultiAdapter((self.portal, request), name='minaraad_config.html') view.themeManager.themes = [(1, 'a'), (2, 'b'), (3, 'c')] request.form['theme_1'] = 'x' request.form['theme_3'] = 'z' view._saveThemes() self.failUnless(view.themeManager.themes == [(1, 'x'), (2, 'b'), (3, 'z')])
def test_browserThemes(self): request = TestRequest() setDefaultSkin(request) view = getMultiAdapter((self.portal, request), name='minaraad_config.html') themes = [(1, 'a'), (2, 'b'), (3, 'c')] themesDict = [{'id': id, 'Title': title} for id, title in themes] view.themeManager.themes = themes self.failUnless(view.themes() == themesDict) request.form['form.button.Edit'] = True request.form['theme_2'] = 'b' self.failUnless(view.themes() == [{'id': 2, 'Title': 'b'}])
def _request(self, path='/', stdin='', basic=None, environment = None, form=None, request=None, publication=BrowserPublication): """Create a request """ env = {} if isinstance(stdin, text_type): stdin = stdin.encode("utf-8") if isinstance(stdin, bytes): stdin = BytesIO(stdin) p = path.split('?') if len(p) == 1: env['PATH_INFO'] = p[0] elif len(p) == 2: env['PATH_INFO'], env['QUERY_STRING'] = p else: raise ValueError("Too many ?s in path", path) env['PATH_INFO'] = urllib.unquote(env['PATH_INFO']) if environment is not None: env.update(environment) if basic: basic_bytes = basic.encode('ascii') if not isinstance(basic, bytes) else basic basic64_bytes = base64.b64encode(basic_bytes) basic64 = basic64_bytes.decode('ascii').strip() env['HTTP_AUTHORIZATION'] = "Basic %s" % basic64 pub = publication(self.db) if request is not None: request = request(stdin, env) else: request = TestRequest(stdin, env) setDefaultSkin(request) request.setPublication(pub) if form: request.form.update(form) return request
def make_request(): """ make request suitable for browser views and Zope2 security. """ response = HTTPResponse(stdout=sys.stdout) request = HTTPRequest( sys.stdin, { 'SERVER_NAME': 'localhost', 'SERVER_PORT': '80', 'REQUEST_METHOD': 'GET', }, response, ) setDefaultSkin(request) alsoProvides(request, IFormLayer) # suitable for testing z3c.form views alsoProvides(request, ITeamworkProductLayer) # product layer return request
def make_request(): """ make request suitable for browser views and Zope2 security. """ response = HTTPResponse(stdout=sys.stdout) request = HTTPRequest( sys.stdin, { 'SERVER_NAME': 'localhost', 'SERVER_PORT': '80', 'REQUEST_METHOD': 'GET', }, response, ) setDefaultSkin(request) alsoProvides(request, IFormLayer) # suitable for testing z3c.form views alsoProvides(request, IQIExtranetProductLayer) # product layer return request
def test_request(): """ make request suitable for browser views and Zope2 security. """ response = HTTPResponse(stdout=sys.stdout) request = HTTPRequest( sys.stdin, { 'SERVER_NAME': 'localhost', 'SERVER_PORT': '80', 'REQUEST_METHOD': 'GET', }, response ) request['ACTUAL_URL'] = 'http://nohost/plone/myform' setDefaultSkin(request) alsoProvides(request, IFormLayer) # suitable for testing z3c.form views return request
def makerequest(app, stdout=None, environ=None): """ Adds an HTTPRequest at app.REQUEST, and returns app.__of__(app.REQUEST). Useful for tests that need to acquire REQUEST. Usage: import makerequest app = makerequest.makerequest(app) You should only wrap the object used as 'root' in your tests. app is commonly a Zope2.app(), but that's not strictly necessary and frequently may be overkill; you can wrap other objects as long as they support acquisition and provide enough of the features of Zope2.app for your tests to run. For example, if you want to call getPhysicalPath() on child objects, app must provide a non-recursive implementation of getPhysicalPath(). *stdout* is an optional file-like object and is used by REQUEST.RESPONSE. The default is sys.stdout. *environ* is an optional mapping to be used in the request. Default is a fresh dictionary. Passing os.environ is not recommended; tests should not pollute the real os.environ. """ if stdout is None: stdout = BytesIO() if environ is None: environ = {} resp = HTTPResponse(stdout=stdout) environ.setdefault('SERVER_NAME', 'nohost') environ.setdefault('SERVER_PORT', '80') environ.setdefault('REQUEST_METHOD', 'GET') req = HTTPRequest(BytesIO(), environ, resp) req._steps = ['noobject'] # Fake a published object. req['ACTUAL_URL'] = req.get('URL') # Zope 2.7.4 # Set default skin so that the request is usable for view look-ups. from zope.publisher.browser import setDefaultSkin setDefaultSkin(req) requestcontainer = RequestContainer(REQUEST=req) return app.__of__(requestcontainer)
def _request(self, path='/', stdin='', basic=None, environment = None, form=None, request=None, publication=BrowserPublication): """Create a request """ env = {} if type(stdin) is str: stdin = StringIO(stdin) p=path.split('?') if len(p)==1: env['PATH_INFO'] = p[0] elif len(p)==2: env['PATH_INFO'], env['QUERY_STRING'] = p else: raise ValueError("Too many ?s in path", path) env['PATH_INFO'] = urllib.unquote(env['PATH_INFO']) if environment is not None: env.update(environment) if basic: env['HTTP_AUTHORIZATION']="Basic %s" % base64.encodestring(basic) pub = publication(self.db) if request is not None: request = request(stdin, env) else: request = TestRequest(stdin, env) setDefaultSkin(request) request.setPublication(pub) if form: # This requires that request class has an attribute 'form' # (BrowserRequest has, TestRequest hasn't) request.form.update(form) return request
def makeTestRequest(environ=None): """Return an HTTPRequest object suitable for testing views.""" from sys import stdin, stdout from ZPublisher.HTTPRequest import HTTPRequest from ZPublisher.HTTPResponse import HTTPResponse from zope.publisher.browser import setDefaultSkin if environ is None: environ = {} environ.setdefault('SERVER_NAME', 'foo') environ.setdefault('SERVER_PORT', '80') environ.setdefault('REQUEST_METHOD', 'GET') resp = HTTPResponse(stdout=stdout) req = HTTPRequest(stdin, environ, resp) req._steps = ['noobject'] # Fake a published object. req['ACTUAL_URL'] = req.get('URL') setDefaultSkin(req) return req
def makeTestRequest(environ=None): """Return an HTTPRequest object suitable for testing views.""" from sys import stdin, stdout from zope.publisher.browser import setDefaultSkin from ZPublisher.HTTPRequest import HTTPRequest from ZPublisher.HTTPResponse import HTTPResponse if environ is None: environ = {} environ.setdefault('SERVER_NAME', 'foo') environ.setdefault('SERVER_PORT', '80') environ.setdefault('REQUEST_METHOD', 'GET') resp = HTTPResponse(stdout=stdout) req = HTTPRequest(stdin, environ, resp) req._steps = ['noobject'] # Fake a published object. req['ACTUAL_URL'] = req.get('URL') setDefaultSkin(req) return req
def test_browserSubscriptions(self): self.login('member') request = TestRequest() setDefaultSkin(request) view = getMultiAdapter((self.portal, request), name='subscriptions_config.html') sm = SubscriptionManager(self.portal) subscriptions = view.subscriptions() self.failUnless(len(sm.subscriptions) == len(subscriptions)) subDict = {} for x in subscriptions: subDict[x['id']] = x for x in sm.subscriptions: self.failUnless(x.id in subDict) self.logout()
def publish_module(module_name, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, environ=os.environ, debug=0, request=None, response=None, extra={}): must_die = 0 status = 200 after_list = [None] from Response import Response from Request import Request from Publish import publish try: try: if response is None: response = Response(stdout=stdout, stderr=stderr) else: stdout = response.stdout if request is None: request = Request(stdin, environ, response) # make sure that the request we hand over has the # default layer/skin set on it; subsequent code that # wants to look up views will likely depend on it from zope.publisher.browser import setDefaultSkin setDefaultSkin(request) for k, v in extra.items(): request[k] = v response = publish(request, module_name, after_list, debug=debug) except SystemExit, v: must_die = sys.exc_info() response.exception(must_die) except ImportError, v: if isinstance(v, TupleType) and len(v) == 3: must_die = v else: must_die = sys.exc_info() response.exception(1, v)
def test_retry_keeps_everything(self): """lowlevel test for retry (see #98440)""" from zope.publisher.browser import TestRequest, setDefaultSkin from zope.publisher.interfaces.browser import IDefaultSkin, IBrowserRequest # create a retryable request request = TestRequest() self.assertTrue(request.supportsRetry()) # create a skin and register it as the default skin class ISomeSkin(Interface): pass provideAdapter(ISomeSkin, (IBrowserRequest, ), IDefaultSkin) # set the default skin for the request setDefaultSkin(request) # create a retried request retried = request.retry() # the requests are not the same self.assertTrue(request is not retried) # the requests both provide the default skin self.assertTrue(ISomeSkin.providedBy(request)) self.assertTrue(ISomeSkin.providedBy(retried))
def publish( request, module_name, after_list, debug=0, # Optimize: call_object=call_object, missing_name=missing_name, dont_publish_class=dont_publish_class, mapply=mapply, ): (bobo_before, bobo_after, object, realm, debug_mode, err_hook, validated_hook, transactions_manager) = get_module_info(module_name) parents = None response = None try: # TODO pass request here once BaseRequest implements IParticipation newInteraction() request.processInputs() request_get = request.get response = request.response # First check for "cancel" redirect: if request_get('SUBMIT', '').strip().lower() == 'cancel': cancel = request_get('CANCEL_ACTION', '') if cancel: raise Redirect, cancel after_list[0] = bobo_after if debug_mode: response.debug_mode = debug_mode if realm and not request.get('REMOTE_USER', None): response.realm = realm if bobo_before is not None: bobo_before() # Get the path list. # According to RFC1738 a trailing space in the path is valid. path = request_get('PATH_INFO') request['PARENTS'] = parents = [object] if transactions_manager: transactions_manager.begin() object = request.traverse(path, validated_hook=validated_hook) if transactions_manager: transactions_manager.recordMetaData(object, request) result = mapply(object, request.args, request, call_object, 1, missing_name, dont_publish_class, request, bind=1) if result is not response: response.setBody(result) if transactions_manager: transactions_manager.commit() endInteraction() return response except: # DM: provide nicer error message for FTP sm = None if response is not None: sm = getattr(response, "setMessage", None) if sm is not None: from asyncore import compact_traceback cl, val = sys.exc_info()[:2] sm('%s: %s %s' % (getattr(cl, '__name__', cl), val, debug_mode and compact_traceback()[-1] or '')) if err_hook is not None: if parents: parents = parents[0] try: try: return err_hook( parents, request, sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], ) except Retry: if not request.supports_retry(): return err_hook( parents, request, sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], ) finally: if transactions_manager: transactions_manager.abort() endInteraction() # Only reachable if Retry is raised and request supports retry. newrequest = request.retry() request.close() # Free resources held by the request. # Set the default layer/skin on the newly generated request setDefaultSkin(newrequest) try: return publish(newrequest, module_name, after_list, debug) finally: newrequest.close() else: if transactions_manager: transactions_manager.abort() endInteraction() raise
def publish(request, module_name, after_list, debug=0, call_object=call_object, missing_name=missing_name, dont_publish_class=dont_publish_class, mapply=mapply, ): (bobo_before, bobo_after, object, realm, debug_mode, err_hook, validated_hook, transactions_manager)= get_module_info(module_name) parents=None response=None try: # TODO pass request here once BaseRequest implements IParticipation newInteraction() request.processInputs() request_get=request.get response=request.response # First check for "cancel" redirect: if request_get('SUBMIT', '').strip().lower()=='cancel': cancel=request_get('CANCEL_ACTION', '') if cancel: raise Redirect(cancel) after_list[0]=bobo_after if debug_mode: response.debug_mode=debug_mode if realm and not request.get('REMOTE_USER', None): response.realm=realm if bobo_before is not None: bobo_before() # Get the path list. # According to RFC1738 a trailing space in the path is valid. path=request_get('PATH_INFO') request['PARENTS']=parents=[object] if transactions_manager: transactions_manager.begin() object=request.traverse(path, validated_hook=validated_hook) if transactions_manager: transactions_manager.recordMetaData(object, request) result=mapply(object, request.args, request, call_object, 1, missing_name, dont_publish_class, request, bind=1) if result is not response: response.setBody(result) if transactions_manager: transactions_manager.commit() endInteraction() return response except: # DM: provide nicer error message for FTP sm = None if response is not None: sm = getattr(response, "setMessage", None) if sm is not None: from asyncore import compact_traceback cl, val= sys.exc_info()[:2] sm('%s: %s %s' % ( getattr(cl, '__name__', cl), val, debug_mode and compact_traceback()[-1] or '')) if ISOAPRequest.providedBy(request): if transactions_manager: transactions_manager.abort() endInteraction() if response is None: response = SOAPResponse(request.response) response.exception() return response if err_hook is not None: if parents: parents=parents[0] try: try: return err_hook(parents, request, sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], ) except Retry: if not request.supports_retry(): return err_hook(parents, request, sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], ) finally: if transactions_manager: transactions_manager.abort() endInteraction() # Only reachable if Retry is raised and request supports retry. newrequest=request.retry() request.close() # Free resources held by the request. # Set the default layer/skin on the newly generated request setDefaultSkin(newrequest) try: return publish(newrequest, module_name, after_list, debug) finally: newrequest.close() else: if transactions_manager: transactions_manager.abort() endInteraction() raise
def publish(request, module_name, after_list, debug=0, # Optimize: call_object=call_object, missing_name=missing_name, dont_publish_class=dont_publish_class, mapply=mapply, ): (bobo_before, bobo_after, object, realm, debug_mode, err_hook, validated_hook, transactions_manager)= get_module_info(module_name) parents=None response=None try: notify(PubStart(request)) # TODO pass request here once BaseRequest implements IParticipation newInteraction() request.processInputs() request_get=request.get response=request.response # First check for "cancel" redirect: if request_get('SUBMIT','').strip().lower()=='cancel': cancel=request_get('CANCEL_ACTION','') if cancel: raise Redirect, cancel after_list[0]=bobo_after if debug_mode: response.debug_mode=debug_mode if realm and not request.get('REMOTE_USER',None): response.realm=realm if bobo_before is not None: bobo_before() # Get the path list. # According to RFC1738 a trailing space in the path is valid. path=request_get('PATH_INFO') request['PARENTS']=parents=[object] if transactions_manager: transactions_manager.begin() object=request.traverse(path, validated_hook=validated_hook) notify(PubAfterTraversal(request)) if transactions_manager: transactions_manager.recordMetaData(object, request) result=mapply(object, request.args, request, call_object,1, missing_name, dont_publish_class, request, bind=1) if result is not response: response.setBody(result) notify(PubBeforeCommit(request)) if transactions_manager: transactions_manager.commit() endInteraction() notify(PubSuccess(request)) return response except: # save in order to give 'PubFailure' the original exception info exc_info = sys.exc_info() # DM: provide nicer error message for FTP sm = None if response is not None: sm = getattr(response, "setMessage", None) if sm is not None: from asyncore import compact_traceback cl,val= sys.exc_info()[:2] sm('%s: %s %s' % ( getattr(cl,'__name__',cl), val, debug_mode and compact_traceback()[-1] or '')) # debug is just used by tests (has nothing to do with debug_mode!) # XXX begin monkeypatch if ISOAPRequest.providedBy(request): if transactions_manager: transactions_manager.abort() endInteraction() if response is None: response = SOAPResponse(request.response) if isinstance(exc_info[1], Unauthorized): response._unauthorized() else: response.exception() return response # XXX end monkeypatch if not debug and err_hook is not None: retry = False if parents: parents=parents[0] try: try: return err_hook(parents, request, sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], ) except Retry: if not request.supports_retry(): return err_hook(parents, request, sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2], ) retry = True finally: # Note: 'abort's can fail. Nevertheless, we want end request handling try: try: notify(PubBeforeAbort(request, exc_info, retry)) finally: if transactions_manager: transactions_manager.abort() finally: endInteraction() notify(PubFailure(request, exc_info, retry)) # Only reachable if Retry is raised and request supports retry. newrequest=request.retry() request.close() # Free resources held by the request. # Set the default layer/skin on the newly generated request if ISkinnable.providedBy(newrequest): setDefaultSkin(newrequest) try: return publish(newrequest, module_name, after_list, debug) finally: newrequest.close() else: # Note: 'abort's can fail. Nevertheless, we want end request handling try: try: notify(PubBeforeAbort(request, exc_info, False)) finally: if transactions_manager: transactions_manager.abort() finally: endInteraction() notify(PubFailure(request, exc_info, False)) raise
def trustedTraverse( ob, path, ignored, ): if not path: return self get = getattr has = hasattr N = None M = rebindFunction # artifical marker if isinstance(path, str): path = path.split('/') else: path = list(path) REQUEST = get(ob, 'REQUEST', None) if REQUEST is None: REQUEST = FakeRequest() setDefaultSkin(REQUEST) REQUEST['TraversalRequestNameStack'] = path path.reverse() pop = path.pop if len(path) > 1 and not path[0]: # Remove trailing slash path.pop(0) if not path[-1]: # If the path starts with an empty string, go to the root first. pop() self = ob.getPhysicalRoot() object = ob while path: name = pop() __traceback_info__ = path, name if name == '..': o = getattr(object, 'aq_parent', M) if o is not M: object = o continue if name and name[:1] in '@+': # Process URI segment parameters. ns, nm = nsParse(name) if ns: try: o = namespaceLookup(ns, nm, object, REQUEST).__of__(object) except TraversalError: raise KeyError(name) object = o continue t = get(object, '__bobo_traverse__', M) if t is not M: o = t(REQUEST, name) else: o = get(object, name, M) if o is M: try: o = object[name] except (AttributeError, TypeError): # better exception o = queryMultiAdapter((object, REQUEST), Interface, name) if o is not None: o = o.__of__(object) else: raise AttributeError(name) object = o return object