示例#1
0
 def build_automap(self):
     """Build the :ref:`automap` file"""
     def handleNode(node, pkg=None, plugin=None):
         attr = node.attr
         file_name = attr['file_name']
         node.attr = dict(
                 name='!!%s' % file_name.capitalize(),
                 pkg=pkg
                 )
         if plugin:
             node.attr['plugin']=plugin
         if attr['file_ext'] == 'py':
             node.attr['path'] = attr['rel_path']
         node.label = file_name
         if node._value is None:
             node._value = ''
             
     self.automap = DirectoryResolver(os.path.join(self.site_path, 'pages'), ext='py', include='*.py',
                                      exclude='_*,.*,*.pyc')()
                                      
     self.automap.walk(handleNode, _mode='', pkg='*')
     for package in self.site.gnrapp.packages.values():
         packagemap = DirectoryResolver(os.path.join(package.packageFolder, 'webpages'),
                                        include='*.py', exclude='_*,.*')()
         packagemap.walk(handleNode, _mode='', pkg=package.id)
         self.automap.setItem(package.id, packagemap, name=package.attributes.get('name_long') or package.id)
         for pluginname,plugin in package.plugins.items():
             pluginmap = DirectoryResolver(plugin.webpages_path,
                                            include='*.py', exclude='_*,.*')()
             pluginmap.walk(handleNode, _mode='', pkg=package.id,plugin=plugin.id)
             self.automap.setItem("%s._plugin.%s"%(package.id,plugin.id), pluginmap, name=plugin.id)
     self.automap.toXml(os.path.join(self.site_path, 'automap.xml'))
示例#2
0
    def build_automap(self):
        """add???"""
        def handleNode(node, pkg=None):
            attr = node.attr
            file_name = attr['file_name']
            node.attr = dict(name='!!%s' % file_name.capitalize(), pkg=pkg)
            if attr['file_ext'] == 'py':
                node.attr['path'] = attr['rel_path']
            node.label = file_name
            if node._value is None:
                node._value = ''

        self.automap = DirectoryResolver(os.path.join(self.site_path, 'pages'),
                                         ext='py',
                                         include='*.py',
                                         exclude='_*,.*,*.pyc')()

        self.automap.walk(handleNode, _mode='', pkg='*')
        for package in self.site.gnrapp.packages.values():
            packagemap = DirectoryResolver(os.path.join(
                package.packageFolder, 'webpages'),
                                           include='*.py',
                                           exclude='_*,.*')()
            packagemap.walk(handleNode, _mode='', pkg=package.id)
            self.automap.setItem(package.id,
                                 packagemap,
                                 name=package.attributes.get('name_long')
                                 or package.id)
        self.automap.toXml(os.path.join(self.site_path, 'automap.xml'))
示例#3
0
 def updateLocalizationFiles(self,scan_all=True):
     for s in self.slots:
         if scan_all or s['destFolder'] != self.genroroot:
             locbag = Bag()
             for root in s['roots']:
                 d = DirectoryResolver(root,include='*.py,*.js')()
                 d.walk(self._updateModuleLocalization,locbag=locbag,_mode='deep',destFolder=s['destFolder'] )
             locbag.toXml(os.path.join(s['destFolder'],'localization.xml'),pretty=True,typeattrs=False, typevalue=False)
     self.buildLocalizationDict()
示例#4
0
 def updateLocalizationFiles(self, scan_all=True):
     for s in self.slots:
         if scan_all or s['destFolder'] != self.genroroot:
             locbag = Bag()
             for root in s['roots']:
                 d = DirectoryResolver(root, include='*.py,*.js')()
                 d.walk(self._updateModuleLocalization,
                        locbag=locbag,
                        _mode='deep',
                        destFolder=s['destFolder'])
             locbag.toXml(os.path.join(s['destFolder'], 'localization.xml'),
                          pretty=True,
                          typeattrs=False,
                          typevalue=False)
     self.buildLocalizationDict()
示例#5
0
class ResourceLoader(object):
    """Base class to load :ref:`intro_resources`"""
    def __init__(self, site=None):
        self.site = site
        self.site_path = self.site.site_path
        self.site_name = self.site.site_name
        self.gnr_config = self.site.gnr_config
        self.gnrapp = self.site.gnrapp
        self.debug = self.site.debug
        self.gnr_static_handler = self.site.getStatic('gnr')
        self.build_automap()
        self.page_factories = {}
        self.default_path = self.site.default_page and self.site.default_page.split('/')
        
    def find_webtools(self):
        """TODO"""
        def isgnrwebtool(cls):
            return inspect.isclass(cls) and issubclass(cls, BaseWebtool) and cls is not BaseWebtool
            
        tools = {}
        webtool_pathlist = []
        if 'webtools' in self.gnr_config['gnr.environment_xml']:
            for path in self.gnr_config['gnr.environment_xml'].digest('webtools:#a.path'):
                webtool_pathlist.append(expandpath(path))
        for package in self.gnrapp.packages.values():
            webtool_pathlist.append(os.path.join(package.packageFolder, 'webtools'))
        project_resource_path = os.path.join(self.site_path, '..', '..', 'webtools')
        webtool_pathlist.append(os.path.normpath(project_resource_path))
        for path in webtool_pathlist:
            if not os.path.isdir(path):
                continue
            for tool_module in os.listdir(path):
                if tool_module.endswith('.py'):
                    module_path = os.path.join(path, tool_module)
                    try:
                        module = gnrImport(module_path, avoidDup=True)
                        tool_classes = inspect.getmembers(module, isgnrwebtool)
                        tool_classes = [(name.lower(), value) for name, value in tool_classes]
                        tools.update(dict(tool_classes))
                    except ImportError:
                        pass
        return tools
        
    def build_automap(self):
        """Build the :ref:`automap` file"""
        def handleNode(node, pkg=None, plugin=None):
            attr = node.attr
            file_name = attr['file_name']
            node.attr = dict(
                    name='!!%s' % file_name.capitalize(),
                    pkg=pkg
                    )
            if plugin:
                node.attr['plugin']=plugin
            if attr['file_ext'] == 'py':
                node.attr['path'] = attr['rel_path']
            node.label = file_name
            if node._value is None:
                node._value = ''
                
        self.automap = DirectoryResolver(os.path.join(self.site_path, 'pages'), ext='py', include='*.py',
                                         exclude='_*,.*,*.pyc')()
                                         
        self.automap.walk(handleNode, _mode='', pkg='*')
        for package in self.site.gnrapp.packages.values():
            packagemap = DirectoryResolver(os.path.join(package.packageFolder, 'webpages'),
                                           include='*.py', exclude='_*,.*')()
            packagemap.walk(handleNode, _mode='', pkg=package.id)
            self.automap.setItem(package.id, packagemap, name=package.attributes.get('name_long') or package.id)
            for pluginname,plugin in package.plugins.items():
                pluginmap = DirectoryResolver(plugin.webpages_path,
                                               include='*.py', exclude='_*,.*')()
                pluginmap.walk(handleNode, _mode='', pkg=package.id,plugin=plugin.id)
                self.automap.setItem("%s._plugin.%s"%(package.id,plugin.id), pluginmap, name=plugin.id)
        self.automap.toXml(os.path.join(self.site_path, 'automap.xml'))
        
    @property
    def sitemap(self):
        """Return the sitemap Bag (if there is no sitemap, creates it)"""
        if not hasattr(self, '_sitemap'):
            sitemap_path = os.path.join(self.site_path, 'sitemap.xml')
            if not os.path.isfile(sitemap_path):
                sitemap_path = os.path.join(self.site_path, 'automap.xml')
            _sitemap = Bag(sitemap_path)
            _sitemap.setBackRef()
            self._sitemap = _sitemap
        return self._sitemap
        
    def get_page_node(self, path_list, default_path=None):
        """Get the deepest :ref:`bagnode` in the sitemap :ref:`bag` associated with the given url
        
        :param path_list: TODO
        :param default: TODO"""
        def escape_path_list(path_list):
            return [p.replace('.','\\.') for p in path_list]
        def unescape_path_list(path_list):
            return [p.replace('\\.','.') for p in path_list]
        path_list = escape_path_list(path_list)
        page_node = self.sitemap.getDeepestNode('.'.join(path_list))
        if not page_node and self.site.mainpackage: # try in the main package
            page_node = self.sitemap.getDeepestNode('.'.join([self.site.mainpackage] + path_list))
        if page_node:
            page_node_attributes = page_node.getInheritedAttributes()
            if page_node_attributes.get('path'):
                page_node._tail_list=unescape_path_list(getattr(page_node,'_tail_list',[]))
                return page_node, page_node_attributes
            else:
                page_node = self.sitemap.getDeepestNode('.'.join(path_list + ['index']))
                if page_node:
                    page_node_attributes = page_node.getInheritedAttributes()
                    if page_node_attributes.get('path'):
                        page_node._tail_list=unescape_path_list(getattr(page_node,'_tail_list',[]))
                        return page_node, page_node_attributes
        if not page_node and default_path:
            page_node, page_node_attributes = self.get_page_node(default_path)
            if page_node:
                page_node._tail_list =  unescape_path_list(path_list)
            return page_node, page_node_attributes
        return None, None
        
    def __call__(self, path_list, request, response, environ=None,request_kwargs=None):
        page_node = None
        request_kwargs = request_kwargs or dict()
        mobile = request_kwargs.pop('_mobile',False)
        if mobile:
            page_node, page_node_attributes = self.get_page_node(['mobile']+path_list)
        if not page_node:
            page_node, page_node_attributes = self.get_page_node(path_list, default_path=self.default_path)
        if not page_node:
            return None
        request_args = page_node._tail_list
        path = page_node_attributes.get('path')
        pkg = page_node_attributes.get('pkg')
        plugin = page_node_attributes.get('plugin')
        page_class = self.get_page_class(path=path, pkg=pkg, plugin=plugin,request_args=request_args,request_kwargs=request_kwargs)
        page = page_class(site=self.site, request=request, response=response,
                          request_kwargs=request_kwargs, request_args=request_args,
                          filepath=path, packageId=page_class._packageId, pluginId=plugin,  basename=path, environ=environ)
        return page
        
    def get_page_class(self, path=None, pkg=None, plugin=None,request_args=None,request_kwargs=None):
        """TODO
        
        :param path: TODO
        :param pkg: the :ref:`package <packages>` object"""
        if pkg == '*':
            module_path = os.path.join(self.site_path, path)
            pkg = self.site.config['packages?default']
        else:
            if plugin:
                module_path= os.path.join(self.gnrapp.packages[pkg].plugins[plugin].webpages_path, path)
            else:
                module_path = os.path.join(self.gnrapp.packages[pkg].packageFolder, 'webpages', path)
            
        # if module_path in self.page_factories:
        #    return self.page_factories[module_path]
        page_module = gnrImport(module_path, avoidDup=True)
        page_factory = getattr(page_module, 'page_factory', GnrWebPage)
        custom_class = getattr(page_module, 'GnrCustomWebPage')
        mainPkg = pkg
        if hasattr(custom_class,'getMainPackage'):
            kw = dict()
            if 'page_id' in request_kwargs:
                kw = self.site.register.pageStore(request_kwargs['page_id']).getItem('pageArgs') or dict()
                kw.update(request_kwargs)
            mainPkg = custom_class.getMainPackage(request_args=request_args,request_kwargs=kw)
        py_requires = splitAndStrip(getattr(custom_class, 'py_requires', ''), ',')
        plugin_webpage_classes = self.plugin_webpage_classes(path, pkg=mainPkg)
        for plugin_webpage_class in plugin_webpage_classes:
            plugin_py_requires = splitAndStrip(getattr(plugin_webpage_class, 'py_requires', ''), ',')
            py_requires.extend(plugin_py_requires)
        page_class = cloneClass('GnrCustomWebPage', page_factory)
        page_class.__module__ = page_module.__name__
        self.page_class_base_mixin(page_class, pkg=mainPkg)
        page_class.dojo_version = getattr(custom_class, 'dojo_version', None) or self.site.config[
                                                                                 'dojo?version'] or '11'
        page_class.theme = getattr(custom_class, 'theme', None) or self.site.config['dojo?theme'] or 'tundra'
        page_class.gnrjsversion = getattr(custom_class, 'gnrjsversion', None) or self.site.config[
                                                                                 'gnrjs?version'] or '11'
        page_class.maintable = getattr(custom_class, 'maintable', None)
        page_class.recordLock = getattr(custom_class, 'recordLock', None)
        page_class.user_polling = int(
                getattr(custom_class, 'user_polling', None) or self.site.config['polling?user'] or 3)
        page_class.auto_polling = int(
                getattr(custom_class, 'auto_polling', None) or self.site.config['polling?auto'] or 30)
        if hasattr(custom_class,'polling_enabled'):
            page_class.polling_enabled = getattr(custom_class, 'polling_enabled')
        page_class.eagers = getattr(custom_class, 'eagers', {})
        page_class.css_requires = []
        page_class.js_requires = splitAndStrip(getattr(custom_class, 'js_requires', ''), ',')
        page_class.pageOptions = getattr(custom_class, 'pageOptions', {})
        page_class.auth_tags = getattr(custom_class, 'auth_tags', '')
        page_class.resourceDirs = self.page_class_resourceDirs(page_class, module_path, pkg=mainPkg)
        self.page_pyrequires_mixin(page_class, py_requires)
        classMixin(page_class, custom_class, only_callables=False)
        page_class.css_requires.extend([x for x in splitAndStrip(getattr(custom_class, 'css_requires', ''), ',') if x])
        page_class.tpldirectories = page_class.resourceDirs + [
                self.gnr_static_handler.path(page_class.gnrjsversion, 'tpl')]
        page_class._packageId = mainPkg
        self.page_class_plugin_mixin(page_class, plugin_webpage_classes)
        self.page_class_custom_mixin(page_class, path, pkg=mainPkg)
        self.page_factories[module_path] = page_class
        return page_class
        
    def page_class_base_mixin(self, page_class, pkg=None):
        """Look for custom classes in the package
        
        :param page_class: TODO
        :param pkg: the :ref:`package <packages>` object"""
        if pkg:
            package = self.gnrapp.packages[pkg]
        if package and package.webPageMixin:
            classMixin(page_class, package.webPageMixin, only_callables=False) # first the package standard
        if self.gnrapp.webPageCustom:
            classMixin(page_class, self.gnrapp.webPageCustom, only_callables=False) # then the application custom
        if package and package.webPageMixinCustom:
            classMixin(page_class, package.webPageMixinCustom, only_callables=False) # finally the package custom
            
    def plugin_webpage_classes(self, path, pkg=None):
        """Look in the plugins folders for a file named as the current webpage and get all classes
        
        :param path: TODO
        :param pkg: the :ref:`package <packages>` object"""
        plugin_webpage_classes = []
        path = path.split(os.path.sep)
        pkg = pkg and self.site.gnrapp.packages[pkg]
        if pkg:
            pkg_plugins = pkg.getPlugins()
            for plugin in pkg_plugins:
                pluginPagePath = os.path.join(plugin.webpages_path, *path)
                if os.path.isfile(pluginPagePath):
                    component_page_module = gnrImport(pluginPagePath, avoidDup=True)
                    component_page_class = getattr(component_page_module, 'GnrCustomWebPage', None)
                    if component_page_class:
                        plugin_webpage_classes.append(component_page_class)
        return plugin_webpage_classes
        
    def page_class_plugin_mixin(self, page_class, plugin_webpage_classes):
        """Mixin the current class with the *plugin_webpage_classes* attribute
        
        :param page_class: TODO
        :param plugin_webpage_classes: TODO"""
        for plugin_webpage_class in plugin_webpage_classes:
            classMixin(page_class, plugin_webpage_class, only_callables=False)
            
    def page_class_custom_mixin(self, page_class, path, pkg=None):
        """Look in the instance custom folder for a file named as the current webpage
        
        :param page_class: TODO
        :param path: TODO
        :param pkg: the :ref:`package <packages>` object"""
        path = path.split(os.path.sep)
        if pkg:
            customPagePath = os.path.join(self.gnrapp.customFolder, pkg, 'webpages', *path)
            if os.path.isfile(customPagePath):
                component_page_module = gnrImport(customPagePath, avoidDup=True)
                component_page_class = getattr(component_page_module, 'WebPage', None)
                if component_page_class:
                    classMixin(page_class, component_page_class, only_callables=False)
    
    def _appendPathIfExists(self,result, path):
        if os.path.exists(path):
            result.append(path)
                    
    def page_class_resourceDirs(self, page_class, path, pkg=None):
        """Build page resources directories
        
        :param page_class: TODO
        :param path: TODO
        :param pkg: the :ref:`package <packages>` object"""
        if pkg:
            pagesPath = os.path.join(self.gnrapp.packages[pkg].packageFolder, 'webpages')
            packageResourcePath =  os.path.join(self.gnrapp.packages[pkg].packageFolder, 'resources')
        else:
            pagesPath = os.path.join(self.site_path, 'pages')
        #curdir = os.path.dirname(os.path.join(pagesPath, path))
        #resourcePkg = None
        result = [] # result is now empty
        fpath = os.path.join(self.site_path, 'resources')
        self._appendPathIfExists(result, fpath) # we add a custom resource folder for current package
        if pkg: # for index page or other pages at root level (out of any package)
            #resourcePkg = self.gnrapp.packages[pkg].attributes.get('resourcePkg')
            fpath = os.path.join(self.site_path, '_custom', pkg, '_resources')
            self._appendPathIfExists(result, fpath) # we add a custom resource folder for current package
        
        fpath = os.path.join(self.site_path, '_resources')
        self._appendPathIfExists(result, fpath) # we add a custom resource folder for common package
            
        #while curdir.startswith(pagesPath):
        #    fpath = os.path.join(curdir, '_resources')
        #    if os.path.isdir(fpath):
        #        result.append(fpath)
        #    curdir = os.path.dirname(curdir) # we add a resource folder for folder 
            # of current page
        #if resourcePkg:
        #    for rp in resourcePkg.split(','):
        #        fpath = os.path.join(self.gnrapp.packages[rp].packageFolder, 'webpages', '_resources')
        #        if os.path.isdir(fpath):
        #            result.append(fpath)
            #result.extend(self.siteResources)
        if packageResourcePath:
            self._appendPathIfExists(result, packageResourcePath)
        resources_list = self.site.resources_dirs
        result.extend(resources_list)
        return result
        
    def package_resourceDirs(self, pkg, omitSiteResources=False, pluginId=None):
        """TODO
        
        :param pkg: the :ref:`package <packages>` object
        :param omitSiteResources: boolean. TODO"""
        pkg = self.gnrapp.packages[pkg]
        result = []
        if not hasattr(pkg, '_resourceDirs'):
            pagesPath = os.path.join(pkg.packageFolder, 'webpages')
            resourcePkg = None
            pkgResourceDirs = [] # result is now empty
            resourcePkg = pkg.attributes.get('resourcePkg')
            fpath = os.path.join(self.site_path, '_custom', pkg.id, '_resources')
            if os.path.isdir(fpath):
                pkgResourceDirs.append(fpath) # we add a custom resource folder for current package
                
            if resourcePkg:
                for rp in resourcePkg.split(','):
                    fpath = os.path.join(self.site_path, '_custom', pkg.id, '_resources')
                    if os.path.isdir(fpath):
                        pkgResourceDirs.append(fpath)
            fpath = os.path.join(pagesPath, '_resources')
            if os.path.isdir(fpath):
                pkgResourceDirs.append(fpath) # we add a resource folder for common package
            rsrc_path = os.path.join(pkg.packageFolder, 'resources')
            if os.path.isdir(rsrc_path):
                pkgResourceDirs.append(rsrc_path)
            pkg._siteResourceDirs = self.site.resources_dirs
            pkg._resourceDirs = pkgResourceDirs
        if pluginId and pluginId in pkg.plugins:
            plugin = pkg.plugins[pluginId]
            if plugin.resources_path:
                result.append(plugin.resources_path)
        result.extend(list(pkg._resourceDirs))
        if not omitSiteResources:
            result.extend(pkg._siteResourceDirs)
            # so we return a list of any possible resource folder starting from
        # most customized and ending with most generic ones
        return result
        
    def site_resources(self):
        """TODO"""
        resources = Bag()
        resources['site'] = os.path.join(self.site_path, 'resources')
        resources_list = [(resource.label, resource.attr.get('path')) for resource in
                          self.site.config['resources'] or []]
        for label, rsrc_path in resources_list:
            if rsrc_path:
                resources[label] = rsrc_path
            else:
                rsrc_path = self.resource_name_to_path(label)
                resources[label] = rsrc_path
        auto_resource_path = self.resource_name_to_path(self.site_name, safe=False)
        if auto_resource_path:
            resources[self.site_name] = os.path.realpath(auto_resource_path)

        for pkg in self.site.gnrapp.packages.values():
            rsrc_path = os.path.join(pkg.packageFolder, 'resources')
            label = 'pkg_%s' % (pkg.id)
            if os.path.isdir(rsrc_path):
                resources[label] = rsrc_path
            plugins = [p for p in pkg.getPlugins() if p.resources_path]
            for plugin in plugins:
                label = 'pkg_%s_%s' % (pkg.id,plugin.id)
                if os.path.isdir(plugin.resources_path):
                    resources[label] = plugin.resources_path
        return resources
        
    def resource_name_to_path(self, res_id, safe=True):
        """TODO
        
        :param res_id: TODO
        :param safe: TODO"""
        project_resource_path = os.path.normpath(os.path.join(self.site_path, '..', '..', 'resources', res_id))
        if os.path.isdir(project_resource_path):
            log.debug('resource_name_to_path(%s) -> %s (project)' % (repr(res_id),repr(project_resource_path)))
            return project_resource_path
        if 'resources' in self.gnr_config['gnr.environment_xml']:
            for path in self.gnr_config['gnr.environment_xml'].digest('resources:#a.path'):
                res_path = expandpath(os.path.join(path, res_id))
                if os.path.isdir(res_path):
                    log.debug('resource_name_to_path(%s) -> %s (gnr config)' % (repr(res_id), repr(res_path)))
                    return res_path
        log.debug('resource_name_to_path(%s) not found.' % repr(res_id))
        if safe:
            raise Exception('Error: resource %s not found' % res_id)
            
    def page_pyrequires_mixin(self, page_class, py_requires):
        """Allow to mixin the :ref:`webpage python requirements <webpages_py_requires>`
        
        :param page_class: TODO
        :param py_requires: TODO"""
        for mix in py_requires:
            if mix:
                self.mixinResource(page_class, page_class.resourceDirs, mix)
                
    def mixinResource(self, kls, resourceDirs, *path):        
        """TODO
        
        :param kls: TODO
        :param resourceDirs: TODO
        :param \*path: TODO"""
        path = os.path.join(*path)
        if ':' in path:
            modName, clsName = path.split(':')
        else:
            modName, clsName = path, '*'
        modPathList = self.getResourceList(resourceDirs, modName, 'py') or []
        if modPathList:
            modPathList.reverse()
            for modPath in modPathList:
                classMixin(kls, '%s:%s' % (modPath, clsName), only_callables=False, site=self)
        else:
            raise GnrMixinError('Cannot import component %s' % modName)
            
    def py_requires_iterator(self, source_class, target_class):
        """TODO
        
        :param source_class: TODO
        :param target_class: TODO"""
        resourceDirs = target_class.resourceDirs
        py_requires = [x for x in splitAndStrip(getattr(source_class, 'py_requires', ''), ',') if x] or []
        for path in py_requires:
            if ':' in path:
                modName, clsName = path.split(':')
            else:
                modName, clsName = path, '*'
            modPathList = self.getResourceList(resourceDirs, modName, 'py') or []
            if modPathList:
                modPathList.reverse()
                for modPath in modPathList:
                    yield '%s:%s' % (modPath, clsName)
                    #classMixin(kls,'%s:%s'%(modPath,clsName),only_callables=False,site=self)
            else:
                raise GnrMixinError('Cannot import component %s' % modName)
                
    def getResourceList(self, resourceDirs, path, ext=None,pkg=None):
        """Find a resource in the current ``_resources`` folder or in parent folders one
        
        :param resourceDirs: TODO
        :param path: TODO
        :param ext: TODO"""
        result = []
        if ext == 'css' or ext == 'js':
            locations = resourceDirs[:]
            locations.reverse()
        else:
            locations = resourceDirs
        if ext and not path.endswith('.%s' % ext): path = '%s.%s' % (path, ext)
        if '*' in path:
            searchpath=os.path.split(path.split('*')[0])[0]
            use_glob=True
        else:
            searchpath=path
            use_glob=False
        for dpath in locations:
            fpath = os.path.join(dpath, searchpath)
            if os.path.exists(fpath):
                if use_glob:
                    result.extend(glob.glob(os.path.join(dpath,path)))
                else:
                    result.append(fpath)
        return uniquify(result)
        
    def loadResource(self, *path, **kwargs):
        """TODO"""
        resource_class = cloneClass('CustomResource', BaseResource)
        pkg=kwargs.pop('pkg', None)
        page=kwargs.pop('page', None)
        pluginId=kwargs.pop('pluginId', None)
        pkgOnly=kwargs.pop('pkgOnly', False)
        if pkg:
            resourceDirs = self.package_resourceDirs(pkg)
            lookupDirs = self.package_resourceDirs(pkg, omitSiteResources=pkgOnly, pluginId=pluginId)
        else:
            resourceDirs = lookupDirs = page.resourceDirs
        resource_class.resourceDirs = resourceDirs
        self.mixinResource(resource_class, lookupDirs, *path)
        return resource_class()
                 
    def mixinPageComponent(self, page, *path,**kwargs):
        """This method is used to mixin a component to a :ref:`webpage` at any time
        
        :param page: the target :ref:`webpage`
        :param \* path: the path of the :ref:`component <components>`"""
        pkg=kwargs.pop('pkg', None)
        pkgOnly=kwargs.pop('pkgOnly', False)
        pluginId=kwargs.pop('pluginId', None)
        component=self.loadResource(*path, page=page, pkg=pkg, pkgOnly=pkgOnly, pluginId=pluginId)
        setattr(component,'__mixin_pkg', pkg)
        setattr(component, '__mixin_path' ,'/'.join(path))
        css_requires = getattr(component,'css_requires',[])
        js_requires = getattr(component,'js_requires',[])
        for css in css_requires:
            if css and not css in page.dynamic_css_requires and not css in page.css_requires:
                page.dynamic_css_requires[css] = page.getResourceUri(css,'css',add_mtime=True,pkg=pkg)
        for js in js_requires:
            if js and not js in page.dynamic_js_requires and not js in page.js_requires:
                page.dynamic_js_requires[js] = page.getResourceUri(js,'js',add_mtime=True,pkg=pkg)
        page.mixin(component,**kwargs)
    
        
    def loadTableScript(self, page, table=None, respath=None, class_name=None):
        """TODO
        
        :param page: TODO
        :param table: the :ref:`database table <table>` name on which the query will be executed,
                      in the form ``packageName.tableName`` (packageName is the name of the
                      :ref:`package <packages>` to which the table belongs to)
        :param respath: TODO
        :param class_name: TODO
        """
        class_name = class_name or 'Main'
        application = self.gnrapp
        if ':' in respath:
            table, respath = respath.split(':')
        if isinstance(table, basestring):
            table = application.db.table(table)
        if not table:
            tablename = '_default'
            modName = os.path.join('tables', tablename, *(respath.split('/')))
        else:
            tablename = table.name
            pkgname = table.pkg.name
            modName = os.path.join('tables','_packages',pkgname, tablename, *(respath.split('/')))
        resourceDirs = page.resourceDirs
        modPathList = self.getResourceList(resourceDirs, modName, 'py')
        if not modPathList and table is not None:
            resourceDirs = self.package_resourceDirs(table.pkg.name)
            modName = os.path.join('tables', tablename, *(respath.split('/')))
            modPathList = self.getResourceList(resourceDirs, modName, 'py')
            if not modPathList:
                tablename = '_default'
                resourceDirs = page.resourceDirs
                modName = os.path.join('tables', tablename, *(respath.split('/')))
                modPathList = self.getResourceList(resourceDirs, modName, 'py')
        modPathList = self.getResourceList(resourceDirs, modName, 'py') or []
        if modPathList:
            modPathList.reverse()
            basePath = modPathList.pop(0)
            resource_module = gnrImport(basePath, avoidDup=True)
            resource_class = getattr(resource_module, class_name, None)
            for modPath in modPathList:
                resource_module = gnrImport(modPath, avoidDup=True)
                resource_class =cloneClass('CustomResource', resource_class)
                custom_resource_class = getattr(resource_module, class_name, None)
                if resource_class:
                    classMixin(resource_class, custom_resource_class, only_callables=False)
            resource_obj = resource_class(page=page, resource_table=table)
            return resource_obj
        else:
            raise GnrWebServerError('Cannot import component %s' % modName)
    
    def resourcesAtPath(self,page=None, pkg=None, path=None, ext='py'):
        """TODO
        
        :param pkg: the :ref:`package <packages>` object
        :param path: TODO
        :param ext: TODO"""
        result = Bag()
        if pkg:
            locations = list(self.package_resourceDirs(pkg))
        else:
            locations = page.resourceDirs
        for dpath in locations:
            dirpath = os.path.join(dpath, path)
            if os.path.isdir(dirpath):
                b = DirectoryResolver(dirpath, include='*.py', dropext=True)
                result.update(b, resolved=True)
        return result
示例#6
0
class ResourceLoader(object):
    """add???"""
    def __init__(self, site=None):
        self.site = site
        self.site_path = self.site.site_path
        self.site_name = self.site.site_name
        self.gnr_config = self.site.gnr_config
        self.gnrapp = self.site.gnrapp
        self.debug = self.site.debug
        self.gnr_static_handler = self.site.getStatic('gnr')
        self.build_automap()
        self.page_factories = {}
        self.default_path = self.site.default_page and self.site.default_page.split(
            '/')

    def find_webtools(self):
        """add???"""
        def isgnrwebtool(cls):
            return inspect.isclass(cls) and issubclass(
                cls, BaseWebtool) and cls is not BaseWebtool

        tools = {}
        webtool_pathlist = []
        if 'webtools' in self.gnr_config['gnr.environment_xml']:
            for path in self.gnr_config['gnr.environment_xml'].digest(
                    'webtools:#a.path'):
                webtool_pathlist.append(expandpath(path))
        for package in self.gnrapp.packages.values():
            webtool_pathlist.append(
                os.path.join(package.packageFolder, 'webtools'))
        project_resource_path = os.path.join(self.site_path, '..', '..',
                                             'webtools')
        webtool_pathlist.append(os.path.normpath(project_resource_path))
        for path in webtool_pathlist:
            if not os.path.isdir(path):
                continue
            for tool_module in os.listdir(path):
                if tool_module.endswith('.py'):
                    module_path = os.path.join(path, tool_module)
                    try:
                        module = gnrImport(module_path, avoidDup=True)
                        tool_classes = inspect.getmembers(module, isgnrwebtool)
                        tool_classes = [(name.lower(), value)
                                        for name, value in tool_classes]
                        tools.update(dict(tool_classes))
                    except ImportError:
                        pass
        return tools

    def build_automap(self):
        """add???"""
        def handleNode(node, pkg=None):
            attr = node.attr
            file_name = attr['file_name']
            node.attr = dict(name='!!%s' % file_name.capitalize(), pkg=pkg)
            if attr['file_ext'] == 'py':
                node.attr['path'] = attr['rel_path']
            node.label = file_name
            if node._value is None:
                node._value = ''

        self.automap = DirectoryResolver(os.path.join(self.site_path, 'pages'),
                                         ext='py',
                                         include='*.py',
                                         exclude='_*,.*,*.pyc')()

        self.automap.walk(handleNode, _mode='', pkg='*')
        for package in self.site.gnrapp.packages.values():
            packagemap = DirectoryResolver(os.path.join(
                package.packageFolder, 'webpages'),
                                           include='*.py',
                                           exclude='_*,.*')()
            packagemap.walk(handleNode, _mode='', pkg=package.id)
            self.automap.setItem(package.id,
                                 packagemap,
                                 name=package.attributes.get('name_long')
                                 or package.id)
        self.automap.toXml(os.path.join(self.site_path, 'automap.xml'))

    @property
    def sitemap(self):
        """add???"""
        if not hasattr(self, '_sitemap'):
            sitemap_path = os.path.join(self.site_path, 'sitemap.xml')
            if not os.path.isfile(sitemap_path):
                sitemap_path = os.path.join(self.site_path, 'automap.xml')
            _sitemap = Bag(sitemap_path)
            _sitemap.setBackRef()
            self._sitemap = _sitemap
        return self._sitemap

    def get_page_node(self, path_list, default=False):
        """Get the deepest node in the sitemap bag associated with the given url
        
        :param path_list: add???
        :param default: add???. Default value is ``False``
        """
        def escape_path_list(path_list):
            return [p.replace('.', '\\.') for p in path_list]

        def unescape_path_list(path_list):
            return [p.replace('\\.', '.') for p in path_list]

        path_list = escape_path_list(path_list)
        page_node = self.sitemap.getDeepestNode('.'.join(path_list))
        if not page_node and self.site.mainpackage:  # try in the main package
            page_node = self.sitemap.getDeepestNode(
                '.'.join([self.site.mainpackage] + path_list))
        if page_node:
            page_node_attributes = page_node.getInheritedAttributes()
            if page_node_attributes.get('path'):
                page_node._tail_list = unescape_path_list(
                    getattr(page_node, '_tail_list', []))
                return page_node, page_node_attributes
            else:
                page_node = self.sitemap.getDeepestNode('.'.join(path_list +
                                                                 ['index']))
                if page_node:
                    page_node_attributes = page_node.getInheritedAttributes()
                    if page_node_attributes.get('path'):
                        page_node._tail_list = unescape_path_list(
                            getattr(page_node, '_tail_list', []))
                        return page_node, page_node_attributes
        if self.default_path and not default:
            page_node, page_node_attributes = self.get_page_node(
                self.default_path, default=True)
            page_node._tail_list = unescape_path_list(path_list)
            return page_node, page_node_attributes
        return None, None

    def __call__(self, path_list, request, response, environ=None):
        page_node, page_node_attributes = self.get_page_node(path_list)
        if not page_node:
            return None
        request_args = page_node._tail_list
        path = page_node_attributes.get('path')
        pkg = page_node_attributes.get('pkg')
        page_class = self.get_page_class(path=path, pkg=pkg)
        page = page_class(site=self.site,
                          request=request,
                          response=response,
                          request_kwargs=self.site.parse_request_params(
                              request.params),
                          request_args=request_args,
                          filepath=path,
                          packageId=pkg,
                          basename=path,
                          environ=environ)
        return page

    def get_page_class(self, path=None, pkg=None):
        """add???
        
        :param path: add???. Default value is ``None``
        :param pkg: add???. Default value is ``None``
        :returns: add???
        """
        if pkg == '*':
            module_path = os.path.join(self.site_path, path)
            pkg = self.site.config['packages?default']
        else:
            module_path = os.path.join(self.gnrapp.packages[pkg].packageFolder,
                                       'webpages', path)

        # if module_path in self.page_factories:
        #    return self.page_factories[module_path]
        page_module = gnrImport(module_path, avoidDup=True)
        page_factory = getattr(page_module, 'page_factory', GnrWebPage)
        custom_class = getattr(page_module, 'GnrCustomWebPage')
        py_requires = splitAndStrip(getattr(custom_class, 'py_requires', ''),
                                    ',')
        plugin_webpage_classes = self.plugin_webpage_classes(path, pkg=pkg)
        for plugin_webpage_class in plugin_webpage_classes:
            plugin_py_requires = splitAndStrip(
                getattr(plugin_webpage_class, 'py_requires', ''), ',')
            py_requires.extend(plugin_py_requires)
        page_class = cloneClass('GnrCustomWebPage', page_factory)
        page_class.__module__ = page_module
        self.page_class_base_mixin(page_class, pkg=pkg)
        page_class.dojo_version = getattr(
            custom_class, 'dojo_version',
            None) or self.site.config['dojo?version'] or '11'
        page_class.theme = getattr(
            custom_class, 'theme',
            None) or self.site.config['dojo?theme'] or 'tundra'
        page_class.gnrjsversion = getattr(
            custom_class, 'gnrjsversion',
            None) or self.site.config['gnrjs?version'] or '11'
        page_class.maintable = getattr(custom_class, 'maintable', None)
        page_class.recordLock = getattr(custom_class, 'recordLock', None)
        page_class.user_polling = int(
            getattr(custom_class, 'user_polling', None)
            or self.site.config['polling?user'] or 3)
        page_class.auto_polling = int(
            getattr(custom_class, 'auto_polling', None)
            or self.site.config['polling?auto'] or 30)
        page_class.eagers = getattr(custom_class, 'eagers', {})
        page_class.css_requires = []
        page_class.js_requires = splitAndStrip(
            getattr(custom_class, 'js_requires', ''), ',')
        page_class.pageOptions = getattr(custom_class, 'pageOptions', {})
        page_class.auth_tags = getattr(custom_class, 'auth_tags', '')
        page_class.resourceDirs = self.page_class_resourceDirs(page_class,
                                                               module_path,
                                                               pkg=pkg)
        self.page_pyrequires_mixin(page_class, py_requires)
        classMixin(page_class, custom_class, only_callables=False)
        page_class.css_requires.extend([
            x for x in splitAndStrip(getattr(custom_class, 'css_requires', ''),
                                     ',') if x
        ])
        page_class.tpldirectories = page_class.resourceDirs + [
            self.gnr_static_handler.path(page_class.gnrjsversion, 'tpl')
        ]
        page_class._packageId = pkg
        self.page_class_plugin_mixin(page_class, plugin_webpage_classes)
        self.page_class_custom_mixin(page_class, path, pkg=pkg)
        self.page_factories[module_path] = page_class
        return page_class

    def page_class_base_mixin(self, page_class, pkg=None):
        """Look for custom classes in the package
        
        :param page_classe: add???
        :param pkg: add???. Default value is ``None``
        """
        if pkg:
            package = self.gnrapp.packages[pkg]
        if package and package.webPageMixin:
            classMixin(page_class, package.webPageMixin,
                       only_callables=False)  # first the package standard
        if self.gnrapp.webPageCustom:
            classMixin(page_class,
                       self.gnrapp.webPageCustom,
                       only_callables=False)  # then the application custom
        if package and package.webPageMixinCustom:
            classMixin(page_class,
                       package.webPageMixinCustom,
                       only_callables=False)  # finally the package custom

    def plugin_webpage_classes(self, path, pkg=None):
        """Look in the plugins folders for a file named as the current webpage and get all classes
        
        :param path: add???
        :param pkg: add???. Default value is ``None``
        """
        plugin_webpage_classes = []
        path = path.split(os.path.sep)
        pkg = pkg and self.site.gnrapp.packages[pkg]
        if pkg:
            pkg_plugins = pkg.getPlugins()
            for plugin in pkg_plugins:
                pluginPagePath = os.path.join(plugin.webpages_path, *path)
                if os.path.isfile(pluginPagePath):
                    component_page_module = gnrImport(pluginPagePath,
                                                      avoidDup=True)
                    component_page_class = getattr(component_page_module,
                                                   'GnrCustomWebPage', None)
                    if component_page_class:
                        plugin_webpage_classes.append(component_page_class)
        return plugin_webpage_classes

    def page_class_plugin_mixin(self, page_class, plugin_webpage_classes):
        """Mixin the current class with the *plugin_webpage_classes* attribute
        
        :param page_class: add???
        :param plugin_webpage_classes: add???
        """
        for plugin_webpage_class in plugin_webpage_classes:
            classMixin(page_class, plugin_webpage_class, only_callables=False)

    def page_class_custom_mixin(self, page_class, path, pkg=None):
        """Look in the instance custom folder for a file named as the current webpage
        
        :param page_class: add???
        :param pkg: add???. Default value is ``None``
        """
        path = path.split(os.path.sep)
        if pkg:
            customPagePath = os.path.join(self.gnrapp.customFolder, pkg,
                                          'webpages', *path)
            if os.path.isfile(customPagePath):
                component_page_module = gnrImport(customPagePath,
                                                  avoidDup=True)
                component_page_class = getattr(component_page_module,
                                               'WebPage', None)
                if component_page_class:
                    classMixin(page_class,
                               component_page_class,
                               only_callables=False)

    def page_class_resourceDirs(self, page_class, path, pkg=None):
        """Build page resources directories
        
        :param page_class: add???
        :param pkg: add???. Default value is ``None``
        """
        if pkg:
            pagesPath = os.path.join(self.gnrapp.packages[pkg].packageFolder,
                                     'webpages')
        else:
            pagesPath = os.path.join(self.site_path, 'pages')
        curdir = os.path.dirname(os.path.join(pagesPath, path))
        resourcePkg = None
        result = []  # result is now empty
        if pkg:  # for index page or other pages at root level (out of any package)
            resourcePkg = self.gnrapp.packages[pkg].attributes.get(
                'resourcePkg')
            fpath = os.path.join(self.site_path, '_custom', pkg, '_resources')
            if os.path.isdir(fpath):
                result.append(
                    fpath
                )  # we add a custom resource folder for current package
        fpath = os.path.join(self.site_path, '_resources')

        if os.path.isdir(fpath):
            result.append(
                fpath)  # we add a custom resource folder for common package

        while curdir.startswith(pagesPath):
            fpath = os.path.join(curdir, '_resources')
            if os.path.isdir(fpath):
                result.append(fpath)
            curdir = os.path.dirname(
                curdir)  # we add a resource folder for folder
            # of current page
        if resourcePkg:
            for rp in resourcePkg.split(','):
                fpath = os.path.join(self.gnrapp.packages[rp].packageFolder,
                                     'webpages', '_resources')
                if os.path.isdir(fpath):
                    result.append(fpath)
            #result.extend(self.siteResources)
        resources_list = self.site.resources_dirs
        result.extend(resources_list)
        return result

    def package_resourceDirs(self, pkg):
        """add???
        
        :param pkg: add???
        """
        pkg = self.gnrapp.packages[pkg]
        if not hasattr(pkg, '_resourceDirs'):
            pagesPath = os.path.join(pkg.packageFolder, 'webpages')
            resourcePkg = None
            result = []  # result is now empty
            resourcePkg = pkg.attributes.get('resourcePkg')
            fpath = os.path.join(self.site_path, '_custom', pkg.id,
                                 '_resources')
            if os.path.isdir(fpath):
                result.append(
                    fpath
                )  # we add a custom resource folder for current package

            if resourcePkg:
                for rp in resourcePkg.split(','):
                    fpath = os.path.join(self.site_path, '_custom', pkg.id,
                                         '_resources')
                    if os.path.isdir(fpath):
                        result.append(fpath)
            fpath = os.path.join(pagesPath, '_resources')
            if os.path.isdir(fpath):
                result.append(
                    fpath)  # we add a resource folder for common package
            result.extend(self.site.resources_dirs)
            pkg._resourceDirs = result
            # so we return a list of any possible resource folder starting from
        # most customized and ending with most generic ones
        return pkg._resourceDirs

    def site_resources(self):
        """add???"""
        resources = Bag()
        for pkg in self.site.gnrapp.packages.values():
            rsrc_path = os.path.join(pkg.packageFolder, 'resources')
            label = 'pkg_%s' % (pkg.id)
            if os.path.isdir(rsrc_path):
                resources[label] = rsrc_path
            plugins = [p for p in pkg.getPlugins() if p.resources_path]
            for plugin in plugins:
                label = 'pkg_%s_%s' % (pkg.id, plugin.id)
                if os.path.isdir(plugin.resources_path):
                    resources[label] = plugin.resources_path

        resources_list = [(resource.label, resource.attr.get('path'))
                          for resource in self.site.config['resources'] or []]
        for label, rsrc_path in resources_list:
            if rsrc_path:
                resources[label] = rsrc_path
            else:
                rsrc_path = self.resource_name_to_path(label)
                resources[label] = rsrc_path
        auto_resource_path = self.resource_name_to_path(self.site_name,
                                                        safe=False)
        if auto_resource_path:
            resources[self.site_name] = os.path.realpath(auto_resource_path)
        return resources

    def resource_name_to_path(self, res_id, safe=True):
        """add???
        
        :param res_id: add???
        :param safe: add???. Default value is ``True``
        """
        project_resource_path = os.path.normpath(
            os.path.join(self.site_path, '..', '..', 'resources', res_id))
        if os.path.isdir(project_resource_path):
            log.debug('resource_name_to_path(%s) -> %s (project)' %
                      (repr(res_id), repr(project_resource_path)))
            return project_resource_path
        if 'resources' in self.gnr_config['gnr.environment_xml']:
            for path in self.gnr_config['gnr.environment_xml'].digest(
                    'resources:#a.path'):
                res_path = expandpath(os.path.join(path, res_id))
                if os.path.isdir(res_path):
                    log.debug('resource_name_to_path(%s) -> %s (gnr config)' %
                              (repr(res_id), repr(res_path)))
                    return res_path
        log.debug('resource_name_to_path(%s) not found.' % repr(res_id))
        if safe:
            raise Exception('Error: resource %s not found' % res_id)

    def page_pyrequires_mixin(self, page_class, py_requires):
        """add???
        
        :param page_class: add???
        :param py_requires: add???
        """
        for mix in py_requires:
            if mix:
                self.mixinResource(page_class, page_class.resourceDirs, mix)

    def mixinResource(self, kls, resourceDirs, *path):
        """add???
        
        :param kls: add???
        :param resourceDirs: add???
        :param \*path: add???
        """
        path = os.path.join(*path)
        if ':' in path:
            modName, clsName = path.split(':')
        else:
            modName, clsName = path, '*'
        modPathList = self.getResourceList(resourceDirs, modName, 'py') or []
        if modPathList:
            modPathList.reverse()
            for modPath in modPathList:
                classMixin(kls,
                           '%s:%s' % (modPath, clsName),
                           only_callables=False,
                           site=self)
        else:
            raise GnrMixinError('Cannot import component %s' % modName)

    def py_requires_iterator(self, source_class, target_class):
        """add???
        
        :param source_class: add???
        :param target_class: add???
        """
        resourceDirs = target_class.resourceDirs
        py_requires = [
            x for x in splitAndStrip(getattr(source_class, 'py_requires', ''),
                                     ',') if x
        ] or []
        for path in py_requires:
            if ':' in path:
                modName, clsName = path.split(':')
            else:
                modName, clsName = path, '*'
            modPathList = self.getResourceList(resourceDirs, modName,
                                               'py') or []
            if modPathList:
                modPathList.reverse()
                for modPath in modPathList:
                    yield '%s:%s' % (modPath, clsName)
                    #classMixin(kls,'%s:%s'%(modPath,clsName),only_callables=False,site=self)
            else:
                raise GnrMixinError('Cannot import component %s' % modName)

    def getResourceList(self, resourceDirs, path, ext=None):
        """Find a resource in the current ``_resources`` folder or in parent folders one
        
        :param resourceDirs: add???
        :param path: add???
        :param ext: add???. Default value is ``None``
        """
        result = []
        if ext == 'css' or ext == 'js':
            locations = resourceDirs[:]
            locations.reverse()
        else:
            locations = resourceDirs
        if ext and not path.endswith('.%s' % ext): path = '%s.%s' % (path, ext)
        if '*' in path:
            searchpath = os.path.split(path.split('*')[0])[0]
            use_glob = True
        else:
            searchpath = path
            use_glob = False
        for dpath in locations:
            fpath = os.path.join(dpath, searchpath)
            if os.path.exists(fpath):
                if use_glob:
                    result.extend(glob.glob(os.path.join(dpath, path)))
                else:
                    result.append(fpath)
        return result

    def loadResource(self, pkg, *path):
        """add???
        
        :param pkg: add???
        :param \* path: add???
        :returns: add???
        """
        resourceDirs = self.package_resourceDirs(pkg)
        resource_class = cloneClass('CustomResource', BaseResource)
        resource_class.resourceDirs = resourceDirs
        self.mixinResource(resource_class, resourceDirs, *path)
        return resource_class()

    def mixinPageComponent(self, page, pkg, *path):
        """add???
        
        :param page: add???
        :param pkg: add???
        :param \* path: add???
        """
        component = self.loadResource(pkg, *path)
        css_requires = getattr(component, 'css_requires', [])
        js_requires = getattr(component, 'js_requires', [])
        for css in css_requires:
            if css and not css in page.css_requires:
                page.css_requires.append(css)
        for js in js_requires:
            if js and not js in page.js_requires:
                page.js_requires.append(js)
        page.mixin(component)

    def loadTableScript(self,
                        page,
                        table=None,
                        respath=None,
                        class_name=None,
                        _onDefault=None):
        """add???
        
        :param page: add???
        :param table: add???. Default value is ``None``
        :param respath: add???. Default value is ``None``
        :param class_name: add???. Default value is ``None``
        :param _onDefault: add???. Default value is ``None``
        """
        class_name = class_name or 'Main'
        application = self.gnrapp
        if not table:
            _onDefault = True
        if ':' in respath:
            table, respath = respath.split(':')
        if _onDefault:
            tablename = '_default'
            resourceDirs = page.resourceDirs
        else:
            if isinstance(table, basestring):
                table = application.db.table(table)
            tablename = table.name
            resourceDirs = self.package_resourceDirs(table.pkg.name)
        modName = os.path.join('tables', tablename, *(respath.split('/')))
        #resourceDirs = application.packages[table.pkg.name].resourceDirs
        modPathList = self.getResourceList(resourceDirs, modName, 'py') or []
        if modPathList:
            modPathList.reverse()
            basePath = modPathList.pop(0)
            resource_module = gnrImport(basePath, avoidDup=True)
            resource_class = getattr(resource_module, class_name, None)
            resource_obj = resource_class(page=page, resource_table=table)
            for modPath in modPathList:
                resource_module = gnrImport(modPath, avoidDup=True)
                resource_class = getattr(resource_module, class_name, None)
                if resource_class:
                    instanceMixin(resource_obj,
                                  resource_class,
                                  only_callables=False)
            return resource_obj
        elif not _onDefault:
            return self.loadTableScript(page,
                                        table=table,
                                        respath=respath,
                                        _onDefault=True)
        else:
            raise GnrWebServerError('Cannot import component %s' % modName)

    def resourcesAtPath(self, pkg, path, ext):
        """add???
        
        :param pkg: add???
        :param path: add???
        :param ext: add???
        :returns: add???
        """
        result = Bag()
        locations = list(self.package_resourceDirs(pkg))
        for dpath in locations:
            dirpath = os.path.join(dpath, path)
            if os.path.isdir(dirpath):
                b = DirectoryResolver(dirpath, include='*.py', dropext=True)
                result.update(b, resolved=True)
        return result