Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/hoa_majors/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pathlib import Path

from hoa_majors import __version__
from hoa_majors.cli import audit, courses, crawl, info, plans, search
from hoa_majors.cli import audit, courses, crawl, info, plans, repo, search
from hoa_majors.config import DEFAULT_DATA_DIR, logger


Expand Down Expand Up @@ -61,6 +61,12 @@ def main():
info_parser.add_argument("course_code", help="课程代码")
info_parser.add_argument("--data-dir", type=Path, default=DEFAULT_DATA_DIR, help="数据存储目录")

# repo
repo_parser = subparsers.add_parser("repo", help="获取课程对应的 OpenAuto 仓库 ID")
repo_parser.add_argument("plan_id", help="培养方案 ID (fah)")
repo_parser.add_argument("course_code", help="课程代码")
repo_parser.add_argument("--data-dir", type=Path, default=DEFAULT_DATA_DIR, help="数据存储目录")

if len(sys.argv) == 1:
parser.print_help()
sys.exit(0)
Expand Down Expand Up @@ -100,6 +106,8 @@ def main():
courses.list_courses(args.plan_id, args.data_dir)
elif args.command == "info":
info.get_course_info(args.plan_id, args.course_code, args.data_dir)
elif args.command == "repo":
repo.run(args)
else:
parser.print_help()

Expand Down
49 changes: 49 additions & 0 deletions src/hoa_majors/cli/repo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import tomllib
from pathlib import Path

from hoa_majors.config import logger


def load_lookup_table(data_dir: Path) -> dict:
"""Load the lookup_table.toml file"""
lookup_path = data_dir / "lookup_table.toml"
if not lookup_path.exists():
logger.warning(f"Lookup table not found at {lookup_path}")
return {}
try:
with open(lookup_path, "rb") as f:
return tomllib.load(f)
except Exception as e:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Catching a broad Exception can hide unexpected errors and make debugging harder. It's better to catch more specific exceptions that you expect to handle. In this case, tomllib.load can raise tomllib.TOMLDecodeError, and file operations can raise OSError.

Suggested change
except Exception as e:
except (tomllib.TOMLDecodeError, OSError) as e:

logger.error(f"Failed to load lookup table: {e}")
return {}


def get_repo_id(plan_id: str, course_code: str, data_dir: Path) -> str:
"""
获取课程对应的 OpenAuto 仓库 ID。

逻辑:
1. 如果 course_code 不在 lookup table 中 -> 返回 course_code
2. 如果该 course_code 下存在 plan_id 对应的 key -> 返回该 value
3. 如果该 course_code 下存在 DEFAULT key -> 返回 DEFAULT 对应的 value
4. 否则 -> 返回 course_code
"""
lookup = load_lookup_table(data_dir)

if course_code not in lookup:
return course_code

mapping = lookup[course_code]

if plan_id in mapping:
return mapping[plan_id]
elif "DEFAULT" in mapping:
return mapping["DEFAULT"]
else:
return course_code
Comment on lines +33 to +43

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for finding the repository ID can be simplified and made more concise by using the dict.get() method with default values. This improves readability and maintainability.

Suggested change
if course_code not in lookup:
return course_code
mapping = lookup[course_code]
if plan_id in mapping:
return mapping[plan_id]
elif "DEFAULT" in mapping:
return mapping["DEFAULT"]
else:
return course_code
mapping = lookup.get(course_code)
if not mapping:
return course_code
return mapping.get(plan_id, mapping.get("DEFAULT", course_code))



def run(args):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better code clarity and maintainability, it's good practice to add type hints to function arguments. The args parameter is an argparse.Namespace object. Using a string for the type hint avoids needing to import argparse just for type checking.

Suggested change
def run(args):
def run(args: "argparse.Namespace"):

"""Entry point for the repo command"""
repo_id = get_repo_id(args.plan_id, args.course_code, args.data_dir)
print(repo_id)