message.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. from pathlib import Path
  2. from typing import Optional, Union
  3. class Location:
  4. def __init__(
  5. self, path: Union[Path, str], module: Optional[str], function: Optional[str], line: int, character: int
  6. ):
  7. if isinstance(path, Path):
  8. self._path = path
  9. elif isinstance(path, str):
  10. self._path = Path(path)
  11. else:
  12. raise ValueError
  13. self.module = module or None
  14. self.function = function or None
  15. self.line = None if line == -1 else line
  16. self.character = None if character == -1 else character
  17. @property
  18. def path(self):
  19. return self._path
  20. def absolute_path(self) -> Path:
  21. return self._path.absolute()
  22. def relative_path(self, root: Path) -> Path:
  23. return self._path.relative_to(root)
  24. def __repr__(self) -> str:
  25. return f"{self._path}:L{self.line}:{self.character}"
  26. def __hash__(self) -> int:
  27. return hash((self._path, self.line, self.character))
  28. def __eq__(self, other: object) -> bool:
  29. if not isinstance(other, Location):
  30. return False
  31. return self._path == other._path and self.line == other.line and self.character == other.character
  32. def __lt__(self, other: object) -> bool:
  33. if not isinstance(other, Location):
  34. raise ValueError
  35. if self._path == other._path:
  36. if self.line == other.line:
  37. return (self.character or -1) < (other.character or -1)
  38. return (self.line or -1) < (other.line or -1) # line can be None if it's a file-global warning
  39. return self._path < other._path
  40. class Message:
  41. def __init__(self, source: str, code: str, location: Location, message: str):
  42. self.source = source
  43. self.code = code
  44. self.location = location
  45. self.message = message
  46. def __repr__(self) -> str:
  47. return f"{self.source}-{self.code}"
  48. def __eq__(self, other: object) -> bool:
  49. if not isinstance(other, Message):
  50. return False
  51. if self.location == other.location:
  52. return self.code == other.code
  53. return False
  54. def __lt__(self, other) -> bool:
  55. if self.location == other.location:
  56. return self.code < other.code
  57. return self.location < other.location
  58. def make_tool_error_message(
  59. filepath: Union[Path, str],
  60. source: str,
  61. code: str,
  62. message: str,
  63. line: int = 0,
  64. character: int = 0,
  65. module: str = None,
  66. function: str = None,
  67. ) -> Message:
  68. location = Location(path=filepath, module=module, function=function, line=line, character=character)
  69. return Message(source=source, code=code, location=location, message=message)