def getViewFactoryData(factory): """Squeeze some useful information out of the view factory""" info = {'path': None, 'url': None, 'template': None, 'resource': None, 'referencable': True} # Always determine the most basic factory # Commonly, factories are wrapped to provide security or location, for # example. If those wrappers play nice, then they provide a `factory` # attribute, that points to the original factory. while hasattr(factory, 'factory'): factory = factory.factory if getattr(factory, '__name__', '').startswith('SimpleViewClass'): # In the case of a SimpleView, the base is really what we are # interested in. Usually the first listed class is the interesting one. base = factory.__bases__[0] info['path'] = base.__module__ + '.' + base.__name__ info['template'] = relativizePath(factory.index.filename) info['template_obj'] = factory.index # Basic Type is a factory elif isinstance(factory, (six.string_types, float, int, list, tuple)): info['referencable'] = False elif factory.__module__ is not None: if factory.__module__.startswith(BROWSER_DIRECTIVES_MODULE): info['path'] = getPythonPath(factory.__bases__[0]) # XML-RPC view factory, generated during registration elif (factory.__module__.startswith(XMLRPC_DIRECTIVES_MODULE) # JSON-RPC view factory, generated during registration # This is needed for the 3rd party jsonserver implementation # TODO: See issue http://www.zope.org/Collectors/Zope3-dev/504, ri or factory.__module__.startswith(JSONRPC_DIRECTIVES_MODULE)): # Those factories are method publisher and security wrapped info['path'] = getPythonPath(factory.__bases__[0].__bases__[0]) if not info['path'] and not hasattr(factory, '__name__'): # A factory that is a class instance; since we cannot reference instances, # reference the class. info['path'] = getPythonPath(factory.__class__) if not info['path']: # Either a simple class-based factory, or not. It doesn't # matter. We have tried our best; just get the Python path as # good as you can. info['path'] = getPythonPath(factory) if info['referencable']: info['url'] = info['path'].replace('.', '/') if isinstance(factory, IconViewFactory): info['resource'] = factory.rname return info
def __init__(self, context, request): super(ModuleDetails, self).__init__(context, request) items = list(self.context.items()) items.sort() self.text_files = [] self.zcml_files = [] self.modules = [] self.interfaces = [] self.classes = [] self.functions = [] for name, obj in items: entry = {'name': name, 'url': absoluteURL(obj, self.request)} if IFunctionDocumentation.providedBy(obj): entry['doc'] = formatDocString( obj.getDocString(), self.context.getPath()) entry['signature'] = obj.getSignature() self.functions.append(entry) elif IModuleDocumentation.providedBy(obj): entry['doc'] = formatDocString( obj.getDocString(), obj.getPath(), True) self.modules.append(entry) elif IInterface.providedBy(obj): entry['path'] = getPythonPath(removeAllProxies(obj)) entry['doc'] = formatDocString( obj.__doc__, obj.__module__, True) self.interfaces.append(entry) elif IClassDocumentation.providedBy(obj): entry['doc'] = formatDocString( obj.getDocString(), self.context.getPath(), True) self.classes.append(entry) elif IZCMLFile.providedBy(obj): self.zcml_files.append(entry) elif ITextFile.providedBy(obj): self.text_files.append(entry)
def getViewInfoDictionary(reg): """Build up an information dictionary for a view registration.""" # get configuration info if isinstance(reg.doc, (str, unicode)): doc = reg.doc zcml = None else: doc = None zcml = getParserInfoInfoDictionary(reg.doc) # get layer layer = None if ILayer.providedBy(reg.required[-1]): layer = getInterfaceInfoDictionary(reg.required[-1]) info = {'name' : reg.name or '<i>no name</i>', 'type' : getPythonPath(getPresentationType(reg.required[-1])), 'factory' : getViewFactoryData(reg.value), 'required': [getInterfaceInfoDictionary(iface) for iface in reg.required], 'provided' : getInterfaceInfoDictionary(reg.provided), 'layer': layer, 'doc': doc, 'zcml': zcml } # Educated guess of the attribute name info.update(getPermissionIds('publishTraverse', klass=reg.value)) return info
def _getInterfaceDetails(self, schema): schema = LocationProxy(schema, self.context, getPythonPath(schema)) details = InterfaceDetails(schema, self.request) details._getFieldName = _getFieldName return details
def getAdapterInfoDictionary(reg): """Return a PT-friendly info dictionary for an adapter registration.""" factory = getRealFactory(reg.value) path = getPythonPath(factory) url = None if isReferencable(path): url = path.replace('.', '/') if isinstance(reg.doc, (str, unicode)): doc = reg.doc zcml = None else: doc = None zcml = getParserInfoInfoDictionary(reg.doc) return { 'provided': getInterfaceInfoDictionary(reg.provided), 'required': [getInterfaceInfoDictionary(iface) for iface in reg.required if iface is not None], 'name': getattr(reg, 'name', _('<subscription>')), 'factory': path, 'factory_url': url, 'doc': doc, 'zcml': zcml}
def getInterface(self): """Return the interface the utility provides.""" schema = LocationProxy(self.context.interface, self.context, getPythonPath(self.context.interface)) details = InterfaceDetails(schema, self.request) return details
def getAdapterInfoDictionary(reg): """Return a PT-friendly info dictionary for an adapter registration.""" factory = getRealFactory(reg.factory) path = getPythonPath(factory) url = None if isReferencable(path): url = path.replace('.', '/') if isinstance(reg.info, six.string_types): doc = reg.info zcml = None else: doc = None zcml = getParserInfoInfoDictionary(reg.info) name = getattr(reg, 'name', u'') name = name.decode('utf-8') if isinstance(name, bytes) else name return { 'provided': getInterfaceInfoDictionary(reg.provided), 'required': [getSpecificationInfoDictionary(iface) for iface in reg.required if iface is not None], 'name': name, 'factory': path, 'factory_url': url, 'doc': doc, 'zcml': zcml }
def getUtilityInfoDictionary(reg): """Return a PT-friendly info dictionary for a factory.""" component = reg.component # Check whether we have an instance of some custom type or not # Unfortunately, a lot of utilities have a `__name__` attribute, so we # cannot simply check for its absence # TODO: Once we support passive display of instances, this insanity can go # away. if not isinstance(component, (types.MethodType, types.FunctionType, six.class_types, InterfaceClass)): component = getattr(component, '__class__', component) path = getPythonPath(component) # provided interface id iface_id = '%s.%s' % (reg.provided.__module__, reg.provided.getName()) # Determine the URL if isinstance(component, InterfaceClass): url = 'Interface/%s' % path else: url = None if isReferencable(path): url = 'Code/%s' % path.replace('.', '/') return {'name': six.text_type(reg.name) or _('<i>no name</i>'), 'url_name': utilitymodule.encodeName(reg.name or '__noname__'), 'iface_id': iface_id, 'path': path, 'url': url}
def getHandler(self): """Return information about the handler.""" if self.context.handler is not None: path = getPythonPath(self.context.handler) return { 'path': path, 'url': isReferencable(path) and path.replace('.', '/') or None} return None
def getDirectlyProvidedInterfaces(self): # This comes from apidoc... # Getting the directly provided interfaces works only on naked objects naked = removeSecurityProxy(self.obj) return [ utilities.getPythonPath(iface) for iface in zope.interface.directlyProvidedBy(naked) ]
def getModuleInterfaces(self): """Return entries about interfaces the module provides""" entries = [] for iface in self.context.getDeclaration(): entries.append({ 'name': iface.__name__, 'path': getPythonPath(removeAllProxies(iface)) }) return entries
def getTypes(self): """Return a list of interface types that are specified for this interface.""" # We have to really, really remove all proxies, since self.context (an # interface) is usually security proxied and location proxied. To get # the types, we need all proxies gone, otherwise the proxies' # interfaces are picked up as well. iface = removeAllProxies(self.context) return [{'name': type.getName(), 'path': getPythonPath(type)} for type in interface.getInterfaceTypes(iface)]
def getEntries(self, columns=True): """Return info objects for all modules and classes in the associated apidoc container. """ if (not hasattr(self.context, "apidoc") or not hasattr(self.context.apidoc, "items")): return None entries = [] for name, obj in self.context.apidoc.items(): entry = { 'name': name, 'obj': obj, 'path': getPythonPath(removeAllProxies(obj)), 'url': u'', 'doc': None, 'ispackage': False, 'ismodule': False, 'isinterface': False, 'isclass': False, 'isfunction': False, 'istextfile': False, 'iszcmlfile': False, 'signature': None } entry['url'] = "%s/%s" % (self.context.path.replace('.', '/'), name) if hasattr(obj, "getDocString"): entry['doc'] = self.getDocHeading(obj.getDocString()) elif hasattr(obj, "getDoc") and isinstance(removeAllProxies(obj), InterfaceClass): entry['doc'] = self.getDocHeading(obj.getDoc()) if isinstance(obj, Class): entry['isclass'] = True elif isinstance(obj, TextFile): entry['istextfile'] = True elif isinstance(obj, ZCMLFile): entry['iszcmlfile'] = True elif isinstance(obj, Function): entry['isfunction'] = True if hasattr(obj, 'getSignature'): entry['signature'] = obj.getSignature() elif (isinstance(obj, Module) and os.path.basename(obj.getFileName()) in ['__init.py__', '__init__.pyc', '__init__.pyo']): entry['ispackage'] = True elif isinstance(obj, Module): entry['ismodule'] = True elif isinstance(obj, InterfaceClass): entry['isinterface'] = True entries.append(entry) entries.sort(lambda x, y: cmp(x['name'], y['name'])) return entries
def items(self): sm = zapi.getSiteManager() ifaces = {} while sm is not None: for reg in sm.registrations(): if isinstance(reg, UtilityRegistration): path = getPythonPath(reg.provided) ifaces[path] = UtilityInterface(self, path, reg.provided) sm = queryNextSiteManager(sm) items = ifaces.items() items.sort(lambda x, y: cmp(x[0].split('.')[-1], y[0].split('.')[-1])) return items
def getBases(self): """Get all bases of this class Example:: >>> from tests import getInterfaceDetails >>> details = getInterfaceDetails() >>> details.getBases() ['zope.interface.Interface'] """ # Persistent interfaces are security proxied, so we need to strip the # security proxies off iface = removeSecurityProxy(self.context) return [getPythonPath(base) for base in iface.__bases__]
def getFieldInfoDictionary(field, format=None): """Return a page-template-friendly information dictionary.""" format = format or _getDocFormat(field) info = {'name': field.getName(), 'required': field.required, 'required_string': field.required and u'required' or u'optional', 'default': repr(field.default), 'title': field.title} # Determine the interface of the field iface = getFieldInterface(field) info['iface'] = {'name': iface.getName(), 'id': getPythonPath(iface)} # Determine the field class class_ = field.__class__ info['class'] = {'name': class_.__name__, 'path': getPythonPath(class_).replace('.', '/')} # Render the field description info['description'] = renderText(field.description or u'', format=format) return info
def test__qualname__descriptor_path(self): # When the __qualname__ is not a string but a descriptor object, # getPythonPath does not raise an AttributeError # https://github.com/zopefoundation/zope.app.apidoc/issues/25 from zope.app.apidoc.utilities import getPythonPath class O(object): "namespace object" o = O() o.__qualname__ = object() o.__name__ = 'foo' self.assertEqual('zope.app.apidoc.tests.foo', getPythonPath(o))
def getSubdirectives(self): """Create a list of subdirectives.""" dirs = [] for ns, name, schema, handler, info in self.context.subdirs: details = self._getInterfaceDetails(schema) path = getPythonPath(handler) url = isReferencable(path) and path.replace('.', '/') or None dirs.append({ 'namespace': ns, 'name': name, 'schema': details, 'handler': {'path': path, 'url': url}, 'info': info, }) return dirs
def _listClasses(self, classes): info = [] for cls in classes: unwrapped_cls = removeAllProxies(cls) fullpath = getPythonPath(unwrapped_cls) if not fullpath: continue path, name = fullpath.rsplit('.', 1) info.append({ 'path': path or None, 'path_parts': self.getPathParts(path) or None, 'name': name, 'url': fullpath and fullpath.replace('.', '/') or None, 'doc': self.getDocHeading(cls.__doc__) or None }) return info
def getFactoryInfoDictionary(reg): """Return a PT-friendly info dictionary for a factory.""" factory = reg.component callable = factory # Usually only zope.component.factory.Factory instances have this attribute if IFactory.providedBy(factory) and hasattr(factory, '_callable'): callable = factory._callable elif hasattr(callable, '__class__'): callable = callable.__class__ path = getPythonPath(callable) return {'name': six.text_type(reg.name) or _('<i>no name</i>'), 'title': getattr(factory, 'title', u''), 'description': renderText(getattr(factory, 'description', u''), module=callable.__module__), 'url': isReferencable(path) and path.replace('.', '/') or None}
def getEntries(self, columns=True): """Return info objects for all modules and classes in this module.""" entries = [{'name': name, # only for interfaces; should be done differently somewhen 'path': getPythonPath(removeAllProxies(obj)), 'url': zapi.absoluteURL(obj, self.request), 'ismodule': zapi.isinstance(obj, Module), 'isinterface': zapi.isinstance( removeAllProxies(obj), InterfaceClass), 'isclass': zapi.isinstance(obj, Class), 'isfunction': zapi.isinstance(obj, Function), 'istextfile': zapi.isinstance(obj, TextFile), 'iszcmlfile': zapi.isinstance(obj, ZCMLFile)} for name, obj in self.context.items()] entries.sort(lambda x, y: cmp(x['name'], y['name'])) if columns: entries = columnize(entries) return entries
def objectURL(self, value, field, rootURL): naked = removeSecurityProxy(self.context) bound = field.bind(naked.context) obj = bound.fromUnicode(value) if obj is None: return try: isInterface = IInterface.providedBy(obj) except AttributeError: # probably an object that does not like to play nice with the CA isInterface = False # The object mught be an instance; in this case get a link to the class if not hasattr(obj, '__name__'): obj = getattr(obj, '__class__') path = getPythonPath(obj) if isInterface: return rootURL+'/../Interface/%s/index.html' % path if isReferencable(path): return rootURL + '/%s/index.html' %(path.replace('.', '/'))
def _listClasses(self, classes): """Prepare a list of classes for presentation.""" info = [] codeModule = zapi.getUtility(IDocumentationModule, "Code") for cls in classes: # We need to removeAllProxies because the security checkers for # zope.app.container.contained.ContainedProxy and # zope.app.i18n.messagecatalog.MessageCatalog prevent us from # accessing __name__ and __module__. unwrapped_cls = removeAllProxies(cls) path = getPythonPath(unwrapped_cls) url = None try: klass = zapi.traverse(codeModule, path.replace('.', '/')) url = zapi.absoluteURL(klass, self.request) except TraversalError: # If one of the classes is implemented in C, we will not # be able to find it. pass info.append({'path': path or None, 'url': url}) return info
def items(self): # Use a list of site managers, since we want to support multiple bases smlist = [zope.component.getSiteManager()] seen = [] ifaces = {} while smlist: # Get the next site manager sm = smlist.pop() # If we have already looked at this site manager, then skip it if sm in seen: # pragma: no cover continue # Add the current site manager to the list of seen ones seen.append(sm) # Add the bases of the current site manager to the list of site # managers to be processed smlist += list(sm.__bases__) for reg in sm.registeredUtilities(): path = getPythonPath(reg.provided) ifaces[path] = UtilityInterface(self, path, reg.provided) items = sorted(ifaces.items(), key=lambda x: x[0].split('.')[-1]) return items
def getViewInfoDictionary(reg): """Build up an information dictionary for a view registration.""" # get configuration info if isinstance(reg.info, six.string_types): doc = reg.info zcml = None else: doc = None zcml = getParserInfoInfoDictionary(reg.info) info = {'name' : six.text_type(reg.name) or _('<i>no name</i>'), 'type' : getPythonPath(getPresentationType(reg.required[-1])), 'factory' : getViewFactoryData(reg.factory), 'required': [getInterfaceInfoDictionary(iface) for iface in reg.required], 'provided' : getInterfaceInfoDictionary(reg.provided), 'doc': doc, 'zcml': zcml } # Educated guess of the attribute name info.update(getPermissionIds('publishTraverse', klass=reg.factory)) return info
def getTypeInfoDictionary(type): """Return a PT-friendly info dictionary for a type.""" path = getPythonPath(type) return {'name': type.__name__, 'module': type.__module__, 'url': isReferencable(path) and path.replace('.', '/') or None}
def getInterfaceInfo(iface): if iface is None: return None path = getPythonPath(iface) return {'path': path, 'url': isReferencable(path) and path or None}
def getTypeLink(type): if type is types.NoneType: return None path = getPythonPath(type) return isReferencable(path) and path.replace('.', '/') or None
def getTypeLink(self, obj_type): if obj_type is types.NoneType: return None path = utilities.getPythonPath(obj_type) return path.replace('.', '/')
def getPythonPath(self): return utilities.getPythonPath(self.obj)