python.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. from typing import List
  2. from openhands.linter.base import BaseLinter, LintResult
  3. from openhands.linter.utils import run_cmd
  4. def python_compile_lint(fname: str) -> list[LintResult]:
  5. try:
  6. with open(fname, 'r') as f:
  7. code = f.read()
  8. compile(code, fname, 'exec') # USE TRACEBACK BELOW HERE
  9. return []
  10. except SyntaxError as err:
  11. err_lineno = getattr(err, 'end_lineno', err.lineno)
  12. err_offset = getattr(err, 'end_offset', err.offset)
  13. if err_offset and err_offset < 0:
  14. err_offset = err.offset
  15. return [
  16. LintResult(
  17. file=fname, line=err_lineno, column=err_offset or 1, message=err.msg
  18. )
  19. ]
  20. def flake_lint(filepath: str) -> list[LintResult]:
  21. fatal = 'F821,F822,F831,E112,E113,E999,E902'
  22. flake8_cmd = f'flake8 --select={fatal} --isolated {filepath}'
  23. try:
  24. cmd_outputs = run_cmd(flake8_cmd)
  25. except FileNotFoundError:
  26. return []
  27. results: list[LintResult] = []
  28. if not cmd_outputs:
  29. return results
  30. for line in cmd_outputs.splitlines():
  31. parts = line.split(':')
  32. if len(parts) >= 4:
  33. _msg = parts[3].strip()
  34. if len(parts) > 4:
  35. _msg += ': ' + parts[4].strip()
  36. results.append(
  37. LintResult(
  38. file=filepath,
  39. line=int(parts[1]),
  40. column=int(parts[2]),
  41. message=_msg,
  42. )
  43. )
  44. return results
  45. class PythonLinter(BaseLinter):
  46. @property
  47. def supported_extensions(self) -> List[str]:
  48. return ['.py']
  49. def lint(self, file_path: str) -> list[LintResult]:
  50. error = flake_lint(file_path)
  51. if not error:
  52. error = python_compile_lint(file_path)
  53. return error
  54. def compile_lint(self, file_path: str, code: str) -> List[LintResult]:
  55. try:
  56. compile(code, file_path, 'exec')
  57. return []
  58. except SyntaxError as e:
  59. return [
  60. LintResult(
  61. file=file_path,
  62. line=e.lineno,
  63. column=e.offset,
  64. message=str(e),
  65. rule='SyntaxError',
  66. )
  67. ]