Improve error messages
This commit is contained in:
parent
b656fe55c2
commit
769c82e33b
@ -37,7 +37,10 @@ def guess_memon_version(obj: Any) -> Format:
|
||||
except KeyError:
|
||||
return Format.MEMON_LEGACY
|
||||
except TypeError:
|
||||
raise ValueError("Invalid JSON structure for memon file")
|
||||
raise ValueError(
|
||||
"This JSON file is not a correct memon file : the top-level "
|
||||
"value is not an object"
|
||||
)
|
||||
|
||||
if version == "0.1.0":
|
||||
return Format.MEMON_0_1_0
|
||||
|
@ -99,7 +99,9 @@ def parse_command(line: str) -> Tuple[str, Optional[str]]:
|
||||
return CommandVisitor().visit(command_grammar.parse(line)) # type: ignore
|
||||
except ParseError:
|
||||
if line.strip()[0] == "#":
|
||||
raise ParseError(f"Invalid command syntax : {line}") from None
|
||||
raise ParseError(
|
||||
"Line starts with '#' but it couldn't be parsed as a valid command"
|
||||
) from None
|
||||
else:
|
||||
raise
|
||||
|
||||
|
@ -93,6 +93,32 @@ class DoubleColumnChartLine:
|
||||
def __str__(self) -> str:
|
||||
return f"{self.position} |{self.timing}|"
|
||||
|
||||
def raise_if_unfit(self, bytes_per_panel: int) -> None:
|
||||
self.raise_if_position_unfit(bytes_per_panel)
|
||||
self.raise_if_timing_unfit(bytes_per_panel)
|
||||
|
||||
def raise_if_position_unfit(self, bytes_per_panel: int) -> None:
|
||||
expected_length = 4 * bytes_per_panel
|
||||
actual_length = len(self.position.encode("shift-jis-2004"))
|
||||
if expected_length != actual_length:
|
||||
raise SyntaxError(
|
||||
f"Invalid position part. Since #bpp={bytes_per_panel}, the \
|
||||
position part of a line should be {expected_length} bytes long, \
|
||||
but {self.position!r} is {actual_length} bytes long"
|
||||
)
|
||||
|
||||
def raise_if_timing_unfit(self, bytes_per_panel: int) -> None:
|
||||
if self.timing is None:
|
||||
return
|
||||
|
||||
length = len(self.timing.encode("shift-jis-2004"))
|
||||
if length % bytes_per_panel != 0:
|
||||
raise SyntaxError(
|
||||
f"Invalid timing part. Since #bpp={bytes_per_panel}, the timing \
|
||||
part of a line should be divisible by {bytes_per_panel}, but \
|
||||
{self.timing!r} is {length} bytes long so it's not"
|
||||
)
|
||||
|
||||
|
||||
class DoubleColumnChartLineVisitor(NodeVisitor):
|
||||
def __init__(self) -> None:
|
||||
@ -145,7 +171,10 @@ def split_double_byte_line(line: str) -> List[str]:
|
||||
"""
|
||||
encoded_line = line.encode("shift-jis-2004")
|
||||
if len(encoded_line) % 2 != 0:
|
||||
raise ValueError(f"Invalid chart line : {line}")
|
||||
raise ValueError(
|
||||
"Line of odd length encountered while trying to split a double-byte "
|
||||
f"line : {line!r}"
|
||||
)
|
||||
symbols = []
|
||||
for i in range(0, len(encoded_line), 2):
|
||||
symbols.append(encoded_line[i : i + 2].decode("shift-jis-2004"))
|
||||
@ -166,7 +195,8 @@ class UnfinishedLongNote:
|
||||
def ends_at(self, end: BeatsTime) -> LongNote:
|
||||
if end < self.time:
|
||||
raise ValueError(
|
||||
f"Invalid end time ({end}) for long note starting at {self.time}"
|
||||
"Invalid end time. A long note starting at "
|
||||
f"{self.time} cannot end at {end} (which is earlier)"
|
||||
)
|
||||
return LongNote(
|
||||
time=self.time,
|
||||
@ -228,7 +258,7 @@ def pick_correct_long_note_candidates(
|
||||
solutions: List[Solution] = problem.getSolutions()
|
||||
if not solutions:
|
||||
raise SyntaxError(
|
||||
"Invalid long note arrow pattern in bloc :\n"
|
||||
"Impossible arrow pattern found in block :\n"
|
||||
+ "\n".join("".join(line) for line in bloc)
|
||||
)
|
||||
solution = min(solutions, key=long_note_solution_heuristic)
|
||||
@ -283,7 +313,7 @@ class JubeatAnalyserParser:
|
||||
try:
|
||||
method = getattr(self, f"do_{command}")
|
||||
except AttributeError:
|
||||
raise SyntaxError(f"Unknown analyser command : {command}") from None
|
||||
raise SyntaxError(f"Unknown jubeat analyser command : {command}") from None
|
||||
|
||||
if value is not None:
|
||||
method(value)
|
||||
@ -341,7 +371,7 @@ class JubeatAnalyserParser:
|
||||
if bpp not in (1, 2):
|
||||
raise ValueError(f"Unexcpected bpp value : {value}")
|
||||
elif self.circle_free and bpp == 1:
|
||||
raise ValueError("#bpp can only be 2 when #circlefree is activated")
|
||||
raise ValueError("Can't set #bpp to 1 when #circlefree is on")
|
||||
else:
|
||||
self.bytes_per_panel = int(value)
|
||||
|
||||
@ -349,18 +379,17 @@ class JubeatAnalyserParser:
|
||||
self.hold_by_arrow = int(value) == 1
|
||||
|
||||
def do_holdbytilde(self, value: str) -> None:
|
||||
if int(value):
|
||||
raise ValueError("jubeatools does not support #holdbytilde")
|
||||
raise NotImplementedError("jubeatools does not support #holdbytilde")
|
||||
|
||||
def do_circlefree(self, raw_value: str) -> None:
|
||||
activate = bool(int(raw_value))
|
||||
if activate and self.bytes_per_panel != 2:
|
||||
raise ValueError("#circlefree can only be activated when #bpp=2")
|
||||
raise ValueError("#circlefree can only be on when #bpp=2")
|
||||
self.circle_free = activate
|
||||
|
||||
def _wrong_format(self, f: str) -> None:
|
||||
raise ValueError(
|
||||
f"{f} command indicates this file uses another jubeat analyser "
|
||||
f"{f} command means that this file uses another jubeat analyser "
|
||||
"format than the one the currently selected parser is designed for"
|
||||
)
|
||||
|
||||
@ -381,15 +410,15 @@ class JubeatAnalyserParser:
|
||||
length_as_shift_jis = len(symbol.encode("shift-jis-2004"))
|
||||
if length_as_shift_jis != bpp:
|
||||
raise ValueError(
|
||||
f"Invalid symbol definition. Since #bpp={bpp}, timing symbols "
|
||||
f"should be {bpp} bytes long but '{symbol}' is {length_as_shift_jis}"
|
||||
f"Invalid symbol definition. Since #bpp={bpp}, timing symbols \
|
||||
should be {bpp} bytes long but '{symbol}' is {length_as_shift_jis}"
|
||||
)
|
||||
if timing > self.beats_per_section:
|
||||
message = (
|
||||
"Invalid symbol definition conscidering the number of beats per section :\n"
|
||||
f"*{symbol}:{timing}"
|
||||
raise ValueError(
|
||||
f"Invalid symbol definition. Since sections only last \
|
||||
{self.beats_per_section} beats, a symbol cannot happen \
|
||||
afterwards at {timing}"
|
||||
)
|
||||
raise ValueError(message)
|
||||
self.symbols[symbol] = timing
|
||||
|
||||
def is_short_line(self, line: str) -> bool:
|
||||
|
@ -55,19 +55,28 @@ class Frame:
|
||||
bars: Dict[int, Dict[int, str]] = field(default_factory=dict)
|
||||
|
||||
def dump(self, length: Decimal) -> Iterator[str]:
|
||||
# Check that bars are contiguous
|
||||
for a, b in windowed(sorted(self.bars), 2):
|
||||
if b is not None and a is not None and b - a != 1:
|
||||
raise ValueError("Frame has discontinuous bars")
|
||||
# Check all bars are in the same 4-bar group
|
||||
if self.bars.keys() != set(bar % 4 for bar in self.bars):
|
||||
raise ValueError("Frame contains bars from different 4-bar groups")
|
||||
|
||||
self.raise_if_unfit()
|
||||
for pos, bar in zip_longest(self.dump_positions(), self.dump_bars(length)):
|
||||
if bar is None:
|
||||
bar = ""
|
||||
yield f"{pos} {bar}"
|
||||
|
||||
def raise_if_unfit(self) -> None:
|
||||
if not self.bars_are_contiguous():
|
||||
raise ValueError("Frame has discontinuous bars")
|
||||
if not self.all_bars_are_from_the_same_group():
|
||||
raise ValueError("Frame contains bars from different 4-bar groups")
|
||||
|
||||
def bars_are_contiguous(self) -> bool:
|
||||
return all(
|
||||
b - a == 1
|
||||
for a, b in windowed(sorted(self.bars), 2)
|
||||
if b is not None and a is not None
|
||||
)
|
||||
|
||||
def all_bars_are_from_the_same_group(self) -> bool:
|
||||
return self.bars.keys() == set(bar % 4 for bar in self.bars)
|
||||
|
||||
def dump_positions(self) -> Iterator[str]:
|
||||
for y in range(4):
|
||||
yield "".join(
|
||||
@ -121,9 +130,7 @@ class MemoDumpedSection(JubeatAnalyserDumpedSection):
|
||||
chosen_symbols[time_in_section] = symbol
|
||||
bars[bar_index][time_index] = symbol
|
||||
elif time_in_section not in self.symbols:
|
||||
raise ValueError(
|
||||
f"No symbol defined for time in section : {time_in_section}"
|
||||
)
|
||||
raise ValueError(f"No symbol defined for time : {time_in_section}")
|
||||
|
||||
# Create frame by bar
|
||||
section_symbols = ChainMap(chosen_symbols, self.symbols)
|
||||
|
@ -98,13 +98,7 @@ class MemoParser(JubeatAnalyserParser):
|
||||
self._do_bpp(value)
|
||||
|
||||
def append_chart_line(self, line: DoubleColumnChartLine) -> None:
|
||||
if len(line.position.encode("shift-jis-2004")) != 4 * self.bytes_per_panel:
|
||||
raise SyntaxError(
|
||||
f"Invalid chart line for #bpp={self.bytes_per_panel} : {line}"
|
||||
)
|
||||
if line.timing is not None and self.bytes_per_panel == 2:
|
||||
if len(line.timing.encode("shift-jis-2004")) % 2 != 0:
|
||||
raise SyntaxError(f"Invalid chart line for #bpp=2 : {line}")
|
||||
line.raise_if_unfit(self.bytes_per_panel)
|
||||
self.current_chart_lines.append(line)
|
||||
if len(self.current_chart_lines) == 4:
|
||||
self._push_frame()
|
||||
|
@ -92,13 +92,7 @@ class Memo1Parser(JubeatAnalyserParser):
|
||||
self._do_bpp(value)
|
||||
|
||||
def append_chart_line(self, line: DoubleColumnChartLine) -> None:
|
||||
if len(line.position.encode("shift-jis-2004")) != 4 * self.bytes_per_panel:
|
||||
raise SyntaxError(
|
||||
f"Invalid chart line for #bpp={self.bytes_per_panel} : {line}"
|
||||
)
|
||||
if line.timing is not None and self.bytes_per_panel == 2:
|
||||
if len(line.timing.encode("shift-jis-2004")) % 2 != 0:
|
||||
raise SyntaxError(f"Invalid chart line for #bpp=2 : {line}")
|
||||
line.raise_if_unfit(self.bytes_per_panel)
|
||||
self.current_chart_lines.append(line)
|
||||
if len(self.current_chart_lines) == 4:
|
||||
self._push_frame()
|
||||
|
Loading…
Reference in New Issue
Block a user