Flask-uploads has something called UploadSet which is described as a "single collection of files". I can use this upload set to save my file to a predefined location. I've defined my setup:
app = Flask(__name__)
app.config['UPLOADS_DEFAULT_DEST'] = os.path.realpath('.') + '/uploads'
app.config['UPLOADED_PHOTOS_ALLOW'] = set(['png', 'jpg', 'jpeg'])
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
# setup flask-uploads
photos = UploadSet('photos')
configure_uploads(app, photos)
#app.route('/doit', method=["POST"])
def doit():
myfile = request.files['file']
photos.save(myfile, 'subfolder_test', 'filename_test')
return ''' blah '''
This should save to ./uploads/photos/subfolder_test/filename_test.png
My test image is: 2.6MB and is a png file. When I upload this file, I get the error:
...
File "/home/btw/flask/app.py", line 57, in doit
photos.save(myfile, 'subfolder_test', 'filename_test')
File "/usr/local/lib/python2.7/dist-packages/flaskext/uploads.py", line 388, in save
raise UploadNotAllowed()
UploadNotAllowed
However it doesn't say exactly what is not allowed. I have also tried removing all constraints, but the app still throws this error. Why?
EDIT:
Okay, so I figured out that it's not actually the constraints that is causing the problem. It is the subfolder and/or the filename that is causing the problem:
# This works
# saves to: ./uploads/photos/filename_test.png
photos.save(myfile)
But I want to save to my custom location ./uploads/photos/<custom_subdir>/<custom_filename>. What is the correct way of doing this?
You need to give your filename_test the extension as well
photos.save(myfile, 'subfolder_test', 'filename_test.png')
The UploadSet checks the extension on the new file name and will throw the exception if the new extension is not allowed.
Since you are not giving the new file an extension, it does not recognize it.
You can add a dot to file's name, then the file's extension will be appended.
photos.save(myfile, 'subfolder_test', 'filename_test' + '.')
save(storage, folder=None, name=None)
Parameters:
storage – The uploaded file to save.
folder – The subfolder within the upload set to save to.
name – The name to save the file as. If it ends with a dot, the file’s extension will be appended to the end.
Related
I've made a custom operator for saving the current .blend file to a network drive. This yields about 20% performance boost compared to the default blender save function. First the .blend file is saved to the local temp directory and then moved over to the network drive.
Here is my code:
class toolbox_OP_SaveToNetwork(Operator):
bl_idname = 'toolbox.save_to_network'
bl_label = 'Save'
bl_description = "Save file locally and copy it to it's network path"
def execute(self, context):
if(bpy.data.is_saved == False):
return {"FINISHED"}
# return bpy.ops.toolbox.save_as_to_network("INVOKE_DEFAULT")
print("Save locally, copy to network drive...")
filename = bpy.path.basename(bpy.data.filepath)
tmp_filepath = os.path.join(tempfile.gettempdir(), filename)
report = bpy.ops.wm.save_as_mainfile(filepath=tmp_filepath, check_existing=False, copy=True)
if report == {"FINISHED"}:
# shutil seems to be slower than native os move
# shutil.move(tmp_filepath, bpy.data.filepath)
os.system('move %s %s' % (tmp_filepath, bpy.data.filepath))
return {"FINISHED"}
else:
return report
I would also like to implement the Save As functionality. This is helpful if I don't want to save by overriding my current file but rather incrementing it's version.
Now here is my problem:
Let's say I have test01.blend and want to save as test02.blend
If i use my script, then after saving the file the test01.blend file would still be opened in blender, because I have to use the copy=True argument in the bpy.ops.wm.save_as_mainfile operator. (This has to be used so blender does not open the .blend file which get saved in the local temp directory)
Is it somehow possible to change the filepath of the current opened .blend file via the python API without opening/loading a new file?
After the operation bpy.data.filepath should the point to path/to/file/test02.blend instead of path/to/file/test01.blend
I am trying to create a simple GUI with streamlit and python for my aspect-based sentiment analysis project, the user should be able to upload a .txt file so that I can run the model on that file. I already created the widget for uploading a file. My question is:
The uploaded file should be added to a specific folder, how can I specify an exact location for the uploaded file to be saved?
uploaded_file = st.file_uploader('FILE UPLOAD')
(This is the code for the upload widget)
The file_uploader function does not save the file to disk, it writes to a BytesIO buffer.
The UploadedFile class is a subclass of BytesIO, and therefore it is “file-like”. This means you can pass them anywhere where a file is expected.
https://docs.streamlit.io/en/stable/api.html?highlight=file_uploader#streamlit.file_uploader
If you want to save the result as a file, use the standard Python file io capabilities:
with open(filename, "wb") as f:
f.write(buf.getbuffer())
To add to what #RandyZwitch said you can use this function to save to a directory of your choice (directory/folder "tempDir")
def save_uploaded_file(uploadedfile):
with open(os.path.join("tempDir",uploadedfile.name),"wb") as f:
f.write(uploadedfile.getbuffer())
return st.success("Saved file :{} in tempDir".format(uploadedfile.name))
And apply the function below your uploaded file like below
datafile = st.file_uploader("Upload CSV",type=['csv'])
if datafile is not None:
file_details = {"FileName":datafile.name,"FileType":datafile.type}
df = pd.read_csv(datafile)
st.dataframe(df)
# Apply Function here
save_uploaded_file(datafile)
You can define path like this:
from pathlib import Path
path = "C:/Projects/ex1/your_file"
file_path = Path(path)
uploaded_file = st.file_uploader(file_path)
my users can upload an image of themselves and use that as an avatar. Now I am struggling how to retrieve a default fallback image if they haven't uploaded an image themselves.
The path to the avatar is "//mysite.com/avatar/username".
So far I have this code, which works fine when the user has uploaded an avatar themselves, but it gives me the following error when I try to retrieve the default image:
raise IOError(errno.EACCES, 'file not accessible', filename)
IOError: [Errno 13] file not accessible: '/Users/myuser/Documents/github/mysite/static/images/profile.png'
def get(self):
path = self.request.path.split('/')
action = self.get_action(path)
if action:
e = employees.filter('username = ', action).get()
if e.avatar:
self.response.headers['Content-Type'] = "image/png"
self.response.out.write(e.avatar)
else:
self.response.headers['Content-Type'] = 'image/png'
path = os.path.join(os.path.split(__file__)[0], 'static/images/profile.png')
with open(path, 'r') as f:
print self.response.out.write(f.read())
I have defined the "/static"-folder as a static_dir in my app.yaml.
I know I can place the profile.png in the root-folder, but I prefer to have it in the "/static/images"-folder.
Any ideas?
If you declared the file itself as a static_file or its directory or any directory in its filepath a static_dir inside your app/service's .yaml config file then, by default, it's not accessible to the application code.
You need to also configure it as application_readable. From Handlers element:
application_readable
Optional. Boolean. By default, files declared in static file handlers
are uploaded as static data and are only served to end users. They
cannot be read by an application. If this field is set to true, the
files are also uploaded as code data so your application can read
them. Both uploads are charged against your code and static data
storage resource quotas.
I am trying to add some validation for user uploaded files. This requires running through a custom script I made called "sumpin", which only takes a filepath as a variable and sends back JSON data that will verify. Everything inside my script is working independently, putting it together where the error occurs.
Since this is file validation, I decided to expand my file_extension validator that was already working.
models.py
from allauthdemo.fileuploadapp.slic3rcheck import sumpin
def user_directory_path_files(instance, filename):
return os.path.join('uploads', str(instance.objectid), filename)
def validate_file_extension(value):
ext = os.path.splitext(value.name)[1]
valid_extensions = ['.stl','.STL']
if not ext in valid_extensions:
raise ValidationError(u'Please upload a .stl file type only')
data = sumpin(value.path)
print (data)
class subfiles(models.Model):
STL = models.FileField(_('STL Upload'),
upload_to=user_directory_path_files, validators=[validate_file_extension])
The error that I get is that the path (value.path) is not valid.
This is the incorrect path because the upload_to tag must change this at a later point. This may be obvious, but I also need to have the file at the filepath location when my script is called. So essentially my questions are...
How can pass the "upload_to" path into my validator to run through my custom script?
Is there a better method to deal with uploaded files, like in the main class with a "save" or "clean" function?
I've found my own answer, but I'll post it here in case someone runs across this issue in the future.
I was incorrect, a validator wouldn't actually download the file. I need to use a file upload handler, which is shown below.
import os
from django.core.files.storage import default_storage
from allauthdemo.fileuploadapp.slic3rcheck import sumpin
def handle_uploaded_file(f):
with open(default_storage.path('tmp/'+f.name), 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
data = sumpin(default_storage.path('tmp/'+f.name))
os.remove(default_storage.path('tmp/'+f.name))
return data
then I call this inside my views.py.
from allauthdemo.fileuploadapp.uploadhandler import handle_uploaded_file
#login_required
def STLupload(request):
# Handle file upload
if request.method == 'POST':
formA = ObjectUp(request.POST, request.FILES)
if formA is_valid():
data = handle_uploaded_file(request.FILES['STL'])
This will return whatever I called to return within handle_upload_file, which worked perfect for my issues. Hopefully someone will find this useful the future.
Currently, I am using the following method for uploading files (via HTML form) in Pyramid.
if request.params.get('form.submitted'):
upload_directory = os.getcwd() + '/myapp/static/uploads/'
my_file = request.POST.get('thumbnail')
saved_file = str(upload_directory) + str(my_file.filename)
perm_file = open(saved_file, 'w')
shutil.copyfileobj(my_file.file, perm_file)
my_file.file.close()
perm_file.close()
I am just wondering, is this a good way of saving file uploads, are there any security concerns with my method? How else can I improve my method. Thanks.
You'll want to use something like werkzug's safe_join rather than just adding the upload directory to the given file name. An attacker could create a POST with a filename of ../../../some/important/path and cause this script to overwrite some file outside of your upload_directory.