def getPythonPath(obj): """Return the path of the object in standard Python notation. This method should try very hard to return a string, even if it is not a valid Python path. """ if obj is None: return None # Even for methods `im_class` and `__module__` is not allowed to be # accessed (which is probably not a bad idea). So, we remove the security # proxies for this check. naked = removeSecurityProxy(obj) qname = '' if isinstance(getattr(naked, '__qualname__', None), str): # Python 3 (being sure to protect against non-str __qualname__ # that we could get on some versions of Cython. See # https://github.com/zopefoundation/zope.app.apidoc/issues/25). # This makes unbound functions inside classes do the same # thing as they do an Python 2: return just their class name. qname = naked.__qualname__ qname = qname.split('.')[0] if hasattr(naked, 'im_class'): # Python 2, unbound methods naked = naked.im_class if isinstance(naked, types.MethodType): naked = type(naked.__self__) module = getattr(naked, '__module__', _marker) if module is _marker: return naked.__name__ return '%s.%s' %(module, qname or naked.__name__)
def renderText(text, module=None, format=None, dedent=True): # dedent is ignored, we always dedent if not text: return u'' if module is not None: if isinstance(module, six.string_types): module = sys.modules.get(module, None) if format is None: format = getDocFormat(module) if format is None: format = 'zope.source.rest' assert format in _format_dict.values() if isinstance(text, bytes): text = text.decode('utf-8', 'replace') try: text = dedentString(text) except TypeError as e: return u'Failed to render non-text (%r): %s' % (text, e,) source = createObject(format, text) renderer = getMultiAdapter((source, TestRequest())) return renderer.render()
def getMenuLink(self, node): """Return the HTML link of the node that is displayed in the menu.""" obj = node.context apidoc_url = findAPIDocumentationRootURL(self.context, self.request) if isinstance(obj, Utility): iface = getParent(obj) return '%s/Utility/%s/%s/index.html' % (apidoc_url, getName(iface), getName(obj)) if isinstance(obj, UtilityInterface): return '%s/Interface/%s/index.html' % (apidoc_url, getName(obj))
def testCorrectFactories(self): path = os.path.join(test_directory, 'testfiles') request = TestRequest() resource = DirectoryResourceFactory(path, checker, 'files')(request) image = resource['test.gif'] self.assert_(proxy.isinstance(image, FileResource)) template = resource['test.pt'] self.assert_(proxy.isinstance(template, PageTemplateResource)) file = resource['test.txt'] self.assert_(proxy.isinstance(file, FileResource)) file = resource['png'] self.assert_(proxy.isinstance(file, FileResource))
def _simpleGetFunctionSignature(func, ignore_self=False): """Return the signature of a function or method.""" _checkFunctionType(func) try: args, varargs, varkw, defaults = inspect.getargspec(func) except TypeError: # On Python 2, inspect.getargspec can't handle certain types # of callable things, like object.__init__ (<slot wrapper '__init__'> is not # a python function), but it *can* handle them on Python 3. # Punt on Python 2 return '(<unknown>)' placeholder = object() sig = '(' # By filling up the default tuple, we now have equal indeces for args and # default. if defaults is not None: defaults = (placeholder,) * (len(args) - len(defaults)) + defaults else: defaults = (placeholder,) * len(args) str_args = [] for name, default in zip(args, defaults): # Neglect self, since it is always there and not part of the signature. # This way the implementation and interface signatures should match. if name == 'self' and (isinstance(func, types.MethodType) or ignore_self): # NOTE: this is actually covered, and removing the condition will break # tests. The coverage report doesn't show it, though, for some reason. continue # pragma: no cover # Make sure the name is a string if isinstance(name, (tuple, list)): name = '(' + ', '.join(name) + ')' elif not isinstance(name, str): # pragma: no cover name = repr(name) if default is placeholder: str_args.append(name) else: str_args.append(name + '=' + repr(default)) if varargs: str_args.append('*' + varargs) if varkw: str_args.append('**' + varkw) sig += ', '.join(str_args) return sig + ')'
def attributes(self): context = removeSecurityProxy(self.context) attrs = [{'name': (ns and context.prefixes[ns]+':' or '') + name, 'value': value, 'url': None, 'values': []} for (ns, name), value in context.attrs.items()] names = context.schema.names(True) rootURL = absoluteURL(findDocModule(self), self.request) for attr in attrs: name = (attr['name'] in names) and attr['name'] or attr['name']+'_' field = context.schema.get(name) if isinstance(field, (GlobalObject, GlobalInterface)): attr['url'] = self.objectURL(attr['value'], field, rootURL) elif isinstance(field, Tokens): field = field.value_type values = attr['value'].strip().split() if len(values) == 1: attr['value'] = values[0] attr['url'] = self.objectURL(values[0], field, rootURL) else: for value in values: if isinstance(field, (GlobalObject, GlobalInterface)): url = self.objectURL(value, field, rootURL) else: break attr['values'].append({'value': value, 'url': url}) # Make sure that the attributes are in the same order they are defined # in the schema. fieldNames = getFieldNamesInOrder(context.schema) fieldNames = [name.endswith('_') and name[:-1] or name for name in fieldNames] attrs.sort(lambda x, y: _compareAttrs(x, y, fieldNames)) if not IRootDirective.providedBy(context): return attrs xmlns = [] for uri, prefix in context.prefixes.items(): name = prefix and ':'+prefix or '' xmlns.append({'name': 'xmlns'+name, 'value': uri, 'url': None, 'values': []}) xmlns.sort(lambda x, y: cmp(x['name'], y['name'])) return xmlns + attrs
def setBody(self, body): """Sets the body of the response""" # A SOAP view can return a Fault directly to indicate an error. if isinstance(body, Fault): self._error = body if not self._error: try: target = self._request._target body = premarshal(body) output = StringIO() result = body if hasattr(result, 'typecode'): tc = result.typecode else: tc = TC.Any(aslist=1, pname=target + 'Response') result = [result] SoapWriter(output).serialize(result, tc) output.seek(0) if not self._status_set: self.setStatus(200) self.setHeader('content-type', 'text/xml') self._body = output.read() self._updateContentLength() return except Exception, e: self._error = ZSI.FaultFromException(e, 0)
def setResult(self, result): """Sets the result of the response Sets the return body equal to the (string) argument "body". Also updates the "content-length" return header. If the body is a 2-element tuple, then it will be treated as (title,body) If is_error is true then the HTML will be formatted as a Zope error message instead of a generic HTML page. """ body = premarshal(result) if isinstance(body, xmlrpclib.Fault): # Convert Fault object to XML-RPC response. body = xmlrpclib.dumps(body, methodresponse=True) else: # Marshall our body as an XML-RPC response. Strings will be sent # as strings, integers as integers, etc. We do *not* convert # everything to a string first. try: body = xmlrpclib.dumps((body,), methodresponse=True, allow_none=True) except: # We really want to catch all exceptions at this point! self.handleException(sys.exc_info()) return headers = [('content-type', 'text/xml;charset=utf-8'), ('content-length', str(len(body)))] self._headers.update(dict((k, [v]) for (k, v) in headers)) super(XMLRPCResponse, self).setResult(DirectResult((body,)))
def setResult(self, result): """Sets the result of the response Sets the return body equal to the (string) argument "body". Also updates the "content-length" return header. If the body is a 2-element tuple, then it will be treated as (title,body) If is_error is true then the HTML will be formatted as a Zope error message instead of a generic HTML page. """ body = premarshal(result) if isinstance(body, xmlrpclib.Fault): # Convert Fault object to XML-RPC response. body = xmlrpclib.dumps(body, methodresponse=True) else: # Marshall our body as an XML-RPC response. Strings will be sent # as strings, integers as integers, etc. We do *not* convert # everything to a string first. try: body = xmlrpclib.dumps((body,), methodresponse=True, allow_none=True) except: # We really want to catch all exceptions at this point! self.handleException(sys.exc_info()) return super(XMLRPCResponse, self).setResult( DirectResult((body,), [('content-type', 'text/xml;charset=utf-8'), ('content-length', str(len(body)))]) )
def getMenuTitle(self, node): """Return the title of the node that is displayed in the menu.""" if isinstance(node.context, TypeInterface): iface = node.context.interface else: iface = node.context # Interfaces have no security declarations, so we have to unwrap. return removeSecurityProxy(iface).getName()
def getMenuTitle(self, node): """Return the title of the node that is displayed in the menu.""" obj = node.context if isinstance(obj, UtilityInterface): return getName(obj).split('.')[-1] if obj.name == NONAME: return 'no name' return obj.name
def getMenuTitle(self, node): """Return the title of the node that is displayed in the menu.""" obj = node.context if isinstance(obj, Namespace): name = obj.getShortName() if name == 'ALL': return 'All Namespaces' return name return getName(obj)
def getMenuLink(self, node): """Return the HTML link of the node that is displayed in the menu.""" obj = node.context if isinstance(obj, Directive): ns = getParent(obj) apidoc_url = findAPIDocumentationRootURL(self.context, self.request) return '%s/ZCML/%s/%s/index.html' % ( apidoc_url, getName(ns), getName(obj)) return None
def handle_class(dotted_path, ob=None): """Determine, whether the given path/obj references a Python class. """ if ob is None: try: ob = resolve(dotted_path) except ImportError: return None if not isinstance(ob, (types.ClassType, type)): return None return DocGrokClass(dotted_path)
def handle_interface(dotted_path, ob=None): """Determine, whether the given path/obj references an interface. """ if ob is None: try: ob = resolve(dotted_path) except ImportError: return None if not isinstance(removeAllProxies(ob), InterfaceClass): return None return DocGrokInterface(dotted_path)
def handleException(self, exc_info): """Handle Errors during publsihing and wrap it in XML-RPC XML >>> import sys >>> resp = XMLRPCResponse() >>> try: ... raise AttributeError('xyz') ... except: ... exc_info = sys.exc_info() ... resp.handleException(exc_info) >>> resp.getStatusString() '200 Ok' >>> resp.getHeader('content-type') 'text/xml;charset=utf-8' >>> body = ''.join(resp.consumeBody()) >>> 'Unexpected Zope exception: AttributeError: xyz' in body True """ t, value = exc_info[:2] s = '%s: %s' % (getattr(t, '__name__', t), value) # Create an appropriate Fault object. Unfortunately, we throw away # most of the debugging information. More useful error reporting is # left as an exercise for the reader. Fault = xmlrpclib.Fault fault_text = None try: if isinstance(value, Fault): fault_text = value elif isinstance(value, Exception): fault_text = Fault(-1, "Unexpected Zope exception: " + s) else: fault_text = Fault(-2, "Unexpected Zope error value: " + s) except: fault_text = Fault(-3, "Unknown Zope fault type") # Do the damage. self.setResult(fault_text) # XML-RPC prefers a status of 200 ("ok") even when reporting errors. self.setStatus(200)
def handleException(self, exc_info): """Handle Errors during publsihing and wrap it in XML-RPC XML >>> import sys >>> resp = XMLRPCResponse() >>> try: ... raise AttributeError('xyz') ... except: ... exc_info = sys.exc_info() ... resp.handleException(exc_info) >>> resp.getStatusString() '200 OK' >>> resp.getHeader('content-type') 'text/xml;charset=utf-8' >>> body = ''.join(resp.consumeBody()) >>> 'Unexpected Zope exception: AttributeError: xyz' in body True """ t, value = exc_info[:2] s = '%s: %s' % (getattr(t, '__name__', t), value) # Create an appropriate Fault object. Unfortunately, we throw away # most of the debugging information. More useful error reporting is # left as an exercise for the reader. Fault = xmlrpclib.Fault fault_text = None try: if isinstance(value, Fault): fault_text = value elif isinstance(value, Exception): fault_text = Fault(-1, "Unexpected Zope exception: " + s) else: fault_text = Fault(-2, "Unexpected Zope error value: " + s) except: fault_text = Fault(-3, "Unknown Zope fault type") # Do the damage. self.setResult(fault_text) # XML-RPC prefers a status of 200 ("ok") even when reporting errors. self.setStatus(200)
def getFunctionSignature(func): """Return the signature of a function or method.""" if not isinstance(func, (types.FunctionType, types.MethodType)): raise TypeError("func must be a function or method") args, varargs, varkw, defaults = inspect.getargspec(func) placeholder = object() sig = '(' # By filling up the default tuple, we now have equal indeces for args and # default. if defaults is not None: defaults = (placeholder,)*(len(args)-len(defaults)) + defaults else: defaults = (placeholder,)*len(args) str_args = [] for name, default in zip(args, defaults): # Neglect self, since it is always there and not part of the signature. # This way the implementation and interface signatures should match. if name == 'self' and type(func) == types.MethodType: continue # Make sure the name is a string if isinstance(name, (tuple, list)): name = '(' + ', '.join(name) + ')' elif not isinstance(name, str): name = repr(name) if default is placeholder: str_args.append(name) else: str_args.append(name + '=' + repr(default)) if varargs: str_args.append('*'+varargs) if varkw: str_args.append('**'+varkw) sig += ', '.join(str_args) return sig + ')'
def getFileInfo(self): """Get the file where the directive was declared.""" # ZCML directive `info` objects do not have security declarations, so # everything is forbidden by default. We need to remove the security # proxies in order to get to the data. info = removeSecurityProxy(self.context.info) if isinstance(info, ParserInfo): return {'file': relativizePath(info.file), 'line': info.line, 'column': info.column, 'eline': info.eline, 'ecolumn': info.ecolumn} return None
def testFactory(self): f = configfile(''' <permission id="zope.Foo" title="Zope Foo Permission" /> <class class="zope.security.tests.exampleclass.ExampleClass"> <factory id="test.Example" title="Example content" description="Example description" /> </class>''') xmlconfig(f) obj = zope.component.createObject('test.Example') self.failUnless(proxy.isinstance(obj, exampleclass.ExampleClass))
def setResult(self, result): """Sets the result of the response Sets the return body equal to the (string) argument "body". Also updates the "content-length" return header. If the body is a 2-element tuple, then it will be treated as (title,body) If is_error is true then the HTML will be formatted as a Zope error message instead of a generic HTML page. """ body = premarshal(result) if isinstance(body, xmlrpclib.Fault): # Convert Fault object to XML-RPC response. body = xmlrpclib.dumps(body, methodresponse=True) else: # Marshall our body as an XML-RPC response. Strings will be sent # as strings, integers as integers, etc. We do *not* convert # everything to a string first. try: body = xmlrpclib.dumps((body,), methodresponse=True, allow_none=True) except: # We really want to catch all exceptions at this point! self.handleException(sys.exc_info()) return # HTTP response payloads are byte strings, and methods like # consumeBody rely on that, but xmlrpc.client.dumps produces # native strings, which is incorrect on Python 3. if not isinstance(body, bytes): body = body.encode('utf-8') headers = [('content-type', 'text/xml;charset=utf-8'), ('content-length', str(len(body)))] self._headers.update(dict((k, [v]) for (k, v) in headers)) super(XMLRPCResponse, self).setResult(DirectResult((body,)))
def testPluggableFactories(self): path = os.path.join(test_directory, 'testfiles') request = TestRequest() resource = DirectoryResourceFactory(path, checker, 'files')(request) class ImageResource(object): def __init__(self, image, request): pass class ImageResourceFactory(object): def __init__(self, path, checker, name): pass def __call__(self, request): return ImageResource(None, request) from zope.browserresource.interfaces import IResourceFactoryFactory provideUtility(ImageResourceFactory, IResourceFactoryFactory, 'gif') image = resource['test.gif'] self.assertTrue(proxy.isinstance(image, ImageResource)) file = resource['test.txt'] self.assertTrue(proxy.isinstance(file, FileResource))
def handleException(self, exc_info): """Handle exceptions that occur during processing.""" type, value = exc_info[:2] content = "".join(traceback.format_tb(exc_info[-1])) if IUnauthorized.providedBy(value): self.setStatus(401) self.setBody("") #XXXself._body = "" #self._updateContentLength() return if not isinstance(value, Fault): value = ZSI.FaultFromException(u"%s : %s" % (value, content), 0) self.setStatus(500) self.setBody(value)
def renderText(text, module=None, format=None, dedent=True): if not text: return u'' if module is not None: if isinstance(module, (str, unicode)): module = sys.modules.get(module, None) if format is None: format = getDocFormat(module) if format is None: format = 'zope.source.rest' assert format in _format_dict.values() text = dedentString(text) if not isinstance(text, unicode): text = text.decode('latin-1', 'replace') source = createObject(format, text) renderer = getMultiAdapter((source, TestRequest())) return renderer.render()
def testURL3Level(self): request = TestRequest() request._vh_root = support.site ob.__parent__ = support.site ob.__name__ = 'ob' path = os.path.join(test_directory, 'testfiles') files = DirectoryResourceFactory(path, checker, 'test_files')(request) files.__parent__ = ob file = files['test.gif'] self.assertEqual(file(), 'http://127.0.0.1/@@/test_files/test.gif') subdir = files['subdir'] self.assertTrue(proxy.isinstance(subdir, DirectoryResource)) file = subdir['test.gif'] self.assertEqual(file(), 'http://127.0.0.1/@@/test_files/subdir/test.gif')
def testFactory(self): from zope.component import createObject from zope.configuration.xmlconfig import xmlconfig from zope.security import proxy from zope.security.tests import exampleclass self.meta() f = configfile(''' <permission id="zope.Foo" title="Zope Foo Permission" /> <class class="zope.security.tests.exampleclass.ExampleClass"> <factory id="test.Example" title="Example content" description="Example description" /> </class>''') xmlconfig(f) obj = createObject('test.Example') self.assertTrue(proxy.isinstance(obj, exampleclass.ExampleClass))
def _prepareResult(self, result): # we've asked json to return unicode; result should be unicode encoding = getCharsetUsingRequest(self._request) or 'utf-8' enc = encoding.lower() if not enc in interfaces.JSON_CHARSETS: encoding = 'utf-8' # encode outgoing boundary. if isinstance(result, unicode): body = result.encode(encoding) charset = encoding else: # something's wrong. JSON did not return unicode. raise TypeError("JSON did not return unicode (%s)" % type(result)) # set content type self.setHeader('content-type', "application/x-javascript;charset=%s" % charset) return body
def getPythonPath(obj): """Return the path of the object in standard Python notation. This method should try very hard to return a string, even if it is not a valid Python path. """ if obj is None: return None # Even for methods `im_class` and `__module__` is not allowed to be # accessed (which is probably not a bad idea). So, we remove the security # proxies for this check. naked = removeSecurityProxy(obj) name = naked.__name__ if hasattr(naked, "im_class"): naked = naked.im_class name = naked.__name__ # Py3 version: if PY3 and isinstance(naked, types.FunctionType): name = naked.__qualname__.split('.')[0] module = getattr(naked, '__module__', _marker) if module is _marker: return name return '%s.%s' %(module, name)
def _evalId(id): if isinstance(id, Global): id = id.__name__ if id == 'CheckerPublic': id = 'zope.Public' return id
def processInputs(self): """take the converted request and make useful args of it.""" json = zope.component.getUtility(IJSONReader) stream = self._body_instream input = [] incoming = stream.read(1000) while incoming: input.append(incoming) incoming = stream.read(1000) input = ''.join(input) # ensure unicode if not isinstance(input, unicode): input = self._decode(input) try: data = json.read(input) except: # catch any error since we don't know which library is used as # parser raise exception.ParseError # get the params params = data.get('params', []) if self.jsonId is None: self.jsonId = data.get('id', self._jsonId) # get the json version. The version 1.0 offers no version argument. # The version 1.1 offers a version key and since version 2.0 the # version is given with the ``jsonrpc`` key. Let's try to find the # version for our request. self.jsonVersion = data.get('version', self.jsonVersion) self.jsonVersion = data.get('jsonrpc', self.jsonVersion) if self.jsonVersion in ['1.0', '1.1', '2.0']: # json-rpc 1.0 and 1.1 if isinstance(params, list): args = params # version 1.0 and 1.1 uses a list of arguments for arg in args: if isinstance(arg, dict): # set every dict key value as form items and support at # least ``:list`` and ``:tuple`` input field name postifx # conversion. for key, d in arg.items(): key = str(key) pos = key.rfind(":") if pos > 0: match = self._typeFormat.match(key, pos + 1) if match is not None: key, type_name = key[:pos], key[pos + 1:] if type_name == 'list' and not isinstance(d, list): d = [d] if type_name == 'tuple' and not isinstance(d, tuple): d = tuple(d) self.form[key] = d elif isinstance(params, dict): # process the key/value pair params. This arguments get stored # in the request.form argument and we skip it from method calls. # This means this library will not support key word arguments # for method calls. It will instead store them in the form. # This has two reasons. # 1. Zope doesn't support kwargs in the publication # implementation. It only supports positional arguments # 2. The JSON-RPC specification doesn't allow to use positional # and keyword arguments on one method call # 3. Python doesn't allow to convert kwargs to positional # arguments because a dict doesn't provide an order # This means you should avoid to call a method with kwargs. # just use positional arguments if possible. Or get them from # directly from the request or request.form argument in your # code. Let me know if this is a real problem for you and you # like to implement a different kwarg handling. We have some # ideas for add support for this. args = params # set every dict key value as form items and support at # least ``:list`` and ``:tuple`` input field name postifx # conversion. for key, d in args.items(): key = str(key) pos = key.rfind(":") if pos > 0: match = self._typeFormat.match(key, pos + 1) if match is not None: key, type_name = key[:pos], key[pos + 1:] if type_name == 'list' and not isinstance(d, list): d = [d] if type_name == 'tuple' and not isinstance(d, tuple): d = tuple(d) self.form[key] = d args = [] elif params is None: args = [] else: raise TypeError( 'Unsupported JSON-RPC version (%s)' % self.jsonVersion) self._args = tuple(args) # make environment, cookies, etc., available to request.get() super(JSONRPCRequest, self).processInputs() self._environ['JSONRPC_MODE'] = True # split here on '.' for get path suffix steps functionstr = data['method'] function = functionstr.split('.') if function: # translate '.' to '/' in function to represent object traversal. self.setPathSuffix(function)
def findAPIDocumentationRootURL(context, request): if isinstance(context, APIDocumentation): return absoluteURL(context, request) else: return findAPIDocumentationRootURL(getParent(context), request)
def getInfo(self): """Get the file where the directive was declared.""" if isinstance(self.context.info, (str, unicode)): return self.context.info return None
def findAPIDocumentationRoot(context, request=None): if isinstance(context, APIDocumentation): return context return findAPIDocumentationRoot(getParent(context), request)