From 000614912d94bcd1e107aa7729502ca232122e5c Mon Sep 17 00:00:00 2001
From: Stepland <16676308+Stepland@users.noreply.github.com>
Date: Tue, 4 May 2021 13:39:40 +0200
Subject: [PATCH] Add more linting and code formating
---
.flake8 | 32 +++++
docs/repo maintenance.md | 4 +-
jubeatools/cli.py | 5 +-
jubeatools/formats/__init__.py | 5 +-
.../formats/jubeat_analyser/__init__.py | 12 +-
jubeatools/formats/jubeat_analyser/command.py | 5 +-
.../formats/jubeat_analyser/dump_tools.py | 4 +-
.../formats/jubeat_analyser/load_tools.py | 13 +-
.../formats/jubeat_analyser/memo/dump.py | 18 +--
.../formats/jubeat_analyser/memo/load.py | 15 +--
.../formats/jubeat_analyser/memo1/dump.py | 23 +---
.../formats/jubeat_analyser/memo1/load.py | 19 +--
.../formats/jubeat_analyser/memo2/dump.py | 19 +--
.../formats/jubeat_analyser/memo2/load.py | 18 +--
.../jubeat_analyser/mono_column/dump.py | 19 +--
.../jubeat_analyser/mono_column/load.py | 17 +--
.../jubeat_analyser/tests/memo/test_memo.py | 9 +-
.../jubeat_analyser/tests/memo1/test_memo1.py | 2 +-
.../jubeat_analyser/tests/memo2/test_memo2.py | 1 -
.../jubeat_analyser/tests/test_examples.py | 3 +-
jubeatools/formats/memon/memon.py | 92 ++++++++-------
jubeatools/formats/memon/test_memon.py | 1 -
jubeatools/song.py | 2 +-
jubeatools/testutils/strategies.py | 5 +-
jubeatools/utils.py | 2 +-
poetry.lock | 111 +++++++++++++++++-
pyproject.toml | 2 +
utils/check_code.sh | 2 +
utils/format_code.sh | 13 ++
29 files changed, 264 insertions(+), 209 deletions(-)
create mode 100644 .flake8
create mode 100755 utils/check_code.sh
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..8e6fd7c
--- /dev/null
+++ b/.flake8
@@ -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
\ No newline at end of file
diff --git a/docs/repo maintenance.md b/docs/repo maintenance.md
index 7df64bf..0bd6c29 100644
--- a/docs/repo maintenance.md
+++ b/docs/repo maintenance.md
@@ -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
`$ poetry run mypy .`
1. Format the code
`$ poetry run sh ./utils/format_code.sh`
+1. Run checks
`$ poetry run sh ./utils/check_code.sh`
1. Make sure the unit tests pass
`$ 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 :
diff --git a/jubeatools/cli.py b/jubeatools/cli.py
index 1127cad..4a8d833 100644
--- a/jubeatools/cli.py
+++ b/jubeatools/cli.py
@@ -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
diff --git a/jubeatools/formats/__init__.py b/jubeatools/formats/__init__.py
index b21ca82..37d5997 100644
--- a/jubeatools/formats/__init__.py
+++ b/jubeatools/formats/__init__.py
@@ -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 (
diff --git a/jubeatools/formats/jubeat_analyser/__init__.py b/jubeatools/formats/jubeat_analyser/__init__.py
index 6636ffe..9226fe1 100644
--- a/jubeatools/formats/jubeat_analyser/__init__.py
+++ b/jubeatools/formats/jubeat_analyser/__init__.py
@@ -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
diff --git a/jubeatools/formats/jubeat_analyser/command.py b/jubeatools/formats/jubeat_analyser/command.py
index 3f99e4e..24ecec7 100644
--- a/jubeatools/formats/jubeat_analyser/command.py
+++ b/jubeatools/formats/jubeat_analyser/command.py
@@ -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)
diff --git a/jubeatools/formats/jubeat_analyser/dump_tools.py b/jubeatools/formats/jubeat_analyser/dump_tools.py
index 7a5a00c..cddca67 100644
--- a/jubeatools/formats/jubeat_analyser/dump_tools.py
+++ b/jubeatools/formats/jubeat_analyser/dump_tools.py
@@ -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
diff --git a/jubeatools/formats/jubeat_analyser/load_tools.py b/jubeatools/formats/jubeat_analyser/load_tools.py
index ba1acae..fe468ce 100644
--- a/jubeatools/formats/jubeat_analyser/load_tools.py
+++ b/jubeatools/formats/jubeat_analyser/load_tools.py
@@ -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
diff --git a/jubeatools/formats/jubeat_analyser/memo/dump.py b/jubeatools/formats/jubeat_analyser/memo/dump.py
index ae5167a..2aef9b7 100644
--- a/jubeatools/formats/jubeat_analyser/memo/dump.py
+++ b/jubeatools/formats/jubeat_analyser/memo/dump.py
@@ -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]
diff --git a/jubeatools/formats/jubeat_analyser/memo/load.py b/jubeatools/formats/jubeat_analyser/memo/load.py
index 46ac1bb..f4ebfd1 100644
--- a/jubeatools/formats/jubeat_analyser/memo/load.py
+++ b/jubeatools/formats/jubeat_analyser/memo/load.py
@@ -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):
diff --git a/jubeatools/formats/jubeat_analyser/memo1/dump.py b/jubeatools/formats/jubeat_analyser/memo1/dump.py
index cbee23f..da96201 100644
--- a/jubeatools/formats/jubeat_analyser/memo1/dump.py
+++ b/jubeatools/formats/jubeat_analyser/memo1/dump.py
@@ -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]
diff --git a/jubeatools/formats/jubeat_analyser/memo1/load.py b/jubeatools/formats/jubeat_analyser/memo1/load.py
index 4479d05..7f1d511 100644
--- a/jubeatools/formats/jubeat_analyser/memo1/load.py
+++ b/jubeatools/formats/jubeat_analyser/memo1/load.py
@@ -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):
diff --git a/jubeatools/formats/jubeat_analyser/memo2/dump.py b/jubeatools/formats/jubeat_analyser/memo2/dump.py
index 50c0113..460f12c 100644
--- a/jubeatools/formats/jubeat_analyser/memo2/dump.py
+++ b/jubeatools/formats/jubeat_analyser/memo2/dump.py
@@ -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]
diff --git a/jubeatools/formats/jubeat_analyser/memo2/load.py b/jubeatools/formats/jubeat_analyser/memo2/load.py
index b6c6cc0..df7f24c 100644
--- a/jubeatools/formats/jubeat_analyser/memo2/load.py
+++ b/jubeatools/formats/jubeat_analyser/memo2/load.py
@@ -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
diff --git a/jubeatools/formats/jubeat_analyser/mono_column/dump.py b/jubeatools/formats/jubeat_analyser/mono_column/dump.py
index 0ef471c..8d43058 100644
--- a/jubeatools/formats/jubeat_analyser/mono_column/dump.py
+++ b/jubeatools/formats/jubeat_analyser/mono_column/dump.py
@@ -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")
diff --git a/jubeatools/formats/jubeat_analyser/mono_column/load.py b/jubeatools/formats/jubeat_analyser/mono_column/load.py
index 6e45515..f2d987a 100644
--- a/jubeatools/formats/jubeat_analyser/mono_column/load.py
+++ b/jubeatools/formats/jubeat_analyser/mono_column/load.py
@@ -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
diff --git a/jubeatools/formats/jubeat_analyser/tests/memo/test_memo.py b/jubeatools/formats/jubeat_analyser/tests/memo/test_memo.py
index 11b117a..5061aa6 100644
--- a/jubeatools/formats/jubeat_analyser/tests/memo/test_memo.py
+++ b/jubeatools/formats/jubeat_analyser/tests/memo/test_memo.py
@@ -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
diff --git a/jubeatools/formats/jubeat_analyser/tests/memo1/test_memo1.py b/jubeatools/formats/jubeat_analyser/tests/memo1/test_memo1.py
index f6177f6..29a64a0 100644
--- a/jubeatools/formats/jubeat_analyser/tests/memo1/test_memo1.py
+++ b/jubeatools/formats/jubeat_analyser/tests/memo1/test_memo1.py
@@ -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
diff --git a/jubeatools/formats/jubeat_analyser/tests/memo2/test_memo2.py b/jubeatools/formats/jubeat_analyser/tests/memo2/test_memo2.py
index d7ac0ef..6097236 100644
--- a/jubeatools/formats/jubeat_analyser/tests/memo2/test_memo2.py
+++ b/jubeatools/formats/jubeat_analyser/tests/memo2/test_memo2.py
@@ -14,7 +14,6 @@ from jubeatools.song import (
Chart,
LongNote,
Metadata,
- NotePosition,
SecondsTime,
Song,
TapNote,
diff --git a/jubeatools/formats/jubeat_analyser/tests/test_examples.py b/jubeatools/formats/jubeat_analyser/tests/test_examples.py
index af66d87..061a271 100644
--- a/jubeatools/formats/jubeat_analyser/tests/test_examples.py
+++ b/jubeatools/formats/jubeat_analyser/tests/test_examples.py
@@ -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)
diff --git a/jubeatools/formats/memon/memon.py b/jubeatools/formats/memon/memon.py
index 71d77ef..8f3877f 100644
--- a/jubeatools/formats/memon/memon.py
+++ b/jubeatools/formats/memon/memon.py
@@ -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)
diff --git a/jubeatools/formats/memon/test_memon.py b/jubeatools/formats/memon/test_memon.py
index ee3ceae..0e61ee3 100644
--- a/jubeatools/formats/memon/test_memon.py
+++ b/jubeatools/formats/memon/test_memon.py
@@ -1,6 +1,5 @@
import tempfile
from pathlib import Path
-from typing import Callable
import hypothesis.strategies as st
from hypothesis import given
diff --git a/jubeatools/song.py b/jubeatools/song.py
index ff29d1b..59ae26a 100644
--- a/jubeatools/song.py
+++ b/jubeatools/song.py
@@ -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
diff --git a/jubeatools/testutils/strategies.py b/jubeatools/testutils/strategies.py
index 6e20290..d89e1c7 100644
--- a/jubeatools/testutils/strategies.py
+++ b/jubeatools/testutils/strategies.py
@@ -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
diff --git a/jubeatools/utils.py b/jubeatools/utils.py
index 7ed459d..85e9b6b 100644
--- a/jubeatools/utils.py
+++ b/jubeatools/utils.py
@@ -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:
diff --git a/poetry.lock b/poetry.lock
index 84dc9ac..a10c0c0 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -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"},
diff --git a/pyproject.toml b/pyproject.toml
index 8b51a1b..ce75734 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -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'
diff --git a/utils/check_code.sh b/utils/check_code.sh
new file mode 100755
index 0000000..e84b441
--- /dev/null
+++ b/utils/check_code.sh
@@ -0,0 +1,2 @@
+flake8
+mypy jubeatools
\ No newline at end of file
diff --git a/utils/format_code.sh b/utils/format_code.sh
index c0601fa..7081492 100755
--- a/utils/format_code.sh
+++ b/utils/format_code.sh
@@ -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
\ No newline at end of file