def test_should_match_multiple_files(self): # given filename_raw = 'b' # when # then with self.assertRaisesRegex(FileNotFoundError, 'ambiguous'): FileHelper.get_full_filename(filename_raw)
def _copyAssets(folder_path): global html_doc_path global asset_files print '[HTMLBuilder] Copying assets...' # copy assets for i in asset_files: src_folder = html_doc_path + i + path_sep dest_folder = folder_path + i + path_sep # if folder doesn't exist, create it if not os.path.exists(dest_folder): os.makedirs(dest_folder) print '[HTMLBuilder] Created asset folder: ' + dest_folder # copy files to target folder for z, st in enumerate(asset_files[i]): src = src_folder + st FileHelper.copyFile(src, dest_folder) # copy images src_folder = html_doc_path + 'img' + path_sep dest_folder = folder_path + 'img' + path_sep # if folder doesn't exist, create it if not os.path.exists(dest_folder): os.makedirs(dest_folder) print '[HTMLBuilder] Created asset folder: ' + dest_folder FileHelper.copyDir(src_folder, dest_folder)
def doParsing(contestId): payload = {} with requests.Session() as sessionElement: parseContest(sessionElement, contestId) FileHelper.doWrite( "temp", os.path.expanduser(readConfig.get("CodeForcesPath")))
def test_should_not_match_any_filename(self): # given filename_raw = 'a' # when # then with self.assertRaisesRegex(FileNotFoundError, 'not found'): FileHelper.get_full_filename(filename_raw)
def write_combined_dict( dfs, base_file_name=r"CME Group Futures Price - Prior " r"Settle (COMBINED).xlsx", base_path=os.path.join(os.getcwd(), "etl_outputs_xlsx"), ): base_file_name, folder_ext = base_file_name.split(".") initial_file_name = f"{base_file_name}.xlsx" initial_write_path = os.path.join(base_path, initial_file_name) print(initial_write_path) if fh.file_checker(initial_write_path): etl.fancy_excel_writer(initial_write_path, dfs) else: try: except_file_nm = fh.get_file_name("etl_outputs_xlsx", base_file_name) except_write_path = os.path.join(base_path, except_file_nm) etl.fancy_excel_writer(except_write_path, dfs) except Exception as e: logging.exception( "Exception Occurred: Could not write to main " "path", e) return None
def getData(keyWord = '',page = -1,type = ''): targetUrl = getUrl(keyWord,page,type) todayTime = datetime.date.today() filePath = FileHelper.getPath(todayTime,'youku',urls[keyWord]) fileName = '%s/html.txt' % filePath FileHelper.getContent2FileWithoutProcess(fileName=fileName,targetUrl=targetUrl) content = open(fileName,'r') temp = content.read().decode('utf-8') soup = BeautifulSoup(temp,'html.parser') count = -1 #过滤第一个 Rank = (page-1) * 42 resultFileName='' if type == TYPE_DAILY: resultFileName='%s/RankDaily.txt' % filePath if type == TYPE_WEEKLY: resultFileName='%s/RankWeekly.txt' % filePath for tag in soup.findAll(True): if(tag.name == 'img' and tag.has_attr('alt') and tag.has_attr('src') and not tag.has_attr('attr')): Rank = Rank+1 FileHelper.save2File(content = 'Rank.%s %s ' % (Rank,tag['alt'] ), fileName=resultFileName,type= FileHelper.TYPE_APPEND) if (tag.has_attr('class') and tag.name == 'span' and ''.join(tag['class']) == 'p-num'): FileHelper.save2File(content = 'VV : %s \n' % tag.string , fileName=resultFileName,type= FileHelper.TYPE_APPEND) content.close() FileHelper.delFile(fileName)
def resumableDownload(self, filehash, filename=None): # not thread safely.single thread filehash_path = os.path.join(self.downloadpath, filehash) tempjson = os.path.join(filehash_path, 'temp.json') if not os.path.isfile(tempjson): # save chunks result into the temp.json self.list(filehash) if self.links: i = 0 for link in self.links: if 'Hash' in link.keys(): self.chunks.update({ i: { 'filehash': link.get('Hash'), 'success': False } }) i += 1 FileHelper.saveFile(tempjson, json.dumps(self.chunks)) else: print("no chunks.Error get the {} chunks result".format( filehash)) # download chunk with open(tempjson) as target_file: self.chunks = json.load(target_file) if self.chunks: for chunk, chunk_result in self.chunks.iteritems(): if not chunk_result.get('success'): chunk_result['success'] = self.downloadhash( chunk_result.get('filehash'), filehash_path) or chunk_result.get('success') FileHelper.saveFile(tempjson, json.dumps(self.chunks)) # merge chunks if filename: localfile = os.path.join(filehash_path, filename) else: localfile = os.path.join(filehash_path, filehash) with open(localfile, 'wb') as target_file: for i in range(len(self.chunks)): chunk = os.path.join( filehash_path, self.chunks.get(str(i)).get('filehash')) with open(chunk, 'rb') as source_file: for line in source_file: target_file.write(line) try: os.remove(chunk) # 删除该分片,节约空间 except Exception, e: print("{0}:{1} remove failed:{2}".format( chunk, os.path.isfile(chunk), e)) try: os.remove(tempjson) except Exception, e: print("{0}:{1} remove failed:{2}".format( tempjson, os.path.isfile(tempjson), e))
def getData(keyWord = '',type = ''): targetUrl = getUrl(keyWord,type) todayTime = datetime.date.today() filePath = FileHelper.getPath(todayTime,'tencent',urls[keyWord]) fileName = '%s/html.txt' % filePath FileHelper.getContent2FileWithoutProcess(fileName=fileName,targetUrl=targetUrl) content = open(fileName,'r') temp = content.read().decode('utf-8') soup = BeautifulSoup(temp,'html.parser') count = -1 #过滤第一个 Rank = 0 resultFileName='' if type == TYPE_DAILY: resultFileName='%s/RankDaily.txt' % filePath if type == TYPE_WEEKLY: resultFileName='%s/RankWeekly.txt' % filePath if type == TYPE_MONTHLY: resultFileName='%s/RankMonthly.txt' % filePath for tag in soup.findAll(True): if(tag.name == 'a' and tag.has_attr('href') and (''.join(tag['href']).find('cover') > 0)): Rank = Rank+1 FileHelper.save2File(content = 'Rank.%s %s ' % (Rank,tag['title'] ), fileName=resultFileName,type= FileHelper.TYPE_APPEND) if (tag.has_attr('class') and tag.name == 'strong' and ''.join(tag['class']) == 'num'): FileHelper.save2File(content = 'VV : %s \n' % tag.string , fileName=resultFileName,type= FileHelper.TYPE_APPEND) content.close() FileHelper.delFile(fileName)
def doParsing(contestId): payload = { 'name': readConfig.get("AtCoderUsername"), 'password': readConfig.get("AtCoderPassword") } with requests.Session() as sessionElement: retVal = sessionElement.post(getLoginUrl(contestId), data=payload) parseContest(sessionElement, contestId) FileHelper.doWrite("temp", os.path.expanduser(readConfig.get("AtCoderPath")))
def RemovalTask(): DirPath = str(sys.argv[1]) Minitues = int(sys.argv[2]) MailTo = str(sys.argv[3]) rList = FileHelper.DuplicateRemover(DirPath) LogTime = str(time.ctime()) LogFileName = str("Duplicates_Removed_at_%s.log" % (LogTime)) if (FileHelper.GenreateLogFile(rList, LogFileName, LogTime)): print('Success: Log file generated.') MailSender.SendMail(LogFileName, MailTo) else: print( "Failure: Unable to create logfile.\nPlease enter valid directory path and try again!" )
async def run(self, amount): # url = "http://localhost:8080/{}" tasks = [] bttv_dict = FileHelper.JSONread( 'C:\\Users\\BIGNIG\\Documents\\Python Scripts\\FrankerFaceZ\\emotedata_bttv.json' ) # create instance of Semaphore sem = asyncio.Semaphore(100) # Create client session that will ensure we dont open new connection # per each request. # self.amount = amount async with ClientSession() as session: # pass Semaphore and session to every GET request found = False for emote in bttv_dict.keys(): if emote == 'LXHeart': found = True if found: # if self.amount > 0: url = self.bttvEmoteUrlStart + \ bttv_dict[emote]+self.bttvEmoteUrlEnd task = asyncio.ensure_future( self.bound_fetch(sem, url, session, emote)) tasks.append(task) # self.amount -= 1 # else: # break else: print('Skipping {}'.format(emote)) responses = asyncio.gather(*tasks) await responses print(responses)
def addOrderObserver(strategy): observer = Observer() event_handler = FileEventHandler.FileEventHandler() FileHelper.create(strategy.get('path')) observer.schedule(event_handler, strategy.get('path'), True) observer.start() try: while True: try: time.sleep(1) scanorder(strategy) except Exception as e: print('except:', e) except KeyboardInterrupt: observer.stop() observer.join()
def create_items(self, image, parent, strings): for d in strings: item = QTreeWidgetItem(parent) item.setText(0, d) item.setIcon(0, FileHelper.get_image(image)) parent.addChild(item) self.all_tree_items.append(item)
def __setParserFile(self, file_path): obj = 0 file_str = FileHelper.getFileStr(file_path) file_name = file_path.split(path_sep)[-1] file_folder_path = path_sep.join(file_path.split(path_sep)[:-1]) # ident md5 = hashlib.md5() md5.update(file_path) file_id = md5.hexdigest() # get doc comments comments = _getComments(file_str) comments_arr = [] for i, comment_str in enumerate(comments): docu = _parseComment(comment_str, file_id) if docu: comments_arr.append(docu) if len(comments_arr) > 0: comments_arr = _groupContstructors(comments_arr) obj = { 'id': file_id, 'docu': comments_arr, 'file_name': file_name, 'file_path': file_folder_path } return obj
def test_should_match_file(self): # given filename_raw = 'c' expected_filename = 'cryotherapy.xlsx' # when filename = FileHelper.get_full_filename(filename_raw) # then self.assertEqual(expected_filename, filename)
def parseContest(sessionElement, contestId): contestUrl = getContestUrl(contestId) allProblemsPage = sessionElement.get(contestUrl) allProblemsPageText = BeautifulSoup(allProblemsPage.text) problemIndex = 0 for div in allProblemsPageText.findAll('div', 'problemindexholder'): for innerDiv in div.findAll('div', 'sample-tests'): basePath = os.path.expanduser(readConfig.get("CodeForcesPath")) contestPath = os.path.join(basePath, contestId) problemPath = os.path.join(contestPath, chr(ord('A') + problemIndex)) FileHelper.createDir(problemPath) FileHelper.copyFile("template.cpp", os.path.join(problemPath, "sol.cpp")) FileHelper.copyFile("template.java", os.path.join(problemPath, "sol.java")) inputCaseNumber = 0 outputCaseNumber = 0 caseNumber = 0 for preTag in innerDiv.findAll('pre'): for br in preTag.findAll('br'): br.replace_with('\n') if caseNumber % 2 == 0: inputCase = preTag.text testFileName = readConfig.get("inputFileFormat") testFileName = testFileName.replace( "$testCaseNumber$", str(inputCaseNumber)) testFile = os.path.join(problemPath, testFileName) FileHelper.doWrite(testFile, inputCase) inputCaseNumber += 1 else: outputCase = preTag.text testFileName = readConfig.get("outputFileFormat") testFileName = testFileName.replace( "$testCaseNumber$", str(outputCaseNumber)) testFile = os.path.join(problemPath, testFileName) FileHelper.doWrite(testFile, outputCase) outputCaseNumber += 1 caseNumber += 1 problemIndex += 1
def create_button(self, func_name, name_button, icon="", shortcut=""): icon_btn = FileHelper.get_image(icon) button = QAction(QIcon(icon_btn), name_button, self) button.setIcon(icon_btn) button.setShortcut(shortcut) button.triggered.connect(func_name) return button
def __init__(self, search_folder, save_folder): self.search_folder = search_folder self.file_helper = FileHelper.PredictionFileManager( load_folder=self.search_folder, save_folder=save_folder) self.predicting = True self.base_directory = search_folder
def main(): print("Start Work") print('操作系统信息:' + str(platform.architecture())) FileHelper.Init() DataProcess.Init() t = threading.Thread(target=MonitorRunGame.Monitor) t.start() UIView.Init()
def __init__(self, host='127.0.0.1', port='5001'): self.ipfs_host = host self.ipfs_port = port self.connect = ipfsapi.connect(self.ipfs_host, self.ipfs_port) self.log = "" self.chunks = {} self.objects = None self.links = [] self.downloadpath = os.path.join(FileHelper.getRootPath(), 'download')
def read_options_from_xml(): xml_doc = minidom.parse(FileHelper.find_way_to_file("options.xml")) xml_color.append([]) for item in xml_doc.getElementsByTagName('highlight')[0].getElementsByTagName("item"): xml_color[0].append(item.attributes["color"].value) xml_basic.append([]) for item in xml_doc.getElementsByTagName('basic')[0].getElementsByTagName("gothic_src"): xml_basic[0].append(item.attributes["root"].value)
def generate(data, folder_path): global html_doc_path global html_doc_folder # check if folder path is the same as the jsdoc html path if not os.path.isdir(folder_path): os.makedirs(folder_path) if not os.path.samefile(html_doc_path, folder_path): pages = [] # set up the pages for i, item in enumerate(data): file_name = '.'.join(item['file_name'].split('.')[:-1]) pages.append({ 'html':_buildPage(item, folder_path), 'file':file_name }) # if there are pages if len(pages) > 0: html_folder_path = folder_path + html_doc_folder if not os.path.isdir(html_folder_path): os.makedirs(html_folder_path) print '[HTMLBuilder] Created html base folder: ' + html_folder_path # copy asset _copyAssets(folder_path) # save the pages for i, page in enumerate(pages): save_path = html_folder_path + page['file'] + '.html' print 'Saving ' + save_path FileHelper.writeFile(page['html'], save_path) # create the index file _createIndexFile(folder_path) else: print '[HTMLBuilder] No pages to build...' else: print '[HTMLBuilder] Cannot generate HTML. Same path error.'
def __init__(self, pi_address, framerate, save_folder): self.pi_address = pi_address self.base_page_address = 'http://' + self.pi_address + '/index.html' self.video_stream_address = 'http://' + self.pi_address + '/stream.mjpg' self.framerate = framerate self.file_helper = FileHelper.VideoFileManager(save_folder = save_folder) self.streaming = False self.streaming_data = queue.Queue()
def CheackGame(): global RunningGame list = GetRunningGame() needsaveinfo = [] for info in RunningGame: if all(x.SteamId != info.SteamId for x in list): needsaveinfo.append(info) RunningGame = list print('自动检测到的停止运行的游戏:', len(needsaveinfo)) FileHelper.CopyFile(needsaveinfo)
def scanorder(strategy): path = strategy.get('path') files = [] FileHelper.listdir(path, files) for file in files: if (FileHelper.getext(file) == 'txt'): nowTime = lambda: int(round(time.time() * 1000)) content = FileHelper.read_one_line(file) create_order(strategy, content) # DBHelper.query("order", None) bakPath = path + "/bak/"; FileHelper.create(bakPath) filename = FileHelper.getbasename(file); FileHelper.copy(file, bakPath + filename + "_" + str(nowTime()) + ".txt")
def test_should_find_filenames(self): # given filenames_raw = ['d', 'c'] expected_filenames = [ 'data_banknote_authentication.csv', 'cryotherapy.xlsx' ] # when filenames = FileHelper.prepare_filenames(filenames_raw) # then for expected_filename, filename in zip(expected_filenames, filenames): self.assertEqual(expected_filename, filename)
def run(): inText = input( "Enter the name of the file to add zcta data to (or enter 'exit' to exit): " ) if inText.upper() != 'EXIT': fileName = fh.parseToCSVFileName(inText) if fileName == 'N': print("Invalid file name was provided, please try again.") else: print("Attempting to read data...\n") data = fh.readInCSVPandas(fileName, -1) zipCol = input("What column contains the zip code (name label)? ") fh.writeOutCSVPandas("withZCTA_" + fileName, appendZCTADataToFile(data, zipCol)) print("Done.")
def upload(self, local_file): try: start = time.time() result = self.connect.add(local_file) end = time.time() print('upload {0} ,size is {1}, cost:{2}'.format( local_file, FileHelper.getSize(local_file), (end - start))) # TODO save filename in DB return result.get('Hash') except Exception, e: # TODO save e in the log return None
def processSlgLine(headers, line): PATTERN = re.compile(r'''((?:[^,"']|"[^"]*"|'[^']*')+)''') dataList = PATTERN.split(line)[1::2] toWrite = "{" index = 0 for name in headers: name = FileHelper.stripnl(name) dataContent = FileHelper.stripnl(dataList[index]) if "chip" in name: dataContent = "(" + dataContent + ")" if dataContent.startswith('\"'): toWrite += "\"{0}\" : {1},".format(name, dataContent) else: toWrite += "\"{0}\" : \"{1}\",".format(name, dataContent) index += 1 toWrite = toWrite[:-1] toWrite += "}," return toWrite
async def run(cls): tasks = [] json = FileHelper.JSONread('updated_emotes.json') sem = asyncio.Semaphore(500) async with ClientSession() as session: json_start = max(json.values()) for image_id in range(json_start, 500000): # pass Semaphore and session to every GET request task = asyncio.ensure_future( cls.bound_fetch(sem, cls.global_emotes_url.format(image_id), session, image_id)) tasks.append(task) responses = asyncio.gather(*tasks) await responses for response in responses._result: if response is not None: json[response[0]] = response[1] print(json) FileHelper.JSONwrite('updated_emotes.json', json)
def parseProblem(sessionElement, contestId, problemRelativeUrl, problemIndex): problemUrl = getProblemUrl(contestId, problemRelativeUrl) problemPage = sessionElement.get(problemUrl) problemPageText = BeautifulSoup(problemPage.text) basePath = os.path.expanduser(readConfig.get("AtCoderPath")) contestPath = os.path.join(basePath, contestId) problemPath = os.path.join(contestPath, chr(ord('A') + problemIndex)) FileHelper.createDir(problemPath) FileHelper.copyFile("template.cpp", os.path.join(problemPath, "sol.cpp")) FileHelper.copyFile("template.java", os.path.join(problemPath, "sol.java")) inputCaseNumber = 0 outputCaseNumber = 0 for divs in problemPageText.findChildren('div', {"class": "part"}): for div in divs.findAll('section', {}): children = div.findChildren('h3') for child in children: headerString = div.h3.string if ("Input" in headerString) and (("Sample" in headerString) or ("Example" in headerString)): inputCase = div.pre.string testFileName = readConfig.get("inputFileFormat") testFileName = testFileName.replace( "$testCaseNumber$", str(inputCaseNumber)) testFile = os.path.join(problemPath, testFileName) FileHelper.doWrite(testFile, inputCase) inputCaseNumber += 1 if ("Output" in headerString) and ( ("Sample" in headerString) or ("Example" in headerString)): outputCase = div.pre.string testFileName = readConfig.get("outputFileFormat") testFileName = testFileName.replace( "$testCaseNumber$", str(outputCaseNumber)) testFile = os.path.join(problemPath, testFileName) FileHelper.doWrite(testFile, outputCase) outputCaseNumber += 1
def get_dict_of_dfs(dict_of_hrefs, browser, minutes_page_sleep_floor=2, minutes_page_sleep_ceiling=5): """ Accepts dictionary of names: hrefs and returns a dictionary of DataFrames containing the scraped, parsed, and tabularized data :param dict_of_hrefs: Dictionary of names to hrefs :param browser: Webdriver browser object :param sleep_floor: Lower bound of time to sleep between loading page and pulling the source data :param sleep_ceiling: Upper bound of time to sleep between loading page :param minutes_page_sleep_ceiling: Lower bound of time to sleep between pages (in minutes) :param minutes_page_sleep_floor: Upper bound of time to sleep between pages (in minutes) :return: Dictionary of DataFrames """ dict_of_dfs = {} for href_name, href in dict_of_hrefs.items(): print(f"Scraping started for: {href_name}") raw_html, current_tmstmp = html_from_javascript(browser, href) df, prettified_soup = df_from_html(raw_html, href_name, current_tmstmp) fh.save_raw_file(prettified_soup, href_name, "outputs_txt") dict_of_dfs[href_name] = df time_to_sleep = random.randint(minutes_page_sleep_floor * 60, minutes_page_sleep_ceiling * 60) print(f"\t<data collection ended for {href_name} - now sleeping for " f"sleeping for {time_to_sleep} seconds>\n") time.sleep(time_to_sleep) browser.close() return dict_of_dfs
def read_keywords_from_xml(): xml_doc = minidom.parse(FileHelper.find_way_to_file("keywords.xml")) xml_data.append([]) # While to takes elements from xml file for item in xml_doc.getElementsByTagName('keywords')[0].getElementsByTagName("item"): xml_data[0].append(item.attributes["word"].value) xml_data.append([]) for item in xml_doc.getElementsByTagName('opertors')[0].getElementsByTagName("item"): xml_data[1].append(item.attributes["symbol"].value) xml_data.append([]) for item in xml_doc.getElementsByTagName('function')[0].getElementsByTagName("item"): xml_data[2].append(item.attributes["func"].value) xml_data.append([])
def initDataFileDic(): #使用的全局变量.begin: global m_globalDataFileDic #使用的全局变量.end if not os.path.exists(m_dataPath): os.makedirs(m_dataPath) Logger.log("create path【data】...", LOG_TAG) return Logger.log("【data】path is exist!!!! \n\n\n", LOG_TAG) m_globalDataFileDic = FileHelper.getFileList(m_dataPath) print("data文件的总数 = %d" % len(m_globalDataFileDic.keys())) for keystr, val in m_globalDataFileDic.items(): Logger.log("---->>> %s : %s \n" % (keystr, val), LOG_TAG) print("Tip: DataFileDic init success!")
def main(): destFile = open(destFilePath, "w") destFile.write("") lineIndex = 0 headerList = [] toWrite = "{ \"cards\":[" with open(srcFilePath) as f: for line in f: if lineIndex == 0: # this is the first line of the file, aka headers headers = line.split(",") else: # this is an actual data line print(" - Processing card %s\r" % lineIndex) toWrite += processSlgLine(headers, line) lineIndex = lineIndex + 1 toWrite = toWrite[:-1] toWrite += "]}" FileHelper.appendLineTo(toWrite, destFilePath, False) print("Finished parsing csv file.")
def __setParser(self): config = self.__CONFIG path = config['source_path'] #get files files = FileHelper.getFilePaths(path, 'js') if len(files) > 0: file_str_arr = [] for i, f in enumerate(files): parsed = self.__setParserFile(f) if parsed: file_str_arr.append(parsed) # type of output _outputDoc(config, file_str_arr) else: print 'No Javascript files to parse...' exit()
def getData(keyWord = '',type = ''): targetUrl = getUrl(keyWord,type) todayTime = datetime.date.today() filePath = FileHelper.getPath(todayTime,'aqy',urls[keyWord]) fileName = '%s/json.txt' % filePath FileHelper.getContent2FileWithoutProcess(fileName=fileName,targetUrl=targetUrl) content = open(fileName,'r') temp = content.read().decode('utf-8') dic = json.loads(temp) key = '' resultFileName = '' if type == TYPE_DAILY: resultFileName='%s/RankDaily.txt' % filePath key = 'album_count_yesterday' if type == TYPE_WEEKLY: resultFileName='%s/RankWeekly.txt' % filePath key = 'album_count_lastweek' count = len(dic['data']) for i in range(count): FileHelper.save2File(content= 'Rank.%s %s VV : %s \n' % (i+1,dic['data'][i]['album_name'],dic['data'][i][key]), fileName=resultFileName,type= FileHelper.TYPE_APPEND) content.close() FileHelper.delFile(fileName)
class MainWindow(QMainWindow): ''' This is the main window of the BPMonitor. ''' def __init__(self, parent=None): ''' This is the initializer of the main window ''' super(MainWindow, self).__init__(parent) #======================================= # initial the member field #======================================= self.interval_in_seconds = 5 self.q_time_elapsed = QTime(0, 0, 0, 0) self.timer = QTimer() self.timer.setSingleShot(False) self.timer.setInterval(1000) self.connect(self.timer, SIGNAL("timeout()"), self.updateTheTime) # Data receiver self.data_receiver = DataTransfer() self.serial_settings = {} # Data holder self.data_holder = DataHolder() self.connect(self.data_receiver.qtobj, SIGNAL("NewData"),\ self.data_holder.on_receive_data) # File helper self.file_helper = FileHelper() self.connect(self.data_receiver.qtobj, SIGNAL("NewData"),\ self.file_helper.writeToSignalFile) # Plot_helpers self.bp_ecg_plot_helper = PlottingHelper(self, \ BP_ECG_signal_names, 1000) self.acc_plot_helper = PlottingHelper(self, \ ACC_signal_names, 100) #===================================================== # Set central widget #===================================================== self.setWindowTitle('UCare BP Monitor') self.setWindowIcon(QIcon('icon/icon.png')) # ========================================= # 1: set plot widget # ========================================= self.plotwidget = QWidget() self.plotVBox = QVBoxLayout() # Add plotting widget to the plotVBox for name in BP_ECG_names: self.plotVBox.addWidget(self.bp_ecg_plot_helper.curve_plots[name]) label = QLabel(name) label.setAlignment(Qt.AlignCenter) self.plotVBox.addWidget(label) #for key, curve_plot in self.bp_ecg_plot_helper.curve_plots.items(): # self.plotVBox.addWidget(curve_plot) for key, curve_plot in self.acc_plot_helper.curve_plots.items(): self.plotVBox.addWidget(curve_plot) label = QLabel(key) label.setAlignment(Qt.AlignCenter) self.plotVBox.addWidget(label) self.plotwidget.setLayout(self.plotVBox) # ========================================= # 2: set event widget # ========================================= self.eventWidget = QWidget() self.eventVBox = QVBoxLayout() # ============================ # 2-a: set eventButton widget # ============================ self.eventButtonWidget = EventButtonsWidget() self.connect(self.eventButtonWidget.qtobj, SIGNAL("NewEvent"), self.addEventLog) # ============================ # 2-b: set eventLog widget # ============================ self.eventLogList = QListWidget() # ============================ # 2-c: add the widgets into eventWidget # ============================ self.eventVBox.addWidget(self.eventButtonWidget) self.eventVBox.addWidget(QLabel(u"事件日志")) self.eventVBox.addWidget(self.eventLogList) self.eventWidget.setLayout(self.eventVBox) # ========================================= # 3: add widgets into centralWidget # ========================================= centralWidget = QWidget() centralHBox = QHBoxLayout() centralHBox.addWidget(self.plotwidget) centralHBox.addWidget(self.eventWidget) centralWidget.setLayout(centralHBox) self.setCentralWidget(centralWidget) self.connect(self.data_holder.qtobj, SIGNAL("UpdateCurve"),\ self.update_curves) #======================================= # Set dock windows #======================================= #self. #======================================= # Set statusbar #======================================= self.statusbar = self.statusBar() self.label_time_elapsed = QLabel() self.label_time_elapsed.setText(self.q_time_elapsed.toString()) self.statusbar.addPermanentWidget(self.label_time_elapsed) #======================================= # Set actions #======================================= # Open a file tip_text = 'Open an existing data file.' open_file_action = self.create_action('&Open a file', \ self.open_file, QKeySequence.Open, 'icon\open.png',\ tip_text, False) open_file_action.setEnabled(False) # Save the file tip_text = 'Save data into a file.' save_file_action = self.create_action('&Save into file', \ self.save_file, QKeySequence.Save, 'icon\save.png',\ tip_text, False) # Bluetooth settings tip_text = 'Settings of bluetooth. Ctrl+B' bt_settings_action = self.create_action('&Bluetooth Settings',\ self.bt_settings, 'Ctrl+B', 'icon\settings.png',\ tip_text, False) # Plotting start tip_text = 'Start ploting the signals. Ctrl+C' self.start_action = self.create_action('Start | &Continue plotting.',\ self.start_plot, 'Ctrl+C', 'icon\start.png', \ tip_text, True) self.start_action.setEnabled(False) # Plotting pause tip_text = 'Pause the plotting. Ctrl+P' self.pause_action = self.create_action('&Pause the plotting.', \ self.pause_plot, 'Ctrl+P', 'icon\pause.png',\ tip_text, True) self.pause_action.setEnabled(False) # Plotting stop tip_text = 'Stop the plotting. Ctrl+E' self.stop_action = self.create_action('&End the plotting.', \ self.stop_plot, 'Ctrl+E', 'icon\stop.png',\ tip_text, True) self.stop_action.setEnabled(False) # Set the plotting actions into a action group #plot_group = QActionGroup(self) #self.add_actions(plot_group, (self.start_action, self.pause_action, \ # self.stop_action)) # Scale the plotting #============================================= # Set the tool bar #============================================= # the file toolbar file_tool_bar = self.addToolBar("File") file_tool_bar.setObjectName("FileToolBar") self.add_actions(file_tool_bar, (open_file_action, \ save_file_action)) # the bluetooth toolbar bt_tool_bar = self.addToolBar("Bluetooth") bt_tool_bar.setObjectName("Bluetooth") self.add_actions(bt_tool_bar, (bt_settings_action, )) # the plotting toolbar plot_tool_bar = self.addToolBar("Plotting") plot_tool_bar.setObjectName("Plotting") self.add_actions(plot_tool_bar, (self.start_action, self.pause_action, \ self.stop_action, None)) self.scale_spinbox = QSpinBox() self.scale_spinbox.setRange(1, 50) self.scale_spinbox.setValue(5) self.scale_spinbox.setSuffix('s') scale_label = QLabel('Seconds to plot.') self.connect(self.scale_spinbox, SIGNAL('valueChanged(int)'), self.scale_changed) plot_tool_bar.addWidget(scale_label) plot_tool_bar.addWidget(self.scale_spinbox) #============================================= # Set the menu bar #============================================= # the file menu file_menu = self.menuBar().addMenu('&File') self.add_actions(file_menu, (open_file_action, save_file_action)) # the bluetooth menu bt_menu = self.menuBar().addMenu('&Bluetooth') self.add_actions(bt_menu, (bt_settings_action, )) def addEventLog(self, message): print message self.eventLogList.addItem(str(message)) self.file_helper.writeToEventFile(str(message)) def updateTheTime(self): self.q_time_elapsed = self.q_time_elapsed.addSecs(1) self.label_time_elapsed.setText(self.q_time_elapsed.toString()) #print "Timer: ", self.q_time_elapsed.toString() def saveFilesAs(self): ''' Save the files to the right directory with the right name after cellecting data. ''' formats = ["*.uSig", "*.uEvent"] fname = QFileDialog.getSaveFileName(self, u"请选择数据保存的位置和名称", \ self.file_helper.getFileName(), "Signal & Event Files: (%s)" % " ".join(formats)) if fname: fname = str(fname) if '.uSig' in fname: fname = fname[0:-5] if '.uEvent' in fname: fname = fname[0:-7] print "FileName getted: " + fname (dirname, name) = os.path.split(fname) if not os.path.exists(dirname): os.path.mkdir(dirname) os.rename(self.file_helper.getFileName()+'.uSig', fname+'.uSig') os.rename(self.file_helper.getFileName()+'.uEvent', fname+'.uEvent') else: print "Warning: Files are not saved." def add_actions(self, target, actions): '''helps add actions to the target, which is either a menubar or \ a toolbar.''' for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def update_curves(self): ''' update the curves''' if self.start_action.isChecked(): self.bp_ecg_plot_helper.update_curves(self.data_holder.time_seq,\ self.data_holder.signals, \ self.interval_in_seconds) self.acc_plot_helper.update_curves(self.data_holder.time_seq\ [0:len(self.data_holder.time_seq):10],\ self.data_holder.signals, \ self.interval_in_seconds) def create_action(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): '''This is a action_helper helps to create an action''' action = QAction(text, self) if icon is not None: action.setIcon(QIcon(icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def open_file(self): ''' Open an existing data file''' print 'MainWindow.open_file() was triggered.' def save_file(self): ''' Save the data received from bluetooth into a file''' print 'MainWindow.save_file() was triggered.' def bt_settings(self): ''' Let user set the parameters of bluetooth connection.''' print 'MainWindow.bt_settings() was triggered.' dialog = SerialSettingsDialog(self) if dialog.exec_(): self.serial_settings = dialog.settings() print self.serial_settings if self.data_receiver.open(self.serial_settings): if self.data_receiver.serial.isOpen(): print 'Open serial successfully' self.start_action.setEnabled(True) sleep(0.1) else: print "Serial port is not open." else: print "Unable to open serial port." def start_plot(self): ''' Start or restart plotting the signals.''' #if self.start_action.isChecked(): # print "Already started." # return print 'MainWindow.start_plot() was triggered.' if self.serial_settings == {}: #Show a dialog here!!! self.statusBar().showMessage('Set the serial first.') else: self.file_helper.openFilesToWrite() self.eventButtonWidget.startLogging() self.data_receiver.startTransfer() self.data_receiver.start() self.timer.start() self.startTime = QDateTime.currentMSecsSinceEpoch() self.stop_action.setEnabled(True) self.statusBar().showMessage('Start plotting.') self.start_action.setEnabled(False) def pause_plot(self): ''' Pause plotting the signals.''' print 'MainWindow.pause_plot() was triggered.' if not self.start_action.isChecked(): self.pause_action.setChecked(False) return else: self.data_receiver.pauseTransfer() self.pause_action.setChecked(True) self.statusBar().showMessage('Pause plotting.') def stop_plot(self): ''' Stop plotting the signals.''' print 'MainWindow.start_plot() was triggered.' self.data_receiver.pauseTransfer() self.data_receiver.close() self.eventButtonWidget.endLogging() self.timer.stop() self.file_helper.closeFiles() self.statusBar().showMessage('Stop plotting.') self.saveFilesAs() self.start_action.setEnabled(True) self.stop_action.setEnabled(False) def scale_changed(self): ''' Update the scale factor.''' self.interval_in_seconds = self.scale_spinbox.value() print ' scale_spinbox triggered. Plot %d seconds.' \ % self.interval_in_seconds def closeEvent(self, event): self.file_helper.closeFiles() self.statusBar().showMessage('Close.') print "closeEvent."
def getData(keyWord = ''): if keyWord == '': print 'params lost' return False todayTime = datetime.date.today() targetUrl = 'http://tv.sohu.com/%s' % keyWord filePath = FileHelper.getPath(todayTime,'sohu',urls[keyWord]) fileName = '%s/html.txt' % filePath FileHelper.getContent2FileWithoutProcess(fileName=fileName,targetUrl=targetUrl) content = open(fileName,'r') temp = content.read().decode('utf-8') soup = BeautifulSoup(temp,'html.parser') count = -1 #过滤第一个 for tag in soup.findAll(True): if tag.has_attr('class'): #print ''.join(tag['class']) if (''.join(tag['class']) == 'at' and tag.name == 'a') or (tag.name == 'span' and ''.join(tag['class']) == 'vTotal'): count = count + 1 if count <= 200 and count >= 1 : if count == 1: FileHelper.save2File(content= 'RankDaily \n' , fileName=('%s/RankDaily.txt'% filePath),type= FileHelper.TYPE_APPEND) #日榜数据 FileHelper.save2File(content= '%s \n' %tag.string , fileName=('%s/RankDaily.txt'% filePath ) ,type= FileHelper.TYPE_APPEND) if count > 200 and count <= 400 : if count == 201: FileHelper.save2File(content= 'RankWeekly \n' , fileName=('%s/RankWeekly.txt'% filePath ) ,type= FileHelper.TYPE_APPEND) #周榜数据 FileHelper.save2File(content= '%s \n' %tag.string , fileName=('%s/RankWeekly.txt'% filePath ) ,type= FileHelper.TYPE_APPEND) if count > 400 and count <= 600 : if count == 401: FileHelper.save2File(content= 'RankMonth \n' , fileName=('%s/RankMonthly.txt'% filePath ) ,type= FileHelper.TYPE_APPEND) #月榜数据 FileHelper.save2File(content= '%s \n' %tag.string , fileName=('%s/RankMonthly.txt'% filePath ) ,type= FileHelper.TYPE_APPEND) if count > 600 : if count == 601: FileHelper.save2File(content= 'RankTotal \n' , fileName=('%s/RankTotal.txt'% filePath ) ,type= FileHelper.TYPE_APPEND) #总计数据 FileHelper.save2File(content= '%s \n' %tag.string , fileName=('%s/RankTotal.txt'% filePath) ,type= FileHelper.TYPE_APPEND) #print tag.string content.close() FileHelper.delFile(fileName)
def getData(keyWord = ''): targetUrl = getUrl(keyWord) todayTime = datetime.date.today() filePath = FileHelper.getPath(todayTime,'letv',urls[keyWord]) fileName = '%s/html.txt' % filePath FileHelper.getContent2FileWithoutProcess(fileName=fileName,targetUrl=targetUrl) content = open(fileName,'r') temp = content.read().decode('utf-8') soup = BeautifulSoup(temp,'html.parser') rank = 0 for tag in soup.findAll(True): # 每50条为分割 if(tag.name == 'a' and tag.has_attr('href') and (''.join(tag['href']).find('www.le.com') > 0) and rank<150): rank = rank + 1 if rank <= 50: FileHelper.save2File(content = 'Rank.%s %s ' % (rank,tag.string ), fileName='%s/RankDaily.txt' % filePath,type= FileHelper.TYPE_APPEND) if rank <=100 and rank >50: FileHelper.save2File(content = 'Rank.%s %s ' % (rank-50,tag.string ), fileName='%s/RankWeekly.txt' % filePath,type= FileHelper.TYPE_APPEND) if rank <= 150 and rank > 100: FileHelper.save2File(content = 'Rank.%s %s ' % (rank-100,tag.string ), fileName='%s/RankMonthly.txt' % filePath,type= FileHelper.TYPE_APPEND) if (tag.has_attr('class') and tag.name == 'span' and ''.join(tag['class']) == 't-5' and rank<150): if rank <= 50: FileHelper.save2File(content = 'VV : %s \n' % tag.string , fileName='%s/RankDaily.txt' % filePath,type= FileHelper.TYPE_APPEND) if rank <=100 and rank >50: FileHelper.save2File(content = 'VV : %s \n' % tag.string , fileName='%s/RankWeekly.txt' % filePath,type= FileHelper.TYPE_APPEND) if rank <= 150 and rank > 100: FileHelper.save2File(content = 'VV : %s \n' % tag.string , fileName='%s/RankMonthly.txt' % filePath,type= FileHelper.TYPE_APPEND) content.close() FileHelper.delFile(fileName)
def __init__(self, parent=None): ''' This is the initializer of the main window ''' super(MainWindow, self).__init__(parent) #======================================= # initial the member field #======================================= self.interval_in_seconds = 5 self.q_time_elapsed = QTime(0, 0, 0, 0) self.timer = QTimer() self.timer.setSingleShot(False) self.timer.setInterval(1000) self.connect(self.timer, SIGNAL("timeout()"), self.updateTheTime) # Data receiver self.data_receiver = DataTransfer() self.serial_settings = {} # Data holder self.data_holder = DataHolder() self.connect(self.data_receiver.qtobj, SIGNAL("NewData"),\ self.data_holder.on_receive_data) # File helper self.file_helper = FileHelper() self.connect(self.data_receiver.qtobj, SIGNAL("NewData"),\ self.file_helper.writeToSignalFile) # Plot_helpers self.bp_ecg_plot_helper = PlottingHelper(self, \ BP_ECG_signal_names, 1000) self.acc_plot_helper = PlottingHelper(self, \ ACC_signal_names, 100) #===================================================== # Set central widget #===================================================== self.setWindowTitle('UCare BP Monitor') self.setWindowIcon(QIcon('icon/icon.png')) # ========================================= # 1: set plot widget # ========================================= self.plotwidget = QWidget() self.plotVBox = QVBoxLayout() # Add plotting widget to the plotVBox for name in BP_ECG_names: self.plotVBox.addWidget(self.bp_ecg_plot_helper.curve_plots[name]) label = QLabel(name) label.setAlignment(Qt.AlignCenter) self.plotVBox.addWidget(label) #for key, curve_plot in self.bp_ecg_plot_helper.curve_plots.items(): # self.plotVBox.addWidget(curve_plot) for key, curve_plot in self.acc_plot_helper.curve_plots.items(): self.plotVBox.addWidget(curve_plot) label = QLabel(key) label.setAlignment(Qt.AlignCenter) self.plotVBox.addWidget(label) self.plotwidget.setLayout(self.plotVBox) # ========================================= # 2: set event widget # ========================================= self.eventWidget = QWidget() self.eventVBox = QVBoxLayout() # ============================ # 2-a: set eventButton widget # ============================ self.eventButtonWidget = EventButtonsWidget() self.connect(self.eventButtonWidget.qtobj, SIGNAL("NewEvent"), self.addEventLog) # ============================ # 2-b: set eventLog widget # ============================ self.eventLogList = QListWidget() # ============================ # 2-c: add the widgets into eventWidget # ============================ self.eventVBox.addWidget(self.eventButtonWidget) self.eventVBox.addWidget(QLabel(u"事件日志")) self.eventVBox.addWidget(self.eventLogList) self.eventWidget.setLayout(self.eventVBox) # ========================================= # 3: add widgets into centralWidget # ========================================= centralWidget = QWidget() centralHBox = QHBoxLayout() centralHBox.addWidget(self.plotwidget) centralHBox.addWidget(self.eventWidget) centralWidget.setLayout(centralHBox) self.setCentralWidget(centralWidget) self.connect(self.data_holder.qtobj, SIGNAL("UpdateCurve"),\ self.update_curves) #======================================= # Set dock windows #======================================= #self. #======================================= # Set statusbar #======================================= self.statusbar = self.statusBar() self.label_time_elapsed = QLabel() self.label_time_elapsed.setText(self.q_time_elapsed.toString()) self.statusbar.addPermanentWidget(self.label_time_elapsed) #======================================= # Set actions #======================================= # Open a file tip_text = 'Open an existing data file.' open_file_action = self.create_action('&Open a file', \ self.open_file, QKeySequence.Open, 'icon\open.png',\ tip_text, False) open_file_action.setEnabled(False) # Save the file tip_text = 'Save data into a file.' save_file_action = self.create_action('&Save into file', \ self.save_file, QKeySequence.Save, 'icon\save.png',\ tip_text, False) # Bluetooth settings tip_text = 'Settings of bluetooth. Ctrl+B' bt_settings_action = self.create_action('&Bluetooth Settings',\ self.bt_settings, 'Ctrl+B', 'icon\settings.png',\ tip_text, False) # Plotting start tip_text = 'Start ploting the signals. Ctrl+C' self.start_action = self.create_action('Start | &Continue plotting.',\ self.start_plot, 'Ctrl+C', 'icon\start.png', \ tip_text, True) self.start_action.setEnabled(False) # Plotting pause tip_text = 'Pause the plotting. Ctrl+P' self.pause_action = self.create_action('&Pause the plotting.', \ self.pause_plot, 'Ctrl+P', 'icon\pause.png',\ tip_text, True) self.pause_action.setEnabled(False) # Plotting stop tip_text = 'Stop the plotting. Ctrl+E' self.stop_action = self.create_action('&End the plotting.', \ self.stop_plot, 'Ctrl+E', 'icon\stop.png',\ tip_text, True) self.stop_action.setEnabled(False) # Set the plotting actions into a action group #plot_group = QActionGroup(self) #self.add_actions(plot_group, (self.start_action, self.pause_action, \ # self.stop_action)) # Scale the plotting #============================================= # Set the tool bar #============================================= # the file toolbar file_tool_bar = self.addToolBar("File") file_tool_bar.setObjectName("FileToolBar") self.add_actions(file_tool_bar, (open_file_action, \ save_file_action)) # the bluetooth toolbar bt_tool_bar = self.addToolBar("Bluetooth") bt_tool_bar.setObjectName("Bluetooth") self.add_actions(bt_tool_bar, (bt_settings_action, )) # the plotting toolbar plot_tool_bar = self.addToolBar("Plotting") plot_tool_bar.setObjectName("Plotting") self.add_actions(plot_tool_bar, (self.start_action, self.pause_action, \ self.stop_action, None)) self.scale_spinbox = QSpinBox() self.scale_spinbox.setRange(1, 50) self.scale_spinbox.setValue(5) self.scale_spinbox.setSuffix('s') scale_label = QLabel('Seconds to plot.') self.connect(self.scale_spinbox, SIGNAL('valueChanged(int)'), self.scale_changed) plot_tool_bar.addWidget(scale_label) plot_tool_bar.addWidget(self.scale_spinbox) #============================================= # Set the menu bar #============================================= # the file menu file_menu = self.menuBar().addMenu('&File') self.add_actions(file_menu, (open_file_action, save_file_action)) # the bluetooth menu bt_menu = self.menuBar().addMenu('&Bluetooth') self.add_actions(bt_menu, (bt_settings_action, ))
def _outputDoc(config, data): output_type = config['output_type'].lower() folder_path = config['save_path'] is_file_path = 0 # check if save_path is already a file path sp = folder_path.split(path_sep) if len(sp[-1]) > 0 and len((sp[-1]).split('.')) > 1: file_name = sp[-1] folder_path = path_sep.join(sp[:-1]) + path_sep is_file_path = 1 else: file_name = config['file_name'] if 'file_name' in config else 'feed' if len(file_name.split('.')) > 1: is_file_path = 1 # make sure save_path has a trailing slash if folder_path[-1] != path_sep: folder_path = folder_path + path_sep headers = {} # build save path save_path = folder_path + file_name # remove multiple slashes sp = [] for i, s in enumerate(save_path.split(path_sep)): if i == 0: sp.append(s) elif len(s.strip()) > 0: sp.append(s) # if not a relative path, save_path = '/'.join(sp) # json output if output_type == 'json': data_output = json.dumps(data) if not is_file_path: save_path = save_path + '.json' print 'Saving file: ' + save_path FileHelper.writeFile(data_output, save_path) elif output_type == 'html': print 'Saving HTML Files...' HTMLBuilder.generate(data, folder_path) else: print 'Output type not supported: ' + output_type
INFO_TYPE = 'info' ALBUM_TYPE = 'album' #拼接url 替换videoid def getUrl(videoid = '',type = ''): if videoid == '' or type == '': print 'params lost' else : if type == COUNT_TYPE: return 'http://cache.video.qiyi.com/jp/pc/%s/?src=760859ef3a0046e0932d0381e641cbb6&callback=window.Q.__callbacks__.cby7lfmi' % videoid if type == PERCENT_TYPE: return 'http://cache.video.qiyi.com/pc/pr/%s/playCountPCMobileCb?callback=playCountPCMobileCb' % videoid if type == INFO_TYPE: return 'http://mixer.video.iqiyi.com/jp/mixin/videos/%s?callback=window.Q.__callbacks__.cbvccih6&status=1' % videoid #return 'http://cache.video.qiyi.com/jp/vi/%s/778e9e5286f2ca6a94d8b5da0062f978/?status=1&callback=window.Q.__callbacks__.cbyexhk1' % videoid if type == ALBUM_TYPE: return 'http://cache.video.qiyi.com/jp/avlist/%s/1/50/?albumId=%s&pageNo=1&pageNum=50&callback=window.Q.__callbacks__.cbs2bcrj' % (videoid,videoid) if __name__ == '__main__': #202909701 山海经 #202938201 太阳的后裔 FileHelper.parseAblum('202909701') dicIds = FileHelper.readVideoIdsfAblum() print len(dicIds['data']) for i in range(0,len(dicIds['data'])): videoid = dicIds['data'][i]['videoid'] FileHelper.getContent2File('percent.txt', getUrl(videoid=videoid, type=PERCENT_TYPE), PERCENT_TYPE) FileHelper.getContent2File('info.txt', getUrl(videoid=videoid, type=INFO_TYPE), INFO_TYPE) dataMix.mixData(videoid)
def _createIndexFile(folder_path): global html_doc_folder doc_path = folder_path + html_doc_folder file_list = FileHelper._getFileLists(doc_path, 'html', 0) save_path = folder_path + 'index.html' wrapper = [ '<!DOCTYPE html5>', '<html>', '<head>', '$styles', '$scripts', '</head>', '<body id="index">', '<header><h1>Index</h1></header>', '<div id="content">', ' <div class="main">$content</div>', '</div>', '</body>', '</html>' ] wrapper = '\n'.join(wrapper) list_templ = [ '<li>' ' <h3><a href="$href">$name</a></h3>' '</li>' ] list_templ = '\n'.join(list_templ) # docs docs = [] t = Template(list_templ) for i, fl in enumerate(file_list): rp = {} rp['href'] = html_doc_folder + fl rp['name'] = '.'.join(fl.split('.')[:-1]) docs.append(t.safe_substitute(rp)) if len(docs) > 0: docs = '<ul>' + ''.join(docs) + '</ul>' else: docs = '<ul><li>No files.</li></ul>' d = {} # css styles d['styles'] = _setStyles(folder_path) # js files d['scripts'] = _setScripts(folder_path) d['content'] = docs t = Template(wrapper) print 'Saving Index file...' print 'Saving ' + save_path FileHelper.writeFile(t.safe_substitute(d), save_path)