Skip to content

Commit d588fd9

Browse files
authored
feat: add try/except helpers (#362)
* feat: add try/except helpers * remove find_case_body * restore comment
1 parent afaa7f2 commit d588fd9

2 files changed

Lines changed: 258 additions & 7 deletions

File tree

packages/helpers/python/py_helpers.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ def inherits_from(self, *args):
392392
id_list = [node.id for node in self.tree.bases]
393393
return all(arg in id_list for arg in args)
394394

395-
# Find an array of conditions in an if statement
395+
# Find an array of if statements
396396

397397
def find_ifs(self):
398398
return self._find_all(ast.If)
@@ -495,10 +495,44 @@ def find_case_guard(self):
495495
return Node(guard)
496496
return Node()
497497

498-
def find_case_body(self):
499-
if not isinstance(self.tree, ast.match_case):
498+
def find_trys(self):
499+
return self._find_all(ast.Try)
500+
501+
def find_excepts(self):
502+
if not isinstance(self.tree, ast.Try):
503+
return []
504+
return [Node(handler) for handler in self.tree.handlers]
505+
506+
def find_except(self, except_type=None, name=None):
507+
if not isinstance(self.tree, ast.Try):
500508
return Node()
501-
return Node(ast.Module(self.tree.body, []))
509+
for handler in self.tree.handlers:
510+
if except_type is None and handler.type is None:
511+
return Node(handler)
512+
if isinstance(handler.type, ast.Name):
513+
if handler.type.id == except_type:
514+
if (name is None and handler.name is None) or handler.name == name:
515+
return Node(handler)
516+
return Node()
517+
518+
def has_except(self, except_type=None, name=None):
519+
if self.find_except(except_type, name) == Node():
520+
return False
521+
return True
522+
523+
def find_try_else(self):
524+
if not isinstance(self.tree, ast.Try):
525+
return Node()
526+
if not self.tree.orelse:
527+
return Node()
528+
return Node(ast.Module(self.tree.orelse, []))
529+
530+
def find_finally(self):
531+
if not isinstance(self.tree, ast.Try):
532+
return Node()
533+
if not self.tree.finalbody:
534+
return Node()
535+
return Node(ast.Module(self.tree.finalbody, []))
502536

503537
# Returs a Boolean indicating if the statements passed as arguments
504538
# are found in the same order in the tree (statements can be non-consecutive)

packages/helpers/python/py_helpers.test.py

Lines changed: 220 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,23 +1103,240 @@ def test_find_case_body(self):
11031103
self.assertTrue(
11041104
node.find_matches()[0]
11051105
.find_match_cases()[0]
1106-
.find_case_body()
1106+
.find_body()
11071107
.is_equivalent("print(0)\nprint('spam')")
11081108
)
11091109
self.assertTrue(
11101110
node.find_matches()[0]
11111111
.find_match_cases()[1]
1112-
.find_case_body()
1112+
.find_body()
11131113
.is_equivalent("print(a, b)")
11141114
)
11151115
self.assertTrue(
11161116
node.find_matches()[0]
11171117
.find_match_cases()[2]
1118-
.find_case_body()
1118+
.find_body()
11191119
.is_equivalent("pass")
11201120
)
11211121

11221122

1123+
class TestTryExceptHelpers(unittest.TestCase):
1124+
def test_find_trys(self):
1125+
self.maxDiff = None
1126+
code_str = """
1127+
try:
1128+
x = 1 / 0
1129+
except ZeroDivisionError:
1130+
print("division by zero")
1131+
except ValueError as e:
1132+
print(f"value error: {e}")
1133+
else:
1134+
print("no error")
1135+
finally:
1136+
print("cleanup")
1137+
1138+
try:
1139+
y = int("abc")
1140+
except:
1141+
pass
1142+
"""
1143+
node = Node(code_str)
1144+
1145+
self.assertEqual(len(node.find_trys()), 2)
1146+
self.assertTrue(
1147+
node.find_trys()[0].is_equivalent(
1148+
"try:\n x = 1 / 0\nexcept ZeroDivisionError:\n print('division by zero')\nexcept ValueError as e:\n print(f'value error: {e}')\nelse:\n print('no error')\nfinally:\n print('cleanup')"
1149+
)
1150+
)
1151+
self.assertTrue(
1152+
node.find_trys()[1].is_equivalent("try:\n y = int('abc')\nexcept:\n pass")
1153+
)
1154+
self.assertTrue(node.find_trys()[0].find_body().is_equivalent("x = 1 / 0"))
1155+
1156+
def test_find_excepts(self):
1157+
code_str = """
1158+
try:
1159+
x = 1 / 0
1160+
except ZeroDivisionError:
1161+
print("division by zero")
1162+
except ValueError as e:
1163+
print(f"value error: {e}")
1164+
except:
1165+
print("other error")
1166+
finally:
1167+
print("cleanup")
1168+
"""
1169+
node = Node(code_str)
1170+
1171+
try_stmt = node.find_trys()[0]
1172+
excepts = try_stmt.find_excepts()
1173+
1174+
self.assertEqual(len(excepts), 3)
1175+
1176+
def test_find_excepts_no_try(self):
1177+
code_str = """
1178+
x = 1
1179+
print(x)
1180+
"""
1181+
node = Node(code_str)
1182+
1183+
self.assertEqual(node.find_excepts(), [])
1184+
1185+
def test_find_except(self):
1186+
code_str = """
1187+
try:
1188+
x = 1 / 0
1189+
except ZeroDivisionError:
1190+
print("division by zero")
1191+
except ValueError as e:
1192+
print(f"value error: {e}")
1193+
except Exception as ex:
1194+
print(f"exception: {ex}")
1195+
except:
1196+
print("other error")
1197+
"""
1198+
node = Node(code_str)
1199+
try_stmt = node.find_trys()[0]
1200+
self.assertTrue(
1201+
try_stmt.find_except("ZeroDivisionError")
1202+
.find_body()
1203+
.is_equivalent("print('division by zero')")
1204+
)
1205+
self.assertTrue(
1206+
try_stmt.find_except("ValueError", "e")
1207+
.find_body()
1208+
.is_equivalent("print(f'value error: {e}')")
1209+
)
1210+
self.assertTrue(
1211+
try_stmt.find_except("Exception", "ex")
1212+
.find_body()
1213+
.is_equivalent("print(f'exception: {ex}')")
1214+
)
1215+
self.assertTrue(
1216+
try_stmt.find_except().find_body().is_equivalent("print('other error')")
1217+
)
1218+
1219+
def test_has_except(self):
1220+
code_str = """
1221+
try:
1222+
x = 1 / 0
1223+
except ZeroDivisionError:
1224+
print("division by zero")
1225+
except ValueError as e:
1226+
print(f"value error: {e}")
1227+
except Exception as ex:
1228+
print(f"exception: {ex}")
1229+
except:
1230+
print("other error")
1231+
"""
1232+
node = Node(code_str)
1233+
1234+
try_stmt = node.find_trys()[0]
1235+
1236+
self.assertTrue(try_stmt.has_except("ZeroDivisionError"))
1237+
self.assertTrue(try_stmt.has_except("ValueError", "e"))
1238+
self.assertTrue(try_stmt.has_except("Exception", "ex"))
1239+
self.assertFalse(try_stmt.has_except("FileNotFoundError"))
1240+
self.assertFalse(try_stmt.has_except("ValueError", "ex"))
1241+
1242+
def test_has_except_no_try(self):
1243+
code_str = """
1244+
x = 1
1245+
print(x)
1246+
"""
1247+
node = Node(code_str)
1248+
1249+
self.assertFalse(node.has_except("ValueError"))
1250+
1251+
def test_find_try_else(self):
1252+
code_str = """
1253+
try:
1254+
x = 1
1255+
except ValueError:
1256+
print("error")
1257+
else:
1258+
print("success")
1259+
x = 2
1260+
finally:
1261+
print("cleanup")
1262+
"""
1263+
node = Node(code_str)
1264+
1265+
try_stmt = node.find_trys()[0]
1266+
else_block = try_stmt.find_try_else()
1267+
1268+
self.assertTrue(else_block.is_equivalent("print('success')\nx = 2"))
1269+
1270+
def test_find_try_else_no_else(self):
1271+
code_str = """
1272+
try:
1273+
x = 1
1274+
except ValueError:
1275+
print("error")
1276+
finally:
1277+
print("cleanup")
1278+
"""
1279+
node = Node(code_str)
1280+
1281+
try_stmt = node.find_trys()[0]
1282+
else_block = try_stmt.find_try_else()
1283+
1284+
self.assertTrue(else_block.is_empty())
1285+
1286+
def test_find_try_else_no_try(self):
1287+
code_str = """
1288+
x = 1
1289+
print(x)
1290+
"""
1291+
node = Node(code_str)
1292+
1293+
self.assertTrue(node.find_try_else().is_empty())
1294+
1295+
def test_find_finally(self):
1296+
code_str = """
1297+
try:
1298+
x = 1
1299+
except ValueError:
1300+
print("error")
1301+
else:
1302+
print("success")
1303+
finally:
1304+
print("cleanup")
1305+
x = None
1306+
"""
1307+
node = Node(code_str)
1308+
1309+
try_stmt = node.find_trys()[0]
1310+
finally_block = try_stmt.find_finally()
1311+
1312+
self.assertTrue(finally_block.is_equivalent("print('cleanup')\nx = None"))
1313+
1314+
def test_find_finally_no_finally(self):
1315+
code_str = """
1316+
try:
1317+
x = 1
1318+
except ValueError:
1319+
print("error")
1320+
else:
1321+
print("success")
1322+
"""
1323+
node = Node(code_str)
1324+
1325+
try_stmt = node.find_trys()[0]
1326+
finally_block = try_stmt.find_finally()
1327+
1328+
self.assertTrue(finally_block.is_empty())
1329+
1330+
def test_find_finally_no_try(self):
1331+
code_str = """
1332+
x = 1
1333+
print(x)
1334+
"""
1335+
node = Node(code_str)
1336+
1337+
self.assertTrue(node.find_finally().is_empty())
1338+
1339+
11231340
class TestForLoopsHelpers(unittest.TestCase):
11241341
def test_find_for_statements(self):
11251342
self.maxDiff = None

0 commit comments

Comments
 (0)