* Bump pylint from 2.13.5 to 3.1.0 Bumps [pylint](https://github.com/pylint-dev/pylint) from 2.13.5 to 3.1.0. - [Release notes](https://github.com/pylint-dev/pylint/releases) - [Commits](https://github.com/pylint-dev/pylint/compare/v2.13.5...v3.1.0) --- updated-dependencies: - dependency-name: pylint dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * bend knee to pylint --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Bannon <jbann1994@gmail.com>
131 lines
4.5 KiB
Python
131 lines
4.5 KiB
Python
import sys
|
|
from typing import List
|
|
from typing import TypeVar
|
|
|
|
from ytdl_sub.script.types.resolvable import BuiltInFunctionType
|
|
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
|
|
from ytdl_sub.script.utils.exceptions import UserException
|
|
from ytdl_sub.script.utils.type_checking import FunctionSpec
|
|
from ytdl_sub.script.utils.type_checking import is_union
|
|
|
|
UserExceptionT = TypeVar("UserExceptionT", bound=UserException)
|
|
|
|
|
|
class ParserExceptionFormatter:
|
|
def __init__(self, text: str, start: int, end: int, exception: UserExceptionT):
|
|
self._text = text
|
|
self._start = start
|
|
self._end = end
|
|
self._exception = exception
|
|
|
|
def _exception_text(self, border: int):
|
|
"""
|
|
Format for single-line exceptions
|
|
"""
|
|
text_left = max(0, self._start - border)
|
|
text_right = min(len(self._text), self._start + border)
|
|
relative_start = self._start - text_left
|
|
|
|
exception_text: str = ""
|
|
if text_left > 3:
|
|
exception_text = "… "
|
|
relative_start += len(exception_text)
|
|
|
|
exception_text += self._text[text_left:text_right]
|
|
|
|
if text_right < len(self._text) - 3:
|
|
exception_text += " …"
|
|
|
|
exception_text += "\n"
|
|
exception_text += f"{' ' * relative_start}^"
|
|
|
|
return "\n" + exception_text
|
|
|
|
@property
|
|
def _is_multi_line(self) -> bool:
|
|
return "\n" in self._text
|
|
|
|
def _exception_text_lines(self, border_lines: int = 0) -> str:
|
|
"""
|
|
Format for multi-line exceptions
|
|
"""
|
|
split_text = self._text.split("\n")
|
|
|
|
start_line: int = sys.maxsize
|
|
end_line: int = -1
|
|
pos: int = 0
|
|
for idx, line in enumerate(split_text):
|
|
if self._start <= pos < self._end:
|
|
start_line = min(start_line, idx)
|
|
end_line = max(end_line, idx + 1)
|
|
pos += len(line)
|
|
|
|
true_start_line = start_line
|
|
start_line = max(0, start_line - border_lines)
|
|
end_line = min(len(split_text), end_line + border_lines)
|
|
|
|
# Get min leading spaces between all lines to return
|
|
min_leading_spaces = sys.maxsize
|
|
for line in split_text[start_line:end_line]:
|
|
min_leading_spaces = min(min_leading_spaces, len(line) - len(line.lstrip()))
|
|
|
|
to_return: List[str] = []
|
|
for idx in range(start_line, end_line):
|
|
if idx == true_start_line:
|
|
to_return.append(f">>> {split_text[idx][min_leading_spaces:]}")
|
|
else:
|
|
to_return.append(f" {split_text[idx][min_leading_spaces:]}")
|
|
|
|
return "\n" + "\n".join(to_return)
|
|
|
|
def highlight(self) -> UserExceptionT:
|
|
"""
|
|
Returns
|
|
-------
|
|
Exception with human-readable error highlighting for invalid syntax
|
|
"""
|
|
if self._is_multi_line:
|
|
invalid_syntax = self._exception_text_lines(border_lines=3)
|
|
else:
|
|
invalid_syntax = self._exception_text(border=20)
|
|
|
|
return self._exception.__class__(f"{invalid_syntax}\n{str(self._exception)}")
|
|
|
|
|
|
class FunctionArgumentsExceptionFormatter:
|
|
def __init__(
|
|
self,
|
|
input_spec: FunctionSpec,
|
|
function_instance: BuiltInFunctionType,
|
|
):
|
|
self._input_spec = input_spec
|
|
self._name = function_instance.name
|
|
self._input_args = function_instance.args
|
|
|
|
def _received_args_str(self) -> str:
|
|
received_type_names: List[str] = []
|
|
for arg in self._input_args:
|
|
if isinstance(arg, BuiltInFunctionType):
|
|
if is_union(arg.output_type()):
|
|
readable_type_names = ", ".join(
|
|
sorted(type_.type_name() for type_ in arg.output_type().__args__)
|
|
)
|
|
received_type_names.append(f"%{arg.name}(...)->Union[{readable_type_names}]")
|
|
else:
|
|
received_type_names.append(f"%{arg.name}(...)->{arg.output_type().type_name()}")
|
|
else:
|
|
received_type_names.append(arg.type_name())
|
|
|
|
return f"({', '.join(name for name in received_type_names)})"
|
|
|
|
def highlight(self) -> IncompatibleFunctionArguments:
|
|
"""
|
|
Returns
|
|
-------
|
|
Exception with human-readable error highlighting for incompatible function arguments
|
|
"""
|
|
return IncompatibleFunctionArguments(
|
|
f"Incompatible arguments passed to function {self._name}.\n"
|
|
f"Expected {self._input_spec.human_readable_input_args()}\n"
|
|
f"Received {self._received_args_str()}"
|
|
)
|