Skip to content

feat: Streamlit 디버그 UI를 khoa 템플릿에 맞춰 정합 (fixture 저장 배선, enum 파라미터, 에러 상세) - #14

Merged
digitie merged 1 commit into
mainfrom
feat/unify-streamlit-debug-ui
Aug 29, 2026
Merged

digitie merged 1 commit into
mainfrom
feat/unify-streamlit-debug-ui

Conversation

@digitie

@digitie digitie commented Aug 29, 2026

Copy link
Copy Markdown
Owner

배경

이번 세션에서 여러 저장소의 Streamlit 디버그 UI를 하나의 표준 템플릿(examples/streamlit_debug_ui.py, 6개 고정 탭, 카탈로그 기반 제네릭 렌더링)으로 통일하는 작업 중 하나입니다. 기준 템플릿은 python-khoa-api의 examples/streamlit_debug_ui.py / src/khoa/debug.py입니다.

이 저장소(python-krex-api)는 조사 시점에 이미 표준 경로 컨벤션과 카탈로그 기반 제네릭 렌더링(inspect.signature 기반 자동 위젯 생성, if function_name == ... 하드코딩 분기 없음)을 쓰고 있어 khoa 다음으로 격차가 작은 저장소였습니다. 이번 PR은 조사에서 지목된 남은 4가지 격차를 좁힙니다.

변경 사항

  1. pyproject.toml: debug-ui extra를 템플릿과 정확히 ["pandas>=2", "streamlit>=1.36"]로 맞춤 (기존에는 streamlit>=1.35만 있었고 pandas가 없었음).
  2. Processed Result 탭: st.dataframe(rows) 대신 pd.json_normalize(rows, sep=".")를 사용해 raw.* 같은 중첩 필드를 컬럼으로 펼쳐서 보여줌.
  3. enum 파라미터 → selectbox: ParameterSpec에 kind/choices 필드를 추가하고, codes.py에 이미 있는 KrexCode 서브클래스(RoadOperator, CarType, IOType, TimeUnit, TCSType, Direction, DiscountType)를 실제 위젯으로 노출했습니다.
    • 주의: krex/client.py가 from __future__ import annotations를 쓰기 때문에 기본 inspect.signature()는 어노테이션을 문자열로 반환합니다('RoadOperator | str'). eval_str=True로 호출해야 실제 타입 객체를 얻어 enum을 감지할 수 있어, 이 부분을 함께 고쳤습니다(원래 계획엔 없었지만 고치지 않으면 enum selectbox가 전부 text_input으로 렌더링되는 실제 버그였습니다).
    • 필수 파라미터는 codes.py의 기존 기본값(예: traffic.by_ic의 ex_div_code="00")을 그대로 selectbox 초기값으로 쓰고, 선택 파라미터는 (미설정) 빈 옵션을 추가해 값 생략이 여전히 가능하도록 했습니다.
  4. 에러 딕셔너리 구조화: krex/debug.py의 exception_to_debug_error()가 이제 type/message에 더해 traceback 전체와, KrexError 계열이면 code/http_status/retry_after/url/params provider 필드를 채웁니다. 반환 전 redact_sensitive()를 거쳐 params 안의 key/serviceKey 등을 마스킹합니다.
  5. Fixture / Testcase 탭 배선 (가장 중요): 기존에는 to_fixture_dict() 미리보기만 있고 실제 저장 버튼이 없었습니다. 이제 case name / description / assertion mode(snapshot/schema_only/required_fields/count) / exclude fields / required fields / overwrite 체크박스를 입력받고, "Save as fixture" 버튼이 실제 save_fixture()를 호출해 tests/fixtures/{function}/{case}.json에 저장합니다.

검증

  • python -m pytest -q -m "not live" → 84 passed, 5 deselected
  • python -m ruff check . → All checks passed
  • python -m mypy src/krex → Success: no issues found in 10 source files
  • Streamlit AppTest 스모크 테스트: streamlit.testing.v1.AppTest로 앱을 직접 구동해 확인했습니다.
    • 최초 렌더링에 예외 없음, 6개 탭 정확히 생성됨.
    • traffic.by_ic 선택 시 ex_div_code/in_out/time_unit/tcs_type/car_type 5개가 실제로 st.selectbox로 렌더링되고 기본값이 기존 DEFAULT_PARAMS와 일치함을 확인.
    • 로컬 .env의 실제 키로 라이브 호출 → Pydantic Model / Processed Result(24개 컬럼으로 pd.json_normalize 펼쳐짐) / Validation Errors(success) 모두 정상 렌더링.
    • 더미 키로 라이브 호출 → KrexError 발생, Validation Errors 탭에 type/message/traceback/code/http_status/retry_after/url/params 전 필드가 채워진 JSON이 표시되고 params.key가 <REDACTED>로 마스킹됨을 확인.
    • Fixture 탭에서 "Save as fixture" 클릭 → 스크래치 디렉터리에 실제 traffic-by-ic/traffic-by-ic-debug.json 파일이 생성되고 "Saved: ..." 성공 메시지가 표시됨을 확인.

커버하지 못한 부분 (정직하게 공개)

  • Debug Trace 탭은 이번 조사에서 지목된 4가지 격차에 포함되지 않아 손대지 않았습니다. 현재도 catalog 테이블 + 선택 API json + run.trace 리스트 + DebugRun.catalog 테이블을 보여주지만, khoa 템플릿처럼 요청 URL/파라미터/응답 상태코드/소요시간을 한 번에 정리한 형태는 아닙니다(다만 URL/status_code/소요 관련 정보는 Raw Response 탭의 run.request/run.response에서 이미 확인 가능합니다).
  • 카탈로그(ApiCatalogItem)에 required_params/optional_params 필드는 추가하지 않았습니다. 이 저장소는 khoa처럼 카탈로그 dict에 파라미터 메타데이터를 박아두는 대신 inspect.signature(method, eval_str=True)로 실제 클라이언트 메서드 시그니처를 읽어 폼을 생성합니다. 이 방식은 하드코딩 분기 없이 여전히 제네릭하고, 시그니처가 바뀌면 자동으로 반영된다는 장점이 있어 굳이 중복되는 메타데이터 필드를 추가하지 않았습니다. 다만 표준 템플릿과 100% 동일한 데이터 모델은 아니라는 점을 밝혀둡니다.
  • enum selectbox는 codes.py에 정의된 KrexCode 서브클래스가 타입 힌트로 잡히는 파라미터에 한해서만 적용됩니다(ex_div_code, in_out, time_unit, tcs_type, car_type, direction, discount_type 등). unit_code, route_no, vds_id 같은 순수 문자열 코드는 여전히 text_input이며, 이는 애초에 enum이 아니므로 의도된 동작입니다.
  • traffic.avc_raw, restarea.list_all 등 라이브 자격증명이 필요한 나머지 API 전부를 이번 스모크 테스트에서 개별 실행해보지는 않았습니다(대표로 traffic.by_ic 1건만 성공/실패 양쪽 경로를 라이브로 확인). 폼 생성 로직 자체는 카탈로그 전체 API에 대해 일괄 동작하는 제네릭 코드이므로 나머지 API도 동일하게 동작할 것으로 예상하지만, 100% 커버리지를 주장하지는 않습니다.

참고

  • 템플릿 원본: python-khoa-api의 examples/streamlit_debug_ui.py(534줄), src/khoa/debug.py

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01XF9V2q4mAmhmXn6t5G9Hfe

…rror detail)

khoa의 examples/streamlit_debug_ui.py를 기준 템플릿으로 삼아 이 저장소의
Streamlit 디버그 UI에 남아있던 격차를 좁힌다.

- pyproject.toml debug-ui extra에 pandas>=2 추가, streamlit 하한을 1.36으로
  올려 템플릿과 정확히 맞춘다.
- Processed Result 탭이 st.dataframe(rows) 대신 pd.json_normalize(rows,
  sep=".")를 쓰도록 바꿔 raw.* 중첩 필드를 컬럼으로 펼친다.
- ParameterSpec에 kind/choices 필드를 추가하고, inspect.signature를
  eval_str=True로 호출해 `RoadOperator | str` 같은 문자열 어노테이션에서
  실제 KrexCode 서브클래스를 복원한 뒤 codes.py의 기존 enum choices()를
  selectbox로 노출한다(하드코딩 if function_name== 분기 없이 여전히
  카탈로그/시그니처 기반 제네릭 렌더링 유지).
- debug.exception_to_debug_error가 traceback과 KrexError의 provider 필드
  (code/http_status/retry_after/url/params)를 담도록 확장하고
  redact_sensitive()를 통과시킨다.
- Fixture / Testcase 탭이 미리보기만 하던 것을 case name/description/
  assertion mode 입력과 실제 save_fixture() 호출 버튼으로 배선한다.

AppTest로 실제 라이브 API 호출(성공/인증실패 양쪽 경로)과 fixture 저장까지
스모크 테스트로 검증했다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XF9V2q4mAmhmXn6t5G9Hfe
@digitie
digitie merged commit c6d8717 into main Aug 29, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant