1
0
mirror of synced 2024-11-13 18:10:48 +01:00

Add more linting and code formating

This commit is contained in:
Stepland 2021-05-04 13:39:40 +02:00
parent 02f917e6be
commit 000614912d
29 changed files with 264 additions and 209 deletions

32
.flake8 Normal file
View File

@ -0,0 +1,32 @@
[flake8]
ignore =
# break after binary op.
# black does its thing and I leave it that way
W503
# f-string is missing placeholders
# really don't want to be bothered for so little
F541
# whitespace before ':'
# let black handle that
E203
# blank line contains whitespace
# let black handle that as well
W293
# do not assign a lambda expression, use a def
# I know when I need that one, thank you very much
E731
exclude =
.git
__pycache__
dist
build
per-file-ignores =
# Allow re-exporting in __init__.py files
__init__.py: F401
# Allow star imports in test example files
example*.py: F405, F403
# Silence weird false positive on inline comments ...
jubeatools/formats/jubeat_analyser/symbols.py: E262
# there's a field named "l" in a marshmallow schema
jubeatools/formats/memon/memon.py: E741
max-line-length = 120

View File

@ -9,9 +9,11 @@
## Making a new release
Sanity checks before anything serious happens, from the repo's root :
1. Run mypy and fix **all** the errors <br> `$ poetry run mypy .`
1. Format the code <br> `$ poetry run sh ./utils/format_code.sh`
1. Run checks <br> `$ poetry run sh ./utils/check_code.sh`
1. Make sure the unit tests pass <br> `$ poetry run pytest`
1. Fix all encountered errors
1. Rince and repeat until everythings is ok
Now that this is done you can move on to actually making a new version,
while still being in the repo's root :

View File

@ -1,11 +1,12 @@
"""Command Line Interface"""
from pathlib import Path
from typing import Any, Dict, Optional
from typing import Any, Dict
import click
from jubeatools.formats import DUMPERS, LOADERS
from jubeatools.formats.enum import JUBEAT_ANALYSER_FORMATS, Format
from jubeatools.formats.enum import Format
from jubeatools.formats.guess import guess_format

View File

@ -2,10 +2,7 @@
Module containing all the load/dump code for all file formats
"""
from pathlib import Path
from typing import IO, Any, Callable, Dict
from jubeatools.song import Song
from typing import Dict
from .enum import Format
from .jubeat_analyser import (

View File

@ -16,11 +16,7 @@ The machine-readable variants or these text formats are partially documented
- http://yosh52.web.fc2.com/jubeat/holdmarker.html
"""
from .memo1.dump import dump_memo1
from .memo1.load import load_memo1
from .memo2.dump import dump_memo2
from .memo2.load import load_memo2
from .memo.dump import dump_memo
from .memo.load import load_memo
from .mono_column.dump import dump_mono_column
from .mono_column.load import load_mono_column
from .memo import dump_memo, load_memo
from .memo1 import dump_memo1, load_memo1
from .memo2 import dump_memo2, load_memo2
from .mono_column import dump_mono_column, load_mono_column

View File

@ -24,9 +24,8 @@ Known hash commands :
- #bpp # bytes per panel (2 by default)
"""
from decimal import Decimal
from numbers import Number
from typing import Any, Iterable, List, Optional, Tuple, Union
from typing import Any, List, Optional, Tuple
from parsimonious import Grammar, NodeVisitor, ParseError
from parsimonious.nodes import Node
@ -148,5 +147,5 @@ ESCAPE_TABLE = str.maketrans({'"': BACKSLASH + '"', BACKSLASH: BACKSLASH + BACKS
def dump_value(value: str) -> str:
"""backslash-escapes \ and " from a string"""
"""Escapes backslashes and " from a string"""
return value.translate(ESCAPE_TABLE)

View File

@ -1,6 +1,6 @@
"""Collection of tools realted to dumping to jubeat analyser formats"""
from abc import ABC, abstractmethod
from copy import deepcopy
from dataclasses import dataclass, field
from decimal import Decimal
from fractions import Fraction
@ -19,7 +19,7 @@ from typing import (
Union,
)
from more_itertools import collapse, intersperse, mark_ends, windowed
from more_itertools import windowed
from sortedcontainers import SortedDict, SortedKeyList
from jubeatools.formats.filetypes import ChartFile

View File

@ -1,4 +1,5 @@
"""Collection of parsing tools that are common to all the jubeat analyser formats"""
import re
import warnings
from collections import Counter
@ -6,17 +7,7 @@ from copy import deepcopy
from dataclasses import astuple, dataclass
from decimal import Decimal
from itertools import product, zip_longest
from typing import (
AbstractSet,
Dict,
Iterator,
List,
Optional,
Sequence,
Set,
Tuple,
Union,
)
from typing import AbstractSet, Dict, List, Optional, Set, Tuple, Union
import constraint
from parsimonious import Grammar, NodeVisitor, ParseError

View File

@ -1,19 +1,14 @@
from collections import ChainMap, defaultdict
from copy import deepcopy
from dataclasses import dataclass, field
from decimal import Decimal
from fractions import Fraction
from functools import partial
from io import StringIO
from itertools import chain, zip_longest
from itertools import zip_longest
from math import ceil
from pathlib import Path
from typing import Callable, Dict, Iterator, List, Optional, Set, Tuple, Union, cast
from typing import Dict, Iterator, List, Union
from more_itertools import chunked, collapse, intersperse, mark_ends, windowed
from sortedcontainers import SortedKeyList
from jubeatools.formats.filetypes import ChartFile, JubeatFile
from jubeatools.formats.filetypes import ChartFile
from jubeatools.song import (
BeatsTime,
Chart,
@ -26,22 +21,17 @@ from jubeatools.song import (
)
from jubeatools.version import __version__
from ..command import dump_command
from ..dump_tools import (
BEATS_TIME_TO_SYMBOL,
COMMAND_ORDER,
DEFAULT_EXTRA_SYMBOLS,
DIRECTION_TO_ARROW,
DIRECTION_TO_LINE,
NOTE_TO_CIRCLE_FREE_SYMBOL,
JubeatAnalyserDumpedSection,
LongNoteEnd,
SortedDefaultDict,
create_sections_from_chart,
fraction_to_decimal,
jubeat_analyser_file_dumper,
)
from ..symbols import CIRCLE_FREE_SYMBOLS, NOTE_SYMBOLS
from ..symbols import NOTE_SYMBOLS
AnyNote = Union[TapNote, LongNote, LongNoteEnd]

View File

@ -1,16 +1,13 @@
import warnings
from collections import ChainMap
from copy import deepcopy
from dataclasses import astuple, dataclass
from decimal import Decimal
from functools import reduce
from itertools import chain, product, zip_longest
from itertools import product
from pathlib import Path
from typing import Dict, Iterator, List, Mapping, Optional, Set, Tuple, Union
from typing import Dict, Iterator, List, Mapping, Set, Tuple, Union
import constraint
from more_itertools import collapse, mark_ends
from parsimonious import Grammar, NodeVisitor, ParseError
from jubeatools.song import (
BeatsTime,
@ -31,24 +28,18 @@ from ..files import load_files
from ..load_tools import (
CIRCLE_FREE_TO_NOTE_SYMBOL,
EMPTY_BEAT_SYMBOLS,
LONG_ARROWS,
LONG_DIRECTION,
DoubleColumnChartLine,
DoubleColumnFrame,
JubeatAnalyserParser,
UnfinishedLongNote,
decimal_to_beats,
find_long_note_candidates,
is_double_column_chart_line,
is_empty_line,
is_simple_solution,
long_note_solution_heuristic,
parse_double_column_chart_line,
pick_correct_long_note_candidates,
split_double_byte_line,
)
from ..symbol_definition import is_symbol_definition, parse_symbol_definition
from ..symbols import CIRCLE_FREE_SYMBOLS, NOTE_SYMBOLS
from ..symbols import CIRCLE_FREE_SYMBOLS
class MemoFrame(DoubleColumnFrame):

View File

@ -1,19 +1,14 @@
from collections import ChainMap, defaultdict
from copy import deepcopy
from collections import defaultdict
from dataclasses import dataclass, field
from decimal import Decimal
from fractions import Fraction
from functools import partial
from io import StringIO
from itertools import chain, zip_longest
from itertools import zip_longest
from math import ceil
from pathlib import Path
from typing import Dict, Iterator, List, Optional, Set, Tuple, Union
from typing import Dict, Iterator, List, Union
from more_itertools import chunked, collapse, intersperse, mark_ends, windowed
from sortedcontainers import SortedKeyList
from more_itertools import collapse, intersperse, mark_ends, windowed
from jubeatools.formats.filetypes import ChartFile, JubeatFile
from jubeatools.formats.filetypes import ChartFile
from jubeatools.song import (
BeatsTime,
Chart,
@ -27,22 +22,16 @@ from jubeatools.song import (
from jubeatools.utils import lcm
from jubeatools.version import __version__
from ..command import dump_command
from ..dump_tools import (
BEATS_TIME_TO_SYMBOL,
COMMAND_ORDER,
DEFAULT_EXTRA_SYMBOLS,
DIRECTION_TO_ARROW,
DIRECTION_TO_LINE,
NOTE_TO_CIRCLE_FREE_SYMBOL,
JubeatAnalyserDumpedSection,
LongNoteEnd,
SortedDefaultDict,
create_sections_from_chart,
fraction_to_decimal,
jubeat_analyser_file_dumper,
)
from ..symbols import CIRCLE_FREE_SYMBOLS, NOTE_SYMBOLS
from ..symbols import NOTE_SYMBOLS
AnyNote = Union[TapNote, LongNote, LongNoteEnd]

View File

@ -1,16 +1,12 @@
import warnings
from collections import ChainMap
from copy import deepcopy
from dataclasses import astuple, dataclass
from decimal import Decimal
from functools import reduce
from itertools import chain, product, zip_longest
from itertools import product
from pathlib import Path
from typing import Dict, Iterator, List, Mapping, Optional, Set, Tuple, Union
from typing import Dict, Iterator, List, Mapping, Set, Tuple, Union
import constraint
from more_itertools import collapse, mark_ends
from parsimonious import Grammar, NodeVisitor, ParseError
from more_itertools import mark_ends
from jubeatools.song import (
BeatsTime,
@ -31,24 +27,17 @@ from ..files import load_files
from ..load_tools import (
CIRCLE_FREE_TO_NOTE_SYMBOL,
EMPTY_BEAT_SYMBOLS,
LONG_ARROWS,
LONG_DIRECTION,
DoubleColumnChartLine,
DoubleColumnFrame,
JubeatAnalyserParser,
UnfinishedLongNote,
decimal_to_beats,
find_long_note_candidates,
is_double_column_chart_line,
is_empty_line,
is_simple_solution,
long_note_solution_heuristic,
parse_double_column_chart_line,
pick_correct_long_note_candidates,
split_double_byte_line,
)
from ..symbol_definition import is_symbol_definition, parse_symbol_definition
from ..symbols import CIRCLE_FREE_SYMBOLS, NOTE_SYMBOLS
from ..symbols import CIRCLE_FREE_SYMBOLS
class Memo1Frame(DoubleColumnFrame):

View File

@ -1,19 +1,15 @@
from collections import ChainMap, defaultdict
from copy import deepcopy
from collections import defaultdict
from dataclasses import dataclass, field
from decimal import Decimal
from fractions import Fraction
from functools import partial
from io import StringIO
from itertools import chain, zip_longest
from math import ceil
from pathlib import Path
from typing import Dict, Iterator, List, Optional, Set, Tuple, Union
from typing import Dict, Iterator, List, Optional, Union
from more_itertools import chunked, collapse, intersperse, mark_ends, windowed
from more_itertools import collapse, intersperse, mark_ends, windowed
from sortedcontainers import SortedKeyList
from jubeatools.formats.filetypes import ChartFile, JubeatFile
from jubeatools.formats.filetypes import ChartFile
from jubeatools.song import (
BeatsTime,
BPMEvent,
@ -31,20 +27,15 @@ from jubeatools.version import __version__
from ..command import dump_command
from ..dump_tools import (
BEATS_TIME_TO_SYMBOL,
COMMAND_ORDER,
DEFAULT_EXTRA_SYMBOLS,
DIFFICULTIES,
DIRECTION_TO_ARROW,
DIRECTION_TO_LINE,
NOTE_TO_CIRCLE_FREE_SYMBOL,
LongNoteEnd,
SortedDefaultDict,
create_sections_from_chart,
fraction_to_decimal,
jubeat_analyser_file_dumper,
)
from ..symbols import CIRCLE_FREE_SYMBOLS, NOTE_SYMBOLS
from ..symbols import NOTE_SYMBOLS
AnyNote = Union[TapNote, LongNote, LongNoteEnd]

View File

@ -1,15 +1,10 @@
import warnings
from collections import ChainMap
from copy import deepcopy
from dataclasses import astuple, dataclass
from decimal import Decimal
from functools import reduce
from itertools import chain, product, zip_longest
from itertools import product, zip_longest
from pathlib import Path
from typing import Dict, Iterator, List, Mapping, Optional, Set, Tuple, Union
import constraint
from more_itertools import collapse, mark_ends
from parsimonious import Grammar, NodeVisitor, ParseError
from parsimonious.nodes import Node
@ -33,22 +28,13 @@ from ..files import load_files
from ..load_tools import (
CIRCLE_FREE_TO_NOTE_SYMBOL,
EMPTY_BEAT_SYMBOLS,
LONG_ARROWS,
LONG_DIRECTION,
JubeatAnalyserParser,
UnfinishedLongNote,
decimal_to_beats,
find_long_note_candidates,
is_double_column_chart_line,
is_empty_line,
is_simple_solution,
long_note_solution_heuristic,
parse_double_column_chart_line,
pick_correct_long_note_candidates,
split_double_byte_line,
)
from ..symbol_definition import is_symbol_definition, parse_symbol_definition
from ..symbols import CIRCLE_FREE_SYMBOLS, NOTE_SYMBOLS
from ..symbols import CIRCLE_FREE_SYMBOLS
@dataclass

View File

@ -1,18 +1,10 @@
from collections import ChainMap, defaultdict
from copy import deepcopy
from dataclasses import dataclass, field
from decimal import Decimal
from fractions import Fraction
from functools import partial
from io import StringIO
from itertools import chain
from pathlib import Path
from typing import Dict, Iterator, List, Mapping, Optional, Tuple
from typing import Dict, Iterator, List
from more_itertools import collapse, intersperse, mark_ends, windowed
from sortedcontainers import SortedKeyList
from more_itertools import collapse, intersperse, mark_ends
from jubeatools.formats.filetypes import ChartFile, JubeatFile
from jubeatools.formats.filetypes import ChartFile
from jubeatools.song import (
BeatsTime,
Chart,
@ -27,16 +19,13 @@ from jubeatools.version import __version__
from ..dump_tools import (
BEATS_TIME_TO_SYMBOL,
COMMAND_ORDER,
DEFAULT_EXTRA_SYMBOLS,
DIRECTION_TO_ARROW,
DIRECTION_TO_LINE,
NOTE_TO_CIRCLE_FREE_SYMBOL,
JubeatAnalyserDumpedSection,
LongNoteEnd,
SortedDefaultDict,
create_sections_from_chart,
fraction_to_decimal,
jubeat_analyser_file_dumper,
)
@ -156,7 +145,7 @@ def _dump_mono_column_chart(
# Actual output to file
file = StringIO()
file.write(f"// Converted using jubeatools {__version__}\n")
file.write(f"// https://github.com/Stepland/jubeatools\n\n")
file.write("// https://github.com/Stepland/jubeatools\n\n")
for _, section in sections.items():
file.write(section.render(circle_free) + "\n")

View File

@ -1,22 +1,16 @@
import re
import warnings
from collections import Counter
from copy import deepcopy
from dataclasses import astuple, dataclass
from decimal import Decimal
from enum import Enum
from functools import reduce
from itertools import product
from pathlib import Path
from typing import Dict, Iterator, List, Set, Tuple, Union
import constraint
from parsimonious import Grammar, NodeVisitor, ParseError
from parsimonious.nodes import Node
from jubeatools.song import (
BeatsTime,
BPMEvent,
Chart,
LongNote,
Metadata,
@ -33,21 +27,16 @@ from ..command import is_command, parse_command
from ..files import load_files
from ..load_tools import (
CIRCLE_FREE_TO_BEATS_TIME,
LONG_ARROWS,
LONG_DIRECTION,
JubeatAnalyserParser,
UnfinishedLongNote,
decimal_to_beats,
find_long_note_candidates,
is_empty_line,
is_separator,
is_simple_solution,
long_note_solution_heuristic,
pick_correct_long_note_candidates,
split_double_byte_line,
)
from ..symbol_definition import is_symbol_definition, parse_symbol_definition
from ..symbols import CIRCLE_FREE_SYMBOLS, NOTE_SYMBOLS
from ..symbols import CIRCLE_FREE_SYMBOLS
mono_column_chart_line_grammar = Grammar(
r"""
@ -78,7 +67,9 @@ def is_mono_column_chart_line(line: str) -> bool:
def parse_mono_column_chart_line(line: str) -> str:
return MonoColumnChartLineVisitor().visit(mono_column_chart_line_grammar.parse(line)) # type: ignore
return MonoColumnChartLineVisitor().visit( # type: ignore
mono_column_chart_line_grammar.parse(line)
)
@dataclass

View File

@ -1,20 +1,15 @@
import tempfile
from decimal import Decimal
from fractions import Fraction
from pathlib import Path
from typing import Set, Union
from hypothesis import example, given
from hypothesis import note as hypothesis_note
from hypothesis import strategies as st
from jubeatools import song
from jubeatools.formats.enum import Format
from jubeatools.formats.guess import guess_format
from jubeatools.formats.jubeat_analyser.memo.dump import _dump_memo_chart, dump_memo
from jubeatools.formats.jubeat_analyser.memo.load import MemoParser, load_memo
from jubeatools.formats.jubeat_analyser.memo.dump import _dump_memo_chart
from jubeatools.formats.jubeat_analyser.memo.load import MemoParser
from jubeatools.testutils import strategies as jbst
from jubeatools.testutils.typing import DrawFunc
from ..test_utils import load_and_dump_then_check, memo_compatible_song
from . import example1, example2, example3

View File

@ -7,7 +7,7 @@ from hypothesis import strategies as st
from jubeatools import song
from jubeatools.formats import Format
from jubeatools.formats.jubeat_analyser.memo1.dump import _dump_memo1_chart, dump_memo1
from jubeatools.formats.jubeat_analyser.memo1.dump import _dump_memo1_chart
from jubeatools.formats.jubeat_analyser.memo1.load import Memo1Parser
from jubeatools.testutils.strategies import NoteOption
from jubeatools.testutils.strategies import notes as notes_strat

View File

@ -14,7 +14,6 @@ from jubeatools.song import (
Chart,
LongNote,
Metadata,
NotePosition,
SecondsTime,
Song,
TapNote,

View File

@ -1,4 +1,3 @@
from functools import wraps
from importlib import resources
import pytest
@ -14,4 +13,4 @@ def test_RorataJins_example() -> None:
with resources.path(data, "RorataJin's example.txt") as p:
format_ = guess_format(p)
loader = LOADERS[format_]
song = loader(p)
_ = loader(p)

View File

@ -1,7 +1,7 @@
from io import StringIO
from itertools import chain
from pathlib import Path
from typing import IO, Any, Dict, Iterable, List, Mapping, Tuple, Union
from typing import Any, Dict, List, Union
import simplejson as json
from marshmallow import (
@ -9,12 +9,12 @@ from marshmallow import (
Schema,
ValidationError,
fields,
post_load,
validate,
validates_schema,
)
from multidict import MultiDict
from jubeatools.song import *
from jubeatools import song as jbt
from jubeatools.utils import lcm
# v0.x.x long note value :
@ -134,36 +134,38 @@ def _load_raw_memon(file: Path) -> Dict[str, Any]:
return res
def _load_memon_note_v0(note: dict, resolution: int) -> Union[TapNote, LongNote]:
position = NotePosition.from_index(note["n"])
time = beats_time_from_ticks(ticks=note["t"], resolution=resolution)
def _load_memon_note_v0(
note: dict, resolution: int
) -> Union[jbt.TapNote, jbt.LongNote]:
position = jbt.NotePosition.from_index(note["n"])
time = jbt.beats_time_from_ticks(ticks=note["t"], resolution=resolution)
if note["l"] > 0:
duration = beats_time_from_ticks(ticks=note["l"], resolution=resolution)
tail_tip = position + NotePosition(*P_VALUE_TO_X_Y_OFFSET[note["p"]])
return LongNote(time, position, duration, tail_tip)
duration = jbt.beats_time_from_ticks(ticks=note["l"], resolution=resolution)
tail_tip = position + jbt.NotePosition(*P_VALUE_TO_X_Y_OFFSET[note["p"]])
return jbt.LongNote(time, position, duration, tail_tip)
else:
return TapNote(time, position)
return jbt.TapNote(time, position)
def load_memon_legacy(file: Path) -> Song:
def load_memon_legacy(file: Path) -> jbt.Song:
raw_memon = _load_raw_memon(file)
schema = Memon_legacy()
memon = schema.load(raw_memon)
metadata = Metadata(
metadata = jbt.Metadata(
title=memon["metadata"]["title"],
artist=memon["metadata"]["artist"],
audio=Path(memon["metadata"]["audio"]),
cover=Path(memon["metadata"]["cover"]),
)
global_timing = Timing(
events=[BPMEvent(time=BeatsTime(0), BPM=memon["metadata"]["BPM"])],
beat_zero_offset=SecondsTime(-memon["metadata"]["offset"]),
global_timing = jbt.Timing(
events=[jbt.BPMEvent(time=jbt.BeatsTime(0), BPM=memon["metadata"]["BPM"])],
beat_zero_offset=jbt.SecondsTime(-memon["metadata"]["offset"]),
)
charts: MultiDict[Chart] = MultiDict()
charts: MultiDict[jbt.Chart] = MultiDict()
for memon_chart in memon["data"]:
charts.add(
memon_chart["dif_name"],
Chart(
jbt.Chart(
level=memon_chart["level"],
notes=[
_load_memon_note_v0(note, memon_chart["resolution"])
@ -172,28 +174,28 @@ def load_memon_legacy(file: Path) -> Song:
),
)
return Song(metadata=metadata, charts=charts, global_timing=global_timing)
return jbt.Song(metadata=metadata, charts=charts, global_timing=global_timing)
def load_memon_0_1_0(file: Path) -> Song:
def load_memon_0_1_0(file: Path) -> jbt.Song:
raw_memon = _load_raw_memon(file)
schema = Memon_0_1_0()
memon = schema.load(raw_memon)
metadata = Metadata(
metadata = jbt.Metadata(
title=memon["metadata"]["title"],
artist=memon["metadata"]["artist"],
audio=Path(memon["metadata"]["audio"]),
cover=Path(memon["metadata"]["cover"]),
)
global_timing = Timing(
events=[BPMEvent(time=BeatsTime(0), BPM=memon["metadata"]["BPM"])],
beat_zero_offset=SecondsTime(-memon["metadata"]["offset"]),
global_timing = jbt.Timing(
events=[jbt.BPMEvent(time=jbt.BeatsTime(0), BPM=memon["metadata"]["BPM"])],
beat_zero_offset=jbt.SecondsTime(-memon["metadata"]["offset"]),
)
charts: MultiDict[Chart] = MultiDict()
charts: MultiDict[jbt.Chart] = MultiDict()
for difficulty, memon_chart in memon["data"].items():
charts.add(
difficulty,
Chart(
jbt.Chart(
level=memon_chart["level"],
notes=[
_load_memon_note_v0(note, memon_chart["resolution"])
@ -202,10 +204,10 @@ def load_memon_0_1_0(file: Path) -> Song:
),
)
return Song(metadata=metadata, charts=charts, global_timing=global_timing)
return jbt.Song(metadata=metadata, charts=charts, global_timing=global_timing)
def load_memon_0_2_0(file: Path) -> Song:
def load_memon_0_2_0(file: Path) -> jbt.Song:
raw_memon = _load_raw_memon(file)
schema = Memon_0_2_0()
memon = schema.load(raw_memon)
@ -213,24 +215,24 @@ def load_memon_0_2_0(file: Path) -> Song:
if "preview" in memon["metadata"]:
start = memon["metadata"]["preview"]["position"]
length = memon["metadata"]["preview"]["length"]
preview = Preview(start, length)
preview = jbt.Preview(start, length)
metadata = Metadata(
metadata = jbt.Metadata(
title=memon["metadata"]["title"],
artist=memon["metadata"]["artist"],
audio=Path(memon["metadata"]["audio"]),
cover=Path(memon["metadata"]["cover"]),
preview=preview,
)
global_timing = Timing(
events=[BPMEvent(time=BeatsTime(0), BPM=memon["metadata"]["BPM"])],
beat_zero_offset=SecondsTime(-memon["metadata"]["offset"]),
global_timing = jbt.Timing(
events=[jbt.BPMEvent(time=jbt.BeatsTime(0), BPM=memon["metadata"]["BPM"])],
beat_zero_offset=jbt.SecondsTime(-memon["metadata"]["offset"]),
)
charts: MultiDict[Chart] = MultiDict()
charts: MultiDict[jbt.Chart] = MultiDict()
for difficulty, memon_chart in memon["data"].items():
charts.add(
difficulty,
Chart(
jbt.Chart(
level=memon_chart["level"],
notes=[
_load_memon_note_v0(note, memon_chart["resolution"])
@ -239,10 +241,10 @@ def load_memon_0_2_0(file: Path) -> Song:
),
)
return Song(metadata=metadata, charts=charts, global_timing=global_timing)
return jbt.Song(metadata=metadata, charts=charts, global_timing=global_timing)
def _long_note_tail_value_v0(note: LongNote) -> int:
def _long_note_tail_value_v0(note: jbt.LongNote) -> int:
dx = note.tail_tip.x - note.position.x
dy = note.tail_tip.y - note.position.y
try:
@ -253,7 +255,7 @@ def _long_note_tail_value_v0(note: LongNote) -> int:
) from None
def _get_timing(song: Song) -> Timing:
def _get_timing(song: jbt.Song) -> jbt.Timing:
if song.global_timing is not None:
return song.global_timing
else:
@ -262,7 +264,7 @@ def _get_timing(song: Song) -> Timing:
)
def _raise_if_unfit_for_v0(song: Song, version: str) -> None:
def _raise_if_unfit_for_v0(song: jbt.Song, version: str) -> None:
"""Raises an exception if the Song object is ill-formed or contains information
that cannot be represented in a memon v0.x.y file (includes legacy)"""
@ -311,21 +313,21 @@ def _dump_to_json(memon: dict) -> bytes:
return memon_fp.getvalue().encode("utf-8")
def _compute_resolution(notes: List[Union[TapNote, LongNote]]) -> int:
def _compute_resolution(notes: List[Union[jbt.TapNote, jbt.LongNote]]) -> int:
return lcm(
*chain(
iter(note.time.denominator for note in notes),
iter(
note.duration.denominator
for note in notes
if isinstance(note, LongNote)
if isinstance(note, jbt.LongNote)
),
)
)
def _dump_memon_note_v0(
note: Union[TapNote, LongNote], resolution: int
note: Union[jbt.TapNote, jbt.LongNote], resolution: int
) -> Dict[str, int]:
"""converts a note into the {n, t, l, p} form"""
memon_note = {
@ -334,7 +336,7 @@ def _dump_memon_note_v0(
"l": 0,
"p": 0,
}
if isinstance(note, LongNote):
if isinstance(note, jbt.LongNote):
memon_note["l"] = note.duration.numerator * (
resolution // note.duration.denominator
)
@ -343,7 +345,7 @@ def _dump_memon_note_v0(
return memon_note
def dump_memon_legacy(song: Song, path: Path, **kwargs: dict) -> Dict[Path, bytes]:
def dump_memon_legacy(song: jbt.Song, path: Path, **kwargs: dict) -> Dict[Path, bytes]:
_raise_if_unfit_for_v0(song, "legacy")
timing = _get_timing(song)
@ -383,7 +385,7 @@ def dump_memon_legacy(song: Song, path: Path, **kwargs: dict) -> Dict[Path, byte
return {filepath: _dump_to_json(memon)}
def dump_memon_0_1_0(song: Song, path: Path, **kwargs: dict) -> Dict[Path, bytes]:
def dump_memon_0_1_0(song: jbt.Song, path: Path, **kwargs: dict) -> Dict[Path, bytes]:
_raise_if_unfit_for_v0(song, "v0.1.0")
timing = _get_timing(song)
@ -419,7 +421,7 @@ def dump_memon_0_1_0(song: Song, path: Path, **kwargs: dict) -> Dict[Path, bytes
return {filepath: _dump_to_json(memon)}
def dump_memon_0_2_0(song: Song, path: Path, **kwargs: dict) -> Dict[Path, bytes]:
def dump_memon_0_2_0(song: jbt.Song, path: Path, **kwargs: dict) -> Dict[Path, bytes]:
_raise_if_unfit_for_v0(song, "v0.2.0")
timing = _get_timing(song)

View File

@ -1,6 +1,5 @@
import tempfile
from pathlib import Path
from typing import Callable
import hypothesis.strategies as st
from hypothesis import given

View File

@ -6,9 +6,9 @@ Every output format is created from a Song instance
Most timing-related info is stored as beat fractions,
otherwise a decimal number of seconds is used
"""
from __future__ import annotations
from collections import UserList, namedtuple
from dataclasses import astuple, dataclass, field
from decimal import Decimal
from fractions import Fraction

View File

@ -1,11 +1,12 @@
"""
Hypothesis strategies to generate notes and charts
"""
from decimal import Decimal
from enum import Enum, Flag, auto
from enum import Flag, auto
from itertools import product
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Set, TypeVar, Union
from typing import Any, Dict, Optional, Set, Union
import hypothesis.strategies as st
from multidict import MultiDict

View File

@ -1,7 +1,7 @@
import unicodedata
from functools import reduce
from math import gcd
from typing import Callable, Iterable, Optional, TypeVar
from typing import Callable, Optional, TypeVar
def single_lcm(a: int, b: int) -> int:

111
poetry.lock generated
View File

@ -28,6 +28,31 @@ docs = ["furo", "sphinx", "zope.interface"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
[[package]]
name = "autoflake"
version = "1.4"
description = "Removes unused imports and unused variables"
category = "dev"
optional = false
python-versions = "*"
[package.dependencies]
pyflakes = ">=1.1.0"
[[package]]
name = "autoimport"
version = "0.7.0"
description = "Autoimport missing python libraries."
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
autoflake = "*"
Click = "*"
pyprojroot = "*"
sh = "*"
[[package]]
name = "black"
version = "21.4b2"
@ -65,6 +90,19 @@ category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "flake8"
version = "3.9.1"
description = "the modular source code checker: pep8 pyflakes and co"
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[package.dependencies]
mccabe = ">=0.6.0,<0.7.0"
pycodestyle = ">=2.7.0,<2.8.0"
pyflakes = ">=2.3.0,<2.4.0"
[[package]]
name = "hypothesis"
version = "6.10.1"
@ -129,6 +167,14 @@ docs = ["sphinx (==3.4.3)", "sphinx-issues (==1.2.0)", "alabaster (==0.7.12)", "
lint = ["mypy (==0.812)", "flake8 (==3.9.0)", "flake8-bugbear (==21.3.2)", "pre-commit (>=2.4,<3.0)"]
tests = ["pytest", "pytz", "simplejson"]
[[package]]
name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "more-itertools"
version = "8.7.0"
@ -230,6 +276,22 @@ category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pycodestyle"
version = "2.7.0"
description = "Python style guide checker"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pyflakes"
version = "2.3.1"
description = "passive checker of Python programs"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pyparsing"
version = "2.4.7"
@ -238,6 +300,14 @@ category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "pyprojroot"
version = "0.2.0"
description = "Find project root paths and return relative project files"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "pytest"
version = "6.2.3"
@ -290,6 +360,14 @@ python-versions = "*"
[package.extras]
dev = ["pytest"]
[[package]]
name = "sh"
version = "1.14.1"
description = "Python subprocess replacement"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "simplejson"
version = "3.17.2"
@ -341,7 +419,7 @@ python-versions = "*"
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "2f391539f8bf0d106956ec4f499fc1c98a2305e94cbd2682d913885d78d7a4dd"
content-hash = "4065f5a647b6cfb73d1aeceaae1fee4f94ecccdaa807aa134d3c307c6ecfbbd9"
[metadata.files]
appdirs = [
@ -356,6 +434,13 @@ attrs = [
{file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"},
{file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
]
autoflake = [
{file = "autoflake-1.4.tar.gz", hash = "sha256:61a353012cff6ab94ca062823d1fb2f692c4acda51c76ff83a8d77915fba51ea"},
]
autoimport = [
{file = "autoimport-0.7.0-py3-none-any.whl", hash = "sha256:d98ae9100d7dfbac7183336c69d2a87bfbeebcdeb59253760f1e2a9db27fc970"},
{file = "autoimport-0.7.0.tar.gz", hash = "sha256:1c15c013e9029ec252fa8a1895570c34ff5676eabbdd85ae9514024e22ffee34"},
]
black = [
{file = "black-21.4b2-py3-none-any.whl", hash = "sha256:bff7067d8bc25eb21dcfdbc8c72f2baafd9ec6de4663241a52fb904b304d391f"},
{file = "black-21.4b2.tar.gz", hash = "sha256:fc9bcf3b482b05c1f35f6a882c079dc01b9c7795827532f4cc43c0ec88067bbc"},
@ -368,6 +453,10 @@ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
flake8 = [
{file = "flake8-3.9.1-py2.py3-none-any.whl", hash = "sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"},
{file = "flake8-3.9.1.tar.gz", hash = "sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378"},
]
hypothesis = [
{file = "hypothesis-6.10.1-py3-none-any.whl", hash = "sha256:1d65f58d82d1cbd35b6441bda3bb11cb1adc879d6b2af191aea388fa412171b1"},
{file = "hypothesis-6.10.1.tar.gz", hash = "sha256:586b6c46e90878c2546743afbed348bca51e1f30e3461fa701fad58c2c47c650"},
@ -384,6 +473,10 @@ marshmallow = [
{file = "marshmallow-3.11.1-py2.py3-none-any.whl", hash = "sha256:0dd42891a5ef288217ed6410917f3c6048f585f8692075a0052c24f9bfff9dfd"},
{file = "marshmallow-3.11.1.tar.gz", hash = "sha256:16e99cb7f630c0ef4d7d364ed0109ac194268dde123966076ab3dafb9ae3906b"},
]
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
more-itertools = [
{file = "more-itertools-8.7.0.tar.gz", hash = "sha256:c5d6da9ca3ff65220c3bfd2a8db06d698f05d4d2b9be57e1deb2be5a45019713"},
{file = "more_itertools-8.7.0-py3-none-any.whl", hash = "sha256:5652a9ac72209ed7df8d9c15daf4e1aa0e3d2ccd3c87f8265a0673cd9cbc9ced"},
@ -478,10 +571,22 @@ py = [
{file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
{file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
]
pycodestyle = [
{file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
{file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
]
pyflakes = [
{file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
{file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
]
pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pyprojroot = [
{file = "pyprojroot-0.2.0-py3-none-any.whl", hash = "sha256:741e8b4878a0d6bb6b06ec09aa05797130289e2127aa595b8f1cbadce697909f"},
{file = "pyprojroot-0.2.0.tar.gz", hash = "sha256:a79900dc52ee097bfd8d917a3d45e2b98494c47a57ba3a71bf609d7a156732e8"},
]
pytest = [
{file = "pytest-6.2.3-py3-none-any.whl", hash = "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"},
{file = "pytest-6.2.3.tar.gz", hash = "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634"},
@ -535,6 +640,10 @@ regex = [
rope = [
{file = "rope-0.17.0.tar.gz", hash = "sha256:658ad6705f43dcf3d6df379da9486529cf30e02d9ea14c5682aa80eb33b649e1"},
]
sh = [
{file = "sh-1.14.1-py2.py3-none-any.whl", hash = "sha256:75e86a836f47de095d4531718fe8489e6f7446c75ddfa5596f632727b919ffae"},
{file = "sh-1.14.1.tar.gz", hash = "sha256:39aa9af22f6558a0c5d132881cf43e34828ca03e4ae11114852ca6a55c7c1d8e"},
]
simplejson = [
{file = "simplejson-3.17.2-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:2d3eab2c3fe52007d703a26f71cf649a8c771fcdd949a3ae73041ba6797cfcf8"},
{file = "simplejson-3.17.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:813846738277729d7db71b82176204abc7fdae2f566e2d9fcf874f9b6472e3e6"},

View File

@ -26,6 +26,8 @@ hypothesis = "^6.10.1"
mypy = "^0.812"
isort = "^4.3.21"
toml = "^0.10.2"
flake8 = "^3.9.1"
autoimport = "^0.7.0"
[tool.poetry.scripts]
jubeatools = 'jubeatools.cli:convert'

2
utils/check_code.sh Executable file
View File

@ -0,0 +1,2 @@
flake8
mypy jubeatools

View File

@ -1,2 +1,15 @@
# find all files with unused imports, then hand them off to autoimport
flake8 \
--isolated \
--select=F401 \
--format='%(path)s' \
--exclude=__init__.py \
| sort \
| uniq \
| xargs autoimport
# auto-sort imports in all files
isort -y
# format code
black jubeatools