简体   繁体   中英

Python/Flask - Uploading a file by passing a path from a Jupyter Notebook

Context

I have created a Flask application that allows me to:

(1) upload a GeoTIFF file to a specified folder (UPLOAD_FOLDER)

(2) use GDAL to open the uploaded GeoTIFF as a Pandas data frame, and return a JSON containing all the cell values. The app code is below:

import os
import gdal
import numpy as np
import pandas as pd
import json
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = 'PATH_GOES_HERE'  #specify path
ALLOWED_EXTENSIONS = set(['tif'])

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('get_raster_data',
                                    filename=filename))
    return '''
    <!doctype html>
    <title>Upload raster file</title>
    <h1>Upload raster file</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

@app.route('/rasterdata', methods=['GET'])
def get_raster_data():
    filename = secure_filename(request.args.get('filename'))
    try:
        if filename and allowed_file(filename):
            f = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            rast_data = gdal.Open(f)
            rast_array = np.array(rast_data.GetRasterBand(1).ReadAsArray())
        return pd.DataFrame(rast_array).to_json()
    except IOError:
        pass
    return "Unable to read file"

The application works properly (ie I've tested using a local host and running in debug mode). The application allows me to open a web page with "Choose file" and "upload" buttons. Once I upload the file I am redirected to the '/rasterdata' page which has the expected output.

I have been tasked with creating a Jupyter Notebook that basically only requires users to specify the path to a GeoTIFF that they would like to upload. Once the path is specified the Flask app needs to run and return a data frame of all the GeoTIFF's cell values. From there, the Notebook goes through a few processing steps that require the data frame as the input, but these are not relevant to my question.

Question

How can I upload a file to UPLOAD_FOLDER by simply specifying the path to the GeoTIFF in the Jupyter Notebook? Below is the code from my Jupyter Notebook. I've added comments specifying where I am stuck. I suspect that I will need to modify the Flask app to take in a path name. I could not find any tutorials for this though. All the tutorials I could find give me code that is similar to what I currently have.

url = f'http://localhost:5000/upload'
my_path = r'C:\Users\admievan\Desktop\FlaskGDAL\my_raster.tif'

#Opening the upload page
with urllib.request.urlopen(path) as url:
    #THIS IS WHERE I AM STUCK
    #I want to pass my_path to the Flask application rather than having to
    #manually navigate to the file in the GUI interface that comes up when clicking
    #the "Choose file" button

#Reading the data web page as a panadas data frame
#This part works fine if 'my_raster.tif' is already in the UPLOAD_FOLDER
url = f'http://localhost:5000/rasterdata?filename=my_raster.tif'
df = pd.read_json(url, orient='rows')
df

The requests package is your best friend when it comes to dealing with uploads/extractions and API calls. Whatever your host is for the url is where you would need to pass this through. Uploading is not too difficult and could look something like this:

import os
import base64
import urllib
import json
import requests
def jupyter_upload(token, filePath, resourceDstPath, jupyterUrl='http://localhost:8888'):
    dstPath = urllib.quote(resourceDstPath)
    dstUrl = '%s/api/contents/%s' % (jupyterUrl, dstPath)
    fileName = filePath[1 + filePath.rfind(os.sep):]
    headers = {}
    headers['Authorization'] = 'token '+token
    with open(filePath, 'r') as myfile:
        data=myfile.read()
        b64data=base64.encodestring(data)
        body = json.dumps({
            'content':b64data,
            'name': fileName,
            'path': resourceDstPath,
            'format': 'base64',
            'type':'file'
        })
        return requests.put(dstUrl, data=body, headers=headers, verify=True)`

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM