from genericpath import isdir import os import pandas as pd import transport import copy from jinja2 import Environment, BaseLoader, FileSystemLoader import importlib import importlib.util class components : @staticmethod def folders (_path): _content = os.listdir(_path) return [_name for _name in _content if os.path.isdir(os.sep.join([_path,_name])) if not _name.startswith('_')] @staticmethod def content (_folder) : if os.path.exists(_folder) : # return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))] return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))] else: return [] @staticmethod def menu(_path,_config): """ This function will read menu and sub-menu items from disk structure, The files are loaded will """ _items = components.folders(_path) _layout = copy.deepcopy(_config['layout']) _overwrite = _layout['overwrite'] if 'overwrite' in _layout else {} # # content of each menu item _subItems = [ components.content (os.sep.join([_path,_name]))for _name in _items ] _object = dict(zip(_items,_subItems)) #-- applying overwrites to the menu items for _name in _object : _submenu = _object[_name] _index = 0 for _item in _submenu : text = _item['text'] if text in _overwrite : if 'uri' in _item and 'url' in 'url' in _overwrite[text] : del _item['uri'] _item = dict(_item,**_overwrite[text]) if 'uri' in _item: _item['uri'] = _item['uri'].replace(_layout['root'],'') _submenu[_index] = _item _index += 1 return _object @staticmethod def html(uri,id,_args={}) : """ This function reads a given uri and returns the appropriate html document, and applies environment context """ _html = (open(uri)).read() #return ' '.join(['
'.replace(':id',id),_html,'
']) _html = ' '.join(['
'.replace(':id',id),_html,'
']) appContext = Environment(loader=BaseLoader()).from_string(_html) # # If the rendering of the HTML happens here we should plugin custom functions (at the very least) # return appContext.render(**_args) # return _html @staticmethod def data (_args): """ :store data-store parameters (data-transport, github.com/lnyemba/data-transport) :query query to be applied against the store (expected data-frame) """ _store = _args['store'] reader = transport.factory.instance(**_store) _queries= copy.deepcopy(_store['query']) _data = reader.read(**_query) return _data @staticmethod def csv(uri) : return pd.read(uri).to_html() @staticmethod def load_plugin(**_args): """ This function will load external module form a given location and return a pointer to a function in a given module :path absolute path of the file (considered plugin) to be loaded :name name of the function to be applied """ _path = _args['path'] #os.sep.join([_args['root'],'plugin']) if os.path.isdir(_path): files = os.listdir(_path) if files : files = [name for name in files if name.endswith('.py')] if files: _path = os.sep.join([_path,files[0]]) else: return None else: return None #-- We have a file ... _name = _args['name'] spec = importlib.util.spec_from_file_location(_name, _path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return getattr(module,_name) if hasattr(module,_name) else None @staticmethod def plugins(_config) : PATH= os.sep.join([_config['layout']['root'],'_plugins']) _map = {} if not os.path.exists(PATH) : return _map _conf = _config['plugins'] for _key in _conf : _path = os.sep.join([PATH,_key+".py"]) for _name in _conf[_key] : _pointer = components.load_plugin(path=_path,name=_name) if _pointer : _uri = "/".join(["api",_key,_name]) _map[_uri] = _pointer return _map @staticmethod def context(_config): """ adding custom variables functions to Jinja2, this function should be called after plugins are loaded """ _plugins = _config['plugins'] # if not location: # env = Environment(loader=BaseLoader()) # else: location = _config['layout']['root'] # env = Environment(loader=FileSystemLoader(location)) env = Environment(loader=BaseLoader()) # env.globals['routes'] = _config['plugins'] return env