コード例 #1
0
ファイル: utils.py プロジェクト: CGTIC/Plone_SP
def getObjectDefaultView(context):
    """Get the id of an object's default view
    """

    # courtesy of Producs.CacheSetup

    browserDefault = IBrowserDefault(context, None)

    if browserDefault is not None:
        try:
            return stripLeadingCharacters(browserDefault.defaultView())
        except AttributeError:
            # Might happen if FTI didn't migrate yet.
            pass

    if not IDynamicType.providedBy(context):
        return None

    fti = context.getTypeInfo()
    try:
        # XXX: This isn't quite right since it assumes the action starts
        #with ${object_url}
        action = fti.getActionInfo('object/view')['url'].split('/')[-1]
    except ValueError:
        # If the action doesn't exist, stop
        return None

    # Try resolving method aliases because we need a real template_id here
    if action:
        action = fti.queryMethodID(action, default = action, context = context)
    else:
        action = fti.queryMethodID('(Default)', default = action,
                                   context = context)

    return stripLeadingCharacters(action)
コード例 #2
0
    def _lookupTypeActionTemplate(self, actionId):
        context = aq_inner(self.context)
        if not IDynamicType.providedBy(context):
            # No type info available, so no actions to consult
            return None

        fti = context.getTypeInfo()
        actions = fti.listActionInfos(actionId, context, False, False, False)
        if not actions:
            # Action doesn't exist
            return None
        url = actions[0]['url']
        if url.rstrip('/') == self.object_url().rstrip('/'):
            # (Default) action
            action = '(Default)'
        else:
            # XXX: This isn't quite right since it assumes the action starts
            # with ${object_url}
            action = url.split('/')[-1]

        # Try resolving method aliases because we need a real template_id here
        action = fti.queryMethodID(action, default=action, context=context)

        # Strip off leading /
        if action and action[0] == '/':
            action = action[1:]
        return action
コード例 #3
0
ファイル: context.py プロジェクト: toutpt/plone.app.layout
    def _lookupTypeActionTemplate(self, actionId):
        context = aq_inner(self.context)
        if not IDynamicType.providedBy(context):
            # No type info available, so no actions to consult
            return None

        fti = context.getTypeInfo()
        actions = fti.listActionInfos(actionId, context, False, False, False)
        if not actions:
            # Action doesn't exist
            return None
        url = actions[0]['url']
        if url.rstrip('/') == self.object_url().rstrip('/'):
            # (Default) action
            action = '(Default)'
        else:
            # XXX: This isn't quite right since it assumes the action starts with ${object_url}
            action = url.split('/')[-1]

        # Try resolving method aliases because we need a real template_id here
        action = fti.queryMethodID(action, default=action, context=context)

        # Strip off leading /
        if action and action[0] == '/':
            action = action[1:]
        return action
コード例 #4
0
ファイル: viewlets.py プロジェクト: esteele/Products.Gloworm
    def __call__(self):
        if DebugModeActive:
            alsoProvides(self.request, IGlowormLayer)
            
            # TODO What was this for again?
            from plone.app.layout.globals.interfaces import IViewView
            alsoProvides(self.request, IViewView)
            
            # Apply debug flags to the request
            self.request.debug = DebugFlags()
            self.request.debug.showTAL = True
            self.request.debug.sourceAnnotations = True
            
            # Find the actual content object in the context
            # Calling @@inspect on object/view results in view being self.context
            contentObject = self.context
            while not IDynamicType.providedBy(contentObject):
                contentObject = contentObject.aq_inner.aq_parent
            
            context_state = getMultiAdapter((contentObject, self.request), name='plone_context_state')
            templateId = context_state.view_template_id()
            template = contentObject.unrestrictedTraverse(templateId)
            # template = contentObject.unrestrictedTraverse(templateId and '@@%s' % templateId)

            renderedTemplate = template()
            # Insert the GloWorm panel and wrap the page content in a wrapper div so that we
            # can break the two into two different panels. To do that, we're forced to
            # do some ill-conceived html parsing. BeautifulSoup appears to be changing pages
            # with the TAL included, closing some tags that it shouldn't be and that breaks
            # the page layout. Javascript methods do the same. So, for now, we're stuck with
            # REGEX.
            
            glowormPanel = self.glowormPanelTemplate(self.context, self.request)
            regexp = r"(\</?body[^\>]*\>)([\S\s]*)(</body>)"
            replace = r"""
            \1
            <div id='glowormPageWrapper' class='kssattr-insideInspectableArea-True'>
            \2
            </div> <!-- Close glowormPageWrapper -->
            %s
            \3
            """ % glowormPanel
            
            updatedTemplate = re.sub(regexp, replace, renderedTemplate)
            
            # For cross-browser compatability (ie. everything, not just Firefox), we need to:
            # 1) Remove anything before the doctype
            docString = re.search(r'(<!DOCTYPE[^\>]*\>)', updatedTemplate).group()
            # 2) Remove anything between the doctype and <html> declaration
            # 3) Remove anything after the closing </html>
            htmlBlock = re.search(r'\<html[\S\s]*\<\/html>', updatedTemplate).group()
            updatedTemplate = docString + htmlBlock
            # 4) Insert the metal and tal namespaces into the html declaration
            updatedTemplate = re.sub(r"(\<html[^\>]*)([\>])", r"""\1 xmlns:metal="http://xml.zope.org/namespaces/metal" xmlns:tal="http://xml.zope.org/namespaces/tal"\2""", updatedTemplate)
            
            return updatedTemplate
        else:
            return "Please enable Zope debug/development mode to continue."
コード例 #5
0
ファイル: DiscussionTool.py プロジェクト: nacho22martin/tesis
    def isDiscussionAllowedFor( self, content ):
        """ Get boolean indicating whether discussion is allowed for content.
        """
        if hasattr( aq_base(content), 'allow_discussion' ):
            return bool(content.allow_discussion)

        if IDynamicType.providedBy(content):
            # Grabbing type information objects only works for dynamic types
            typeInfo = content.getTypeInfo()
            if typeInfo:
                return bool( typeInfo.allowDiscussion() )

        return False
コード例 #6
0
ファイル: DiscussionTool.py プロジェクト: bendavis78/zope
    def isDiscussionAllowedFor(self, content):
        """ Get boolean indicating whether discussion is allowed for content.
        """
        if hasattr(aq_base(content), 'allow_discussion'):
            return bool(content.allow_discussion)

        if IDynamicType.providedBy(content):
            # Grabbing type information objects only works for dynamic types
            typeInfo = content.getTypeInfo()
            if typeInfo:
                return bool(typeInfo.allowDiscussion())

        return False
コード例 #7
0
ファイル: folder.py プロジェクト: bendavis78/zope
 def up_info(self):
     up_obj = self.context.aq_inner.aq_parent
     mtool = self._getTool('portal_membership')
     allowed = mtool.checkPermission(ListFolderContents, up_obj)
     if allowed:
         if IDynamicType.providedBy(up_obj):
             up_url = up_obj.getActionInfo('object/folderContents')['url']
             return {'icon': '%s/UpFolder_icon.gif' % self._getPortalURL(),
                     'id': up_obj.getId(),
                     'url': up_url}
         else:
             return {'icon': '',
                     'id': 'Root',
                     'url': ''}
     else:
         return {}
コード例 #8
0
ファイル: folder.py プロジェクト: goschtl/zope
 def up_info(self):
     """Link to the contens view of the parent object"""
     up_obj = aq_parent(aq_inner(self.context))
     mtool = getUtility(IMembershipTool)
     allowed = mtool.checkPermission(ListFolderContents, up_obj)
     if allowed:
         if IDynamicType.providedBy(up_obj):
             up_url = up_obj.getActionInfo('object/folderContents')['url']
             return {'icon': '%s/UpFolder_icon.gif' % self._getPortalURL(),
                     'id': up_obj.getId(),
                     'url': up_url}
         else:
             return {'icon': '',
                     'id': 'Root',
                     'url': ''}
     else:
         return {}
コード例 #9
0
 def up_info(self):
     """Link to the contens view of the parent object"""
     up_obj = aq_parent(aq_inner(self.context))
     mtool = getUtility(IMembershipTool)
     allowed = mtool.checkPermission(ListFolderContents, up_obj)
     if allowed:
         if IDynamicType.providedBy(up_obj):
             up_url = up_obj.getActionInfo('object/folderContents')['url']
             return {'icon': '%s/UpFolder_icon.gif' % self._getPortalURL(),
                     'id': up_obj.getId(),
                     'url': up_url}
         else:
             return {'icon': '',
                     'id': 'Root',
                     'url': ''}
     else:
         return {}
コード例 #10
0
ファイル: utils.py プロジェクト: hoka/plone.app.caching
def getObjectDefaultView(context):
    """Get the id of an object's default view
    """

    # courtesy of Producs.CacheSetup

    browserDefault = IBrowserDefault(context, None)

    if browserDefault is not None:
        try:
            return browserDefault.defaultView()
        except AttributeError:
            # Might happen if FTI didn't migrate yet.
            pass

    if not IDynamicType.providedBy(context):
        return None

    fti = context.getTypeInfo()
    try:
        # XXX: This isn't quite right since it assumes the action starts with ${object_url}
        action = fti.getActionInfo('object/view')['url'].split('/')[-1]
    except ValueError:
        # If the action doesn't exist, stop
        return None

    # Try resolving method aliases because we need a real template_id here
    if action:
        action = fti.queryMethodID(action, default=action, context=context)
    else:
        action = fti.queryMethodID('(Default)',
                                   default=action,
                                   context=context)

    # Strip off leading / and/or @@
    if action and action[0] == '/':
        action = action[1:]
    if action and action.startswith('@@'):
        action = action[2:]
    return action
コード例 #11
0
    def update(self):

        self.path = '/'.join(self.context.getPhysicalPath())
        self.cls = self.context.__class__

        self.fti = None
        self.methodAliases = None

        if IDynamicType.providedBy(self.context):
            self.fti = self.context.getTypeInfo()
            self.methodAliases = sorted(self.fti.getMethodAliases().items())

        self.defaultView = None
        self.viewMethods = []
        if IDynamicViewTypeInformation.providedBy(self.fti):
            self.defaultView = self.fti.defaultView(self.context)
            self.viewMethods = self.fti.getAvailableViewMethods(self.context)

        directly_provided = directlyProvidedBy(self.context)
        self.provided = list(providedBy(self.context).flattened())
        self.provided.sort(key=lambda i: i.__identifier__)
        self.provided = ({
            'dottedname': i.__identifier__,
            'is_marker': i in directly_provided
        } for i in self.provided)
        self.views = []

        generator = getAdapters((
            self.context,
            self.request,
        ), Interface)
        while True:
            try:
                name, view = generator.next()

                if not IView.providedBy(view):
                    continue

                cls = view.__class__
                module = cls.__module__
                template = None

                if isinstance(view, ViewMixinForTemplates):
                    template = view.index.filename
                else:
                    for attr in ('index', 'template', '__call__'):
                        pt = getattr(view, attr, None)
                        if hasattr(pt, 'filename'):
                            template = pt.filename
                            break

                # Deal with silly Five metaclasses
                if (module == 'Products.Five.metaclass'
                        and len(cls.__bases__) > 0):
                    cls = cls.__bases__[0]
                elif cls == ViewMixinForTemplates:
                    cls = None

                self.views.append({
                    'name': name,
                    'class': cls,
                    'template': template,
                })
            except StopIteration:
                break
            except:
                # Some adapters don't initialise cleanly
                pass

        self.views.sort(key=lambda v: v['name'])

        self.methods = []
        self.variables = []

        _marker = object()
        for name in sorted(dir(aq_base(self.context))):
            attr = getattr(aq_base(self.context), name, _marker)
            if attr is _marker:
                continue

            # FIXME: Should we include ComputedAttribute here ? [glenfant]
            if isinstance(attr, (int, long, float, basestring, bool, list,
                                 tuple, dict, set, frozenset)):
                self.variables.append({
                    'name': name,
                    'primitive': True,
                    'value': attr,
                })
            elif (isinstance(attr,
                             (types.MethodType, types.BuiltinFunctionType,
                              types.BuiltinMethodType, types.FunctionType))
                  or attr.__class__.__name__ == 'method-wrapper', ):

                source = None
                if name.endswith('__roles__'):
                    # name without '__roles__' is the last in self.methods since we're in a sorted(...) loop
                    if callable(attr):
                        secu_infos = attr()
                    else:
                        secu_infos = attr
                    if secu_infos is None:
                        secu_label = 'Public'
                    else:
                        secu_label = ''
                        try:
                            secu_label += 'Roles: ' + ', '.join(
                                [r for r in secu_infos[:-1]])
                        except TypeError:
                            # Avoid "TypeError: sequence index must be
                            # integer, not 'slice'", which occurs with the
                            # ``C`` security implementation. This is a rare
                            # case. In development you normally use the
                            # ``Python`` security implementation, where this
                            # error doesn't occur.
                            pass
                        secu_label += '. Permission: ' + secu_infos[-1][
                            1:-11]  # _x_Permission -> x
                    self.methods[-1]['secu_infos'] = secu_label
                else:
                    try:
                        source = inspect.getsourcefile(attr)
                    except TypeError:
                        None

                    signature = name + "()"
                    try:
                        signature = name + inspect.formatargspec(
                            *inspect.getargspec(attr))
                    except TypeError:
                        pass

                    self.methods.append({
                        'signature': signature,
                        'filename': source,
                        'help': inspect.getdoc(attr),
                    })
            else:
                self.variables.append({
                    'name': name,
                    'primitive': False,
                    'value': str(attr),
                })
コード例 #12
0
ファイル: viewlets.py プロジェクト: esteele/Products.Gloworm
    def update(self):
        
        # Tell BeautifulSoup that viewlets and viewletmanagers can be nested.
        BeautifulSoup.NESTABLE_TAGS['tal:viewlet']=['tal:viewletmanager']
        BeautifulSoup.NESTABLE_TAGS['tal:viewletmanager']=['tal:viewlet']
        
        # Render the current page and strip out everything but the <tal:viewletmanager> and <tal:viewlet> tags.
        # TODO We probably don't need BeautifulSoup anymore since we've got such a simple parsetree.
        
        # We need the GloWorm specific browser layer in there so that we can see the tal:viewlet* tags.
        alsoProvides(self.request, IGlowormLayer)
        
        # Find the object providing IDynamicType, that's what we want to inspect
        # Otherwise, we get errors relating to getTypeInfo() 
        contentObject = self.context
        while not IDynamicType.providedBy(contentObject):
            contentObject = contentObject.aq_inner.aq_parent
        
        context_state = getMultiAdapter((contentObject, self.request), name='plone_context_state')
        templateId = context_state.view_template_id()
        # There are instances in which the enclosing view is named 'index' that calling a traverse to 'index' 
        # actually gets this viewlet's index method. Prepending the '@@' seems to take care of that.
        # So, either traverse to @@templateId or nothing depending on the value of templateId.
        try:
            template = contentObject.unrestrictedTraverse(templateId and '@@%s' % templateId)
        except AttributeError:
            # The template isn't a view, just call it without the @@
            template = contentObject.unrestrictedTraverse(templateId)

        renderedTemplate = template()
        
        strippedHTML = ''.join((re.findall('(<\/?tal:viewlet/?[^\>]*>)', renderedTemplate)))
        
        # Soupify the simplified HTML
        soup = BeautifulSoup(strippedHTML)
        self.documentTree = []
        self.outstr = ""
        
        def getChildViewletManagers(node):
            """ Find all viewletmanagers within this node """
            all = node.findAll('tal:viewletmanager')
            stripped = []
            self.outstr += "<ol class='viewletmanager-tree'>"
            for v in all:
                if not(stripped and v.findParent('tal:viewletmanager') and stripped[-1] in v.findParents('tal:viewletmanager')):
                    rawname = v.attrs[0][1][27:] # 27 = len('kssattr-viewletmanagername-')
                    # Break off any extra class names
                    # TODO We should really be safe and check for classes before and after.
                    rawname = rawname.split(' ',1)[0]
                    name = rawname.replace('-','.')
                    # Get the viewletmanager object
                    managerObj = findViewletManager(self, name)
                    if managerObj and not IAmIgnoredByGloworm.providedBy(managerObj):
                        self.outstr += "<li><a href='#' title='Viewlet Manager %s' class='inspectViewletManager kssattr-forviewletmanager-%s'>%s</a>" % (name, name.replace('.', '-'), name)
                        
                        # Look up the viewlets attached to this viewlet manager.
                        # We do it this way because calling viewletManager.viewlets won't see the hidden viewlets...
                        containedViewlets = getAdapters((self.context, self.request, managerObj.__parent__, managerObj),IViewlet)
                        containedViewlets = managerObj.sort([vl for vl in containedViewlets])
                        
                        stripped.append(v)
                        getChildViewlets(v, containedViewlets)
                        self.outstr += "</li>"
            self.outstr += "</ol>"
            return stripped
        
        def getChildViewlets(node, allViewlets=[]):
            """ Find all viewlets within this node """
            all = node.findAll('tal:viewlet')
            stripped = []
            self.outstr += "<ol class='viewlet-tree'>"
            
            def writeHiddenViewlet(viewlet):
                """ Create a list item HTML bit for a hidden viewlet """
                name = viewlet[0]
                managerObj = viewlet[1].manager
                viewletHash = hashViewletInfo(name, managerObj.__name__, getProvidedForViewlet(name, managerObj))
                return "<li><a href='#' title='Hidden viewlet %s' class='viewletMoreInfo hiddenViewlet kssattr-forviewlet-%s'>%s</a></li>" % (name, viewletHash, name)
            
            for v in all:
                if not(stripped and v.findParent('tal:viewlet') and stripped[-1] in v.findParents('tal:viewlet')):
                    viewletHash = v.attrs[0][1][20:] # 20 = len('kssattr-viewlethash-')
                    # Break off any extra class names
                    # TODO We should really be safe and check for classes before and after.
                    viewletHash = viewletHash.split(' ',1)[0]
                    reg = findTemplateViewRegistrationFromHash(viewletHash)
                    if reg:
                        while allViewlets and reg.name != allViewlets[0][0]:
                            self.outstr += writeHiddenViewlet(allViewlets[0])
                            allViewlets.pop(0)
                        
                        if not IAmIgnoredByGloworm.providedBy(allViewlets[0][1]):
                            self.outstr += "<li><a href='#' title='Visible viewlet %s' class='viewletMoreInfo kssattr-forviewlet-%s'>%s</a>" % (reg.name, viewletHash, reg.name)
                            stripped.append(v)
                            getChildViewletManagers(v)
                            self.outstr += "</li>"
                        allViewlets.pop(0) # Remove the current viewlet from the allViewlets list
            
            # Collect any remaining hidden viewletss
            if allViewlets:
                for vlt in allViewlets:
                    self.outstr += writeHiddenViewlet(vlt)
            self.outstr += "</ol>"
            return stripped
        
        getChildViewletManagers(soup)
コード例 #13
0
    def update(self):

        self.path = '/'.join(self.context.getPhysicalPath())
        self.cls = self.context.__class__

        self.fti = None
        self.methodAliases = None

        if IDynamicType.providedBy(self.context):
            self.fti = self.context.getTypeInfo()
            self.methodAliases = sorted(self.fti.getMethodAliases().items())

        self.defaultView = None
        self.viewMethods = []
        if IDynamicViewTypeInformation.providedBy(self.fti):
            self.defaultView = self.fti.defaultView(self.context)
            self.viewMethods = self.fti.getAvailableViewMethods(self.context)

        directly_provided = directlyProvidedBy(self.context)
        self.provided = list(providedBy(self.context).flattened())
        self.provided.sort(key=lambda i: i.__identifier__)
        self.provided = ({'dottedname': i.__identifier__,
                          'is_marker': i in directly_provided}
                          for i in self.provided)
        self.views = []

        generator = getAdapters((self.context, self.request,), Interface)
        while True:
            try:
                name, view = generator.next()

                if not IView.providedBy(view):
                    continue

                cls = view.__class__
                module = cls.__module__
                template = None

                if isinstance(view, ViewMixinForTemplates):
                    template = view.index.filename
                else:
                    for attr in ('index', 'template', '__call__'):
                        pt = getattr(view, attr, None)
                        if hasattr(pt, 'filename'):
                            template = pt.filename
                            break

                # Deal with silly Five metaclasses
                if (
                    module == 'Products.Five.metaclass' and
                    len(cls.__bases__) > 0
                ):
                    cls = cls.__bases__[0]
                elif cls == ViewMixinForTemplates:
                    cls = None

                self.views.append({
                    'name': name,
                    'class': cls,
                    'template': template,
                })
            except StopIteration:
                break
            except:
                # Some adapters don't initialise cleanly
                pass

        self.views.sort(key=lambda v: v['name'])

        self.methods = []
        self.variables = []

        _marker = object()
        for name in sorted(dir(aq_base(self.context))):
            attr = getattr(aq_base(self.context), name, _marker)
            if attr is _marker:
                continue

            # FIXME: Should we include ComputedAttribute here ? [glenfant]
            if isinstance(attr, (int, long, float, basestring, bool, list, tuple, dict, set, frozenset)):
                self.variables.append({
                    'name': name,
                    'primitive': True,
                    'value': attr,
                })
            elif (
                isinstance(attr, (types.MethodType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType)) or
                attr.__class__.__name__ == 'method-wrapper',
            ):

                source = None
                if name.endswith('__roles__'):
                    # name without '__roles__' is the last in self.methods since we're in a sorted(...) loop
                    if callable(attr):
                        secu_infos = attr()
                    else:
                        secu_infos = attr
                    if secu_infos is None:
                        secu_label = 'Public'
                    else:
                        secu_label = ''
                        try:
                            secu_label += 'Roles: ' + ', '.join([r for r in secu_infos[:-1]])
                        except TypeError:
                            # Avoid "TypeError: sequence index must be
                            # integer, not 'slice'", which occurs with the
                            # ``C`` security implementation. This is a rare
                            # case. In development you normally use the
                            # ``Python`` security implementation, where this
                            # error doesn't occur.
                            pass
                        secu_label += '. Permission: ' + secu_infos[-1][1:-11]  # _x_Permission -> x
                    self.methods[-1]['secu_infos'] = secu_label
                else:
                    try:
                        source = inspect.getsourcefile(attr)
                    except TypeError:
                        None

                    signature = name + "()"
                    try:
                        signature = name + inspect.formatargspec(*inspect.getargspec(attr))
                    except TypeError:
                        pass

                    self.methods.append({
                        'signature': signature,
                        'filename': source,
                        'help': inspect.getdoc(attr),
                    })
            else:
                self.variables.append({
                    'name': name,
                    'primitive': False,
                    'value': str(attr),
                })
コード例 #14
0
    def update(self):
        
        self.path = '/'.join(self.context.getPhysicalPath())
        self.cls = self.context.__class__

        self.fti = None
        self.methodAliases = None

        if IDynamicType.providedBy(self.context):
            self.fti = self.context.getTypeInfo()
            self.methodAliases = sorted(self.fti.getMethodAliases().items())
        
        self.defaultView = None
        self.viewMethods = []
        if IDynamicViewTypeInformation.providedBy(self.fti):
            self.defaultView = self.fti.defaultView(self.context)
            self.viewMethods = self.fti.getAvailableViewMethods(self.context)
        
        self.provided = list(providedBy(self.context).flattened())
        self.provided.sort(key=lambda i: i.__identifier__)

        self.views = []
        
        generator = getAdapters((self.context, self.request,), Interface)
        while True:
            try:
                name, view = generator.next()

                if not IView.providedBy(view):
                    continue

                cls = view.__class__
                module = cls.__module__
                template = None

                if isinstance(view, ViewMixinForTemplates):
                    template = view.index.filename
                else:
                    for attr in ('index', 'template', '__call__'):
                        pt = getattr(view, attr, None)
                        if hasattr(pt, 'filename'):
                            template = pt.filename
                            break

                # Deal with silly Five metaclasses
                if (
                    module == 'Products.Five.metaclass' and 
                    len(cls.__bases__) > 0
                ):
                    cls = cls.__bases__[0]
                elif cls == ViewMixinForTemplates:
                    cls = None

                self.views.append({
                    'name': name,
                    'class': cls,
                    'template': template,
                })
            except StopIteration:
                break
            except:
                # Some adapters don't initialise cleanly
                pass
        
        self.views.sort(key=lambda v: v['name'])

        self.methods = []
        self.variables = []

        _marker = object()
        for name in sorted(dir(aq_base(self.context))):
            attr = getattr(aq_base(self.context), name, _marker)
            if attr is _marker:
                continue
            
            if isinstance(attr, (int, long, float, basestring, bool, list, tuple, dict, set, frozenset)):
                self.variables.append({
                    'name': name,
                    'primitive': True,
                    'value': attr,
                })
            elif (
                isinstance(attr, (types.MethodType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType)) or
                attr.__class__.__name__ == 'method-wrapper',
            ):
                
                source = None
                try:
                    source = inspect.getsourcefile(attr)
                except TypeError:
                    None

                signature = name + "()"
                try:
                    signature = name + inspect.formatargspec(*inspect.getargspec(attr))
                except TypeError:
                    pass

                self.methods.append({
                    'signature': signature,
                    'filename': source,
                    'help': inspect.getdoc(attr),
                })
            else:
                self.variables.append({
                    'name': name,
                    'primitive': False,
                    'value': str(attr),
                })