From e76eef79e813d582f6b4faf525bc3e99cc617f19 Mon Sep 17 00:00:00 2001 From: Stepland <10530295-Buggyroom@users.noreply.gitlab.com> Date: Mon, 5 Sep 2022 17:24:56 +0200 Subject: [PATCH] [memo2] friendlier error messages for bpp=2 mistakes --- CHANGELOG.md | 2 + docs/repo maintenance.md | 2 +- .../formats/jubeat_analyser/load_tools.py | 2 +- .../formats/jubeat_analyser/memo2/load.py | 74 ++- .../jubeat_analyser/tests/data/beat(1).txt | 571 ++++++++++++++++++ .../jubeat_analyser/tests/test_examples.py | 8 + jubeatools/formats/memon/v0/test_v0.py | 4 +- 7 files changed, 646 insertions(+), 17 deletions(-) create mode 100644 jubeatools/formats/jubeat_analyser/tests/data/beat(1).txt diff --git a/CHANGELOG.md b/CHANGELOG.md index fe77dcb..80fd5a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # v1.4.1 ## Changed +- [memo2] The parser now displays much friendlier error messages when + it finds uneven byte lengths in `#bpp=2` mode - Minimum required Python version is now 3.9 ## Fixed - A fresh install of jubeatools would fail because of a API break in a diff --git a/docs/repo maintenance.md b/docs/repo maintenance.md index ec28398..b51ed36 100644 --- a/docs/repo maintenance.md +++ b/docs/repo maintenance.md @@ -17,7 +17,7 @@ Sanity checks before anything serious happens, from the repo's root : Now that this is done you can move on to actually making a new version, while still being in the repo's root : -1. Update `CHANGELOG.md` +1. Update `CHANGELOG.md` (I like to follow this changelog style: https://keepachangelog.com/en/1.0.0/) 1. Update `README.md` if you've just added support for a new format 1. Commit everything you want in the new release 1. Run the script
`$ poetry run python utils/bump_version.py {rule}` diff --git a/jubeatools/formats/jubeat_analyser/load_tools.py b/jubeatools/formats/jubeat_analyser/load_tools.py index cae6e52..936e7e3 100644 --- a/jubeatools/formats/jubeat_analyser/load_tools.py +++ b/jubeatools/formats/jubeat_analyser/load_tools.py @@ -385,7 +385,7 @@ class JubeatAnalyserParser: elif self.circle_free and bpp == 1: raise ValueError("Can't set #bpp to 1 when #circlefree is on") else: - self.bytes_per_panel = int(value) + self.bytes_per_panel = bpp def do_holdbyarrow(self, value: str) -> None: self.hold_by_arrow = int(value) == 1 diff --git a/jubeatools/formats/jubeat_analyser/memo2/load.py b/jubeatools/formats/jubeat_analyser/memo2/load.py index 6009586..d41aef5 100644 --- a/jubeatools/formats/jubeat_analyser/memo2/load.py +++ b/jubeatools/formats/jubeat_analyser/memo2/load.py @@ -1,3 +1,4 @@ +import textwrap from dataclasses import astuple, dataclass from decimal import Decimal from itertools import product, zip_longest @@ -63,6 +64,10 @@ class BPM: Event = Union[NoteCluster, Stop, BPM] +def dump_timing_part(events: List[Event]) -> str: + return f"|{''.join(e.dump() for e in events)}|" + + @dataclass class RawMemo2ChartLine: position: str @@ -70,7 +75,7 @@ class RawMemo2ChartLine: def __str__(self) -> str: if self.timing: - return f"{self.position} |{''.join(e.dump() for e in self.timing)}|" + return f"{self.position} {dump_timing_part(self.timing)}" else: return self.position @@ -169,6 +174,16 @@ class Memo2Frame: return "\n".join(res) +CHARACTER_WIDTH_HELP = textwrap.dedent( + """ + Make sure the file is : + - truly encoded as Shift-JIS + - not missusing half-width characters instead of full-width ones + - only using half-width characters in pairs + """ +).strip() + + class Memo2Parser(JubeatAnalyserParser): FORMAT_TAG = "#memo2" @@ -212,22 +227,53 @@ class Memo2Parser(JubeatAnalyserParser): self._do_bpp(value) def append_chart_line(self, raw_line: RawMemo2ChartLine) -> None: - if ( - len(raw_line.position.encode("shift-jis-2004", errors="surrogateescape")) - != 4 * self.bytes_per_panel - ): - raise SyntaxError( - f"Invalid chart line for #bpp={self.bytes_per_panel} : {raw_line}" - ) + position_length = len( + raw_line.position.encode("shift-jis-2004", errors="surrogateescape") + ) + expected_position_length = 4 * self.bytes_per_panel + if position_length != expected_position_length: + message = [ + textwrap.dedent( + f""" + The position part of this chart line : + + {raw_line.position} + + should be {expected_position_length} bytes long (4 × #bpp value) but it is {position_length} + """ + ).strip() + ] + message.append(CHARACTER_WIDTH_HELP) + raise SyntaxError("\n".join(message)) if raw_line.timing is not None and self.bytes_per_panel == 2: - if any( - len(e.string.encode("shift-jis-2004", errors="surrogateescape")) % 2 - != 0 - for e in raw_line.timing - if isinstance(e, NoteCluster) + for note_cluster in ( + elem for elem in raw_line.timing if isinstance(elem, NoteCluster) ): - raise SyntaxError(f"Invalid chart line for #bpp=2 : {raw_line}") + length = len( + note_cluster.string.encode( + "shift-jis-2004", errors="surrogateescape" + ) + ) + if length % 2 != 0: + timing_part = dump_timing_part(raw_line.timing) + message = [ + textwrap.dedent( + f""" + The timing part of this chart line : + + {timing_part} + + contains the following {length} bytes long series of notes : + + {note_cluster.string} + + Series of notes of odd byte lengths should not happen in files that use #bpp=2 + """ + ).strip() + ] + message.append(CHARACTER_WIDTH_HELP) + raise SyntaxError("\n".join(message)) if not raw_line.timing: line = Memo2ChartLine(raw_line.position, None) diff --git a/jubeatools/formats/jubeat_analyser/tests/data/beat(1).txt b/jubeatools/formats/jubeat_analyser/tests/data/beat(1).txt new file mode 100644 index 0000000..4586227 --- /dev/null +++ b/jubeatools/formats/jubeat_analyser/tests/data/beat(1).txt @@ -0,0 +1,571 @@ +#memo2 +#circlefree=1 +#holdbyarrow=1 + +t=150 + +// 1 +A |----| +B |----| + |--@-| +@ |A-B-| +2 +FCC |@-A-| +G |B-C-| +@B@ |D-E-| +DAE |F-G-| +3 +ECCF |@-A-| +FF |B-C-| +@B@ |D-E-| +AD |F---| +4 +CD |@-A-| +E |B-CD| +@@B |E-F-| +@A |G---| + + +G +G +F +5 +C |@-A-| +C@ |B-C-| +@B |--D-| +A |E-F-| + +E + +DF + +6 +FGCE |@-A-| +@@C |B-C-| +DEFG |D-E-| +@ABC |F-G-| +7 +FCF |@-A-| +@@C |B-C-| +DEF |D-E-| +@ABC |F---| +8 +CDE |@-A-| +@@ |B-CD| +E |E-F-| +@ABC |G-H-| + + +GG +FGH + +9 +@ |@-A-| +@ |B-C-| + |----| +@AB |----| + +C< + + +C +10 +1 |----| + |----| + |----| + |@---| +11 +>@ |@--A| +A@ |--B-| + |CD--| +B@A |E---| + +E + +DC + +12 +1 |@--A| +@C + + +E + +F + +13 + |@--A| + |--B-| +1 |CD--| +@< |E---| + +EA +CD +B +@ +14 +A |@--A| +@< |--B-| +B |CD--| +1@ |E---| + +DC + + +E +15 +>@ |@--A| +1A |--B-| + |CD--| +B@ |E---| + +E + +DC + +16 +B1 |@--A| +@< |--B-| +A |CD--| +@A |EFG-| + + +4CD +>C + + +E +>F +G6 + +17 + |@--A| +1 |--B-| + |CD--| +@< |E---| + +EA +CD +B +@ +18 +A |@--A| +@DC |--B-| +B |CD--| +1E@ |E---| +19 +@@FA |@-AB| +HDG |-CD-| +IC |--E-| +BE1 |FGHI| +20 +AFFD |@-AB| +EE |-CD-| + |E---| +CB@ |F---| +21 +A |@-AB| +D |-CD-| +C@@ |--E-| +B |FGHI| + +F +GH +I +E +22 +DHGA |@-AB| +FE |-CD-| + |E-F-| +@BC |G-H-| +23 + |@-AB| +CD |-CD-| +D@ |-E-F| +AB@ |G--H| + +E + +GF +HG +24 +AB@E |@-AB| +@E |CDE-| +CDF |F---| +F |G-HI| + + +GI +H +G +25 +@@@ |@-AB| +C |C-D-| +D |E-FG| +BDA |H-I-| + +GE +H +EIF +EI +26 +@@ |@-AB| +D@C |C-D-| + |E-FG| +BDA |H-I-| + +IEHI +E +EF +G +27 +B |@-AB| +C |C-D-| +@@ |E-FG| +@DA |H-I-| + +I +EH +EGE +IF +28 +@BD |@-AB| +@C |C-D-| +@ |E-FG| +DA |H-I-| + +I +IEE +EGHE +GF +29 +@@ |@-AB| +C |C-D-| +D |E-FG| +BDA |H-I-| + +GE +H +EIF +EI +30 +@@ |@-AB| +D@C |C-D-| + |E-FG| +BDA |H-I-| + +IEHI +E +EF +G +31 +B |@-AB| +C |C-D-| +@@ |E-FG| +@DA |H-I-| + +I +EH +EGE +IF +32 +@BD |@-AB| +@C |C-D-| +@ |E-FG| +DA |H-I-| + + +IEI +EGHE +GF +33 +@@ |@-AB| +DB |-CD-| + |EFGH| +CA |IJKL| + +HI +J +GEK +LF +34 +BD@ |@-AB| +@ |-CD-| +AC |EFGH| + |IJKL| + +H +E +KLG +IJF +35 +@ |@-AB| +DB@ |-CD-| + |EFGH| +CA |IJKL| + +JFI +E +G +LHK +36 + |@-AB| +BD@ |-CD-| +AC@ |EFGH| + |IJKL| + +FE +LK +JI +HG +37 +@@ |@-AB| +C |C-D-| +D |E-FG| +BDA |H-I-| + +GE +H +EIF +EI +38 +@@ |@-AB| +D@C |C-D-| + |E-FG| +BDA |H-I-| + +IEHI +E +EF +G +39 +B |@-AB| +C |C-D-| +@@ |E-FG| +@DA |H-I-| + +I +EH +EGE +IF +40 +@BF |@-AB| +@EC |C-D-| +E@ |E-F-| +DDA |GHIJKLMN| + +GK +HL +IM +JN +41 +@ |@---| + |A-B-| + |--C-| +ȁ |--D-| + + +BD +CCD +A +42 +1Ɂ |@---| + |A---| + |B---| +@ |C---| + +A +BC + + +43 +@A |@---| +C |--A-| +B@ |--B-| +ȁ1 |--C-| +44 +1 |@---| +CC |A---| +BB |B---| +AA@ |C---| +45 +@@A |@---| +@< |--A-| +B |--B-| +1 |----| +46 + |@-A-| +1 |B-C-| +>@ |--D-| + |----| + +D + +C +BA +47 +BA |@---| +AB |--A-| +@1 |--B-| +@< |----| +48 + |@---| + |----| + |----| +1@ |----| +49 +CEA |----| +DBF |@-AB| +C |C---| +@D@ |D-EF| +50 +CC |@---| + |A-B-| +@B@C |C--D| +AA |E-F-| + +F +EFD + +E +51 +D@B |@---| +@C |A-BC| +@D |D---| +AA |E-FG| + +F +EG + +E +52 +BB |@---| + |A---| +@@ |B-CD| +AA |E-F-| + +F +E +CDF +E +53 +DB |@---| +@C@ |A-BC| +@D |D---| +AA |E-FG| + +F +EG + +E +54 + |@---| + |A-B-| +@B@ |C--D| +AA |E-F-| + +CD +EECF +C +F +55 + |@---| +B |A-B-| +@@ |C-DE| +AA@ |--F-| + +CE +FD +ECC +F +56 +FBCE |@-AB| +DA |C-DE| +FCF |F-GH| +C@@ |IJK-| + + +IJG + +KH +57 +H@@D |@-AB| +AE |C---DEFG| +@HBF |H---| +CG |I-JK| + + +J +I +K +58 +F@@ |@---| +DBGE |A-BC| +HFA |D-EF| +DHC |-GH-| +59 +D@ |@---| +BFC |A-BC| +GD@ |D---| +AEEA |E-FG| +60 +D@ |@---| +B |A-BC| +DC@ |D-EF| +AA |-GH-| + +H +HE +FG +F +61 +D@B |@---| +C |A-BC| +D |D---| +A@A |E-FG| + +F +EG + +E +62 +CD |@---| +EECF |A-B-| +@B@C |C--D| +AFA |E-F-| +63 +C |@---| +B |A-B-| +@C@C |C--D| +AA@ |E-F-| + +FD +EDF + + +64 +A |@---| + |A---| +@A |B-CD| +A@@ |-EF-| + +BCD +BFD +ECB +EFB +65 +@ |@---| +@ |----| +@ |----| + |----| +66 + |----| + |----| + |----| + |----| \ No newline at end of file diff --git a/jubeatools/formats/jubeat_analyser/tests/test_examples.py b/jubeatools/formats/jubeat_analyser/tests/test_examples.py index 32a7a91..be919bb 100644 --- a/jubeatools/formats/jubeat_analyser/tests/test_examples.py +++ b/jubeatools/formats/jubeat_analyser/tests/test_examples.py @@ -40,3 +40,11 @@ def test_MTC_Nageki_no_Ki_EXT() -> None: def test_MTC_Mimi_EXT() -> None: """Also an euc-kr file but also has long notes""" try_to_load("MTC_Mimi_EXT.txt") + + +def test_beat_1() -> None: + """This file uses #bpp=2 with half-width hyphens in the timing part, this + is bound to fail on the first line that has an odd length when encoded + to shift-jis, for now I just want to display a friendlier error message""" + with pytest.raises(SyntaxError, match="Series of notes of odd byte lengths"): + try_to_load("beat(1).txt") diff --git a/jubeatools/formats/memon/v0/test_v0.py b/jubeatools/formats/memon/v0/test_v0.py index f2ebd56..f643e97 100644 --- a/jubeatools/formats/memon/v0/test_v0.py +++ b/jubeatools/formats/memon/v0/test_v0.py @@ -73,7 +73,7 @@ def test_memon_0_2_0(song: song.Song) -> None: @st.composite def memon_0_3_0_compatible_song(draw: st.DrawFn) -> song.Song: - return draw( + random_song: song.Song = draw( jbst.song( diffs_strat=memon_diffs(), chart_strat=jbst.chart(timing_strat=st.none()), @@ -81,6 +81,8 @@ def memon_0_3_0_compatible_song(draw: st.DrawFn) -> song.Song: ) ) + return random_song + @given(memon_0_3_0_compatible_song()) def test_memon_0_3_0(song: song.Song) -> None: