1
0
mirror of synced 2025-03-01 16:00:26 +01:00

Fix loaders using the actual enum instances as chart difficulties instead of their associated values

This commit is contained in:
Stepland 2022-04-16 01:23:52 +02:00
parent f76bc2aa88
commit 26b3d46975
11 changed files with 77 additions and 22 deletions

View File

@ -2,6 +2,9 @@
## Changed
- Minimum required Python version is now 3.9
## Fixed
- Most loaders would incorrectly use the internal enum value name as difficulty
names for charts (like `Difficulty.EXTREME`) instead of the regular "display"
name (like `EXT`), not anymore !
- [eve] + [jbsq]
- Custom hakus were not taken into account when computing the time of the last
event, not anymore !

View File

@ -27,9 +27,9 @@ from .symbols import (
)
DIFFICULTIES = {
1: Difficulty.BASIC,
2: Difficulty.ADVANCED,
3: Difficulty.EXTREME,
1: Difficulty.BASIC.value,
2: Difficulty.ADVANCED.value,
3: Difficulty.EXTREME.value,
}
SYMBOL_TO_BEATS_TIME = {c: BeatsTime("1/4") * i for i, c in enumerate(NOTE_SYMBOLS)}

View File

@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any, Iterator, List, Optional
from typing import Any, Iterator, List
from jubeatools import song
from jubeatools.formats.load_tools import make_folder_loader
@ -23,8 +23,8 @@ load_folder = make_folder_loader("*.eve", load_file)
def _load_eve(lines: List[str], file_path: Path, *, beat_snap: int = 240) -> song.Song:
chart = make_chart_from_events(iter_events(lines), beat_snap=beat_snap)
dif = guess_difficulty(file_path.stem) or song.Difficulty.EXTREME
return song.Song(metadata=song.Metadata(), charts={dif: chart})
dif = guess_difficulty(file_path.stem)
return song.Song(metadata=song.Metadata(), charts={dif.value: chart})
def iter_events(lines: List[str]) -> Iterator[Event]:
@ -72,8 +72,8 @@ def parse_event(line: str) -> Event:
return Event(tick, command, value)
def guess_difficulty(filename: str) -> Optional[song.Difficulty]:
def guess_difficulty(filename: str) -> song.Difficulty:
try:
return song.Difficulty(filename.upper())
except ValueError:
return None
return song.Difficulty.EXTREME

View File

@ -1,9 +1,11 @@
from enum import Enum
from hypothesis import given
from jubeatools import song
from jubeatools.formats import Format
from jubeatools.formats.konami.testutils import eve_compatible_song
from jubeatools.testutils.test_patterns import dump_and_load_then_compare
from jubeatools.testutils.test_patterns import dump_and_load, dump_and_load_then_compare
@given(eve_compatible_song())
@ -14,3 +16,19 @@ def test_that_full_chart_roundtrips(song: song.Song) -> None:
bytes_decoder=lambda b: b.decode("ascii"),
load_options={"beat_snap": 12},
)
@given(eve_compatible_song())
def test_that_difficulty_name_is_loaded_properly(original_song: song.Song) -> None:
recovered_song = dump_and_load(
Format.EVE,
original_song,
bytes_decoder=lambda b: b.decode("ascii"),
load_options={"beat_snap": 12},
)
original_dif, _ = original_song.charts.popitem()
recovered_dif, _ = recovered_song.charts.popitem()
assert type(original_dif) == str
assert not isinstance(original_dif, Enum)
assert type(recovered_dif) == str
assert not isinstance(recovered_dif, Enum)

View File

@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any, Optional
from typing import Any
from jubeatools import song
from jubeatools.formats.load_tools import make_folder_loader
@ -31,8 +31,8 @@ def load_jbsq_file(
raw_data = construct.jbsq.parse(bytes_)
events = [make_event_from_construct(e) for e in raw_data.events]
chart = make_chart_from_events(events, beat_snap=beat_snap)
dif = guess_difficulty(file_path.stem) or song.Difficulty.EXTREME
return song.Song(metadata=song.Metadata(), charts={dif: chart})
dif = guess_difficulty(file_path.stem)
return song.Song(metadata=song.Metadata(), charts={dif.value: chart})
def make_event_from_construct(e: construct.Event) -> konami.Event:
@ -43,8 +43,8 @@ def make_event_from_construct(e: construct.Event) -> konami.Event:
)
def guess_difficulty(filename: str) -> Optional[song.Difficulty]:
def guess_difficulty(filename: str) -> song.Difficulty:
try:
return song.Difficulty(filename[-3:].upper())
except ValueError:
return None
return song.Difficulty.EXTREME

View File

@ -1,9 +1,11 @@
from enum import Enum
from hypothesis import given
from jubeatools import song
from jubeatools.formats import Format
from jubeatools.formats.konami.testutils import eve_compatible_song
from jubeatools.testutils.test_patterns import dump_and_load_then_compare
from jubeatools.testutils.test_patterns import dump_and_load, dump_and_load_then_compare
from .construct import jbsq
@ -16,3 +18,19 @@ def test_that_full_chart_roundtrips(song: song.Song) -> None:
bytes_decoder=lambda b: str(jbsq.parse(b)),
load_options={"beat_snap": 12},
)
@given(eve_compatible_song())
def test_that_difficulty_name_is_loaded_properly(original_song: song.Song) -> None:
recovered_song = dump_and_load(
Format.JBSQ,
original_song,
bytes_decoder=lambda b: str(jbsq.parse(b)),
load_options={"beat_snap": 12},
)
original_dif, _ = original_song.charts.popitem()
recovered_dif, _ = recovered_song.charts.popitem()
assert type(original_dif) == str
assert not isinstance(original_dif, Enum)
assert type(recovered_dif) == str
assert not isinstance(recovered_dif, Enum)

View File

@ -14,7 +14,7 @@ simple_beat_strat = jbst.beat_time(
def eve_compatible_song(draw: st.DrawFn) -> song.Song:
"""eve only keeps notes, hakus, timing info and difficulty,
the precision you can get out of it is also severly limited"""
diff = draw(st.sampled_from(list(song.Difficulty)))
diff = draw(st.sampled_from(list(d.value for d in song.Difficulty)))
chart = draw(
jbst.chart(
timing_strat=jbst.timing_info(

View File

@ -39,7 +39,7 @@ def load_malody_file(raw_dict: dict) -> song.Song:
time_map = load_timing_info(file.time, bgm)
timing = time_map.convert_to_timing_info()
chart = song.Chart(level=Decimal(0), timing=timing, notes=load_notes(file.note))
dif = file.meta.version or song.Difficulty.EXTREME
dif = file.meta.version or song.Difficulty.EXTREME.value
return song.Song(metadata=metadata, charts={dif: chart})

View File

@ -16,8 +16,8 @@ from jubeatools.testutils.test_patterns import dump_and_load_then_compare
@st.composite
def difficulty(draw: st.DrawFn) -> str:
d: song.Difficulty = draw(st.sampled_from(list(song.Difficulty)))
return d.value
diff: str = draw(st.sampled_from(list(d.value for d in song.Difficulty)))
return diff
@st.composite

View File

@ -21,7 +21,6 @@ from typing import (
Iterable,
Iterator,
List,
Mapping,
Optional,
Sequence,
Set,
@ -271,6 +270,9 @@ class Difficulty(str, Enum):
ADVANCED = "ADV"
EXTREME = "EXT"
def __str__(self) -> str:
return self.value
@dataclass
class Song:
@ -278,7 +280,7 @@ class Song:
A Song is a set of charts with associated metadata"""
metadata: Metadata
charts: Mapping[str, Chart] = field(default_factory=dict)
charts: Dict[str, Chart] = field(default_factory=dict)
common_timing: Optional[Timing] = None
common_hakus: Optional[Set[BeatsTime]] = None

View File

@ -24,6 +24,20 @@ def dump_and_load_then_compare(
load_options: Optional[dict] = None,
dump_options: Optional[dict] = None,
) -> None:
recovered_song = dump_and_load(
format_, song, bytes_decoder, temp_path, load_options, dump_options
)
assert recovered_song == song
def dump_and_load(
format_: Format,
song: song.Song,
bytes_decoder: Callable[[bytes], str] = lambda b: b.decode("utf-8"),
temp_path: Callable[[], ContextManager[Path]] = open_temp_dir,
load_options: Optional[dict] = None,
dump_options: Optional[dict] = None,
) -> song.Song:
load_options = load_options or {}
dump_options = dump_options or {}
loader = LOADERS[format_]
@ -39,4 +53,4 @@ def dump_and_load_then_compare(
recovered_song = loader(folder_path, **load_options)
recovered_song.minimize_timings()
recovered_song.minimize_hakus()
assert recovered_song == song
return recovered_song