I'll give an example in which I have used eval and where I think it was the best choice.
I was writing a simple software testing utility ... something to test whether student exercises were conforming to the assignment requirements. The goal was to provide a way for a simple configuration file to serve as a test specification (to get around a "chicken-and-egg" issue of using a programming language to describe/document/implement the test cases for elementary programming assignments).
I based my harness on the ConfigParser in the standard libraries. However, I did want the ability to represent arbitrary Python strings (including interpolations of \n, \t, and especially any interpolated hex encoded ASCII characters in the values read therefrom.
My solution was a try around an parsed_string=eval('''%s''' % cfg_read_item) followed by a try of the triple quoteddouble-quoted version ("""%s""") of the same.
This is a case where the alternative would have been to write (or find a pre-written) Python language parser and figure out how to include and adapt it to my program. The risks are minimal (I'm not worried that student submitted code is going to trick my parser, break out if its jail, delete all my files, send my credit card numbers to Romania and so on)*
*(In part because I was testing them under Linux from an untrusted headless user account).
As here others have said, there are other use cases where you're building code from a template based on input data and need to execute that code (meta programming). You should always be able to accomplish those tasks in another way. However, whenever that alternative entails coding effort that approaches writing a general programming language parser/compiler/interpreter .... then eval may be the better approach.