chore: fix pylint warnings

This commit is contained in:
283375 2023-11-02 01:10:31 +08:00
parent 92fcc53015
commit 14f4cef426
Signed by: 283375
SSH Key Fingerprint: SHA256:UcX0qg6ZOSDOeieKPGokA5h7soykG61nz2uxuQgVLSk
15 changed files with 80 additions and 48 deletions

View File

@ -30,3 +30,14 @@ src_paths = ["src/arcaea_offline"]
[tool.pyright] [tool.pyright]
ignore = ["build/"] ignore = ["build/"]
[tool.pylint.main]
jobs = 0
[tool.pylint.logging]
disable = [
"missing-module-docstring",
"missing-class-docstring",
"missing-function-docstring",
"not-callable", # false positive to sqlalchemy `func.*`, remove this when pylint-dev/pylint(#8138) closed
]

View File

@ -1,3 +1,4 @@
black==23.3.0 black==23.3.0
isort==5.12.0 isort==5.12.0
pre-commit==3.3.1 pre-commit==3.3.1
pylint==3.0.2

View File

@ -16,9 +16,8 @@ def calculate_score_range(notes: int, pure: int, far: int):
def calculate_score_modifier(score: int) -> Decimal: def calculate_score_modifier(score: int) -> Decimal:
if score >= 10000000: if score >= 10000000:
return Decimal(2) return Decimal(2)
elif score >= 9800000: if score >= 9800000:
return Decimal(1) + (Decimal(score - 9800000) / 200000) return Decimal(1) + (Decimal(score - 9800000) / 200000)
else:
return Decimal(score - 9500000) / 300000 return Decimal(score - 9500000) / 300000
@ -35,6 +34,7 @@ def calculate_shiny_pure(notes: int, score: int, pure: int, far: int) -> int:
@dataclass @dataclass
class ConstantsFromPlayRatingResult: class ConstantsFromPlayRatingResult:
# pylint: disable=invalid-name
EXPlus: Tuple[Decimal, Decimal] EXPlus: Tuple[Decimal, Decimal]
EX: Tuple[Decimal, Decimal] EX: Tuple[Decimal, Decimal]
AA: Tuple[Decimal, Decimal] AA: Tuple[Decimal, Decimal]
@ -44,10 +44,12 @@ class ConstantsFromPlayRatingResult:
def calculate_constants_from_play_rating(play_rating: Union[Decimal, str, float, int]): def calculate_constants_from_play_rating(play_rating: Union[Decimal, str, float, int]):
# pylint: disable=no-value-for-parameter
play_rating = Decimal(play_rating) play_rating = Decimal(play_rating)
ranges = [] ranges = []
for upperScore, lowerScore in [ for upper_score, lower_score in [
(10000000, 9900000), (10000000, 9900000),
(9899999, 9800000), (9899999, 9800000),
(9799999, 9500000), (9799999, 9500000),
@ -55,10 +57,10 @@ def calculate_constants_from_play_rating(play_rating: Union[Decimal, str, float,
(9199999, 8900000), (9199999, 8900000),
(8899999, 8600000), (8899999, 8600000),
]: ]:
upperScoreModifier = calculate_score_modifier(upperScore) upper_score_modifier = calculate_score_modifier(upper_score)
lowerScoreModifier = calculate_score_modifier(lowerScore) lower_score_modifier = calculate_score_modifier(lower_score)
ranges.append( ranges.append(
(play_rating - upperScoreModifier, play_rating - lowerScoreModifier) (play_rating - upper_score_modifier, play_rating - lower_score_modifier)
) )
return ConstantsFromPlayRatingResult(*ranges) return ConstantsFromPlayRatingResult(*ranges)

View File

@ -5,12 +5,29 @@ from typing import Iterable, List, Optional, Type, Union
from sqlalchemy import Engine, func, inspect, select from sqlalchemy import Engine, func, inspect, select
from sqlalchemy.orm import DeclarativeBase, InstrumentedAttribute, sessionmaker from sqlalchemy.orm import DeclarativeBase, InstrumentedAttribute, sessionmaker
from .calculate import calculate_score_modifier
from .external.arcsong.arcsong_json import ArcSongJsonBuilder from .external.arcsong.arcsong_json import ArcSongJsonBuilder
from .external.exports import ScoreExport, exporters from .external.exports import ScoreExport, exporters
from .models.config import * from .models.config import ConfigBase, Property
from .models.scores import * from .models.scores import (
from .models.songs import * CalculatedPotential,
Score,
ScoreBest,
ScoreCalculated,
ScoresBase,
ScoresViewBase,
)
from .models.songs import (
Chart,
ChartInfo,
Difficulty,
DifficultyLocalized,
Pack,
PackLocalized,
Song,
SongLocalized,
SongsBase,
SongsViewBase,
)
from .singleton import Singleton from .singleton import Singleton
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -27,18 +44,21 @@ class Database(metaclass=Singleton):
if isinstance(self.engine, Engine): if isinstance(self.engine, Engine):
return return
raise ValueError("No sqlalchemy.Engine instance specified before.") raise ValueError("No sqlalchemy.Engine instance specified before.")
elif isinstance(engine, Engine):
if isinstance(self.engine, Engine): if not isinstance(engine, Engine):
logger.warning(
f"A sqlalchemy.Engine instance {self.engine} has been specified "
f"and will be replaced to {engine}"
)
self.engine = engine
else:
raise ValueError( raise ValueError(
f"A sqlalchemy.Engine instance expected, not {repr(engine)}" f"A sqlalchemy.Engine instance expected, not {repr(engine)}"
) )
if isinstance(self.engine, Engine):
logger.warning(
"A sqlalchemy.Engine instance %r has been specified "
"and will be replaced to %r",
self.engine,
engine,
)
self.engine = engine
@property @property
def engine(self) -> Engine: def engine(self) -> Engine:
return self.__engine # type: ignore return self.__engine # type: ignore
@ -60,7 +80,8 @@ class Database(metaclass=Singleton):
# create tables & views # create tables & views
if checkfirst: if checkfirst:
# > https://github.com/kvesteri/sqlalchemy-utils/issues/396 # > https://github.com/kvesteri/sqlalchemy-utils/issues/396
# > view.create_view() causes DuplicateTableError on Base.metadata.create_all(checkfirst=True) # > view.create_view() causes DuplicateTableError on
# > Base.metadata.create_all(checkfirst=True)
# so if `checkfirst` is True, drop these views before creating # so if `checkfirst` is True, drop these views before creating
SongsViewBase.metadata.drop_all(self.engine) SongsViewBase.metadata.drop_all(self.engine)
ScoresViewBase.metadata.drop_all(self.engine) ScoresViewBase.metadata.drop_all(self.engine)

View File

@ -39,10 +39,7 @@ def fix_timestamp(timestamp: int) -> Union[int, None]:
def to_db_value(val: Any) -> Any: def to_db_value(val: Any) -> Any:
if not val: if not val:
return None return None
elif isinstance(val, list): return json.dumps(val, ensure_ascii=False) if isinstance(val, list) else val
return json.dumps(val, ensure_ascii=False)
else:
return val
def is_localized(item: dict, key: str, append_localized: bool = True): def is_localized(item: dict, key: str, append_localized: bool = True):
@ -94,7 +91,7 @@ class ArcaeaParser:
return file_handle.read() return file_handle.read()
def parse(self) -> List[DeclarativeBase]: def parse(self) -> List[DeclarativeBase]:
... raise NotImplementedError()
def write_database(self, session: Session): def write_database(self, session: Session):
results = self.parse() results = self.parse()

View File

@ -37,9 +37,6 @@ class TWebApiRatingMeResult(TypedDict):
class ArcaeaOnlineParser(ArcaeaParser): class ArcaeaOnlineParser(ArcaeaParser):
def __init__(self, filepath):
super().__init__(filepath)
def parse(self) -> List[Score]: def parse(self) -> List[Score]:
api_result_root: TWebApiRatingMeResult = json.loads(self.read_file_text()) api_result_root: TWebApiRatingMeResult = json.loads(self.read_file_text())

View File

@ -6,9 +6,6 @@ from .common import ArcaeaParser, is_localized, set_model_localized_attrs
class PacklistParser(ArcaeaParser): class PacklistParser(ArcaeaParser):
def __init__(self, filepath):
super().__init__(filepath)
def parse(self) -> List[Union[Pack, PackLocalized]]: def parse(self) -> List[Union[Pack, PackLocalized]]:
packlist_json_root = json.loads(self.read_file_text()) packlist_json_root = json.loads(self.read_file_text())

View File

@ -6,9 +6,6 @@ from .common import ArcaeaParser, is_localized, set_model_localized_attrs, to_db
class SonglistParser(ArcaeaParser): class SonglistParser(ArcaeaParser):
def __init__(self, filepath):
super().__init__(filepath)
def parse( def parse(
self, self,
) -> List[Union[Song, SongLocalized, Difficulty, DifficultyLocalized]]: ) -> List[Union[Song, SongLocalized, Difficulty, DifficultyLocalized]]:
@ -61,9 +58,6 @@ class SonglistParser(ArcaeaParser):
class SonglistDifficultiesParser(ArcaeaParser): class SonglistDifficultiesParser(ArcaeaParser):
def __init__(self, filepath):
self.filepath = filepath
def parse(self) -> List[Union[Difficulty, DifficultyLocalized]]: def parse(self) -> List[Union[Difficulty, DifficultyLocalized]]:
songlist_json_root = json.loads(self.read_file_text()) songlist_json_root = json.loads(self.read_file_text())

View File

@ -12,15 +12,13 @@ logger = logging.getLogger(__name__)
class St3ScoreParser(ArcaeaParser): class St3ScoreParser(ArcaeaParser):
def __init__(self, filepath):
super().__init__(filepath)
def parse(self) -> List[Score]: def parse(self) -> List[Score]:
items = [] items = []
with sqlite3.connect(self.filepath) as st3_conn: with sqlite3.connect(self.filepath) as st3_conn:
cursor = st3_conn.cursor() cursor = st3_conn.cursor()
db_scores = cursor.execute( db_scores = cursor.execute(
"SELECT songId, songDifficulty, score, perfectCount, nearCount, missCount, date, modifier FROM scores" "SELECT songId, songDifficulty, score, perfectCount, nearCount, missCount, "
"date, modifier FROM scores"
).fetchall() ).fetchall()
for ( for (
song_id, song_id,
@ -48,7 +46,7 @@ class St3ScoreParser(ArcaeaParser):
date=fix_timestamp(date), date=fix_timestamp(date),
modifier=modifier, modifier=modifier,
clear_type=clear_type, clear_type=clear_type,
comment=f"Parsed from st3", comment="Parsed from st3",
) )
) )
@ -67,8 +65,9 @@ class St3ScoreParser(ArcaeaParser):
if query_score and skip_duplicate: if query_score and skip_duplicate:
logger.info( logger.info(
f"{repr(parsed_score)} skipped because " "%r skipped because potential duplicate item %r found.",
f"potential duplicate item {repr(query_score)} found." parsed_score,
query_score,
) )
continue continue
session.add(parsed_score) session.add(parsed_score)

View File

@ -122,7 +122,9 @@ class ArcSongJsonBuilder:
pack = self.session.scalar(select(Pack).where(Pack.id == song.set)) pack = self.session.scalar(select(Pack).where(Pack.id == song.set))
if not pack: if not pack:
logger.warning(f'Cannot find pack "{song.set}", using placeholder instead.') logger.warning(
'Cannot find pack "%s", using placeholder instead.', song.set
)
pack = Pack(id="unknown", name="Unknown", description="__PLACEHOLDER__") pack = Pack(id="unknown", name="Unknown", description="__PLACEHOLDER__")
song_localized = self.session.scalar( song_localized = self.session.scalar(
select(SongLocalized).where(SongLocalized.id == song.id) select(SongLocalized).where(SongLocalized.id == song.id)

View File

@ -1,8 +1,12 @@
# pylint: disable=too-few-public-methods
from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm.exc import DetachedInstanceError from sqlalchemy.orm.exc import DetachedInstanceError
class ReprHelper: class ReprHelper:
# pylint: disable=no-member
def _repr(self, **kwargs) -> str: def _repr(self, **kwargs) -> str:
""" """
Helper for __repr__ Helper for __repr__

View File

@ -1,3 +1,5 @@
# pylint: disable=too-few-public-methods
from sqlalchemy import TEXT from sqlalchemy import TEXT
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

View File

@ -1,3 +1,5 @@
# pylint: disable=too-few-public-methods, duplicate-code
from typing import Optional from typing import Optional
from sqlalchemy import TEXT, case, func, inspect, select, text from sqlalchemy import TEXT, case, func, inspect, select, text
@ -37,7 +39,8 @@ class Score(ScoresBase):
comment="0: NORMAL, 1: EASY, 2: HARD" comment="0: NORMAL, 1: EASY, 2: HARD"
) )
clear_type: Mapped[Optional[int]] = mapped_column( clear_type: Mapped[Optional[int]] = mapped_column(
comment="0: TRACK LOST, 1: NORMAL CLEAR, 2: FULL RECALL, 3: PURE MEMORY, 4: EASY CLEAR, 5: HARD CLEAR" comment="0: TRACK LOST, 1: NORMAL CLEAR, 2: FULL RECALL, "
"3: PURE MEMORY, 4: EASY CLEAR, 5: HARD CLEAR"
) )
comment: Mapped[Optional[str]] = mapped_column(TEXT()) comment: Mapped[Optional[str]] = mapped_column(TEXT())

View File

@ -1,3 +1,5 @@
# pylint: disable=too-few-public-methods, duplicate-code
from typing import Optional from typing import Optional
from sqlalchemy import TEXT, ForeignKey, func, select from sqlalchemy import TEXT, ForeignKey, func, select
@ -154,7 +156,7 @@ class ChartInfo(SongsBase):
ForeignKey("difficulties.rating_class"), primary_key=True ForeignKey("difficulties.rating_class"), primary_key=True
) )
constant: Mapped[int] = mapped_column( constant: Mapped[int] = mapped_column(
comment="real_constant * 10. For example, Crimson Throne [FTR] is 10.4, then store 104 here." comment="real_constant * 10. For example, Crimson Throne [FTR] is 10.4, then store 104."
) )
notes: Mapped[Optional[int]] notes: Mapped[Optional[int]]

View File

@ -103,7 +103,7 @@ class Searcher:
return list(results) return list(results)
def search(self, string: str, *, limit: int = 10, fuzzy_distance: int = 10): def search(self, string: str, *, limit: int = 10):
query_string = f"{string}" query_string = f"{string}"
query = self.default_query_parser.parse(query_string) query = self.default_query_parser.parse(query_string)
with self.index.searcher() as searcher: with self.index.searcher() as searcher: