Static directory file browsing ending too early - python

I'm currently making a little site to host a large set of UAV image mosaics and want someone who comes in to be able to go through the data folder structure I have been given to find their data. However, I'm aborting before I get to any files. The following code gives the 404 error when I am 3 folders in past "2017 Data." In some cases, this is 1 or 2 folders above where the images are stored.
from flask import Flask, abort, send_file, render_template_string
import os
import remoteSensingData
app = Flask(__name__)
#app.route('/', defaults={'req_path': ''})
#app.route('/<path:req_path>')
def dir_listing(req_path):
BASE_DIR = os.path.abspath("/Users/Huang.LabTech2/Desktop/Images/2017 Data/")
# Joining the base and the requested path
abs_path = os.path.join(BASE_DIR, req_path)
# Return 404 if path doesn't exist
if not os.path.exists(abs_path):
return abort(404)
# Check if path is a file and serve
if os.path.isfile(abs_path):
return send_file(abs_path)
# Show directory contents
files = os.listdir(abs_path)
files = [os.path.join(req_path, f) for f in files]
# return render_template('files.html', files=files)
return render_template_string("""
<ul>
{% for file in files %}
<li>{{ file }}</li>
{% endfor %}
</ul>
""", files=files)
if __name__ == '__main__':
app.run(debug=True)
I have further issues with getting towards my end goal, but they aren't related to this issue, so I will form separate questions for them.

I think your problem is caused by the whitespace in your BASE_DIR path.
You can easily prove it by renaming your folder from 2017 Data to 2017_Data
or you can try to use:
BASE_DIR = os.path.abspath(r"/Users/Huang.LabTech2/Desktop/Images/2017 Data/")

Related

reference media files outside of flask

Using flask. I have made an internal file browser/media player. This is for local network only so everyone who has access to the page has access to these files all ready.
Nevertheless I am dealing with 1000s of files in 1000s of locations. Is it possible to source a file in a html video player, or a img src that is local. The source files cant be moved, so cant go to the static folder etc...
like this
<video src="{{ clip }}" autoplay controls></video>
when clip is the file_path /projects/project_234/video/video_file.mov
I have all the variables needed just not able to get the file to play.
EDIT 01
It has come to my attention that mov files dont play in chrome only mp4's.
#app.route('/projects/<project>/<clip>', methods=['GET'])
def project_page_clip(project, clip):
file_path = request.args.get('file_path')
file_location = file_path
file_name = '90Sec_Approval.mp4'
if file_name:
return send_from_directory(file_location,file_name)
return render_template("project_selected_clip.html", file_path=file_path,
title=project, project=project, clip=clip)
So when clicked on the previous page this just opens the clip on a browser without rendering the project_selected_clip.html template
How can I get it to use the return send from directory as a src on the page instead?
After much deliberation, the best of many evils was to generate symlinks for the fles
This seems to be a big help
So after that... what works for me is to include this;
from Flask import send_file
top_dir = 'top/'
mid_dir = 'mid/'
more_dir = '/and/this/'
filename = 'some_photo.jpg'
#wip.route('/photo')
def photo():
return send_file(top_dir+mid_dir+more_dir+filename)
serves up the file!
Here is an answer to clarify how to use the send_file approach in an app setting with app.route and a url_for.
import os
from flask import Flask, url_for, send_file
app = Flask(__name__)
# set the path where you store your assets - it can be outside of the root dir
app.config['CUSTOM_STATIC_PATH'] = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../archive'))
# have a route listening for requests
#app.route('/this/can/be/anything/<path:filename>')
def send_media(filename):
path = os.path.join(app.config['CUSTOM_STATIC_PATH'], filename)
return send_file(path)
# in your template, you can then use the following
# <img src="{{ url_for('send_media', filename='<dir>/<filename>') }}">

Python: FileNotFoundError: [WinError 3] The system cannot find the path specified:

I am trying to figure out why my output was ending early when listing directories on from my hard drive to a website. I removed the error message for debugging mode and got this error:
FileNotFoundError: [WinError 3] The system cannot find the path specified: 'C:\\Users\\Huang.LabTech2\\Desktop\\Images\\2017 Data\\Air Tractor 402/Air Tractor 402/5-10-2017/IR Filter'
I'm not sure why it is looking for the second Air Tractor 402 folder when running, but this happens with other folders as well:
FileNotFoundError: [WinError 3] The system cannot find the path specified: 'C:\\Users\\Huang.LabTech2\\Desktop\\Images\\2017 Data\\UAV/UAV/Bobby_Hardin/8-16'
My code:
from flask import Flask, abort, send_file, render_template, render_template_string
import os
import remoteSensingData
app = Flask(__name__)
#app.route('/', defaults={'req_path': ''})
#app.route('/<path:req_path>')
def dir_listing(req_path):
BASE_DIR = os.path.abspath(r'C:/Users/Huang.LabTech2/Desktop/Images/2017 Data/')
# Joining the base and the requested path
abs_path = os.path.join("c:", BASE_DIR, req_path)
# Return 404 if path doesn't exist
# if not os.path.exists(abs_path):
# return render_template('404.html'), 404
# Check if path is a file and serve
# if os.path.isfile(abs_path):
# return send_file(abs_path)
# Show directory contents
files = os.listdir(abs_path)
files = [os.path.join(req_path, file) for file in files]
# return render_template('files.html', files=files)
return render_template_string("""
<ul>
{% for file in files %}
<li>{{ file }}</li>
{% endfor %}
</ul>
""", files=files)
if __name__ == '__main__':
app.run(debug=True)
You got the "repetition" because you add the req_path two times: one here:
# Joining the base and the requested path
abs_path = os.path.join("c:", BASE_DIR, req_path)
and one here:
files = [os.path.join(req_path, file) for file in files]
the second should look like this:
files = [f for f in files] # (or just be deleted)

Saving an uploaded file to disk doesn't work in Flask [duplicate]

This question already has an answer here:
Refering to a directory in a Flask app doesn't work unless the path is absolute
(1 answer)
Closed 5 years ago.
I want to store any uploaded image to the static/customlogos folder with the name "logo.png" no matter what its actual name is. I have a basic Flask setup with the typical static and template folders. For simplicity I removed things like extension validation in my code below. However doing it like this throws a FileNotFound error. Since I want to run my app on various environments, I don't want to use a static path. What am I doing wrong? Thanks for your help.
latestfile = request.files['customlogo']
#This prints the file name of the uploaded file
print(latestfile.filename)
#I want to save the uploaded file as logo.png. No matter what the uploaded file name was.
latestfile.save(os.path.join('/static/customlogos', 'logo.png'))
Obviously, you want to save uploaded file as static/customlogos/logo.png, path that is relative to your Flask application directory, but you have specified the absolute non-existing path /static/customlogos.
Furthermore, according to your comments you are developing under Windows, which adds inconsistency to your question.
In any case, to achieve what you want, you need to know the absolute path of your application, and use it as a starting point:
latestfile.save(os.path.join(app.root_path, 'static/customlogos/logo.png'))
Cross-platform variant:
latestfile.save(os.path.join(app.root_path, 'static', 'customlogos', 'logo.png'))
Ninja dust-proof variant:
latestfile.save(os.path.join(app.root_path, app.config['STATIC_FOLDER'], 'customlogos', 'logo.png'))
You can simplify the operation like below:
from flask import Flask, request, session, g, redirect
from flask import url_for, abort, render_template, flash, jsonify
import os
# Create two constant. They direct to the app root folder and logo upload folder
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
UPLOAD_FOLDER = os.path.join(APP_ROOT, 'static', 'customlogos')
# Configure Flask app and the logo upload folder
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# In controller save the file with desired name
latestfile = request.files['customlogo']
full_filename = os.path.join(app.config['UPLOAD_FOLDER'], 'logo.png')
latestfile.save(full_filename)
N.B.: Ensure that you have created customlogos in static folder.

flask - Why url of an image is not identical to its actual path?

I'm using flask.send_file to send images to my client.
However, when I was trying to get the url of a image using url_for, I found the result returned is not the same with the image's path.
def get(self):
print url_for('static', filename='test.jpg')
filename = 'static/img/test.jpg'
return send_file(filename)
I got
/static/test.jpg
in the console.
The file structure is
└── static
└── img
└── test.jpg
Why the url is not /static/img/test.jpg?
EDIT
And when I request from the browser, the code above works well. On the contrast, the browser return error if I change the filename to static/test.jpg.
Because you've told it to print the URL for "test.jpg" inside "static". Since you haven't included any reference to "img", there's no way that url_for can include it.
Note that this has nothing to do with the actual URL you return from the function.
Because you should give url_for the full path to your image relative to the static folder.
So I think in your case it would be
url_for('static', filename='img/test.jpg')
url_for will just concatenate the path you give it to the static folder path, so to generate a URI to that file, but it won't magically map or guess the location of your files.

Python - how to programmatically generate Index.HTML file to list contents of an uploads folder?

I got a web service that allows user to upload files to the "Uploads" folder. These files are accessible by name using the /uploads/filename.ext path. However, unless I know the precise filename, I cannot access files.
How can I programmatically generate and serve a webpage that will provide an index of all files in the /uploads folder if the user types /uploads?
from flask import Flask
from flask import Response, jsonify, request, redirect, url_for
import os
from werkzeug.utils import secure_filename
#configuration
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#retrieve uploads by name
#app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename)
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
################# AUDIO NOTES UPLOAD ####################
#app.route('/', methods=['GET', 'POST'])
def upload_file():
print 'upload file'
try:
os.stat(app.config['UPLOAD_FOLDER'])
except:
os.mkdir(app.config['UPLOAD_FOLDER'])
if request.method == 'POST':
file = request.files['file']
print 'filename: ' + file.filename
if file and allowed_file(file.filename):
print 'allowing file'
filename = secure_filename(file.filename)
print 'secure filename created'
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
print 'file saved'
return redirect(url_for('uploaded_file',filename=filename))
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
'''
################## APP LAUNCH POINT ############################
if __name__ == '__main__':
app.run(host='0.0.0.0')
############################################################
Slightly off-topic, since the original question was for python, but you can generate a static HTML directory listing using tree in HTML output mode:
tree -H "/uploads" -L 1 > index.html
The option -L 1 limits the listing only for the current folder. Without it, the list will recursively include all the subfolders.
It is available in standard repos for most distros. On ubuntu you can install it with sudo apt install tree.
Related:
How can I create a simple index.html file which lists all files/directories?
It sounds like you need to list all of the files that are inside the Upload folder. Python's os.listDir() should be able to help you. I am using listDir to get all the names of the files, and then passing them to my view as a render parameter.
def get_files_from_directory(path):
list_of_files = []
if len(path) > 0:
list_of_files = [ f for f in listdir(path) if isfile(join(path,f)) ]
return list_of files
You could then do something like this:
#app.route('/uploads/<path>')
def list_uploads(path):
list_of_uploads = get_files_from_directory(path)
#render your template with this list_of_uploads.
My recommendation is that you don't give users the option to pass their own paths. This could be a huge security risk for you. Instead, create a URL like: 'http://www.yourwebsite.com/uploads/list'. Which will pass a path you set in your server-side code to get the files they want to look at. This will be much, much safer.

Categories