As an option you can process AttributeError and ValueError in one try-except block and all other Exceptions on the top level like
try:
try:
func()
except AttributeError as e:
if "specific error text" in str(e):
print("The specific AttributeError occurred")
else:
raise
except ValueError:
print("A value error occurred")
except Exception as e:
print("Another error occurred: {}".format(str(e)))
this may look a bit ugly though, so we can extract inner try-except block in a separate function like
def func_with_expected_exceptions_handling():
try:
func()
except AttributeError as e:
if "specific error text" in str(e):
print("The specific AttributeError occurred")
else:
raise
except ValueError:
print("A value error occurred")
and after that
try:
func_with_expected_exceptions_handling()
except Exception as e:
print("Another error occurred: {}".format(str(e)))
this doesn't save us from an actual nested structure, but it may come in handy if this kind of func processing arises in other places.
BTW, I don't think checking for a specific error message in exception is a good idea, we need a little bit more context to see if it can be done easier.
EDIT
If I understood correctly your func looks like
def func(...):
getattr(COMMANDS, cmd.command).command(irc_c, msg, cmd)
and you want to handle error from getattr call.
I can see next options here:
Wrap getattr call in try-except and process AttributeError in-place
def func(...):
try:
commander = getattr(COMMANDS, cmd.command)
except AttributeError:
print('Command {} not found'.format(cmd.command))
else:
commander.command(irc_c, msg, cmd)
Wrap getattr call in try-except, re-raise a custom exception (or ValueError) and process it afterwards in OP try-except
class CommandNotFound(Exception): pass
def func(...):
try:
commander = getattr(COMMANDS, cmd.command)
except AttributeError:
raise CommandNotFound() # or we can use `ValueError` instead
else:
commander.command(irc_c, msg, cmd)
Use default parameter of getattr function and make some kind of logging there like
class DefaultCommand:
def command(self, irc_c, msg, cmd):
print("Command {} is not found".format(cmd.command))
and after that used like
getattr(COMMANDS, cmd.command, DefaultCommand()).command(irc_c, msg, cmd)