fix: 한국어 Windows 환경에서 설치·수집이 실패하는 문제 두 건 - #1
sikkkkkkkkkk wants to merge 2 commits into
Conversation
한국어 로케일 Windows 에서 갓 clone 한 저장소가 설치 단계에서 멈추거나,
설치가 '전체 통과' 로 보고된 뒤 수집이 전부 실패하는 문제를 고친다.
둘 다 이 도구의 주 사용자층(한국어 Windows 비개발자)이 정면으로 맞는 조건이다.
1) requirements.txt — pip 이 파일을 로케일 인코딩(cp949)으로 읽어 실패
pip 은 requirements 파일을 locale.getpreferredencoding() 으로 디코딩한다.
한국어 Windows 에서는 cp949 라서 파일 첫 줄의 한글 주석에서 바로 죽는다:
UnicodeDecodeError: 'cp949' codec can't decode byte 0xec in position 9
setup.ps1 의 1/4 단계가 통째로 실패한다. 경로와는 무관하며(ASCII 경로에서도 재현)
한국어 로케일이면 누구나 맞는다.
pip 은 첫 두 줄의 PEP 263 선언을 인식하므로 coding 선언 한 줄로 해결된다.
pip 24.0(3.12 번들본)에서 재현 후 수정 확인했다.
2) CA 번들 — 경로에 한글이 있으면 모든 HTTPS 요청이 실패
Windows 의 libcurl 은 CA 파일 경로를 ANSI 로 연다. 저장소를 한글 폴더에 두거나
사용자명이 한글이면 certifi 번들을 못 읽고 모든 요청이 죽는다:
curl: (77) error adding trust anchors from locations: CAfile: ...
utils.ensure_ascii_ca_bundle() 이 번들을 ASCII 경로로 복사하고 CURL_CA_BUNDLE
을 그리로 향하게 한다. utils import 시점에 적용되므로 생성되는 crawl_script.py
와 preflight 가 같은 조건으로 동작한다. 사용자가 이미 CURL_CA_BUNDLE 을
지정했으면 건드리지 않는다.
preflight 의 HTTP fetch 검증에서 이 경우만 WARN 이 아니라 FAIL 로 올린다.
기존에는 '네트워크 제한 가능' WARN 이라 CORE 가 전부 PASS 로 요약되고
'[OK] 전체 통과' 로 끝났다 — 실제로는 수집이 하나도 안 되는 상태였다.
오프라인·방화벽으로 인한 실패는 지금처럼 WARN 으로 남는다.
테스트: 431 passed (기존 428 + CA 번들 3건). 새 테스트는 저장소 위치와 무관하게
동작한다 — conftest 가 tmp_path 를 저장소 안으로 고정해서 ASCII 상위 경로를 따로 찾는다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ensure_ascii_ca_bundle() 호출을 fetch 의 try 블록 밖으로 뺀다. 같은 블록 안에 두면 `import utils` 가 실패했을 때 바깥 except 가 그것을 잡아 "네트워크 제한 가능: No module named 'utils'" 로 보고한다. 원인은 import 인데 안내는 오프라인·방화벽을 가리키게 되어 진단을 엉뚱한 곳으로 보낸다. import 이 실패해도 fetch 자체는 그대로 시도한다 — CA 처리는 보조이고, 검증의 본체는 fetch 다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI 검증 (fork PR 이라 워크플로 승인 전이어서 로컬에서 동일 조건으로 돌렸습니다)
같은 조건에서 Windows 로컬(3.12)에서는 e2e 포함 431 passed 입니다. 참고 — 처음에
|
정정 — 2번 항목의 발생 조건을 잘못 적었습니다본문을 수정했습니다. 제출 당시 "한글 경로에 clone 하면 모든 HTTPS 요청이 죽는다" 고 썼는데 사실이 아닙니다. 정확한 조건은 경위. 1번(pip cp949) 문제를 우회하려고 제 셋업 명령에 FAIL 분기 검증도 부실했습니다. 없는 파일( PR 을 유지한 이유. 조건을 알고 나서도 고칠 값어치는 있다고 판단했습니다. 사용자가 인코딩 문제로 다만 지금 당장 아무도 겪지 않는 문제인 것은 맞습니다. 2번을 빼고 1번만 받으시는 편이 낫다고 보시면 해당 커밋을 덜어내겠습니다. 판단에 필요한 정보를 처음에 틀리게 드려서 죄송합니다. 1번(pip cp949) 은 영향받지 않습니다. |
무엇을 고치나
한국어 로케일 Windows 에서 겪은 두 건입니다. 1번은 기본 설치 절차에서 바로 터지는 문제이고, 2번은 특정 조건에서만 터지지만 곧 기본값이 될 조건입니다. 성격이 달라 나눠 적습니다.
1.
requirements.txt— pip 이 cp949 로 읽어 설치가 통째로 실패 (기본 절차에서 발생)README 가 안내하는
powershell -ExecutionPolicy Bypass -File scripts\setup.ps1의 1/4 단계에서 즉시 실패합니다.pip 은 requirements 파일을
locale.getpreferredencoding()으로 디코딩합니다. 한국어 Windows 에서는cp949라서 파일 첫 줄의 한글 주석(# 범용 웹 크롤링 에이전트 …)에서 바로 죽습니다.python -m venv로 갓 만든 venv 에서 발생합니다.pip 은 첫 두 줄의 PEP 263 선언을 인식하므로 coding 선언 한 줄로 해결됩니다. 구버전 pip 에서도 동작하고, 수동
pip install -r requirements.txt경로까지 함께 덮습니다.재현 및 확인 (깨끗한 venv, pip 24.0, ASCII 경로)
2. CA 번들 — UTF-8 모드 + 비ASCII 경로에서 모든 HTTPS 요청 실패
발생 조건은 두 가지가 모두 맞을 때입니다.
PYTHONUTF8=1또는-X utf8) — 이때 파이썬 파일시스템 인코딩이 UTF-8 이 되어 경로를 UTF-8 바이트로 넘깁니다둘이 어긋나서 파일을 못 엽니다. 한쪽만으로는 발생하지 않습니다. 같은 한글 경로에서도 UTF-8 모드가 꺼져 있으면 정상 동작합니다(cp949 로 인코딩되어 ANSI 와 일치).
따라서 README 대로 설치한 사용자는 이 문제를 만나지 않습니다. 이 저장소는
PYTHONUTF8을 어디서도 설정하지 않습니다.그럼에도 고칠 값어치가 있다고 본 이유:
PYTHONUTF8=1을 스스로 켜는 일이 흔합니다 (저도 1번 문제를 우회하려다 켰고, 그래서 이 버그를 만났습니다)utils.ensure_ascii_ca_bundle()이 번들을 ASCII 경로로 복사하고CURL_CA_BUNDLE을 그리로 향하게 합니다.utilsimport 시점에 적용되므로 생성되는crawl_script.py와 preflight 가 같은 조건으로 동작합니다. 경로가 이미 ASCII 면 아무것도 하지 않고, 사용자가CURL_CA_BUNDLE을 지정했다면 건드리지 않습니다.확인: 수정본 +
PYTHONUTF8=1+ 한글 경로 → preflightCORE PASS 13 / FAIL 0.판단은 메인테이너 몫입니다. 지금 당장 아무도 겪지 않는 문제라 2번을 빼고 1번만 받는 선택도 합리적입니다. 그러시면 해당 커밋만 덜어내겠습니다.
2-1. preflight — CA 실패가 WARN 이라 '전체 통과' 로 덮이던 문제
위 상황이 실제로 벌어졌을 때 preflight 는 이렇게 보고했습니다:
HTTPS 수집이 하나도 안 되는 상태인데 "전체 통과" 로 끝나고, 안내 문구가 오프라인을 가리켜 원인에서 멀어집니다. 이 경우만 FAIL 로 올렸습니다. 오프라인·방화벽 실패는 지금처럼 WARN 으로 남습니다.
이 변경은 2번을 빼더라도 단독으로 의미가 있다고 생각합니다.
변경 파일
requirements.txtscripts/utils.pyensure_ascii_ca_bundle()추가, import 시점 적용scripts/preflight.pyensure_ascii_ca_bundle()호출scripts/test_utils.py테스트
python:3.11-slim컨테이너, Linux fresh checkout:418 passed, 두 sync 검사 OK, exit 0.masterbaseline 도 동일하게 통과 (아래 코멘트)431 passed(기존 428 + 신규 3)리뷰어가 볼 만한 지점
utils.pyimport 시점 부수효과. 이 모듈은 지금까지 import 부수효과가 없었습니다. 생성되는crawl_script.py가 첫 요청 전에 자동으로 거치게 하려면 이 자리가 확실하다고 봤는데, 명시적 호출을 선호하시면 바꾸겠습니다.utils를 import 하지 않는 수집 스크립트는 여전히 영향을 받습니다. venv 에sitecustomize.py를 심으면 완전히 덮이지만 더 침습적이라 택하지 않았습니다.tmp_path를 쓰지 않는 이유.pytest.ini의--basetemp=.tmp/pytest때문에tmp_path가 저장소 안에 생기는데, 저장소가 한글 폴더면 그 경로가 비ASCII 라 "경로의 ASCII 여부" 를 검증할 수 없습니다. 그래서 ASCII 상위 경로를 따로 찾습니다.sync_codex_mirror.py의build_mirror()가write_text()로 쓰는데 개행이 플랫폼 기본값입니다. Windows 에서 실행해 커밋하면 미러가 CRLF 로 들어가 CI 가 깨질 수 있습니다.newline="\n"으로 막을 수 있습니다. 범위 밖이라 건드리지 않았습니다.🤖 Generated with Claude Code