Flask not writing to file - python

I've been meaning to log all the users that visit the site to a file.
Using Flask for the backend.
I have not been able to get python to write to the file. Tried keeping exception handling to catch any errors that might be generated while writing. No exceptions are being raised.
Here is the part of the blueprint that should write to file.
from .UserDataCache import UserDataCache
udc = UserDataCache()
#main.route('/')
def index():
s = Suggestion.query.all()
udc.writeUsertoFile()
return render_template('suggestions.html', suggestions = s)
Here is the UserDataCache class:
from flask import request
from datetime import datetime
class UserDataCache():
def __init__(self):
pass
def writeUsertoFile(self):
try:
with open("userData.txt","a") as f:
f.write(str(datetime.now()) + " " + request.remote_addr + " " + request.url + " " + request.headers.get('User-Agent') + "\n")
except IOError,e:
print e
return

I recommend using an absolute path and verifying the permissions on that file. Something like /tmp/UserData.txt or another absolute path should work. The web server's user is what needs the permission to write to the file (www-data if you're using apache2 with Ubuntu, or check your web server's conf file to verify).
As far as why you're not seeing the exception you're catching, I see you're using print. If you're calling the app using a web browser, you'll need to send the error to something else, like a log file or flash it to the browser, or raise an error so it gets logged in the web server error log.

Is your python file name begins with uppercase? If so, try to modify it into lowercase.
I just came into the same problem and copied the exactly same code into two .py file. The only difference is their file name, one being 'Flask_test.py' and another being 'flask_for_test.py'. It's weird that 'Flask_test.py' works just fine except it cannot write into any file and 'flask_for_test.py' works perfectly.
I don't know whether the format of the file name has an effect on the function of python but using lowercase file name works for me.
By the way, all other solutions I found didn't work.

Related

Avoid time-out error in python when trying to write a file to some location [ Python - v3.8+ ]

I am trying to write a file to a specific mount location in Linux. The API returns a path which is required for the further operations. The problem is if the file size is huge, then i face a request time-out error because of which iam not able to get the path. The code is as follows:
#migration_blueprint.route("/migration/upload", methods=["POST"])
def upload_migration_file():
file_abs_path = ""
try:
file = request.files['files']
logger.debug("The file recieved is '{}'".format(file))
file_name = str(datetime.now().strftime("%H%M%s")) + file.filename
proxy_bin = db.find_one("bins", query={"bin_type":"proxy", "status":"active"})
if not proxy_bin:
raise Exception("Proxy Bin not found")
base_proxy_path = "/mnt/share_{}/migration/".format(proxy_bin['_id'])
if not os.path.exists(base_proxy_path):
os.makedirs(base_proxy_path)
file_abs_path = os.path.join(base_proxy_path, file_name)
file.save(file_abs_path)
except Exception as ex:
logger.exception("Error : {}".format(str(ex)))
abort("500",{"message" : str(ex)})
return {"path" : file_abs_path}
Is there any workaround where irrespective of the file size, the file gets written to the location and the path is also returned as response in time ?
You could try uploading files via ajax and polling the server at intervals until the filename is ready (you could also use server side events) or you could use websockets to upload files and then update the client when the filename is available.
I tried to impelement the solution through multiprocessing in python.
from multiprocessing import Process
def copy_file(file_data, abs_path):
file_data.save(abs_path)
In the API i updated it:
p = Process(target=copy_file(file, file_abs_path))
p.start()
# file.save(file_abs_path)

Runtime Error - web.config

I have created a website using flask that takes in a string, creates a url based off the string, parses the url and then feeds it back into the website. I created a function to do so and it works perfectly. However when I implement it within my flask program it started throwing a runtime error that states:
An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.
Details:To enable the details of this specific error message to be viewable on remote machines, please create a customErrors tag within a "web.config" configuration file located in the root directory of the current web application. This customErrors tag should then have its "mode" attribute set to "Off".
I am not familiar with creating a web.config or how to implement this within my flask program. Any help would be appreciated.
Code:
Function that works when ran on it's own:
def parse_wotc():
set_list = []
# Manually enter in value for test
card_url = 'http://gatherer.wizards.com/Pages/Card/Details.aspx?name=' +
'mountain' # (replace mountain) card_name.replace(' ', '+')
soup = BeautifulSoup(requests.get(card_url).text, 'html.parser')
for image in soup.find_all('img'):
if image.get('title') is not None:
set_list.append(image.get('title'))
print(set_list)
return set_list
webapp code:
#app.route('/', methods=['GET', 'POST'])
def index():
card_name = None
card_url = '/static/images/card_back.jpg'
if request.form.get('random_button'):
card_url, card_name = random_card_image(list_card_names)
# When function ran here it give the error
parse_wotc(card_name)
def random_card_image(list_card_names):
"""This function will pull a random card name from the provided list and
return to main program"""
card_name = random.choice(list_card_names)
card_url = 'http://gatherer.wizards.com/Handlers/Image.ashx?name=' +
card_name.replace(' ', '+').lower() + \
'&type=card'
return card_url, card_name
It took a couple of hours to determine what the issue was, but it is working now. The issue is that I made a text file that had a list of card names that I was pulling from to create a random selection - the text file however included a trailing \n on each entry. Therefore it was creating a url with \n in it which was unnoticeable at the time and causing an error. I used rsplit() when creating the name list to remove the trailing \n and now it works perfectly.

Dynamic python/flask route function naming

first off, a disclaimer: I'm not well versed in python or flask, so bear with me.
I'm trying to put together a minimal API using flask, i was planning to dynamically generate routes and their associated procs from the contents of a subdirectory.
The code looks something like this:
from flask import Flask
import os
app = Flask(__name__)
configs = os.getcwd() + "/configs"
for i in os.listdir(configs):
if i.endswith(".json"):
call = "/" + os.path.splitext(i)[0]
#app.route(call, methods=['POST'])
def call():
return jsonify({"status": call + "Success"}), 200
The plan being to iterate over a bunch of config files and use their naes to define the routes. Now, this works for a single config file, but wont work for multiple files as I end up trying to overwrite the function call that is used by each route.
I can factor out most of the code to a separate function as long as i can pass in the call name. However it seems that however i go about this i need to dynamically name the function generated and mapped to the route.
So, my question is: how can use the contents of a variable, such as 'call' to be the function name?
i.e. something like
call = "getinfo"
def call(): # Effectively being evaled as def getinfo():
Everything i've tried hasn't worked, and i'm not confident enough in my python syntax to know if it's because i'm just doing something silly.
Alternatively is there another way to do what i'm trying to achieve?
Thanks for all and any feedback!
Thanks for the help. I've moved to one route and one handler and building up the file list, and handling of the request paths, etc separately.
This is a sanitized version of the model i now have:
from flask import Flask
import os
calls = []
cfgs = {}
app = Flask(__name__)
configs = os.getcwd() + "/configs"
for i in os.listdir(configs):
if i.endswith(".json"):
cfgs[call] = os.path.splitext(i)[0]
calls.extend([call])
#app.route('/<call>', methods=['POST'])
def do(call):
if call not in calls:
abort(400, "invalid call")
# Do stuff
return jsonify({"status": call + "Success"}), 200
if __name__ == '__main__':
app.run(debug=True)
So, thanks to the above comments this is doing what i'm after. Still curious to know if there is any way to use variables in function names?

Python & gdata within Django app: "POST method does not support concurrency"

I am trying to use gdata within a Django app to create a directory in my google drive account. This is the code written within my Django view:
def root(request):
from req_info import email, password
from gdata.docs.service import DocsService
print "Creating folder........"
folder_name = '2015-Q1'
service_client = DocsService(source='spreadsheet create')
service_client.ClientLogin(email, password)
folder = service_client.CreateFolder(folder_name)
Authentication occurs without issue, but that last line of code triggers the following error:
Request Method: GET
Request URL: http://127.0.0.1:8000/
Django Version: 1.7.7
Exception Type: RequestError
Exception Value: {'status': 501, 'body': 'POST method does not support concurrency', 'reason': 'Not Implemented'}
I am using the following software:
Python 2.7.8
Django 1.7.7
PyCharm 4.0.5
gdata 2.0.18
google-api-python-client 1.4.0 (not sure if relevant)
[many other packages that I'm not sure are relevant]
What's frustrating is that the exact same code (see below) functions perfectly when I run it in its own, standalone file (not within a Django view).
from req_info import email, password
from gdata.docs.service import DocsService
print "Creating folder........"
folder_name = '2015-Q1'
service_client = DocsService(source='spreadsheet create')
service_client.ClientLogin(email, password)
folder = service_client.CreateFolder(folder_name)
I run this working code in the same virtual environment and the same PyCharm project as the code that produced the error. I have tried putting the code within a function in a separate file, and then having the Django view call that function, but the error persists.
I would like to get this code working within my Django app.
I don't recall if I got this to work within a Django view, but because Google has since required the use of Oauth 2.0, I had to rework this code anyways. I think the error had something to do with my simultaneous use of two different packages/clients to access Google Drive.
Here is how I ended up creating the folder using the google-api-python-client package:
from google_api import get_drive_service_obj, get_file_key_if_exists, insert_folder
def create_ss():
drive_client, credentials = get_drive_service_obj()
# creating folder if it does not exist
folder = get_file_key_if_exists(drive_client, 'foldername')
if folder: # if folder exists
print 'Folder "' + folder_name + '" already exists.'
else: # if folder doesn't exist
print 'Creating folder........"' + folder_name + '".'
folder = insert_folder(drive_client, folder_name)
After this code, I used a forked version (currently beta) of sheetsync to copy my template spreadsheet and populate the new file with my data. I then had to import sheetsync after the code above to avoid the "concurrency" error. (I could post the code involving sheetsync here too if folks want, but for now, I don't want to get too far off topic.)

I need a super-duper simple CGI Python photo upload

I've looked through tons of answers but the truth is, I only know super basic python and I really need help. I don't know the os module or anything like that and I can't use PHP (not that I know it anyway, but it's not permitted) and I need something so easy that I can understand it.
Basically, I need a CGI upload (I don't need the HTML form, I've got that much down) that will take the photo and save it. That's it. I don't need any fancy place for it to save, I just need the file to be properly uploaded from the form.
I've got various versions of this function and I can't get them working because I don't understand them so PLEASE HELP!!!
import cgi
def savefile (filename, photodoc):
form=cgi.FieldStorage()
name=form[filename]
period=name.split(.)
if period[1]=="jpeg" or period[1]=="jpg" or period[1]=="png":
idk what to do
else:
make an error message
This cgi program will "take the photo and save it. That's it."
#!/usr/bin/python2.7
import cgi
field=cgi.FieldStorage()['fieldname']
open(field.filename, 'wb').write(field.value)
Among the things it doesn't do are error checking and security checking, and specifying in what directory the files should be saved.
Duplicate question but here's what you need:
Depending if windows or linux, first set to binary mode:
try:
import msvcrt
msvcrt.setmode (0, os.O_BINARY)
msvcrt.setmode (1, os.O_BINARY)
except ImportError:
pass
Then:
form = cgi.FieldStorage()
name = form[filename]
period = name.split('.') #You need the quotes around the period
if period[1]=='jpeg' or period[1] == 'jpg' or period[1] =='png':
if upload.filename:
name = os.path.basename(upload.filename)
out = open(YOUR_FILEPATH_HERE + name, 'wb', 1000)
message = "The file '" + name + "' was uploaded successfully"
while True:
packet = upload.file.read(1000)
if not packet:
break
out.write(packet)
out.close()
else:
print 'Error'
Some sources:
How to use Python/CGI for file uploading
http://code.activestate.com/recipes/273844-minimal-http-upload-cgi/

Categories