fix_except.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """Fixer for except statements with named exceptions.
  2. The following cases will be converted:
  3. - "except E, T:" where T is a name:
  4. except E as T:
  5. - "except E, T:" where T is not a name, tuple or list:
  6. except E as t:
  7. T = t
  8. This is done because the target of an "except" clause must be a
  9. name.
  10. - "except E, T:" where T is a tuple or list literal:
  11. except E as t:
  12. T = t.args
  13. """
  14. # Author: Collin Winter
  15. # Local imports
  16. from .. import pytree
  17. from ..pgen2 import token
  18. from .. import fixer_base
  19. from ..fixer_util import Assign, Attr, Name, is_tuple, is_list, syms
  20. def find_excepts(nodes):
  21. for i, n in enumerate(nodes):
  22. if n.type == syms.except_clause:
  23. if n.children[0].value == 'except':
  24. yield (n, nodes[i+2])
  25. class FixExcept(fixer_base.BaseFix):
  26. BM_compatible = True
  27. PATTERN = """
  28. try_stmt< 'try' ':' (simple_stmt | suite)
  29. cleanup=(except_clause ':' (simple_stmt | suite))+
  30. tail=(['except' ':' (simple_stmt | suite)]
  31. ['else' ':' (simple_stmt | suite)]
  32. ['finally' ':' (simple_stmt | suite)]) >
  33. """
  34. def transform(self, node, results):
  35. syms = self.syms
  36. tail = [n.clone() for n in results["tail"]]
  37. try_cleanup = [ch.clone() for ch in results["cleanup"]]
  38. for except_clause, e_suite in find_excepts(try_cleanup):
  39. if len(except_clause.children) == 4:
  40. (E, comma, N) = except_clause.children[1:4]
  41. comma.replace(Name("as", prefix=" "))
  42. if N.type != token.NAME:
  43. # Generate a new N for the except clause
  44. new_N = Name(self.new_name(), prefix=" ")
  45. target = N.clone()
  46. target.prefix = ""
  47. N.replace(new_N)
  48. new_N = new_N.clone()
  49. # Insert "old_N = new_N" as the first statement in
  50. # the except body. This loop skips leading whitespace
  51. # and indents
  52. #TODO(cwinter) suite-cleanup
  53. suite_stmts = e_suite.children
  54. for i, stmt in enumerate(suite_stmts):
  55. if isinstance(stmt, pytree.Node):
  56. break
  57. # The assignment is different if old_N is a tuple or list
  58. # In that case, the assignment is old_N = new_N.args
  59. if is_tuple(N) or is_list(N):
  60. assign = Assign(target, Attr(new_N, Name('args')))
  61. else:
  62. assign = Assign(target, new_N)
  63. #TODO(cwinter) stopgap until children becomes a smart list
  64. for child in reversed(suite_stmts[:i]):
  65. e_suite.insert_child(0, child)
  66. e_suite.insert_child(i, assign)
  67. elif N.prefix == "":
  68. # No space after a comma is legal; no space after "as",
  69. # not so much.
  70. N.prefix = " "
  71. #TODO(cwinter) fix this when children becomes a smart list
  72. children = [c.clone() for c in node.children[:3]] + try_cleanup + tail
  73. return pytree.Node(node.type, children)