Skip to content

Commit

Permalink
select all ruff rules
Browse files Browse the repository at this point in the history
  • Loading branch information
Samoed committed Sep 7, 2024
1 parent b1ca3b6 commit a82b012
Show file tree
Hide file tree
Showing 14 changed files with 61 additions and 88 deletions.
20 changes: 10 additions & 10 deletions courses_processor/compare_courses.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
preselection_file = "Таблица предвыборности.xlsx"


def standardize_course_name(course):
def standardize_course_name(course: str) -> str | None:
if not isinstance(course, str):
return None

Expand Down Expand Up @@ -83,24 +83,24 @@ def standardize_course_name(course):
return course


def timetable_parser(timetable_filename: str):
df = pd.read_excel(timetable_filename, sheet_name="Расписание")
timetable = df.iloc[2:, 5:10].to_numpy().flatten()
def timetable_parser(timetable_filename: str) -> set[str]:
timetable_df = pd.read_excel(timetable_filename, sheet_name="Расписание")
timetable = timetable_df.iloc[2:, 5:10].to_numpy().flatten()
t = pd.Series(timetable)
full_courses = set(t[pd.notna(t)].tolist())
return set(filter(None, map(standardize_course_name, full_courses)))


def preselection_parser(preselection_filename: str, preselection_params):
df = pd.read_excel(preselection_filename, sheet_name=preselection_params["name"])
courses_row = df.iloc[1, 4:-5]
def preselection_parser(preselection_filename: str, preselection_params: dict[str, str]) -> set[str]:
preselection_df = pd.read_excel(preselection_filename, sheet_name=preselection_params["name"])
courses_row = preselection_df.iloc[1, 4:-5]
courses = set(courses_row.tolist())
return set(filter(None, map(standardize_course_name, courses)))


def notion_parser(notion_filename: str) -> set[str]:
df = pd.read_csv(notion_filename)
courses = df["Курсы"].tolist()
notion_df = pd.read_csv(notion_filename)
courses = notion_df["Курсы"].tolist()
standardized_courses = []
for course in map(standardize_course_name, courses):
if isinstance(course, list):
Expand All @@ -110,7 +110,7 @@ def notion_parser(notion_filename: str) -> set[str]:
return set(standardized_courses)


def main(course_folder: str, preselection_params):
def main(course_folder: str, preselection_params: dict[str, str]) -> tuple[set[str], set[str], set[str]]:
notion_courses = notion_parser(course_folder + notion_file)
timetable_courses = timetable_parser(course_folder + timetable_file)
preselection_courses = preselection_parser(course_folder + preselection_file, preselection_params)
Expand Down
43 changes: 5 additions & 38 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,49 +97,16 @@ target-version = "py310"
line-length = 120

[tool.ruff.lint]
select= [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"UP", # pyupgrade
"RUF", # ruff
"N", # flake8-naming
"S", # flake8-bandit
"BLE", # flake8-blind-except
"A", # flake8-builtins
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"PIE", # flake8-pie
"INP", # flake8-no-pep420
"T20", # flake8-print
"PT", # flake8-pytest-style
"RET", # flake8-return
"SIM", # flake8-simplify
"ARG", # flake8-unused-arguments
"PTH", # flake8-use-pathlib
"PL", # pylint
"NPY", # NumPy-specific rules
"TCH", # flake8-type-checking
"TID", # flake8-tidy-imports
# "FAST", # fastapi
# "D", # pydocstyle
# "G", # flake8-logging-format
# "EM", # flake8-errmsg
]
ignore = [
"RUF001",
"ISC001",
]
select= ["ALL"]
ignore = ["D", "EM", "TRY", "G", "COM812", "ISC001"]
allowed-confusables = ["а", "с", "е", "З", "о", "г", "х", "у", "А", "С", "Е", "З", "О", "Р", "В", "М", "К", "р", "В"]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F405", "F403", "D"]
"tests/*.py" = ["S", "PLR2004"]
"tests/*.py" = ["S", "PLR2004", "ERA", "D", "ANN", "SLF"]
"src/itmo_ai_timetable/db/migrations/versions/*.py" = ["N999"]
"courses_processor/*.py" = ["PTH", "T201", "PLW2901", "RUF003", "INP001"]
"src/itmo_ai_timetable/gcal.py" = ["ERA"]

[tool.ruff.lint.isort]
known-first-party = ["itmo_ai_timetable"]
Expand Down
4 changes: 2 additions & 2 deletions src/itmo_ai_timetable/cleaner.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def course_name_cleaner(course: str) -> str | None:
),
"Симулятор DS от Karpov.courses": "Симулятор DS от Karpov.Courses",
"DS симулятор от Karpov.courses": "Симулятор DS от Karpov.Courses",
# appears in only course description
# "Программирование на С++": ["C++ Lite", "C++ Hard"], # noqa: RUF003
# appears in only course description, but this function only uses for preselection and timetable
# "Программирование на С++": ["C++ Lite", "C++ Hard"],
"Uplift-моделирование": "UPLIFT-моделирование",
"Продвинутое A/B-тестирование": "Продвинутое А/B - тестирование",
"А/В тестирование и Reliable ML": "А/В тестирование",
Expand Down
25 changes: 17 additions & 8 deletions src/itmo_ai_timetable/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
import json
from pathlib import Path

from repository import Repository

from itmo_ai_timetable.logger import get_logger
from itmo_ai_timetable.repository import Repository
from itmo_ai_timetable.schedule_parser import ScheduleParser
from itmo_ai_timetable.selection_parser import SelectionParser
from itmo_ai_timetable.transform_ics import export_ics
Expand All @@ -24,14 +23,20 @@ def create_args() -> argparse.Namespace:
subparsers = parser.add_subparsers(required=True, dest="subparser_name")
schedule_parser = subparsers.add_parser(SubparserName.SCHEDULE, help="Обработка excel в ics")
schedule_parser.add_argument(
"--filepath", help="Путь к файлу excel", default="Расписание 1 курс весна 2024.xlsx", type=str
"--filepath",
help="Путь к файлу excel",
default="Расписание 1 курс весна 2024.xlsx",
type=str,
)
schedule_parser.add_argument("--output_path", help="Папка для экспорта ics", default="ics", type=str)
schedule_parser.add_argument("--sheet", help="Страница с расписанием в excel файле", default=0, type=int)

selection_parser = subparsers.add_parser(SubparserName.SELECTION, help="Обработка excel с выборностью")
selection_parser.add_argument(
"--filepath", help="Путь к файлу excel", default="Таблица предвыборности осень 2024 (2 курс).xlsx", type=str
"--filepath",
help="Путь к файлу excel",
default="Таблица предвыборности осень 2024 (2 курс).xlsx",
type=str,
)
selection_parser.add_argument("--output_path", help="Папка для экспорта ics", default="ics", type=str)
selection_parser.add_argument("--sheet_name", help="Страница с расписанием в excel файле", type=str)
Expand All @@ -41,7 +46,11 @@ def create_args() -> argparse.Namespace:
selection_parser.add_argument("--name_column", help="Столбец с именами", default="A", type=str)
selection_parser.add_argument("--course_number", help="Номер курса", default=2, type=int)
selection_parser.add_argument(
"--db", help="Сохранить результат в db", action=argparse.BooleanOptionalAction, type=bool, default=False
"--db",
help="Сохранить результат в db",
action=argparse.BooleanOptionalAction,
type=bool,
default=False,
)
return parser.parse_args()

Expand All @@ -56,8 +65,8 @@ async def main() -> None:
Path.mkdir(output_dir)
match args.subparser_name:
case SubparserName.SCHEDULE:
df = ScheduleParser(args.filepath, args.sheet_num).parse()
export_ics(df, output_path)
schedule = ScheduleParser(args.filepath, args.sheet_num).parse()
export_ics(schedule, output_path)
case SubparserName.SELECTION:
results = SelectionParser(
args.filepath,
Expand All @@ -67,7 +76,7 @@ async def main() -> None:
args.last_select_column,
args.name_column,
).parse()
with Path(output_path).open("w") as f:
with Path(output_path).open("w") as f: # noqa: ASYNC230
json.dump(results, f, ensure_ascii=False, indent=4)
course_number = args.course_number
if args.db:
Expand Down
4 changes: 3 additions & 1 deletion src/itmo_ai_timetable/db/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ class Class(Base):
end_time: Mapped[datetime]
class_type: Mapped[str] = mapped_column(nullable=True)
class_status_id: Mapped[int] = mapped_column(
ForeignKey("class_status.id"), nullable=False, default=get_class_status_id(ClassStatus.need_to_add)
ForeignKey("class_status.id"),
nullable=False,
default=get_class_status_id(ClassStatus.need_to_add),
)
gcal_event_id: Mapped[str] = mapped_column(nullable=True)

Expand Down
1 change: 0 additions & 1 deletion src/itmo_ai_timetable/db/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ def run_migrations_online() -> None:
and associate a connection with the context.
"""

connectable = config.attributes.get("connection", None)

if connectable is None:
Expand Down
4 changes: 2 additions & 2 deletions src/itmo_ai_timetable/db/session_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SessionManager:
def __new__(cls) -> "SessionManager":
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialize()
cls._instance._initialize() # noqa: SLF001
return cls._instance

def _initialize(self) -> None:
Expand All @@ -41,7 +41,7 @@ def engine(self) -> AsyncEngine:

def with_async_session(func: Callable[..., Any]) -> Callable[..., Any]:
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> Any:
async def wrapper(*args: Any, **kwargs: Any) -> Any: # noqa: ANN401
if "session" in kwargs:
return await func(*args, **kwargs)
session_maker = SessionManager().session_maker
Expand Down
11 changes: 6 additions & 5 deletions src/itmo_ai_timetable/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ async def get_course(course_name: str, session: AsyncSession) -> Course | None:

@staticmethod
async def get_existing_classes(
course_id: int, synced_status: ClassStatusTable, session: AsyncSession
course_id: int,
synced_status: ClassStatusTable,
session: AsyncSession,
) -> Sequence[Class]:
query = select(Class).filter(and_(Class.course_id == course_id, Class.class_status == synced_status))
result = await session.execute(query)
Expand Down Expand Up @@ -78,7 +80,7 @@ async def add_classes(classes: list[Pair], *, session: AsyncSession) -> list[str
@with_async_session
async def get_or_create_user(user_name: str, course_number: int, *, session: AsyncSession) -> User:
query = await session.execute(
select(User).filter(and_(User.user_real_name == user_name, User.studying_course == course_number))
select(User).filter(and_(User.user_real_name == user_name, User.studying_course == course_number)),
)
user = query.scalar()
if user is None:
Expand All @@ -90,9 +92,8 @@ async def get_or_create_user(user_name: str, course_number: int, *, session: Asy
@staticmethod
@with_async_session
async def create_matching(selected: dict[str, list[str]], course_number: int, *, session: AsyncSession) -> None:
"""
:param selected: contains pairs of names of users and courses he selected
""":param selected: contains pairs of names of users and courses he selected
:param course_number: number of course
:param session:
:return:
"""
Expand Down
2 changes: 1 addition & 1 deletion src/itmo_ai_timetable/schedule_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def _parse_row(self, cells: Iterable[Cell], pair_start: datetime, pair_end: date
name=title,
pair_type=pair_type,
link=link,
)
),
)
return pairs

Expand Down
11 changes: 6 additions & 5 deletions src/itmo_ai_timetable/selection_parser.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from collections import defaultdict

import openpyxl
from cleaner import course_name_cleaner
from openpyxl.cell import MergedCell
from openpyxl.utils import column_index_from_string

from itmo_ai_timetable.cleaner import course_name_cleaner


class SelectionParser:
def __init__(
Expand All @@ -15,7 +16,7 @@ def __init__(
first_select_column: str,
last_select_column: str,
name_column: str = "A",
):
) -> None:
self.workbook = openpyxl.load_workbook(filepath)
self.sheet = self.workbook[sheet_name]
self.course_row = course_row
Expand All @@ -24,7 +25,7 @@ def __init__(
self.name_column = name_column
self.data_start_row = course_row + 1

def parse(self) -> dict[str, list[str]]:
def parse(self) -> dict[str, list[str | None]]:
courses = self._get_courses()
return self._match_names_to_courses(courses)

Expand All @@ -33,7 +34,7 @@ def _get_courses(self) -> list[tuple[str, str]]:
for cell in self.sheet[self.course_row]:
if isinstance(cell, MergedCell):
if cell.column <= column_index_from_string(
self.start_column
self.start_column,
) or cell.column >= column_index_from_string(self.end_column):
break
raise ValueError(f"Cell {cell} is merged")
Expand All @@ -47,7 +48,7 @@ def _get_courses(self) -> list[tuple[str, str]]:
courses.append((cell.column_letter, cell.value))
return courses

def _match_names_to_courses(self, courses: list[tuple[str, str]]) -> dict[str, list[str]]:
def _match_names_to_courses(self, courses: list[tuple[str, str]]) -> dict[str, list[str | None]]:
matches = defaultdict(list)
for row in self.sheet.iter_rows(min_row=self.data_start_row, min_col=1, max_col=1):
name = row[0].value
Expand Down
4 changes: 1 addition & 3 deletions src/itmo_ai_timetable/settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Any

from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict

Expand All @@ -25,7 +23,7 @@ class Settings(BaseSettings):
timezone: str = "Europe/Moscow"

@property
def database_settings(self) -> Any:
def database_settings(self) -> dict[str, str | int]:
return {
"database": self.postgres_db,
"user": self.postgres_user,
Expand Down
2 changes: 1 addition & 1 deletion src/itmo_ai_timetable/transform_ics.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from ics import Calendar, Event # type: ignore
from ics import Calendar, Event # type: ignore[attr-defined]

from itmo_ai_timetable.schemes import Pair

Expand Down
10 changes: 3 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
def postgres() -> str:
settings = Settings()

tmp_name = ".".join([uuid4().hex, "pytest"])
tmp_name = f"{uuid4().hex}.pytest"
settings.postgres_db = tmp_name
environ["POSTGRES_DB"] = tmp_name

Expand Down Expand Up @@ -57,17 +57,13 @@ def alembic_config(postgres) -> Config:

@pytest.fixture
def alembic_engine(postgres):
"""
Override this fixture to provide pytest-alembic powered tests with a database handle.
"""
"""Override this fixture to provide pytest-alembic powered tests with a database handle."""
return create_async_engine(postgres, echo=True)


@pytest.fixture
async def _migrated_postgres(postgres, alembic_config: Config):
"""
Проводит миграции.
"""
"""Проводит миграции."""
await run_async_upgrade(alembic_config, postgres)


Expand Down
8 changes: 4 additions & 4 deletions tests/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ async def test_add_classes_new_course(session: AsyncSession):
end_time=end_time,
pair_type="Lecture",
link=None,
)
),
]

await Repository.add_classes(classes, session=session)
Expand Down Expand Up @@ -160,7 +160,7 @@ async def test_add_classes_existing_course(session: AsyncSession):
end_time=end_time,
pair_type="Lecture",
link=None,
)
),
]

await Repository.add_classes(classes, session=session)
Expand Down Expand Up @@ -198,7 +198,7 @@ async def test_add_classes_update_existing(session: AsyncSession):
end_time=end_time,
pair_type="Lab",
link=None,
)
),
]

await Repository.add_classes(classes, session=session)
Expand Down Expand Up @@ -235,7 +235,7 @@ async def test_add_classes_delete_existing(session: AsyncSession):
end_time=datetime(2023, 1, 1, 17, 30, tzinfo=tzinfo),
pair_type="Seminar",
link=None,
)
),
]

await Repository.add_classes(classes, session=session)
Expand Down

0 comments on commit a82b012

Please sign in to comment.