-
Notifications
You must be signed in to change notification settings - Fork 11
/
upload_form.py
193 lines (162 loc) · 6.67 KB
/
upload_form.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import os
import inspect
import numpy as np
from astropy.io import fits
from astropy.io import ascii
from astropy import table
from astropy import units as u
from ingest_datasets_better import rename_columns, set_units
from flask import (Flask, request, redirect, url_for, render_template,
send_from_directory, jsonify)
from simple_plot import plotData
from wtforms.validators import ValidationError
import wtforms
from werkzeug import secure_filename
import difflib
UPLOAD_FOLDER = 'uploads/'
ALLOWED_EXTENSIONS = set(['fits', 'csv', 'txt', 'ipac', 'dat', 'tsv'])
valid_column_names = ['Ignore', 'IDs', 'SurfaceDensity', 'VelocityDispersion',
'Radius', 'IsSimulated']
from astropy.io import registry
from astropy.table import Table
table_formats = registry.get_formats(Table)
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# Allow zipping in jinja templates: http://stackoverflow.com/questions/5208252/ziplist1-list2-in-jinja2
import jinja2
env = jinja2.Environment()
env.globals.update(zip=zip)
# http://stackoverflow.com/questions/21306134/iterating-over-multiple-lists-in-python-flask-jinja2-templates
@app.template_global(name='zip')
def _zip(*args, **kwargs): #to not overwrite builtin zip in globals
return __builtins__.zip(*args, **kwargs)
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
def get_file_extension(filename):
print 'filename:', filename
return filename.rsplit('.', 1)[1]
@app.route('/')
def index():
return render_template('upload_form.html')
@app.route('/upload', methods=['POST'])
@app.route('/upload/<fileformat>', methods=['POST'])
def upload_file(fileformat=None):
file = request.files['file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
# print file_data
return redirect(url_for('uploaded_file',
filename=filename,
fileformat=fileformat))
else:
return render_template("upload_form.html", error="File type not supported")
@app.route('/uploads/<filename>')
def uploaded_file(filename, fileformat=None):
try:
table = Table.read(os.path.join(app.config['UPLOAD_FOLDER'], filename),
format=fileformat)
except Exception as ex:
return handle_ambiguous_table(filename, ex)
best_matches = {difflib.get_close_matches(vcn, table.colnames, n=1,
cutoff=0.4)[0]: vcn
for vcn in valid_column_names
if any(difflib.get_close_matches(vcn, table.colnames, n=1, cutoff=0.4))
}
print best_matches
best_column_names = [best_matches[colname] if colname in best_matches else 'Ignore'
for colname in table.colnames]
print 'best_column_names:', best_column_names
return render_template("parse_file.html", table=table, filename=filename,
real_column_names=valid_column_names,
best_column_names=best_column_names,
)
#return send_from_directory(app.config['UPLOAD_FOLDER'],
# filename)
def handle_ambiguous_table(filename, exception):
extension = os.path.splitext(filename)[-1]
best_match = difflib.get_close_matches(extension[1:], table_formats, n=1, cutoff=0.05)
if any(best_match):
best_match = best_match[0]
else:
best_match = ""
# This doesn't work right now - don't know why.
return render_template('upload_form_filetype.html', filename=filename,
best_match_extension=best_match,
exception=exception)
@app.route('/autocomplete_units',methods=['GET'])
def autocomplete_units():
search = request.args.get('term')
print "search: ",search
# print os.getcwd()
allunits = set()
for unitname,unit in inspect.getmembers(u):
if isinstance(unit, u.UnitBase):
try:
for name in unit.names:
allunits.add(name)
except AttributeError:
continue
app.logger.debug(search)
return jsonify(json_list=list(allunits))
@app.route('/validate_units', methods=['GET', 'POST'])
def validate_units():
try:
unit_str = request.args.get('unit_str', 'error', type=str)
u.Unit(unit_str)
OK = True
except:
OK = False
return jsonify(OK=OK)
@app.route('/autocomplete_filetypes',methods=['GET'])
def autocomplete_filetypes():
#print formats
search = request.args.get('term')
readable_formats = table_formats[table_formats['Read']=='Yes']['Format']
#print readable_formats
return jsonify(json_list=list(readable_formats))
@app.route('/autocomplete_column_names',methods=['GET'])
def autocomplete_column_names():
return jsonify(json_list=valid_column_names)
@app.route('/set_columns/<path:filename>', methods=['POST', 'GET'])
def set_columns(filename, fileformat=None):
# This function needs to know about the filename or have access to the
# table; how do we arrange that?
table = Table.read(os.path.join(app.config['UPLOAD_FOLDER'], filename), format=fileformat)
column_data = \
{field:{'Name':value} for field,value in request.form.items() if '_units' not in field}
for field,value in request.form.items():
if '_units' in field:
column_data[field[:-6]]['unit'] = value
# print column_data
units_data = {}
for _, pair in column_data.items():
if pair['Name'] != "Ignore":
units_data[pair['Name']] = pair['unit']
# print 'units_data:', units_data
# print table
rename_columns(table, column_data)
# print 'renamed columns?:', table
set_units(table, units_data)
# print 'units are set?:', table
# plotData(table, filename)
return 'Ok'
def upload_to_github(filename):
"""
WIP: Eventually, we want each file to be uploaded to github and submitted
as a pull request when people submit their data
This will be tricky: we need to have a "replace existing file" logic in
addition to the original submission. We also need an account + API_KEY
etc, which may be the most challenging part.
"""
with open(os.path.join(app.config['UPLOAD_FOLDER'], filename)) as f:
content = f.read()
data = {'path': 'data_files/',
'content': content,
'branch': 'master',
'message': 'Upload a new data file {0}'.format(filename)}
requests.post
pass
if __name__ == '__main__':
app.run(debug=True)