mirror of
https://github.com/NomaDamas/k-skill.git
synced 2026-06-24 02:04:11 +00:00
Keep malformed KTX seat payloads actionable
Convert malformed Korail seat-detail payloads into the existing CLI failure path so advisory lookup callers get a clear retryable error instead of an AttributeError. Constraint: PR #295 review watch item identified successful-but-malformed seat_infos payloads as an unhelpful crash surface. Rejected: Letting raw adapter fallbacks leak AttributeError | CLI users need actionable SystemExit diagnostics at the command boundary. Confidence: high Scope-risk: narrow Directive: Keep detailed seat lookup advisory; validate raw Korail shapes before exposing fields to JSON callers. Tested: PYTHONPATH=.:scripts python3 -m unittest scripts.test_ktx_booking; node --test scripts/skill-docs.test.js; npm run typecheck; python3 -m compileall -q scripts/ktx_booking.py scripts/test_ktx_booking.py; ruff check scripts/ktx_booking.py scripts/test_ktx_booking.py; shellcheck scripts/validate-skills.sh; bash scripts/validate-skills.sh; PATH=<pyenv 3.11.9 shim> npm run ci Not-tested: Plain npm run ci with /opt/homebrew Python 3.14 due local pyexpat/libexpat linkage error reproduced before project tests.
This commit is contained in:
parent
70b92d6b03
commit
eb08ef6134
2 changed files with 46 additions and 1 deletions
|
|
@ -927,9 +927,20 @@ def command_seats(args: argparse.Namespace) -> None:
|
|||
car_payloads: list[dict[str, object]] = []
|
||||
for car in cars:
|
||||
raw = client.car_seats(raw_train, str(car["car_no_raw"]), passenger_count, room_class)
|
||||
raw_seats = raw.get("seat_infos", {}).get("seat_info", [])
|
||||
seat_infos = raw.get("seat_infos") if isinstance(raw, dict) else None
|
||||
if not isinstance(seat_infos, dict):
|
||||
raise SystemExit(
|
||||
f"seat detail data is unavailable for car_no {car['car_no']}; "
|
||||
"retry search or choose another train"
|
||||
)
|
||||
raw_seats = seat_infos.get("seat_info", [])
|
||||
if isinstance(raw_seats, dict):
|
||||
raw_seats = [raw_seats]
|
||||
if not isinstance(raw_seats, list):
|
||||
raise SystemExit(
|
||||
f"seat detail data is unavailable for car_no {car['car_no']}; "
|
||||
"retry search or choose another train"
|
||||
)
|
||||
all_seats = [normalize_seat(seat) for seat in raw_seats if seat.get("h_con_seat_no") != "0A"]
|
||||
seats = sort_seats_for_booking(all_seats)
|
||||
if args.available_only:
|
||||
|
|
|
|||
|
|
@ -797,6 +797,40 @@ class KtxBookingTests(unittest.TestCase):
|
|||
|
||||
self.assertIn("car_no 5", str(exc.exception))
|
||||
|
||||
def test_command_seats_fails_when_seat_payload_is_malformed(self):
|
||||
selected = FakeTrain(train_no="009", dep_time="090000", arr_time="113000", label="selected")
|
||||
train_id = ktx_booking.normalize_train(selected, index=1)["train_id"]
|
||||
client = FakeClient(
|
||||
[],
|
||||
train_details=[(selected, {"h_trn_no": "009"})],
|
||||
cars=[{"h_srcar_no": "05", "h_psrm_cl_cd": "1", "h_seat_cnt": "48", "h_rest_seat_cnt": "4"}],
|
||||
)
|
||||
client.car_seats = lambda *args, **kwargs: {"seat_infos": None}
|
||||
args = argparse.Namespace(
|
||||
dep="서울",
|
||||
arr="부산",
|
||||
date="20260328",
|
||||
time="090000",
|
||||
adults=1,
|
||||
children=0,
|
||||
toddlers=0,
|
||||
seniors=0,
|
||||
train_id=train_id,
|
||||
room="general",
|
||||
train_type="ktx",
|
||||
car_no=None,
|
||||
available_only=False,
|
||||
power_only=False,
|
||||
limit=10,
|
||||
)
|
||||
|
||||
with patch.object(ktx_booking, "build_client", return_value=client):
|
||||
with self.assertRaises(SystemExit) as exc:
|
||||
with redirect_stdout(io.StringIO()):
|
||||
ktx_booking.command_seats(args)
|
||||
|
||||
self.assertIn("seat detail data is unavailable", str(exc.exception))
|
||||
|
||||
def test_command_seats_fails_when_car_data_is_unavailable(self):
|
||||
selected = FakeTrain(train_no="009", dep_time="090000", arr_time="113000", label="selected")
|
||||
train_id = ktx_booking.normalize_train(selected, index=1)["train_id"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue