Source code for RiskQuantLib.Build.router

#!/usr/bin/python
# coding = utf-8
import os,re
[docs]class router(object):
[docs] @staticmethod def formatTag(tagName:str): tagStart = '#<'+tagName+'>' tagEnd = '#</'+tagName+'>' return tagStart, tagEnd
[docs] @staticmethod def stripTag(content:str): """ Delete the row of tag """ return re.sub(r'''#<.*>''', '', content, flags=re.MULTILINE)
[docs] @staticmethod def indent(num:int = 0): return ''.join([' ' for i in range(num)])
[docs] @staticmethod def readContent(pythonSourceFilePath:str, encoding = 'utf-8'): with open(pythonSourceFilePath, 'r', encoding=encoding) as f: content = f.read() return content
[docs] @staticmethod def contentSplit(content:str, tagStart:str, tagEnd:str): """ Split content by given tagStart and tagEnd, return content before tagStart and content after tagEnd """ former = content.split(tagStart)[0].strip(' ').strip('\n\t') ender = content.split(tagEnd)[-1].strip('\n') return former, ender
[docs] @staticmethod def writeContent(content:str, pythonSourceFilePath:str, encoding = 'utf-8'): with open(pythonSourceFilePath, 'w', encoding=encoding) as f: f.truncate() # clear all contents of file f.write(content.strip(' ').strip('\t\n'))
[docs] @staticmethod def findIndentOfLine(content:str, startTextOfLine:str): """ Find the blank before given text. """ tagLine = re.findall(r'''^([ \f\r\t\v]*)'''+startTextOfLine, content, flags=re.MULTILINE) indentOfLine = tagLine[0] if len(tagLine)!=0 else '' return indentOfLine.lstrip('\n')
[docs] @staticmethod def insertToContent(sourceCode:str, tagName:str, content:str): """ Insert some content to given tag position """ tagStart, tagEnd = router.formatTag(tagName) if content.find(tagStart) == -1 or content.find(tagEnd) == -1: return content else: indent = router.findIndentOfLine(content,tagStart) indentedSourceCode = re.sub(r'''^''',indent,sourceCode,flags = re.MULTILINE) former, ender = router.contentSplit(content, tagStart, tagEnd) newContent = former + '\n' + indent + tagStart + '\n' + indentedSourceCode + '\n' + indent + tagEnd + '\n' + ender return newContent
[docs] @staticmethod def injectToContent(content:str, **kwargs): """ Insert several contents into related tag. Contents will be between tagStart and tagEnd. kwargs is a dict whose key is tag name and value is content to be inserted. """ for tagName in kwargs.keys(): tagStart, tagEnd = router.formatTag(tagName) if content.find(tagStart) == -1 or content.find(tagEnd) == -1: continue else: indent = router.findIndentOfLine(content,tagStart) strippedSourceCode = router.stripTag(kwargs[tagName]) indentedSourceCode = re.sub(r'''^''',indent,strippedSourceCode,flags = re.MULTILINE) former, ender = router.contentSplit(content, tagStart, tagEnd) content = former + '\n' + indent + tagStart + '\n' + indentedSourceCode + '\n' + indent + tagEnd + '\n' + ender return content
[docs] @staticmethod def persistToContent(content:str, **kwargs): """ Insert several contents right before related tag. Contents will be before tagStart. kwargs is a dict whose key is tag name and value is content to be inserted. """ for tagName in kwargs.keys(): tagStart, tagEnd = router.formatTag(tagName) if content.find(tagStart) == -1 or content.find(tagEnd) == -1: continue else: indent = router.findIndentOfLine(content,tagStart) strippedSourceCode = router.stripTag(kwargs[tagName]) indentedSourceCode = re.sub(r'''^''',indent,strippedSourceCode,flags = re.MULTILINE) former, ender = router.contentSplit(content, tagStart, tagEnd) content = former + '\n' + indentedSourceCode + '\n' + indent + tagStart + '\n' + indent + tagEnd + '\n' + ender return content
[docs] @staticmethod def insertToFile(sourceCode:str, tagName:str, pythonSourceFilePath:str): """ Read a .py file and insert some code into tag position. """ content = router.readContent(pythonSourceFilePath) newContent = router.insertToContent(sourceCode, tagName, content) router.writeContent(newContent,pythonSourceFilePath)
[docs] @staticmethod def injectToFile(pythonSourceFilePath:str, **kwargs): """ Read a .py file and insert several contents into related tag position. """ content = router.readContent(pythonSourceFilePath) newContent = router.injectToContent(content,**kwargs) router.writeContent(newContent, pythonSourceFilePath)
[docs] @staticmethod def persistToFile(pythonSourceFilePath:str, **kwargs): """ Read a .py file and insert several contents before related tag position. """ content = router.readContent(pythonSourceFilePath) newContent = router.persistToContent(content,**kwargs) router.writeContent(newContent, pythonSourceFilePath)
[docs] @staticmethod def validateInjectTag(injectTag:str, injectPath:str, syntacticSugarPathMap:dict = {}): """ Parse a single tag information. If user does not specify @, use file name as tag name. Then convert dirA.dirB.dirC into dirA/dirB/dirC. Return target file path and target tag name. """ targetPath = injectTag.split('@')[0] if injectTag.find('@')!=-1: targetTag = injectTag.split('@')[-1] else: targetTag = targetPath.split('.')[-1] if targetPath.find('.') == -1 and targetPath in syntacticSugarPathMap: filePath = injectPath + os.sep + syntacticSugarPathMap[targetPath] else: filePath = injectPath + os.sep + targetPath.replace('.', os.sep) + '.py' if os.path.exists(filePath): return filePath, targetTag else: return '', targetTag
[docs] @staticmethod def convertInjectTagToFilePath(injectTag:str, injectPath:str, syntacticSugarPathMap:dict = {}): """ Parse a line of tag information. Split the line by comma, parse every sub-string into (filePath,tagName) and reform them into a list. """ tagList = [i.replace(' ','') for i in injectTag.split(',')] pathList = [router.validateInjectTag(i, injectPath, syntacticSugarPathMap) for i in tagList] return pathList
[docs] @staticmethod def parseInjectTarget(sourceCode:str, injectPath:str, syntacticSugarPathMap:dict = {}): """ Find the line of control comment, split whole content by control comment line. Parse the target file and tag name for every control comment. Finally, return a dict whose key is target file and value is (tag,content) pair. """ import pandas as pd tagPosition = [i.regs[0] for i in re.finditer(r'''^#->.*$''', sourceCode, flags=re.MULTILINE)] tagStart = [i[1] for i in tagPosition] tagEnd = [i[0] for i in tagPosition[1:]] + [len(sourceCode)] tag = [sourceCode[start:end] for start, end in tagPosition] content = [sourceCode[start:end] for start, end in zip(tagStart, tagEnd)] targetPathAndTargetTag = [router.convertInjectTagToFilePath(i.replace('#->',''), injectPath, syntacticSugarPathMap) for i in tag] injectInfoList = [pd.DataFrame([(j[0],j[1],contentId) for j in pathTag]) for contentId,pathTag in enumerate(targetPathAndTargetTag)] injectInfo = pd.concat(injectInfoList).rename(columns = {0:'path',1:'tag',2:'contentId'}) if len(injectInfoList)!=0 else pd.DataFrame(columns = ['path','tag','contentId']) injectInfo = injectInfo[injectInfo['path']!=''] injectContentAfterMerge = injectInfo.groupby(by=['path','tag'], group_keys=False).apply(lambda x:"".join([content[id] for id in x['contentId']])) if injectContentAfterMerge.empty: return {} else: injectContentAfterMerge = injectContentAfterMerge.rename('mergedContent').reset_index() injectContentDict = injectContentAfterMerge.groupby(by='path').apply(lambda x:dict(zip(x['tag'],x['mergedContent']))).to_dict() return injectContentDict