@@ -232,14 +232,14 @@ def get_course_smart(course_arg, client):
232232 if not courses :
233233 sys .exit ("Error: No current courses, try 'agio courses -l'" )
234234 else :
235+ options = [pick .Option (course_str (x ), x ) for x in courses ]
235236 selected_courses = pick .pick (
236- options = courses ,
237+ options = options ,
237238 title = ("Select a course:" ),
238- options_map_func = course_str ,
239239 multiselect = False ,
240240 )
241241 assert selected_courses
242- return selected_courses [0 ]
242+ return selected_courses [0 ]. value
243243
244244 # Try to match a course
245245 matches = course_match (course_arg , courses )
@@ -258,6 +258,10 @@ def get_course_smart(course_arg, client):
258258 return matches [0 ]
259259
260260
261+ class UnsupportedAssignmentError (Exception ):
262+ """Raised if the assignment string cannot be parsed."""
263+
264+
261265def parse_project_string (user_input ):
262266 """Return assignment type, number, and subtitle from a user input string.
263267
@@ -303,7 +307,7 @@ def parse_project_string(user_input):
303307 asstype_abbrev = match .group ("asstype" ).lower ()
304308 if asstype_abbrev not in assignment_types :
305309 asstypes = ", " .join (assignment_types .keys ())
306- sys . exit (
310+ raise UnsupportedAssignmentError (
307311 f"Error: unsupported assignment type: '{ asstype_abbrev } '. "
308312 f"Recognized shortcuts: { asstypes } "
309313 )
@@ -316,6 +320,14 @@ def parse_project_string(user_input):
316320 return asstype , num , subtitle
317321
318322
323+ def parse_project_string_skipper (user_input ):
324+ """Wrap parse_project_string to skip errors."""
325+ try :
326+ return parse_project_string (user_input )
327+ except UnsupportedAssignmentError :
328+ return None
329+
330+
319331def project_str (project ):
320332 """Format project as a string."""
321333 return f"[{ project ['pk' ]} ] { project ['name' ]} "
@@ -326,6 +338,11 @@ def project_match(search, projects):
326338 assert projects
327339 asstype , num , subtitle = parse_project_string (search )
328340
341+ # Filter for only parsable projects
342+ projects = filter (
343+ lambda x : parse_project_string_skipper (x ["name" ]), projects
344+ )
345+
329346 # Remove projects with an assignment type mismatch (Lab vs. Project, etc.)
330347 if asstype :
331348 projects = filter (
@@ -382,14 +399,14 @@ def get_project_smart(project_arg, course_arg, client):
382399 # No project input from the user. Show all projects for current course and
383400 # and prompt the user.
384401 if not project_arg :
402+ options = [pick .Option (project_str (x ), x ) for x in projects ]
385403 selected_projects = pick .pick (
386- options = projects ,
404+ options = options ,
387405 title = "Select a project:" ,
388- options_map_func = project_str ,
389406 multiselect = False ,
390407 )
391408 assert selected_projects
392- return selected_projects [0 ]
409+ return selected_projects [0 ]. value
393410
394411 # User provides strings, try to match a project
395412 matches = project_match (project_arg , projects )
@@ -415,10 +432,15 @@ def group_str(group):
415432 return f"[{ group ['pk' ]} ] { uniqnames_str } "
416433
417434
435+ def group_emails (group ):
436+ """Return group member email addresses."""
437+ members = group ["members" ]
438+ return [x ["username" ] for x in members ]
439+
440+
418441def group_uniqnames (group ):
419442 """Return group member uniqnames."""
420- members = group ["members" ]
421- return [x ["username" ].replace ("@umich.edu" , "" ) for x in members ]
443+ return [x .replace ("@umich.edu" , "" ) for x in group_emails (group )]
422444
423445
424446def is_group_member (uniqname , group ):
@@ -565,7 +587,6 @@ def get_submission_smart(
565587
566588 # Get a group
567589 group = get_group_smart (group_arg , project_arg , course_arg , client )
568-
569590 # User provides "best"
570591 if submission_arg == "best" :
571592 return client .get (f"/api/groups/{ group ['pk' ]} /ultimate_submission/" )
@@ -578,14 +599,14 @@ def get_submission_smart(
578599 # No submissions input from the user. Show all submissions for this group
579600 # and prompt the user.
580601 if not submission_arg :
602+ options = [pick .Option (submission_str (x ), x ) for x in submissions ]
581603 selected_submissions = pick .pick (
582- options = submissions ,
604+ options = options ,
583605 title = "Select a submission:" ,
584- options_map_func = submission_str ,
585606 multiselect = False ,
586607 )
587608 assert selected_submissions
588- return selected_submissions [0 ]
609+ return selected_submissions [0 ]. value
589610
590611 # User provides string "last"
591612 if submission_arg == "last" :
0 commit comments