(self)
| 1337 | yield from ex.format_exception_only(show_group=show_group, _depth=_depth+1, colorize=colorize) |
| 1338 | |
| 1339 | def _find_keyword_typos(self): |
| 1340 | assert self._is_syntax_error |
| 1341 | try: |
| 1342 | import _suggestions |
| 1343 | except ImportError: |
| 1344 | _suggestions = None |
| 1345 | |
| 1346 | # Only try to find keyword typos if there is no custom message |
| 1347 | if self.msg != "invalid syntax" and "Perhaps you forgot a comma" not in self.msg: |
| 1348 | return |
| 1349 | |
| 1350 | if not self._exc_metadata: |
| 1351 | return |
| 1352 | |
| 1353 | line, offset, source = self._exc_metadata |
| 1354 | end_line = int(self.lineno) if self.lineno is not None else 0 |
| 1355 | lines = None |
| 1356 | from_filename = False |
| 1357 | |
| 1358 | if source is None: |
| 1359 | if self.filename: |
| 1360 | try: |
| 1361 | with open(self.filename) as f: |
| 1362 | lines = f.read().splitlines() |
| 1363 | except Exception: |
| 1364 | line, end_line, offset = 0,1,0 |
| 1365 | else: |
| 1366 | from_filename = True |
| 1367 | lines = lines if lines is not None else self.text.splitlines() |
| 1368 | else: |
| 1369 | lines = source.splitlines() |
| 1370 | |
| 1371 | error_code = lines[line -1 if line > 0 else 0:end_line] |
| 1372 | error_code = textwrap.dedent('\n'.join(error_code)) |
| 1373 | |
| 1374 | # Do not continue if the source is too large |
| 1375 | if len(error_code) > 1024: |
| 1376 | return |
| 1377 | |
| 1378 | # If the original code doesn't raise SyntaxError, we can't validate |
| 1379 | # that a keyword replacement actually fixes anything |
| 1380 | try: |
| 1381 | codeop.compile_command(error_code, symbol="exec", flags=codeop.PyCF_ONLY_AST) |
| 1382 | except SyntaxError: |
| 1383 | pass # Good - the original code has a syntax error we might fix |
| 1384 | else: |
| 1385 | return # Original code compiles or is incomplete - can't validate fixes |
| 1386 | |
| 1387 | error_lines = error_code.splitlines() |
| 1388 | tokens = tokenize.generate_tokens(io.StringIO(error_code).readline) |
| 1389 | tokens_left_to_process = 10 |
| 1390 | import difflib |
| 1391 | for token in tokens: |
| 1392 | start, end = token.start, token.end |
| 1393 | if token.type != tokenize.NAME: |
| 1394 | continue |
| 1395 | # Only consider NAME tokens on the same line as the error |
| 1396 | the_end = end_line if line == 0 else end_line + 1 |
no test coverage detected