コード例 #1
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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';"})
コード例 #2
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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})
コード例 #3
0
    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
コード例 #4
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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})
コード例 #5
0
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
コード例 #6
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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})
コード例 #7
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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})
コード例 #8
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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")
コード例 #9
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
def error404(error):
	"""Handle a 404 error (page not found) with a redirect."""
	printIf("404 error: " + str(error))
	return render_template("404.html")
コード例 #10
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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';"})
コード例 #11
0
ファイル: routes.py プロジェクト: lmxtdt/cyanoConstruct
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})
コード例 #12
0
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
    })
コード例 #13
0
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