def newCompZIP(): """Download ZIP file from the design step.""" try: #get information from the request newCompID = request.args.get("id") offset = int(request.args.get("timezoneOffset")) #get the requested component's ZIP file comp = ComponentDB.query.get(newCompID) checkPermission(comp) compZIP = comp.getCompZIP(offset) #make the ZIP into a byte file data = rf.makeZIP(compZIP) except Exception as e: printIf("FAILED TO CREATE ZIP BECAUSE: {}".format(e)) return errorZIP(e) if(data is None): return errorZIP("No/invalid component to create a ZIP from.") return Response(data, headers = {"Content-Type": "application/zip", "Condent-Disposition": "attachment; filename='sequences.zip';"})
def newBackbone2(): """Create a new backbone and add it to the current user's library.""" outputStr = "" validInput = True succeeded = False #get information from the web form try: BBname = request.form["backboneName"] BBdesc = request.form["backboneDesc"] BBseq = request.form["backboneSeq"] BBtype = request.form["backboneType"] BBfeatures = request.form["backboneFeatures"] except Exception as e: printIf(e) validInput = False outputStr = "ERROR: invalid input received.<br>" # check if it exists in the personal library if(validInput): try: getCurrUser().findBackbone(BBname) outputStr = "ERROR: Backbone {name} already exists in your personal library.".format( name = BBname) validInput = False except ee.BackboneNotFoundError: pass #general validation. Includes checking if the backbone is in the default library. if(validInput): validInput, outputStr = rf.validateBackbone(BBname, BBdesc, BBseq, BBtype, BBfeatures) #validation of the sequence & features if(validInput): outputStr, validInput, BBdata = rf.processGBfeatures(BBseq, BBfeatures.splitlines(keepends = True), outputStr) seqBefore = BBdata["seqBefore"] seqAfter = BBdata["seqAfter"] features = BBdata["featureSection"] #create the backbone if(validInput): try: getCurrUser().createBackbone(BBname, BBtype, BBdesc, seqBefore, seqAfter, features) #outputStr libraryName = "Personal" outputStr += ("Successfully created <a target = '_blank' href = '/library#" "{libraryName}{BBname}Backbone'>{BBname}</a>.").format( libraryName = libraryName, BBname = BBname) succeeded = True except Exception as e: outputStr += "ERROR: {}<br>".format(e) return jsonify({"output": outputStr, "succeeded": succeeded})
def new(cls, email): """Create a new user: creates a UserData and a UserDataDB. PARAMTERS: email: string email of the user RETURN: newUserData: created UserData """ printIf("Calling UserData.new({email}).\n".format(email=email)) #type validation if (type(email) != str): raise TypeError("email not a str") #see if a user with the email already exists if (UserDataDB.query.filter_by(email=email).all() != []): raise e.AlreadyExistsError( "User with email {email} already exists.".format(email=email)) #initialize newUserData = cls() #start nextNSid (the first number for the IDs of named sequences of the user) if (email == "default"): nextNSid = 1 else: nextNSid = 101 #add user to database u = UserDataDB(nextNSidPR=nextNSid, nextNSidRBS=nextNSid, nextNSidGOI=nextNSid, nextNSidTERM=nextNSid, email=email) db.session.add(u) db.session.commit() #add database info. to the user newUserData.__DBid = u.id newUserData.__entryDB = u return newUserData
def backboneFile(): """Parse through a backbone .gb file to auto-fill most of the backbone design form.""" outputStr = "" validInput = True succeeded = False featureSection = "" sequenceOutput = "" definition = "" name = "" #get data from web page try: backboneData = request.data size = int(request.args.get("size")) except Exception as e: validInput = False printIf(e) outputStr = "ERROR: Invalid input received." if(validInput): try: #check the size of the data received & size of the data sent are the same if(len(backboneData) != size): raise Exception("File was not completely uploaded to server. Please try again.") #otherwise, process the .gb file using readBackboneGB() outputStr, validInput, fileData = rf.readBackboneGB(backboneData, outputStr) name = fileData["name"] definition = fileData["definition"] featureSection = fileData["features"] sequenceOutput = fileData["sequence"] succeeded = True except Exception as e: validInput = False printIf(e) outputStr = "ERROR: {}".format(e) return jsonify({"output": outputStr, "succeeded": succeeded, "featureStr": featureSection, "sequence": sequenceOutput, "definition": definition, "name": name})
def makeZIP(filesDict): """Make and return a .zip file. PARAMETER: filesDict: dictionary of files; the keys are string file names, while the values are the file contents RETURNS: data: byte data of the complete .zip file """ #type checking if (type(filesDict) != dict): raise TypeError("filesDict not a dict") #check if there are no files to create if (filesDict == {}): printIf("NO SEQUENCE; NO FILES CREATED") return None #make a random and unique submission ID for the folder submissionID = uuid1().hex #paths for folders #get the path for the "files" folder in cyanoConstruct filesDirPath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files") #get the path for the folder that will be created to store the files sessionDir = os.path.join(filesDirPath, submissionID) #create said folder os.mkdir(sessionDir) printIf("MADE DIRECTORY: " + sessionDir) #write files to the folder for fileName in filesDict: newName = os.path.join(sessionDir, fileName) with open(newName, "w") as f: f.write(filesDict[fileName]) #make zip and write it to the zips folder zipPath = os.path.join(os.path.join(filesDirPath, "zips"), submissionID) make_archive(zipPath, "zip", sessionDir) #read zip as a byte file and store it as data with open(zipPath + ".zip", "rb") as f: data = f.readlines() #delete the session directory & zip file rmtree(sessionDir) os.remove(zipPath + ".zip") printIf("FINISHED CREATING FILES FOR SESSION " + submissionID) return data
def backbonePreview(): """Process user-designed features and turn them into .gb file format. NOTES: This is called when the user creates their own features on the backbone design form. It returns a string that the web page will display as part of the features for the backbone in process. """ outputStr = "" validInput = True succeeded = False featureStr = "" #get data try: numFeatures = int(request.form["numFeatures"]) printIf(request.form) except Exception as e: validInput = False printIf(e) outputStr = "ERROR: Invalid input received.<br>" #make features if(validInput): allMolTypes = {"genomicDNA": "genomic DNA", "genomicRNA": "genomic RNA", "mRNA": "mRNA", "tRNA": "tRNA", "rRNA": "rRNA", "otherRNA": "other RNA","otherDNA": "other DNA", "transcribedRNA": "transcribed RNA", "viralcRNA": "viral cRNA", "unassignedDNA": "unassigned DNA", "unassignedRNA": "unassigned RNA"} try: #go through each feature for key in range(numFeatures): featType = request.form["featureType{}".format(key)] #get locations #if there is just locus: the origin if(featType == "none"): continue elif(featType == "origin"): locOrig = int(request.form["locationOrigin{}".format(key)]) if(locOrig < 1): validInput = False outputStr += "ERROR: origin location must be at least 1.<br>" #all other feature types have a start and end location else: locStart = int(request.form["locationStart{}".format(key)]) locEnd = int(request.form["locationEnd{}".format(key)]) if(locStart < 1 or locEnd < 1): outputStr += "ERROR: locations for feature #{} must be at least 1.<br>".format(key) if(locStart > locEnd): validInput = False outputStr += ("ERROR: start location for feature #{} " "is greater than its end location.<br>").format(key) #add to featureStr, format depending on the type of the feature if(featType == "origin"): featureStr += "\trep_origin\t{orig}\n".format(orig = locOrig) #get the direction of the origin direction = False try: direction = request.form["direction{}".format(key)] except Exception: pass #if there is a direction, add it to the string if(direction): if(direction == "none"): pass elif(direction not in ["left", "right", "both"]): raise Exception("invalid direction {}".format(direction)) else: featureStr += "\t\t\t/direction={direction}\n".format(direction = direction) elif(featType == "source"): organism = request.form["organism{}".format(key)] molType = request.form["molType{}".format(key)] if(len(organism) > 64): validInput = False outputStr += "ERROR: organism name must be at most 64 characters long.<br>" molLong = allMolTypes[molType] featureStr += ("\tsource\t\t{start}..{end}\n\t\t\t/organism=\"{organism}\"\n" "\t\t\t/mol_type=\"{molLong}\"\n").format( start = locStart, end = locEnd, organism = organism, molLong = molLong) elif(featType == "CDS"): gene = request.form["geneName{}".format(key)] if(len(gene) > 64): validInput = False outputStr += "ERROR: gene name must be at most 64 characters long.<br>" featureStr += "\tCDS\t\t{start}..{end}\n\t\t\t/gene=\"{geneName}\"\n".format( start = locStart, end = locEnd, geneName = gene) elif(featType == "misc"): note = request.form["miscNote{}".format(key)] if(len(note) > 1024): validInput = False outputStr += "ERROR: note must be at most 1024 characters long.<br>" featureStr += "\tmisc_feature\t{start}..{end}\n\t\t\t/note=\"{note}\"\n".format( start = locStart, end = locEnd, note = note) else: raise Exception("invalid featType {}".format(featType)) #end for loop going through the features except Exception as e: validInput = False printIf(e) outputStr = "ERROR: Invalid input received.<br>" if(validInput): succeeded = True printIf(featureStr) return jsonify({"output": outputStr, "succeeded": succeeded, "featureStr": featureStr})
def loginGoogle(): """Log a user in using Google Sign-In.""" succeeded = False outputStr = "" #get information from the page try: token = request.form["IDtoken"] email = request.form["email"] try: remember = rf.boolJS(request.form["remember"]) except Exception: raise ValueError("invalid remember me") #check token # Specify the CLIENT_ID of the app that accesses the backend: idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID) if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']: raise ValueError('Wrong issuer.') # ID token is valid. Get the user's Google Account ID from the decoded token. userid = idinfo['sub'] #actually log in OR register try: #log in user = UserData.load(email) if(user.getGoogleAssoc()): #check if the Google User ID & email match #This may cause an issue if someone changes their email address #but logs in using the same Google account. Will this ever happen? if(user.getGoogleID() != userid): raise Exception("User ID and Email do not match.") else: login_user(user, remember = remember) outputStr = "Successfully logged in as {email}.".format(email = email) else: raise Exception("Account with this email already exists, not associated with Google.") except ee.UserNotFoundError: #register user = UserData.new(email) #set user up with Google-related info. user.setGoogleAssoc(True) user.setGoogleID(userid) login_user(user, remember = remember) clearSelected() outputStr = "Successfully created account as {email}.".format(email = email) succeeded = True except ValueError: #is raised if there is an invalid token. outputStr = "ERROR: Invalid input." #handle any other errors by transforming them into an error message except Exception as e: outputStr = "ERROR: {}".format(e) printIf(e) return jsonify({"succeeded": succeeded, "output": outputStr})
def error500(error): """Handle a 500 error (database error) with a redirect and database rollback.""" printIf("500 eror: " + str(error)) #roll back the database somehow, because this is invoked by database errors return render_template("500.html")
def error404(error): """Handle a 404 error (page not found) with a redirect.""" printIf("404 error: " + str(error)) return render_template("404.html")
def assemblyZIP(): """Create and send a .zip for an assembled sequence.""" #get info. about the assembled sequence try: compsList = session["assemblyCompIDs"] bbID = session["assemblyBackbone"] offset = session["timezoneOffset"] except KeyError: return errorZIP("No assembled sequence.") #gather the backbone and components from the session try: #get the backbone & see if the user has permission to use it bb = BackboneDB.query.get(bbID) checkPermissionBB(bb) #start the fullSeq with the part of the backbone that is before the insertion fullSeq = bb.getSeqBefore() #index (starting at zero) of the fullSeq to add at i = len(fullSeq) #get features from the backbone features = bb.getFeatures().splitlines() #go through each saved component for compID in compsList: #get the component & see if the user has permission to use it comp = ComponentDB.query.get(compID) checkPermission(comp) #add the component to the assembly #if the component is element 0, (a promoter) if(comp.getPosition() == 0): #add to fullSeq and i fullSeq += comp.getSeq() i = rf.addCompAssemblyGB(comp, features, i) printIf("adding {compID} seq".format(compID = comp.getNameID())) #if the component is any non-0 element else: #?! why IS it like this fullSeq += comp.getLeftSpacer() + comp.getSeq() i = rf.addSpacerAssemblyGB(comp.getLeftSpacer(), features, i) printIf("adding {compID} left spacer: {spacer}".format( compID = comp.getNameID(), spacer = comp.getLeftSpacer())) i = rf.addCompAssemblyGB(comp, features, i) printIf("adding {compID} seq".format(compID = comp.getNameID())) #get the length of the inserted sequence lengthInsertion = i - len(bb.getSeqBefore()) #process the features #go through each feature for j in range(len(features)): #split the features by [AddLength] #the features are formatted like "blah blah [AddLength]20[AddLength] blah blah" #so splitting by [AddLength] will separate out 20 #the length of the insertion can be then added to 20 featRow = features[j].split("[AddLength]") if(len(featRow) > 1): #get every number that is sandwiched by two "[AddLength]"s for k in range(1, len(featRow), 2): #replace the number with the original index + the insertion's length origIndex = int(featRow[k]) featRow[k] = str(origIndex + lengthInsertion) #merge the feature row features[j] = "".join(featRow) #finish the assembly fullSeq += bb.getSeqAfter() fileGB = rf.finishCompAssemblyGB(features, fullSeq, offset, bb.getName()) fileFASTA = ">CyanoConstruct assembled sequence\n" + fullSeq #make the .zip data = rf.makeZIP({"fullSequence.fasta": fileFASTA, "fullSequence.gb": fileGB}) except Exception as e: return errorZIP(e) if(data is None): return errorZIP("No assembled sequence.") return Response(data, headers = {"Content-Type": "application/zip", "Condent-Disposition": "attachment; filename='sequences.zip';"})
def processAssembly(): """Create an assembled sequence using information from the /assemble page.""" outputStr = "" validInput = True succeeded = True #get info. try: #get basic info. offset = int(request.form["timezoneOffset"]) bbID = request.form["backbone"] numMidElem = int(request.form["numMidElements"]) except Exception as e: printIf(e) validInput = False succeeded = False outputStr = "ERROR: bad input." #insert more validation? if(validInput): outputStr = "Backbone:<br>" try: #store timezone offset as a cookie #this is used so the .gb file has a date that is accurate to #the user's timezone. session["timezoneOffset"] = offset #get the backbone #bbID = int(dataDict["backbone"]) bb = BackboneDB.query.get(bbID) #check if the backbone exists. if(bb is None): validInput = False succeeded = False outputStr = "ERROR: Could not find backbone." else: try: #ensure the user has permission to use the backbone checkPermissionBB(bb) #get info. about the backbone for outputStr user = UserDataDB.query.get(bb.getUserID()) if(user.getEmail() == "default"): libraryName = "Default" else: libraryName = "Personal" outputStr += ("Found: <a target = '_blank' href = '/library#" "{libraryName}{BBname}Backbone'>{BBname}</a><br>").format( BBname = bb.getName(), libraryName = libraryName) #save the backbone to the session session["assemblyBackbone"] = bb.getID() except ee.AccessError: validInput = False succeeded = False outputStr += "ERROR: You do not have permission to use this backbone.<br>" except Exception as e: validInput = False succeeded = False printIf(e) #gather the components if(validInput): outputStr += "<br>Components:<br>" #allPositions stores the positions of all of the elements that were submitted allPositions = [0,999] allPositions.extend([x for x in range(1, numMidElem + 1)]) #compsList stores all of the components found compsList = [] #for each position, find the corresponding component for pos in allPositions: #get the type and name from the request elemType = request.form["elemType{}".format(pos)] elemName = request.form["elemName{}".format(pos)] #get the terminalLetter, to be used for searching for components if(pos == 0): terminalLetter = "S" elif(pos == 999): terminalLetter = "T" elif(pos < numMidElem): terminalLetter = "M" else: terminalLetter = "L" #finally search for the component try: #search default library try: foundComp = defaultUser.findComponent(elemType, elemName, pos, terminalLetter) libraryName = "Default" #if not found in the default, search user library except (ee.SequenceNotFoundError, ee.ComponentNotFoundError): foundComp = getCurrUser().findComponent(elemType, elemName, pos, terminalLetter) libraryName = "Personal" #add the found component compsList.append(foundComp.getID()) outputStr += ("Found: <a target = '_blank' href ='/library#" "{libraryName}{nameID}'>{nameID}</a><br>").format( libraryName = libraryName, nameID = foundComp.getNameID()) except (ee.SequenceNotFoundError, ee.ComponentNotFoundError): #if a component was not found outputStr += ("Could not find:<br>Type: {type}<br>Name: {name}" "<br>Position: {pos}<br>" "Terminal letter: {terminalLetter}<br>").format( type = elemType, name = elemName, pos = pos, terminalLetter = terminalLetter) succeeded = False #proceed if succeeded, or if everything was found if(succeeded): #save the component IDs to the session session["assemblyCompIDs"] = compsList outputStr += "<br>Full sequence can be downloaded." else: outputStr += ("<br>Errors in finding components are often due to not having" "a component with the right terminal letter.<br>Sequence not created.") return jsonify({"output": outputStr, "succeeded": succeeded})
def processGBfeatures(seq, features, outputStr): """Process a backbone's sequence and features for storage as a Backbone in the database. FINISH ANNOTATING THIS, IT IS A VERY COMPLICATED AND CONFUSING FUNCTION Calls validateSearchBackbone() PARAMETERS: seq: string sequence of the backbone features: string features outputStr: string of HTML to output to the website. Errors will be added to it. RETURNS: validInput: boolean. True if input is valid, False otherwise. outputStr: HTML string to output to the website so errors are displayed. a dictionary of information for creating a new Backbone, with keys: seqBefore: string sequence of the backbone before the insertion region seqAfter: string sequence of the backbone after the insertion region featureSection: string of the features, formatted for a .gb file Has stylistic modifications (e.g. tabs instead of spaces) and "[AddLength]"s, for use during assembly. """ sequenceBefore = None sequenceAfter = None featureSection = None #get the indices for the start of the left and right pattern #if there are only one of each validInput, outputStr, siteL, siteR = validateSearchBackbone( outputStr, seq) length = len(seq) printIf("siteL {} siteR {}".format(siteL, siteR)) if (validInput): try: #Apologies in advance if this entire section does not make sense. #I barely understood how it worked when I wrote it, and have since #forgotten. #insL is the leftmost index of the insertion region, i.e. the first #nucleotide to be removed. #it uses the numbering of the .gb file, which counts from 1 NOT 0 #which is why it is calculated with + 5, not + 4 if (siteL + 4 >= length): insL = 5 - (length - siteL) else: insL = siteL + 5 #relatedly, insR is the rightmost index of the insertion region, i.e. #the last nucleotide to be removed #I THINK??????? #?! if (siteR + 7 >= length): insR = 8 - (length - siteR) else: insR = siteR + 8 printIf((insL, insR)) if (insR >= insL): insertionAdjustment = (insR - insL) + 1 rightmost = insR else: #if the insertion region wraps back around insertionAdjustment = insR rightmost = length + 1 printIf("insertionAdjustment {} rightmost {}".format( insertionAdjustment, rightmost)) deleteNextLine = False #go through every line of the features for i in range(len(features)): #remove whitespace on the left of the line features[i] = features[i].lstrip() #do nothing if there's nothing in this line if (not features[i]): continue #if the line does NOT begin with "/", so it is a feature key #that says what type the feature is if (features[i][0] != "/"): #split the line into row, which splits the type (?) and location #so "gene 5..10" turns into ["gene", "5..10"] row = features[i].split(maxsplit=1) printIf(features[i]) #if there is a range/location for the feature if (len(row) > 1): #should have numbers in the string of the format NUMBER..NUMBER rowElements = re.split("(\d+..\d+)", row[1]) #determine if it's formatted like join(5..10, 15..20) if (rowElements[0] == "join("): isJoin = True else: isJoin = False pairsRemove = 0 print(rowElements) #every other element in the list should be a number pair #the other elements will be "join(" etc. for j in range(1, len(rowElements), 2): removeFeature = False #get the start and end index of the range startIndex, endIndex = rowElements[j].split("..") newStart = int(startIndex) newEnd = int(endIndex) #make sure the indices are less than the length #if they loop around if (newStart > length): newStart -= length if (newEnd > length): newEnd -= length printIf("newStart {} newEnd {} \t insL {} insR {}". format(newStart, newEnd, insL, insR)) #if the insertion region is in the middle of the sequence #it does NOT loop around at the end if (insR >= insL): #if newStart is within the insertion region if (newStart >= insL and newStart <= insR): #if newEnd is within the insertion region if (newEnd >= insL and newEnd <= insR): #need to remove the feature removeFeature = True printIf( "need to remove the entire thing") #otherwise, shove newStart to insR + 1 #so the range begins at the end of the #insertion region else: newStart = insR + 1 if (newStart > length): newStart = newStart - length #if newEnd is within the insertion region #(but newStart is not) elif (newEnd > insL and newEnd <= insR): #shove newEnd insL - 1 #so the range ends at the beginning of the #insertion region newEnd = insL - 1 if (newEnd < 1): newEnd = length + newEnd insR2 = insR #otherwise the insertion region DOES loop around else: #if newStart is within the insertion region if (newStart <= insR): #if newEnd is also within the insertion region if (newEnd <= insR): #need to remove the entire feature removeFeature = True printIf( "need to remove the entire thing") else: #shove newStart to the end of the #insertion region newStart = insR + 1 if (newStart > length): newStart = newStart - length #if newEnd is within the insertion region if (newEnd >= insL): #end within insertion region if (newStart >= insL): #rneed to remove the entire feature removeFeature = True printIf( "need to remove the entire thing") else: #shove newEnd to the beginning of the #insertion region newEnd = insL - 1 if (newEnd < 1): newEnd = length + newEnd printIf("newStart {} newEnd {} insR {}".format( newStart, newEnd, insR)) printIf("newStart -= insR; newEnd -= insR") #finally, subtract insR from newStart and newEnd #to account for the removal of the insertion region newStart -= insR newEnd -= insR insR2 = length - insR #normally, rightmost = insR #looping, rightmost = length + 1 #normally, insR2 = insR #looping, insR2 = length - insR #?!!!! what is going on #I have previously stated I do not remember how this #section works. So I'm not really sure what insR and #rightmost represent, nor why these if statments are #used. I only know that they work. #dealing with newStart if (newStart >= insR2): #if newStart is to the right of the insertion region if (newStart >= rightmost): #[AddLength]NUMBER[AddLength] indicates the #number must have the length of the inserted #sequence added to it in the final sequence startStr = "[AddLength]{}[AddLength]".format( newStart - insertionAdjustment) else: startStr = str(newStart - insertionAdjustment) else: startStr = str(newStart) #dealing with newEnd if (newEnd >= insR2): #if newEnd is to the right of the insertion region if (newEnd >= rightmost): endStr = "[AddLength]{}[AddLength]".format( newEnd - insertionAdjustment) else: endStr = str(newEnd - insertionAdjustment) else: endStr = str(newEnd) #finally, update rowElements[j] if (removeFeature): rowElements[j] = "" pairsRemove += 1 else: rowElements[j] = "{start}..{end}".format( start=startStr, end=endStr) #end of "for(j in range..." loop #i.e. have gone through all number pairs #proceed to deal with the line as a whole printIf(("isJoin = {} \tpairsRemove = {} \t" "int(len(rowElements) / 2) - 1) = {}").format( isJoin, pairsRemove, int(len(rowElements) / 2) - 1)) #if the entire feature needs to be removed if (pairsRemove == int(len(rowElements) / 2)): deleteNextLine = True features[i] = "" #otherwise, the feature stays else: deleteNextLine = False #replace the row with the properly formatted one #if row[0] is 3 characters or shorter if (len(row[0]) <= 3): #two tabs are needed to look right features[i] = "\t{row1}\t\t{row2}".format( row1=row[0], row2="".join(rowElements)) #if row[0] is longer than 3 characters else: #only one tab is needed features[i] = "\t{row1}\t{row2}".format( row1=row[0], row2="".join(rowElements)) #remove empty numbers in a join if (isJoin): while (features[i].find(",,") != -1): features[i] = features[i].replace(",,", ",") features[i] = features[i].replace("(,", "(") features[i] = features[i].replace(",)", ")") features[i] = features[i].replace("( ", "(") features[i] = features[i].replace(" )", ")") #remove the join() if there's only one set of numbers remaining if (pairsRemove == int(len(rowElements) / 2) - 1): features[i] = features[i].replace("join(", "") features[i] = features[i].replace(")", "") printIf(features[i]) printIf("===") #if this is a qualifier of a feature, e.g. /organism="Saccharomyces cerevisiae" #so there are no numbers to adjust else: #add three tabs to the beginning features[i] = "\t\t\t" + features[i] #clear the line if deleteNextLine is true #i.e. the feature needs to be deleted if (deleteNextLine): features[i] = "" featureSection = "".join(features) #remove the insertion region by setting sequenceBefore and sequenceAfter if (insL <= insR): sequenceBefore = seq[0:insL - 1] sequenceAfter = seq[insR:] else: sequenceBefore = seq[insR:insL - 1] sequenceAfter = "" except Exception as e: outputStr += "ERROR: {}".format(e) validInput = False return (outputStr, validInput, { "seqBefore": sequenceBefore, "seqAfter": sequenceAfter, "featureSection": featureSection })
def makeAllLibraryZIP(user, offset): """Create a .zip file of all components of a user. PARAMETER: user: a UserData whose library will be turned into a .zip offset: integer number of minutes the user's timezone is off from UTC RETURNS: data: byte data of the completed .zip file """ #type checking #if(type(user) != UserData): # raise TypeError("user not a UserData") #directories and paths filesDirPath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files") sessionDir = os.path.join(filesDirPath, uuid1().hex) libraryDir = os.path.join(sessionDir, user.getEmail() + "Library") #make the directories needed try: os.mkdir(sessionDir) except OSError: #if it exists pass os.mkdir(libraryDir) printIf("MADE DIRECTORY: " + libraryDir) #do this. #?! DOES THIS RETURN BACKBONES, ACTUALLY? #get the named sequences, sorted sortedNS = user.getSortedNS() #go through each type (e.g. RBS) for typeKey in sortedNS: #do nothing if the folder would be empty if (sortedNS[typeKey] == []): continue #make folder for the type typeDir = os.path.join(libraryDir, typeKey) os.mkdir(typeDir) #for each named sequence of that type for ns in sortedNS[typeKey]: #get the components derived from the sequence nsComps = ns.getAllComponents() #do nothing if the folder would be empty if (nsComps == []): continue #make folder for the sequence nameDir = os.path.join(typeDir, ns.getName()) os.mkdir(nameDir) #sort the components nsComps.sort() #for each component derived from the sequence for comp in nsComps: #make folder for the component compDir = os.path.join(nameDir, comp.getNameID()) os.mkdir(compDir) #get info. for the component (dict of file names and contents) compZIP = comp.getCompZIP(offset) #write the files for the component for fileName in compZIP: filePath = os.path.join(compDir, fileName) with open(filePath, "w") as f: f.write(compZIP[fileName]) #make the .zip zipPath = os.path.join(sessionDir, "libraryZIP") make_archive(zipPath, "zip", libraryDir) #read zip as a byte file with open(zipPath + ".zip", "rb") as f: data = f.readlines() #delete all folders and files created earlier in this function rmtree(sessionDir) printIf("FINISHED CREATING LIBRARY ZIP FOR USER " + user.getEmail()) return data