Spaces:
Runtime error
Runtime error
Jessica Walkenhorst
commited on
Commit
β’
613f4ac
1
Parent(s):
9957bde
Add workaround for false xls files (#13)
Browse filesalso:
* adds some comments
* excludes some rules from flake8 due to incompatibility with black
- app.py +14 -7
- bin/run-flake8.sh +1 -1
- src/maorganizer/ui.py +44 -11
app.py
CHANGED
@@ -5,6 +5,8 @@ from maorganizer.datawrangling import Person
|
|
5 |
|
6 |
from maorganizer.ui import TASKS, render_xlsx_download_button, create_file_uploader, create_task_selector
|
7 |
|
|
|
|
|
8 |
st.title("π
Meeting Attendance Organizer")
|
9 |
st.markdown("This app fullfills a simple need: Take a list of names of people attending a meeting and peform one (or multiple) of the following tasks:")
|
10 |
st.markdown("""* βοΈ Split their names into first name and surname\n* π Compare two lists with each other and see who is new on the second list\n * π Find people in a list by either searching for their complete names or parts of their name\n * πΎ Write any of the results back out, so you can share it with others""")
|
@@ -12,6 +14,7 @@ st.markdown("""* βοΈ Split their names into first name and surname\n* π Co
|
|
12 |
st.header("π Step 1: Upload your Files")
|
13 |
st.markdown("Upload the file(s) containing your meeting attendees. The expected format is a single column containing the attendees' full names. If you column name is not Name, you will be able to specify the column name after uploading the data. Additional columns will be ignored.")
|
14 |
|
|
|
15 |
meetings = {}
|
16 |
meetings = create_file_uploader()
|
17 |
|
@@ -26,7 +29,6 @@ if meetings:
|
|
26 |
if task == TASKS.SPLIT.value:
|
27 |
|
28 |
filename = st.selectbox("Choose a file π", options=list(meetings.keys()), key=task)
|
29 |
-
#filename = render_file_selector(meetings, key=task)
|
30 |
|
31 |
render_xlsx_download_button({'Full list of Attendees': meetings[filename]},
|
32 |
filename=f"processed-attendees-{Path(filename).stem}.xlsx",
|
@@ -64,9 +66,14 @@ if meetings:
|
|
64 |
with col2:
|
65 |
filename_new = st.selectbox("Choose your updated file", options=set(meetings.keys()) - {filename_old})
|
66 |
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
from maorganizer.ui import TASKS, render_xlsx_download_button, create_file_uploader, create_task_selector
|
7 |
|
8 |
+
# all these beautiful emojis from https://emojidb.org/file-emojis
|
9 |
+
|
10 |
st.title("π
Meeting Attendance Organizer")
|
11 |
st.markdown("This app fullfills a simple need: Take a list of names of people attending a meeting and peform one (or multiple) of the following tasks:")
|
12 |
st.markdown("""* βοΈ Split their names into first name and surname\n* π Compare two lists with each other and see who is new on the second list\n * π Find people in a list by either searching for their complete names or parts of their name\n * πΎ Write any of the results back out, so you can share it with others""")
|
|
|
14 |
st.header("π Step 1: Upload your Files")
|
15 |
st.markdown("Upload the file(s) containing your meeting attendees. The expected format is a single column containing the attendees' full names. If you column name is not Name, you will be able to specify the column name after uploading the data. Additional columns will be ignored.")
|
16 |
|
17 |
+
|
18 |
meetings = {}
|
19 |
meetings = create_file_uploader()
|
20 |
|
|
|
29 |
if task == TASKS.SPLIT.value:
|
30 |
|
31 |
filename = st.selectbox("Choose a file π", options=list(meetings.keys()), key=task)
|
|
|
32 |
|
33 |
render_xlsx_download_button({'Full list of Attendees': meetings[filename]},
|
34 |
filename=f"processed-attendees-{Path(filename).stem}.xlsx",
|
|
|
66 |
with col2:
|
67 |
filename_new = st.selectbox("Choose your updated file", options=set(meetings.keys()) - {filename_old})
|
68 |
|
69 |
+
# filename_new gets automatically populated if there is more than one file
|
70 |
+
# so if there is none, it's because there is only a single file available and no options left for filename_new
|
71 |
+
if filename_new is None:
|
72 |
+
st.info("β¬ Please upload a second file. β¬")
|
73 |
+
else:
|
74 |
+
listcomparison = (
|
75 |
+
{'Original List': meetings[filename_old],
|
76 |
+
'Updated List - Full': meetings[filename_new],
|
77 |
+
'Updated List - Only Updates': meetings[filename_old].update(meetings[filename_new])})
|
78 |
+
|
79 |
+
render_xlsx_download_button(listcomparison, filename=f"{Path(filename_old).stem}-updated.xlsx", key=TASKS.COMPARE.value+'download')
|
bin/run-flake8.sh
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
#!/bin/sh
|
2 |
-
poetry run flake8 src/* tests/*
|
|
|
1 |
#!/bin/sh
|
2 |
+
poetry run flake8 --ignore=W605,W503 src/* tests/*
|
src/maorganizer/ui.py
CHANGED
@@ -27,7 +27,23 @@ class TASKS(str, Enum):
|
|
27 |
|
28 |
def load_df_from_uploaded_data(filename, data, sep=None) -> pd.DataFrame:
|
29 |
if Path(filename).suffix in EXCEL_EXTENSIONS:
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
elif Path(filename).suffix in CSV_EXTENSIONS:
|
32 |
df = pd.read_csv(data, sep=sep)
|
33 |
else:
|
@@ -49,30 +65,45 @@ def make_attendance_data_from_file_uploads(
|
|
49 |
|
50 |
|
51 |
def load_data(uploaded_files) -> Tuple[Dict, bool]:
|
|
|
|
|
|
|
|
|
|
|
52 |
try:
|
53 |
data = make_attendance_data_from_file_uploads(
|
54 |
uploaded_files, sep=None, cname=NAMECOLUMN
|
55 |
)
|
|
|
|
|
|
|
|
|
|
|
56 |
except KeyError:
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
if contains_csvs:
|
61 |
-
separator = st.radio(
|
62 |
"We detected text files in your input. What is their separator?",
|
63 |
sorted(SEPARATORTYPES.keys()),
|
64 |
)
|
|
|
|
|
|
|
65 |
|
66 |
-
|
|
|
67 |
"Column header of your file's name column", NAMECOLUMN
|
68 |
)
|
|
|
69 |
try:
|
70 |
data = make_attendance_data_from_file_uploads(
|
71 |
-
uploaded_files, sep=
|
72 |
)
|
73 |
except KeyError:
|
74 |
st.error(
|
75 |
-
f
|
|
|
|
|
76 |
)
|
77 |
data = {}
|
78 |
|
@@ -115,11 +146,13 @@ def create_task_selector():
|
|
115 |
st.markdown("β **Description:** Split a list of names into first and surname.")
|
116 |
elif task == TASKS.COMPARE.value:
|
117 |
st.markdown(
|
118 |
-
"β **Description:** Compare two attendee lists with each
|
|
|
119 |
)
|
120 |
elif task == TASKS.FIND.value:
|
121 |
st.markdown(
|
122 |
-
"β **Description:** Find attendees in a list by either first name
|
|
|
123 |
)
|
124 |
return task
|
125 |
|
|
|
27 |
|
28 |
def load_df_from_uploaded_data(filename, data, sep=None) -> pd.DataFrame:
|
29 |
if Path(filename).suffix in EXCEL_EXTENSIONS:
|
30 |
+
try:
|
31 |
+
df = pd.read_excel(data)
|
32 |
+
# If engine does not recognize excel as excel, it is likely to be
|
33 |
+
# a text format "disguised" as xls.
|
34 |
+
# (example: PyData Meeting files have .xls extension, but are in fact text files)
|
35 |
+
except ValueError as e:
|
36 |
+
if (
|
37 |
+
str(e)
|
38 |
+
== "Excel file format cannot be determined, you must specify an engine manually."
|
39 |
+
):
|
40 |
+
st.info(
|
41 |
+
f"Your {Path(filename).suffix} file does not seem to be an excel file.\\\n\\\n"
|
42 |
+
"\- Trying to parse it as text file."
|
43 |
+
)
|
44 |
+
df = pd.read_csv(data, sep=sep)
|
45 |
+
else:
|
46 |
+
raise ValueError(e)
|
47 |
elif Path(filename).suffix in CSV_EXTENSIONS:
|
48 |
df = pd.read_csv(data, sep=sep)
|
49 |
else:
|
|
|
65 |
|
66 |
|
67 |
def load_data(uploaded_files) -> Tuple[Dict, bool]:
|
68 |
+
def _files_contain_csv(uploaded_files) -> bool:
|
69 |
+
return bool(
|
70 |
+
sum([Path(file.name).suffix in CSV_EXTENSIONS for file in uploaded_files])
|
71 |
+
)
|
72 |
+
|
73 |
try:
|
74 |
data = make_attendance_data_from_file_uploads(
|
75 |
uploaded_files, sep=None, cname=NAMECOLUMN
|
76 |
)
|
77 |
+
|
78 |
+
# let user specify file format, then retry loading
|
79 |
+
# Retry parsing after letting user manually specify separator and columnname.
|
80 |
+
# Display error **after** the input fields, so if manually specifying separator and columnname
|
81 |
+
# fixes the load issue, the error message disappears.
|
82 |
except KeyError:
|
83 |
+
# Set separator if csv file present
|
84 |
+
if _files_contain_csv(uploaded_files):
|
85 |
+
seperator_key = st.radio(
|
|
|
|
|
86 |
"We detected text files in your input. What is their separator?",
|
87 |
sorted(SEPARATORTYPES.keys()),
|
88 |
)
|
89 |
+
separator = SEPARATORTYPES[seperator_key]
|
90 |
+
else:
|
91 |
+
separator = None
|
92 |
|
93 |
+
# Set columnname
|
94 |
+
columnname = st.text_input(
|
95 |
"Column header of your file's name column", NAMECOLUMN
|
96 |
)
|
97 |
+
|
98 |
try:
|
99 |
data = make_attendance_data_from_file_uploads(
|
100 |
+
uploaded_files, sep=separator, cname=columnname
|
101 |
)
|
102 |
except KeyError:
|
103 |
st.error(
|
104 |
+
f'We could not find a column "{columnname}" in your data.\\\n\\\n'
|
105 |
+
" Please use the options above to specify your column separator (if text/csv file)"
|
106 |
+
" and the column name of the column containing your attendees' names."
|
107 |
)
|
108 |
data = {}
|
109 |
|
|
|
146 |
st.markdown("β **Description:** Split a list of names into first and surname.")
|
147 |
elif task == TASKS.COMPARE.value:
|
148 |
st.markdown(
|
149 |
+
"β **Description:** Compare two attendee lists with each"
|
150 |
+
" and find attendees who have recently joined."
|
151 |
)
|
152 |
elif task == TASKS.FIND.value:
|
153 |
st.markdown(
|
154 |
+
"β **Description:** Find attendees in a list by either first name"
|
155 |
+
" or surname or by substrings."
|
156 |
)
|
157 |
return task
|
158 |
|