Fix loaders using the actual enum instances as chart difficulties instead of their associated values
This commit is contained in:
parent
f76bc2aa88
commit
26b3d46975
@ -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 !
|
||||
|
@ -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)}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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})
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user