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: